Mercurial > hg > beaglert
comparison examples/oscillator_bank/render.cpp @ 300:dbeed520b014 prerelease
Renamed projects to examples
author | Giulio Moro <giuliomoro@yahoo.it> |
---|---|
date | Fri, 27 May 2016 13:58:20 +0100 |
parents | projects/oscillator_bank/render.cpp@3c3a1357657d |
children | e4392164b458 |
comparison
equal
deleted
inserted
replaced
297:a3d83ebdf49b | 300:dbeed520b014 |
---|---|
1 /* | |
2 * render.cpp | |
3 * | |
4 * Created on: Oct 24, 2014 | |
5 * Author: parallels | |
6 */ | |
7 | |
8 | |
9 #include <BeagleRT.h> | |
10 #include <Utilities.h> | |
11 #include <rtdk.h> | |
12 #include <cstdlib> | |
13 #include <cmath> | |
14 #include <cstring> | |
15 #include <time.h> | |
16 | |
17 const float kMinimumFrequency = 20.0f; | |
18 const float kMaximumFrequency = 8000.0f; | |
19 | |
20 float *gWavetable; // Buffer holding the precalculated sine lookup table | |
21 float *gPhases; // Buffer holding the phase of each oscillator | |
22 float *gFrequencies; // Buffer holding the frequencies of each oscillator | |
23 float *gAmplitudes; // Buffer holding the amplitudes of each oscillator | |
24 float *gDFrequencies; // Buffer holding the derivatives of frequency | |
25 float *gDAmplitudes; // Buffer holding the derivatives of amplitude | |
26 | |
27 float gAudioSampleRate; | |
28 int gSampleCount; // Sample counter for indicating when to update frequencies | |
29 float gNewMinFrequency; | |
30 float gNewMaxFrequency; | |
31 | |
32 // Task for handling the update of the frequencies using the matrix | |
33 AuxiliaryTask gFrequencyUpdateTask; | |
34 | |
35 // These settings are carried over from main.cpp | |
36 // Setting global variables is an alternative approach | |
37 // to passing a structure to userData in setup() | |
38 | |
39 extern int gNumOscillators; | |
40 extern int gWavetableLength; | |
41 | |
42 void recalculate_frequencies(); | |
43 | |
44 extern "C" { | |
45 // Function prototype for ARM assembly implementation of oscillator bank | |
46 void oscillator_bank_neon(int numAudioFrames, float *audioOut, | |
47 int activePartialNum, int lookupTableSize, | |
48 float *phases, float *frequencies, float *amplitudes, | |
49 float *freqDerivatives, float *ampDerivatives, | |
50 float *lookupTable); | |
51 } | |
52 | |
53 // setup() is called once before the audio rendering starts. | |
54 // Use it to perform any initialisation and allocation which is dependent | |
55 // on the period size or sample rate. | |
56 // | |
57 // userData holds an opaque pointer to a data structure that was passed | |
58 // in from the call to initAudio(). | |
59 // | |
60 // Return true on success; returning false halts the program. | |
61 bool setup(BeagleRTContext *context, void *userData) | |
62 { | |
63 srandom(time(NULL)); | |
64 | |
65 if(context->audioChannels != 2) { | |
66 rt_printf("Error: this example needs stereo audio enabled\n"); | |
67 return false; | |
68 } | |
69 | |
70 // Initialise the sine wavetable | |
71 if(posix_memalign((void **)&gWavetable, 8, (gWavetableLength + 1) * sizeof(float))) { | |
72 rt_printf("Error allocating wavetable\n"); | |
73 return false; | |
74 } | |
75 for(int n = 0; n < gWavetableLength + 1; n++) | |
76 gWavetable[n] = sinf(2.0 * M_PI * (float)n / (float)gWavetableLength); | |
77 | |
78 // Allocate the other buffers | |
79 if(posix_memalign((void **)&gPhases, 16, gNumOscillators * sizeof(float))) { | |
80 rt_printf("Error allocating phase buffer\n"); | |
81 return false; | |
82 } | |
83 if(posix_memalign((void **)&gFrequencies, 16, gNumOscillators * sizeof(float))) { | |
84 rt_printf("Error allocating frequency buffer\n"); | |
85 return false; | |
86 } | |
87 if(posix_memalign((void **)&gAmplitudes, 16, gNumOscillators * sizeof(float))) { | |
88 rt_printf("Error allocating amplitude buffer\n"); | |
89 return false; | |
90 } | |
91 if(posix_memalign((void **)&gDFrequencies, 16, gNumOscillators * sizeof(float))) { | |
92 rt_printf("Error allocating frequency derivative buffer\n"); | |
93 return false; | |
94 } | |
95 if(posix_memalign((void **)&gDAmplitudes, 16, gNumOscillators * sizeof(float))) { | |
96 rt_printf("Error allocating amplitude derivative buffer\n"); | |
97 return false; | |
98 } | |
99 | |
100 // Initialise buffer contents | |
101 | |
102 float freq = kMinimumFrequency; | |
103 float increment = (kMaximumFrequency - kMinimumFrequency) / (float)gNumOscillators; | |
104 | |
105 for(int n = 0; n < gNumOscillators; n++) { | |
106 gPhases[n] = 0.0; | |
107 | |
108 if(context->analogFrames == 0) { | |
109 // Random frequencies when used without matrix | |
110 gFrequencies[n] = kMinimumFrequency + (kMaximumFrequency - kMinimumFrequency) * ((float)random() / (float)RAND_MAX); | |
111 } | |
112 else { | |
113 // Constant spread of frequencies when used with matrix | |
114 gFrequencies[n] = freq; | |
115 freq += increment; | |
116 } | |
117 | |
118 // For efficiency, frequency is expressed in change in wavetable position per sample, not Hz or radians | |
119 gFrequencies[n] *= (float)gWavetableLength / context->audioSampleRate; | |
120 gAmplitudes[n] = ((float)random() / (float)RAND_MAX) / (float)gNumOscillators; | |
121 gDFrequencies[n] = gDAmplitudes[n] = 0.0; | |
122 } | |
123 | |
124 increment = 0; | |
125 freq = 440.0; | |
126 | |
127 for(int n = 0; n < gNumOscillators; n++) { | |
128 // Update the frequencies to a regular spread, plus a small amount of randomness | |
129 // to avoid weird phase effects | |
130 float randScale = 0.99 + .02 * (float)random() / (float)RAND_MAX; | |
131 float newFreq = freq * randScale; | |
132 | |
133 // For efficiency, frequency is expressed in change in wavetable position per sample, not Hz or radians | |
134 gFrequencies[n] = newFreq * (float)gWavetableLength / context->audioSampleRate; | |
135 | |
136 freq += increment; | |
137 } | |
138 | |
139 // Initialise auxiliary tasks | |
140 if((gFrequencyUpdateTask = BeagleRT_createAuxiliaryTask(&recalculate_frequencies, 85, "beaglert-update-frequencies")) == 0) | |
141 return false; | |
142 | |
143 //for(int n = 0; n < gNumOscillators; n++) | |
144 // rt_printf("%f\n", gFrequencies[n]); | |
145 | |
146 gAudioSampleRate = context->audioSampleRate; | |
147 gSampleCount = 0; | |
148 | |
149 return true; | |
150 } | |
151 | |
152 // render() is called regularly at the highest priority by the audio engine. | |
153 // Input and output are given from the audio hardware and the other | |
154 // ADCs and DACs (if available). If only audio is available, numMatrixFrames | |
155 // will be 0. | |
156 | |
157 void render(BeagleRTContext *context, void *userData) | |
158 { | |
159 // Initialise buffer to 0 | |
160 memset(context->audioOut, 0, 2 * context->audioFrames * sizeof(float)); | |
161 | |
162 // Render audio frames | |
163 oscillator_bank_neon(context->audioFrames, context->audioOut, | |
164 gNumOscillators, gWavetableLength, | |
165 gPhases, gFrequencies, gAmplitudes, | |
166 gDFrequencies, gDAmplitudes, | |
167 gWavetable); | |
168 | |
169 if(context->analogFrames != 0 && (gSampleCount += context->audioFrames) >= 128) { | |
170 gSampleCount = 0; | |
171 gNewMinFrequency = map(context->analogIn[0], 0, 1.0, 1000.0f, 8000.0f); | |
172 gNewMaxFrequency = map(context->analogIn[1], 0, 1.0, 1000.0f, 8000.0f); | |
173 | |
174 // Make sure max >= min | |
175 if(gNewMaxFrequency < gNewMinFrequency) { | |
176 float temp = gNewMaxFrequency; | |
177 gNewMaxFrequency = gNewMinFrequency; | |
178 gNewMinFrequency = temp; | |
179 } | |
180 | |
181 // Request that the lower-priority task run at next opportunity | |
182 //BeagleRT_scheduleAuxiliaryTask(gFrequencyUpdateTask); | |
183 } | |
184 } | |
185 | |
186 // This is a lower-priority call to update the frequencies which will happen | |
187 // periodically when the matrix is enabled. By placing it at a lower priority, | |
188 // it has minimal effect on the audio performance but it will take longer to | |
189 // complete if the system is under heavy audio load. | |
190 | |
191 void recalculate_frequencies() | |
192 { | |
193 float freq = gNewMinFrequency; | |
194 float increment = (gNewMaxFrequency - gNewMinFrequency) / (float)gNumOscillators; | |
195 | |
196 for(int n = 0; n < gNumOscillators; n++) { | |
197 // Update the frequencies to a regular spread, plus a small amount of randomness | |
198 // to avoid weird phase effects | |
199 float randScale = 0.99 + .02 * (float)random() / (float)RAND_MAX; | |
200 float newFreq = freq * randScale; | |
201 | |
202 // For efficiency, frequency is expressed in change in wavetable position per sample, not Hz or radians | |
203 gFrequencies[n] = newFreq * (float)gWavetableLength / gAudioSampleRate; | |
204 | |
205 freq += increment; | |
206 } | |
207 } | |
208 | |
209 | |
210 // cleanup() is called once at the end, after the audio has stopped. | |
211 // Release any resources that were allocated in setup(). | |
212 | |
213 void cleanup(BeagleRTContext *context, void *userData) | |
214 { | |
215 free(gWavetable); | |
216 free(gPhases); | |
217 free(gFrequencies); | |
218 free(gAmplitudes); | |
219 free(gDFrequencies); | |
220 free(gDAmplitudes); | |
221 } |