Mercurial > hg > beaglert
comparison examples/10-Instruments/oscillator-bank/render.cpp @ 493:a23d74e2f6cb prerelease
Minor changes to doxygen
author | Robert Jack <robert.h.jack@gmail.com> |
---|---|
date | Tue, 21 Jun 2016 18:50:03 +0100 |
parents | |
children | b935f890e512 |
comparison
equal
deleted
inserted
replaced
492:e9821d65b9ba | 493:a23d74e2f6cb |
---|---|
1 /* | |
2 ____ _____ _ _ | |
3 | __ )| ____| | / \ | |
4 | _ \| _| | | / _ \ | |
5 | |_) | |___| |___ / ___ \ | |
6 |____/|_____|_____/_/ \_\ | |
7 | |
8 The platform for ultra-low latency audio and sensor processing | |
9 | |
10 http://bela.io | |
11 | |
12 A project of the Augmented Instruments Laboratory within the | |
13 Centre for Digital Music at Queen Mary University of London. | |
14 http://www.eecs.qmul.ac.uk/~andrewm | |
15 | |
16 (c) 2016 Augmented Instruments Laboratory: Andrew McPherson, | |
17 Astrid Bin, Liam Donovan, Christian Heinrichs, Robert Jack, | |
18 Giulio Moro, Laurel Pardue, Victor Zappi. All rights reserved. | |
19 | |
20 The Bela software is distributed under the GNU Lesser General Public License | |
21 (LGPL 3.0), available here: https://www.gnu.org/licenses/lgpl-3.0.txt | |
22 */ | |
23 | |
24 | |
25 #include <Bela.h> | |
26 #include <rtdk.h> | |
27 #include <cstdlib> | |
28 #include <cmath> | |
29 #include <cstring> | |
30 #include <time.h> | |
31 | |
32 const float kMinimumFrequency = 20.0f; | |
33 const float kMaximumFrequency = 8000.0f; | |
34 | |
35 float *gWavetable; // Buffer holding the precalculated sine lookup table | |
36 float *gPhases; // Buffer holding the phase of each oscillator | |
37 float *gFrequencies; // Buffer holding the frequencies of each oscillator | |
38 float *gAmplitudes; // Buffer holding the amplitudes of each oscillator | |
39 float *gDFrequencies; // Buffer holding the derivatives of frequency | |
40 float *gDAmplitudes; // Buffer holding the derivatives of amplitude | |
41 | |
42 float gAudioSampleRate; | |
43 int gSampleCount; // Sample counter for indicating when to update frequencies | |
44 float gNewMinFrequency; | |
45 float gNewMaxFrequency; | |
46 | |
47 // Task for handling the update of the frequencies using the matrix | |
48 AuxiliaryTask gFrequencyUpdateTask; | |
49 | |
50 // These settings are carried over from main.cpp | |
51 // Setting global variables is an alternative approach | |
52 // to passing a structure to userData in setup() | |
53 | |
54 extern int gNumOscillators; | |
55 extern int gWavetableLength; | |
56 | |
57 void recalculate_frequencies(); | |
58 | |
59 extern "C" { | |
60 // Function prototype for ARM assembly implementation of oscillator bank | |
61 void oscillator_bank_neon(int numAudioFrames, float *audioOut, | |
62 int activePartialNum, int lookupTableSize, | |
63 float *phases, float *frequencies, float *amplitudes, | |
64 float *freqDerivatives, float *ampDerivatives, | |
65 float *lookupTable); | |
66 } | |
67 | |
68 // setup() is called once before the audio rendering starts. | |
69 // Use it to perform any initialisation and allocation which is dependent | |
70 // on the period size or sample rate. | |
71 // | |
72 // userData holds an opaque pointer to a data structure that was passed | |
73 // in from the call to initAudio(). | |
74 // | |
75 // Return true on success; returning false halts the program. | |
76 bool setup(BelaContext *context, void *userData) | |
77 { | |
78 srandom(time(NULL)); | |
79 | |
80 if(context->audioChannels != 2) { | |
81 rt_printf("Error: this example needs stereo audio enabled\n"); | |
82 return false; | |
83 } | |
84 | |
85 // Initialise the sine wavetable | |
86 if(posix_memalign((void **)&gWavetable, 8, (gWavetableLength + 1) * sizeof(float))) { | |
87 rt_printf("Error allocating wavetable\n"); | |
88 return false; | |
89 } | |
90 for(int n = 0; n < gWavetableLength + 1; n++) | |
91 gWavetable[n] = sinf(2.0 * M_PI * (float)n / (float)gWavetableLength); | |
92 | |
93 // Allocate the other buffers | |
94 if(posix_memalign((void **)&gPhases, 16, gNumOscillators * sizeof(float))) { | |
95 rt_printf("Error allocating phase buffer\n"); | |
96 return false; | |
97 } | |
98 if(posix_memalign((void **)&gFrequencies, 16, gNumOscillators * sizeof(float))) { | |
99 rt_printf("Error allocating frequency buffer\n"); | |
100 return false; | |
101 } | |
102 if(posix_memalign((void **)&gAmplitudes, 16, gNumOscillators * sizeof(float))) { | |
103 rt_printf("Error allocating amplitude buffer\n"); | |
104 return false; | |
105 } | |
106 if(posix_memalign((void **)&gDFrequencies, 16, gNumOscillators * sizeof(float))) { | |
107 rt_printf("Error allocating frequency derivative buffer\n"); | |
108 return false; | |
109 } | |
110 if(posix_memalign((void **)&gDAmplitudes, 16, gNumOscillators * sizeof(float))) { | |
111 rt_printf("Error allocating amplitude derivative buffer\n"); | |
112 return false; | |
113 } | |
114 | |
115 // Initialise buffer contents | |
116 | |
117 float freq = kMinimumFrequency; | |
118 float increment = (kMaximumFrequency - kMinimumFrequency) / (float)gNumOscillators; | |
119 | |
120 for(int n = 0; n < gNumOscillators; n++) { | |
121 gPhases[n] = 0.0; | |
122 | |
123 if(context->analogFrames == 0) { | |
124 // Random frequencies when used without matrix | |
125 gFrequencies[n] = kMinimumFrequency + (kMaximumFrequency - kMinimumFrequency) * ((float)random() / (float)RAND_MAX); | |
126 } | |
127 else { | |
128 // Constant spread of frequencies when used with matrix | |
129 gFrequencies[n] = freq; | |
130 freq += increment; | |
131 } | |
132 | |
133 // For efficiency, frequency is expressed in change in wavetable position per sample, not Hz or radians | |
134 gFrequencies[n] *= (float)gWavetableLength / context->audioSampleRate; | |
135 gAmplitudes[n] = ((float)random() / (float)RAND_MAX) / (float)gNumOscillators; | |
136 gDFrequencies[n] = gDAmplitudes[n] = 0.0; | |
137 } | |
138 | |
139 increment = 0; | |
140 freq = 440.0; | |
141 | |
142 for(int n = 0; n < gNumOscillators; n++) { | |
143 // Update the frequencies to a regular spread, plus a small amount of randomness | |
144 // to avoid weird phase effects | |
145 float randScale = 0.99 + .02 * (float)random() / (float)RAND_MAX; | |
146 float newFreq = freq * randScale; | |
147 | |
148 // For efficiency, frequency is expressed in change in wavetable position per sample, not Hz or radians | |
149 gFrequencies[n] = newFreq * (float)gWavetableLength / context->audioSampleRate; | |
150 | |
151 freq += increment; | |
152 } | |
153 | |
154 // Initialise auxiliary tasks | |
155 if((gFrequencyUpdateTask = Bela_createAuxiliaryTask(&recalculate_frequencies, 85, "bela-update-frequencies")) == 0) | |
156 return false; | |
157 | |
158 //for(int n = 0; n < gNumOscillators; n++) | |
159 // rt_printf("%f\n", gFrequencies[n]); | |
160 | |
161 gAudioSampleRate = context->audioSampleRate; | |
162 gSampleCount = 0; | |
163 | |
164 return true; | |
165 } | |
166 | |
167 // render() is called regularly at the highest priority by the audio engine. | |
168 // Input and output are given from the audio hardware and the other | |
169 // ADCs and DACs (if available). If only audio is available, numMatrixFrames | |
170 // will be 0. | |
171 | |
172 void render(BelaContext *context, void *userData) | |
173 { | |
174 // Initialise buffer to 0 | |
175 memset(context->audioOut, 0, 2 * context->audioFrames * sizeof(float)); | |
176 | |
177 // Render audio frames | |
178 oscillator_bank_neon(context->audioFrames, context->audioOut, | |
179 gNumOscillators, gWavetableLength, | |
180 gPhases, gFrequencies, gAmplitudes, | |
181 gDFrequencies, gDAmplitudes, | |
182 gWavetable); | |
183 | |
184 if(context->analogFrames != 0 && (gSampleCount += context->audioFrames) >= 128) { | |
185 gSampleCount = 0; | |
186 gNewMinFrequency = map(context->analogIn[0], 0, 1.0, 1000.0f, 8000.0f); | |
187 gNewMaxFrequency = map(context->analogIn[1], 0, 1.0, 1000.0f, 8000.0f); | |
188 | |
189 // Make sure max >= min | |
190 if(gNewMaxFrequency < gNewMinFrequency) { | |
191 float temp = gNewMaxFrequency; | |
192 gNewMaxFrequency = gNewMinFrequency; | |
193 gNewMinFrequency = temp; | |
194 } | |
195 | |
196 // Request that the lower-priority task run at next opportunity | |
197 //Bela_scheduleAuxiliaryTask(gFrequencyUpdateTask); | |
198 } | |
199 } | |
200 | |
201 // This is a lower-priority call to update the frequencies which will happen | |
202 // periodically when the matrix is enabled. By placing it at a lower priority, | |
203 // it has minimal effect on the audio performance but it will take longer to | |
204 // complete if the system is under heavy audio load. | |
205 | |
206 void recalculate_frequencies() | |
207 { | |
208 float freq = gNewMinFrequency; | |
209 float increment = (gNewMaxFrequency - gNewMinFrequency) / (float)gNumOscillators; | |
210 | |
211 for(int n = 0; n < gNumOscillators; n++) { | |
212 // Update the frequencies to a regular spread, plus a small amount of randomness | |
213 // to avoid weird phase effects | |
214 float randScale = 0.99 + .02 * (float)random() / (float)RAND_MAX; | |
215 float newFreq = freq * randScale; | |
216 | |
217 // For efficiency, frequency is expressed in change in wavetable position per sample, not Hz or radians | |
218 gFrequencies[n] = newFreq * (float)gWavetableLength / gAudioSampleRate; | |
219 | |
220 freq += increment; | |
221 } | |
222 } | |
223 | |
224 | |
225 // cleanup() is called once at the end, after the audio has stopped. | |
226 // Release any resources that were allocated in setup(). | |
227 | |
228 void cleanup(BelaContext *context, void *userData) | |
229 { | |
230 free(gWavetable); | |
231 free(gPhases); | |
232 free(gFrequencies); | |
233 free(gAmplitudes); | |
234 free(gDFrequencies); | |
235 free(gDAmplitudes); | |
236 } | |
237 | |
238 /** | |
239 \example 10-oscillator-bank | |
240 | |
241 Oscillator Bank | |
242 ---------------------- | |
243 | |
244 These files demonstrate an oscillator bank implemented in assembly code | |
245 that is used as part of the d-box project. | |
246 */ | |
247 |