comparison projects/filter_IIR/render.cpp @ 3:6810f166482f

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