Mercurial > hg > beaglert
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 } |