annotate projects/filter_IIR/render.cpp @ 12:a6beeba3a648

Initial support for higher matrix sample rates by reducing the number of channels. Input not tested yet, and not all examples updated to new format.
author andrewm
date Thu, 22 Jan 2015 19:00:22 +0000
parents 6810f166482f
children 06f93bef7dd2
rev   line source
victor@3 1 /*
victor@3 2 * render.cpp
victor@3 3 *
victor@3 4 * Created on: Oct 24, 2014
victor@3 5 * Author: Andrew McPherson and Victor Zappi
victor@3 6 */
victor@3 7
victor@3 8
victor@3 9 #include "../../include/render.h"
victor@3 10 #include "../../include/RTAudio.h" // to schedule lower prio parallel process
victor@3 11 #include <rtdk.h>
victor@3 12 #include <cmath>
victor@3 13 #include <stdio.h>
victor@3 14 #include "SampleData.h"
victor@3 15
victor@3 16 SampleData gSampleData; // User defined structure to get complex data from main
victor@3 17 int gReadPtr; // Position of last read sample from file
victor@3 18 int gNumChannels;
victor@3 19
victor@3 20 // filter vars
victor@3 21 float gLastX[2];
victor@3 22 float gLastY[2];
victor@3 23 double lb0, lb1, lb2, la1, la2 = 0.0;
victor@3 24
victor@3 25 // communication vars between the 2 auxiliary tasks
victor@3 26 int gChangeCoeff = 0;
victor@3 27 int gFreqDelta = 0;
victor@3 28
victor@3 29 void initialise_filter(float freq);
victor@3 30
victor@3 31 void calculate_coeff(float cutFreq);
victor@3 32
victor@3 33 bool initialise_aux_tasks();
victor@3 34
victor@3 35 // Task for handling the update of the frequencies using the matrix
victor@3 36 AuxiliaryTask gChangeCoeffTask;
victor@3 37
victor@3 38 void check_coeff();
victor@3 39
victor@3 40 // Task for handling the update of the frequencies using the matrix
victor@3 41 AuxiliaryTask gInputTask;
victor@3 42
victor@3 43 void read_input();
victor@3 44
victor@3 45
victor@3 46 extern float gCutFreq;
victor@3 47
victor@3 48
victor@3 49 // initialise_render() is called once before the audio rendering starts.
victor@3 50 // Use it to perform any initialisation and allocation which is dependent
victor@3 51 // on the period size or sample rate.
victor@3 52 //
victor@3 53 // userData holds an opaque pointer to a data structure that was passed
victor@3 54 // in from the call to initAudio().
victor@3 55 //
victor@3 56 // Return true on success; returning false halts the program.
victor@3 57
victor@3 58 bool initialise_render(int numChannels, int numMatrixFramesPerPeriod,
victor@3 59 int numAudioFramesPerPeriod, float matrixSampleRate,
victor@3 60 float audioSampleRate, void *userData)
victor@3 61 {
victor@3 62
victor@3 63 // Retrieve a parameter passed in from the initAudio() call
victor@3 64 gSampleData = *(SampleData *)userData;
victor@3 65
victor@3 66 gReadPtr = -1;
victor@3 67 gNumChannels = numChannels;
victor@3 68
victor@3 69 initialise_filter(200);
victor@3 70
victor@3 71 // Initialise auxiliary tasks
victor@3 72 if(!initialise_aux_tasks())
victor@3 73 return false;
victor@3 74
victor@3 75 return true;
victor@3 76 }
victor@3 77
victor@3 78 // render() is called regularly at the highest priority by the audio engine.
victor@3 79 // Input and output are given from the audio hardware and the other
victor@3 80 // ADCs and DACs (if available). If only audio is available, numMatrixFrames
victor@3 81 // will be 0.
victor@3 82
victor@3 83 void render(int numMatrixFrames, int numAudioFrames, float *audioIn, float *audioOut,
victor@3 84 uint16_t *matrixIn, uint16_t *matrixOut)
victor@3 85 {
victor@3 86 for(int n = 0; n < numAudioFrames; n++) {
victor@3 87 float sample = 0;
victor@3 88 float out = 0;
victor@3 89
victor@3 90 // If triggered...
victor@3 91 if(gReadPtr != -1)
victor@3 92 sample += gSampleData.samples[gReadPtr++]; // ...read each sample...
victor@3 93
victor@3 94 if(gReadPtr >= gSampleData.sampleLen)
victor@3 95 gReadPtr = -1;
victor@3 96
victor@3 97 out = lb0*sample+lb1*gLastX[0]+lb2*gLastX[1]-la1*gLastY[0]-la2*gLastY[1];
victor@3 98
victor@3 99 gLastX[1] = gLastX[0];
victor@3 100 gLastX[0] = out;
victor@3 101 gLastY[1] = gLastY[0];
victor@3 102 gLastY[0] = out;
victor@3 103
victor@3 104 for(int channel = 0; channel < gNumChannels; channel++)
victor@3 105 audioOut[n * gNumChannels + channel] = out; // ...and put it in both left and right channel
victor@3 106
victor@3 107 }
victor@3 108
victor@3 109 // Request that the lower-priority tasks run at next opportunity
victor@3 110 scheduleAuxiliaryTask(gChangeCoeffTask);
victor@3 111 scheduleAuxiliaryTask(gInputTask);
victor@3 112 }
victor@3 113
victor@3 114 // First calculation of coefficients
victor@3 115
victor@3 116 void initialise_filter(float freq)
victor@3 117 {
victor@3 118 calculate_coeff(freq);
victor@3 119 }
victor@3 120
victor@3 121
victor@3 122 // Calculate the filter coefficients
victor@3 123 // second order low pass butterworth filter
victor@3 124
victor@3 125 void calculate_coeff(float cutFreq)
victor@3 126 {
victor@3 127 // Initialise any previous state (clearing buffers etc.)
victor@3 128 // to prepare for calls to render()
victor@3 129 float sampleRate = 44100;
victor@3 130 double f = 2*M_PI*cutFreq/sampleRate;
victor@3 131 double denom = 4+2*sqrt(2)*f+f*f;
victor@3 132 lb0 = f*f/denom;
victor@3 133 lb1 = 2*lb0;
victor@3 134 lb2 = lb0;
victor@3 135 la1 = (2*f*f-8)/denom;
victor@3 136 la2 = (f*f+4-2*sqrt(2)*f)/denom;
victor@3 137 gLastX[0] = gLastX [1] = 0;
victor@3 138 gLastY[0] = gLastY[1] = 0;
victor@3 139
victor@3 140 }
victor@3 141
victor@3 142
victor@3 143 // Initialise the auxiliary tasks
victor@3 144 // and print info
victor@3 145
victor@3 146 bool initialise_aux_tasks()
victor@3 147 {
victor@3 148 if((gChangeCoeffTask = createAuxiliaryTaskLoop(&check_coeff, 90, "beaglert-check-coeff")) == 0)
victor@3 149 return false;
victor@3 150
victor@3 151 if((gInputTask = createAuxiliaryTaskLoop(&read_input, 50, "beaglert-read-input")) == 0)
victor@3 152 return false;
victor@3 153
victor@3 154 rt_printf("Press 'a' to trigger sample, 's' to stop\n");
victor@3 155 rt_printf("Press 'z' to low down cut-off freq of 100 Hz, 'x' to raise it up\n");
victor@3 156 rt_printf("Press 'q' to quit\n");
victor@3 157
victor@3 158 return true;
victor@3 159 }
victor@3 160
victor@3 161 // Check if cut-off freq has been changed
victor@3 162 // and new coefficients are needed
victor@3 163
victor@3 164 void check_coeff()
victor@3 165 {
victor@3 166 if(gChangeCoeff == 1)
victor@3 167 {
victor@3 168 gCutFreq += gFreqDelta;
victor@3 169 gCutFreq = gCutFreq < 0 ? 0 : gCutFreq;
victor@3 170 gCutFreq = gCutFreq > 22050 ? 22050 : gCutFreq;
victor@3 171
victor@3 172 rt_printf("Cut-off frequency: %f\n", gCutFreq);
victor@3 173
victor@3 174 calculate_coeff(gCutFreq);
victor@3 175 gChangeCoeff = 0;
victor@3 176 }
victor@3 177 }
victor@3 178
victor@3 179 // This is a lower-priority call to periodically read keyboard input
victor@3 180 // and trigger samples. By placing it at a lower priority,
victor@3 181 // it has minimal effect on the audio performance but it will take longer to
victor@3 182 // complete if the system is under heavy audio load.
victor@3 183
victor@3 184 void read_input()
victor@3 185 {
victor@3 186 // This is not a real-time task!
victor@3 187 // Cos getchar is a system call, not handled by Xenomai.
victor@3 188 // This task will be automatically down graded.
victor@3 189
victor@3 190 char keyStroke = '.';
victor@3 191
victor@3 192 keyStroke = getchar();
victor@3 193 while(getchar()!='\n'); // to read the first stroke
victor@3 194
victor@3 195 switch (keyStroke)
victor@3 196 {
victor@3 197 case 'a':
victor@3 198 gReadPtr = 0;
victor@3 199 break;
victor@3 200 case 's':
victor@3 201 gReadPtr = -1;
victor@3 202 break;
victor@3 203 case 'z':
victor@3 204 gChangeCoeff = 1;
victor@3 205 gFreqDelta = -100;
victor@3 206 break;
victor@3 207 case 'x':
victor@3 208 gChangeCoeff = 1;
victor@3 209 gFreqDelta = 100;
victor@3 210 break;
victor@3 211 case 'q':
victor@3 212 gShouldStop = true;
victor@3 213 break;
victor@3 214 default:
victor@3 215 break;
victor@3 216 }
victor@3 217 }
victor@3 218
victor@3 219
victor@3 220
victor@3 221 // cleanup_render() is called once at the end, after the audio has stopped.
victor@3 222 // Release any resources that were allocated in initialise_render().
victor@3 223
victor@3 224 void cleanup_render()
victor@3 225 {
victor@3 226 delete[] gSampleData.samples;
victor@3 227 }