Mercurial > hg > beaglert
comparison projects/d-box/render.cpp @ 50:be427da6fb9c newapi
Removed old testing code that stopped audio after 10 seconds; command line parameter updates; D-Box updates (not fully working yet)
author | andrewm |
---|---|
date | Sat, 30 May 2015 12:34:32 -0500 |
parents | 42a683058b6a |
children | 4f8db16f17b5 |
comparison
equal
deleted
inserted
replaced
49:bb40e7e06b8c | 50:be427da6fb9c |
---|---|
3 * | 3 * |
4 * Created on: May 28, 2014 | 4 * Created on: May 28, 2014 |
5 * Author: Victor Zappi | 5 * Author: Victor Zappi |
6 */ | 6 */ |
7 | 7 |
8 #include "../../include/RTAudio.h" | 8 #include "../../include/BeagleRT.h" |
9 #include "../../include/PRU.h" | 9 #include "../../include/PRU.h" |
10 #include "StatusLED.h" | 10 #include "StatusLED.h" |
11 #include "config.h" | 11 #include "config.h" |
12 #include "OscillatorBank.h" | 12 #include "OscillatorBank.h" |
13 #include "FeedbackOscillator.h" | 13 #include "FeedbackOscillator.h" |
37 #define ADC_PIN4 4 | 37 #define ADC_PIN4 4 |
38 #define ADC_PIN5 5 | 38 #define ADC_PIN5 5 |
39 #define ADC_PIN6 6 | 39 #define ADC_PIN6 6 |
40 #define ADC_PIN7 7 | 40 #define ADC_PIN7 7 |
41 | 41 |
42 | |
43 #define N_OCT 4.0 // maximum number of octaves on sensor 1 | 42 #define N_OCT 4.0 // maximum number of octaves on sensor 1 |
44 | 43 |
45 extern vector<OscillatorBank*> gOscBanks; | 44 extern vector<OscillatorBank*> gOscBanks; |
46 extern int gCurrentOscBank; | 45 extern int gCurrentOscBank; |
47 extern int gNextOscBank; | 46 extern int gNextOscBank; |
48 extern PRU *gPRU; | 47 extern PRU *gPRU; |
49 extern StatusLED gStatusLED; | 48 extern StatusLED gStatusLED; |
50 extern bool gIsLoading; | 49 extern bool gIsLoading; |
51 extern bool gAudioIn; | 50 extern bool gAudioIn; |
52 extern int gPeriodSize; | |
53 | 51 |
54 float *gOscillatorBuffer1, *gOscillatorBuffer2; | 52 float *gOscillatorBuffer1, *gOscillatorBuffer2; |
55 float *gOscillatorBufferRead, *gOscillatorBufferWrite; | 53 float *gOscillatorBufferRead, *gOscillatorBufferWrite; |
56 int gOscillatorBufferReadPointer = 0; | 54 int gOscillatorBufferReadPointer = 0; |
57 int gOscillatorBufferReadCurrentSize = 0; | 55 int gOscillatorBufferReadCurrentSize = 0; |
76 | 74 |
77 // This comes from sensor.cpp where it records the most recent touch location on | 75 // This comes from sensor.cpp where it records the most recent touch location on |
78 // sensor 0. | 76 // sensor 0. |
79 extern float gSensor0LatestTouchPos; | 77 extern float gSensor0LatestTouchPos; |
80 extern int gSensor0LatestTouchNum; | 78 extern int gSensor0LatestTouchNum; |
81 uint16_t gPitchLatestInput = 0; | 79 float gPitchLatestInput = 0; |
82 | 80 |
83 extern float gSensor1LatestTouchPos[]; | 81 extern float gSensor1LatestTouchPos[]; |
84 //extern float gSensor1LatestTouchSizes[]; | 82 //extern float gSensor1LatestTouchSizes[]; |
85 extern int gSensor1LatestTouchCount; | 83 extern int gSensor1LatestTouchCount; |
86 extern int gSensor1LatestTouchIndex; | 84 extern int gSensor1LatestTouchIndex; |
92 // FSR value from matrix input | 90 // FSR value from matrix input |
93 extern int gLastFSRValue; | 91 extern int gLastFSRValue; |
94 | 92 |
95 // Loop points from matrix input 4 | 93 // Loop points from matrix input 4 |
96 const int gLoopPointsInputBufferSize = 256; | 94 const int gLoopPointsInputBufferSize = 256; |
97 uint16_t gLoopPointsInputBuffer[gLoopPointsInputBufferSize]; | 95 float gLoopPointsInputBuffer[gLoopPointsInputBufferSize]; |
98 int gLoopPointsInputBufferPointer = 0; | 96 int gLoopPointsInputBufferPointer = 0; |
99 int gLoopPointMin = 0, gLoopPointMax = 0; | 97 float gLoopPointMin = 0, gLoopPointMax = 0; |
100 | 98 |
101 // multiplier to activate or mute audio in | 99 // multiplier to activate or mute audio in |
102 int audioInStatus = 0; | 100 int audioInStatus = 0; |
103 | 101 |
104 // xenomai timer | 102 // xenomai timer |
105 SRTIME prevChangeNs = 0; | 103 SRTIME prevChangeNs = 0; |
106 | 104 |
107 // pitch vars | 105 // pitch vars |
108 float octaveSplitter; | 106 float octaveSplitter; |
109 u_int16_t semitones[((int)N_OCT*12)+1]; | 107 float semitones[((int)N_OCT*12)+1]; |
110 float deltaTouch = 0; | 108 float deltaTouch = 0; |
111 float deltaWeightP = 0.5; | 109 float deltaWeightP = 0.5; |
112 float deltaWeightI = 0.0005; | 110 float deltaWeightI = 0.0005; |
113 | 111 |
114 // filter vars | 112 // filter vars |
141 | 139 |
142 void wavetable_interpolate(int numSamplesIn, int numSamplesOut, | 140 void wavetable_interpolate(int numSamplesIn, int numSamplesOut, |
143 float *tableIn, float *tableOut, | 141 float *tableIn, float *tableOut, |
144 float *sineTable, float sineMix); | 142 float *sineTable, float sineMix); |
145 | 143 |
146 inline uint16_t hysteresis_oscillator(uint16_t input, uint16_t risingThreshold, | 144 inline float hysteresis_oscillator(float input, float risingThreshold, |
147 uint16_t fallingThreshold, bool *rising); | 145 float fallingThreshold, bool *rising); |
146 | |
147 void render_medium_prio(); | |
148 void render_low_prio(); | |
148 | 149 |
149 #ifdef DBOX_CAPE_TEST | 150 #ifdef DBOX_CAPE_TEST |
150 void render_capetest(int numMatrixFrames, int numAudioFrames, float *audioIn, float *audioOut, | 151 void render_capetest(int numMatrixFrames, int numAudioFrames, float *audioIn, float *audioOut, |
151 uint16_t *matrixIn, uint16_t *matrixOut); | 152 uint16_t *matrixIn, uint16_t *matrixOut); |
152 #endif | 153 #endif |
153 | 154 |
154 bool initialise_render(int numMatrixChannels, int numAudioChannels, | 155 bool initialise_render(BeagleRTContext *context, void *userData) { |
155 int numMatrixFramesPerPeriod, | |
156 int numAudioFramesPerPeriod, | |
157 float matrixSampleRate, float audioSampleRate, | |
158 void *userData) { | |
159 int oscBankHopSize = *(int *)userData; | 156 int oscBankHopSize = *(int *)userData; |
160 | 157 |
161 if(numMatrixChannels != 8) { | 158 if(context->analogChannels != 8) { |
162 printf("Error: D-Box needs matrix enabled with 8 channels.\n"); | 159 printf("Error: D-Box needs matrix enabled with 8 channels.\n"); |
163 return false; | 160 return false; |
164 } | 161 } |
165 | 162 |
166 // Allocate two buffers for rendering oscillator bank samples | 163 // Allocate two buffers for rendering oscillator bank samples |
167 // One will be used for writing in the background while the other is used for reading | 164 // One will be used for writing in the background while the other is used for reading |
168 // on the audio thread. 8-byte alignment needed for the NEON code. | 165 // on the audio thread. 8-byte alignment needed for the NEON code. |
169 if(posix_memalign((void **)&gOscillatorBuffer1, 8, oscBankHopSize * gNumAudioChannels * sizeof(float))) { | 166 if(posix_memalign((void **)&gOscillatorBuffer1, 8, oscBankHopSize * context->audioChannels * sizeof(float))) { |
170 printf("Error allocating render buffers\n"); | 167 printf("Error allocating render buffers\n"); |
171 return false; | 168 return false; |
172 } | 169 } |
173 if(posix_memalign((void **)&gOscillatorBuffer2, 8, oscBankHopSize * gNumAudioChannels * sizeof(float))) { | 170 if(posix_memalign((void **)&gOscillatorBuffer2, 8, oscBankHopSize * context->audioChannels * sizeof(float))) { |
174 printf("Error allocating render buffers\n"); | 171 printf("Error allocating render buffers\n"); |
175 return false; | 172 return false; |
176 } | 173 } |
177 gOscillatorBufferWrite = gOscillatorBuffer1; | 174 gOscillatorBufferWrite = gOscillatorBuffer1; |
178 gOscillatorBufferRead = gOscillatorBuffer2; | 175 gOscillatorBufferRead = gOscillatorBuffer2; |
179 | 176 |
180 memset(gOscillatorBuffer1, 0, oscBankHopSize * gNumAudioChannels * sizeof(float)); | 177 memset(gOscillatorBuffer1, 0, oscBankHopSize * context->audioChannels * sizeof(float)); |
181 memset(gOscillatorBuffer2, 0, oscBankHopSize * gNumAudioChannels * sizeof(float)); | 178 memset(gOscillatorBuffer2, 0, oscBankHopSize * context->audioChannels * sizeof(float)); |
182 | 179 |
183 // Initialise the dynamic wavetable used by the oscillator bank | 180 // Initialise the dynamic wavetable used by the oscillator bank |
184 // It should match the size of the static one already allocated in the OscillatorBank object | 181 // It should match the size of the static one already allocated in the OscillatorBank object |
185 // Don't forget a guard point at the end of the table | 182 // Don't forget a guard point at the end of the table |
186 gDynamicWavetableLength = gOscBanks[gCurrentOscBank]->lookupTableSize; | 183 gDynamicWavetableLength = gOscBanks[gCurrentOscBank]->lookupTableSize; |
187 if(posix_memalign((void **)&gDynamicWavetable, 8, (gDynamicWavetableLength + 1) * sizeof(float))) { | 184 if(posix_memalign((void **)&gDynamicWavetable, 8, (gDynamicWavetableLength + 1) * sizeof(float))) { |
188 printf("Error allocating wavetable\n"); | 185 printf("Error allocating wavetable\n"); |
189 return false; | 186 return false; |
190 } | 187 } |
191 | 188 |
192 gFeedbackOscillator.initialise(8192, 10.0, matrixSampleRate); | 189 gFeedbackOscillator.initialise(8192, 10.0, context->analogSampleRate); |
193 | 190 |
194 for(int n = 0; n < gDynamicWavetableLength + 1; n++) | 191 for(int n = 0; n < gDynamicWavetableLength + 1; n++) |
195 gDynamicWavetable[n] = 0; | 192 gDynamicWavetable[n] = 0; |
196 | 193 |
197 // pitch | 194 // pitch |
198 float midPos = (float)65535/2.0; | 195 float midPos = 0.5; |
199 octaveSplitter = round((float)65535/(N_OCT)); | 196 octaveSplitter = 1.0 / N_OCT; |
200 int numOfSemi = 12*N_OCT; | 197 int numOfSemi = 12*N_OCT; |
201 int middleSemitone = 12*N_OCT/2; | 198 int middleSemitone = 12*N_OCT/2; |
202 int lastSemitone = middleSemitone+numOfSemi/2; | 199 int lastSemitone = middleSemitone+numOfSemi/2; |
203 float inc = (float)65535/(N_OCT*12.0); | 200 float inc = 1.0 / (N_OCT*12.0); |
204 int i = -1; | 201 int i = -1; |
205 for(int semi=middleSemitone; semi<=lastSemitone; semi++) | 202 for(int semi=middleSemitone; semi<=lastSemitone; semi++) |
206 semitones[semi] = ( midPos + (++i)*inc) + 0.5; | 203 semitones[semi] = ( midPos + (++i)*inc) + 0.5; |
207 i = 0; | 204 i = 0; |
208 for(int semi=middleSemitone-1; semi>=0; semi--) | 205 for(int semi=middleSemitone-1; semi>=0; semi--) |
210 | 207 |
211 if(gAudioIn) | 208 if(gAudioIn) |
212 audioInStatus = 1; | 209 audioInStatus = 1; |
213 | 210 |
214 // filter | 211 // filter |
215 blockSize = 2*gPeriodSize; | 212 blockSize = context->audioFrames; |
216 filterState[0] = (ne10_float32_t *) NE10_MALLOC ((FILTER_TAP_NUM+blockSize-1) * sizeof (ne10_float32_t)); | 213 filterState[0] = (ne10_float32_t *) NE10_MALLOC ((FILTER_TAP_NUM+blockSize-1) * sizeof (ne10_float32_t)); |
217 filterState[1] = (ne10_float32_t *) NE10_MALLOC ((FILTER_TAP_NUM+blockSize-1) * sizeof (ne10_float32_t)); | 214 filterState[1] = (ne10_float32_t *) NE10_MALLOC ((FILTER_TAP_NUM+blockSize-1) * sizeof (ne10_float32_t)); |
218 filterIn[0] = (ne10_float32_t *) NE10_MALLOC (blockSize * sizeof (ne10_float32_t)); | 215 filterIn[0] = (ne10_float32_t *) NE10_MALLOC (blockSize * sizeof (ne10_float32_t)); |
219 filterIn[1] = (ne10_float32_t *) NE10_MALLOC (blockSize * sizeof (ne10_float32_t)); | 216 filterIn[1] = (ne10_float32_t *) NE10_MALLOC (blockSize * sizeof (ne10_float32_t)); |
220 filterOut[0] = (ne10_float32_t *) NE10_MALLOC (blockSize * sizeof (ne10_float32_t)); | 217 filterOut[0] = (ne10_float32_t *) NE10_MALLOC (blockSize * sizeof (ne10_float32_t)); |
221 filterOut[1] = (ne10_float32_t *) NE10_MALLOC (blockSize * sizeof (ne10_float32_t)); | 218 filterOut[1] = (ne10_float32_t *) NE10_MALLOC (blockSize * sizeof (ne10_float32_t)); |
222 ne10_fir_init_float(&filter[0], FILTER_TAP_NUM, filterTaps, filterState[0], blockSize); | 219 ne10_fir_init_float(&filter[0], FILTER_TAP_NUM, filterTaps, filterState[0], blockSize); |
223 ne10_fir_init_float(&filter[1], FILTER_TAP_NUM, filterTaps, filterState[1], blockSize); | 220 ne10_fir_init_float(&filter[1], FILTER_TAP_NUM, filterTaps, filterState[1], blockSize); |
224 | 221 |
225 // peak outputs | 222 // peak outputs |
226 PeakBurst[0].setAttackRate(.00001 * matrixSampleRate); | 223 PeakBurst[0].setAttackRate(.00001 * context->analogSampleRate); |
227 PeakBurst[1].setAttackRate(.00001 * matrixSampleRate); | 224 PeakBurst[1].setAttackRate(.00001 * context->analogSampleRate); |
228 PeakBurst[0].setDecayRate(.5 * matrixSampleRate); | 225 PeakBurst[0].setDecayRate(.5 * context->analogSampleRate); |
229 PeakBurst[1].setDecayRate(.5 * matrixSampleRate); | 226 PeakBurst[1].setDecayRate(.5 * context->analogSampleRate); |
230 PeakBurst[0].setSustainLevel(0.0); | 227 PeakBurst[0].setSustainLevel(0.0); |
231 PeakBurst[1].setSustainLevel(0.0); | 228 PeakBurst[1].setSustainLevel(0.0); |
232 | 229 |
233 // Initialise auxiliary tasks | 230 // Initialise auxiliary tasks |
234 if((gMediumPriorityRender = createAuxiliaryTaskLoop(&render_medium_prio, 90, "dbox-calculation-medium")) == 0) | 231 if((gMediumPriorityRender = BeagleRT_createAuxiliaryTask(&render_medium_prio, BEAGLERT_AUDIO_PRIORITY - 10, "dbox-calculation-medium")) == 0) |
235 return false; | 232 return false; |
236 if((gLowPriorityRender = createAuxiliaryTaskLoop(&render_low_prio, 85, "dbox-calculation-low")) == 0) | 233 if((gLowPriorityRender = BeagleRT_createAuxiliaryTask(&render_low_prio, BEAGLERT_AUDIO_PRIORITY - 15, "dbox-calculation-low")) == 0) |
237 return false; | 234 return false; |
238 | 235 |
239 return true; | 236 return true; |
240 } | 237 } |
241 | 238 |
242 void render(int numMatrixFrames, int numAudioFrames, float *audioIn, float *audioOut, | 239 void render(BeagleRTContext *context, void *userData) |
243 uint16_t *matrixIn, uint16_t *matrixOut) | |
244 { | 240 { |
245 #ifdef DBOX_CAPE_TEST | 241 #ifdef DBOX_CAPE_TEST |
246 render_capetest(numMatrixFrames, numAudioFrames, audioIn, audioOut, matrixIn, matrixOut); | 242 render_capetest(numMatrixFrames, numAudioFrames, audioIn, audioOut, matrixIn, matrixOut); |
247 #else | 243 #else |
248 if(gOscBanks[gCurrentOscBank]->state==bank_toreset) | 244 if(gOscBanks[gCurrentOscBank]->state==bank_toreset) |
249 gOscBanks[gCurrentOscBank]->resetOscillators(); | 245 gOscBanks[gCurrentOscBank]->resetOscillators(); |
250 | 246 |
251 if(gOscBanks[gCurrentOscBank]->state==bank_playing) | 247 if(gOscBanks[gCurrentOscBank]->state==bank_playing) |
252 { | 248 { |
253 assert(gNumAudioChannels == 2); | 249 assert(context->audioChannels == 2); |
254 | 250 |
255 #ifdef OLD_OSCBANK | 251 #ifdef OLD_OSCBANK |
256 memset(audioOut, 0, numAudioFrames * gNumAudioChannels * sizeof(float)); | 252 memset(audioOut, 0, numAudioFrames * * sizeof(float)); |
257 | 253 |
258 /* Render the oscillator bank. The oscillator bank function is written in NEON assembly | 254 /* Render the oscillator bank. The oscillator bank function is written in NEON assembly |
259 * and it strips out all extra checks, so find out in advance whether we can render a whole | 255 * and it strips out all extra checks, so find out in advance whether we can render a whole |
260 * block or whether the frame will increment in the middle of this buffer. | 256 * block or whether the frame will increment in the middle of this buffer. |
261 */ | 257 */ |
288 gOscBanks[gCurrentOscBank]->oscillatorAmplitudes, | 284 gOscBanks[gCurrentOscBank]->oscillatorAmplitudes, |
289 gOscBanks[gCurrentOscBank]->oscillatorNormFreqDerivatives, | 285 gOscBanks[gCurrentOscBank]->oscillatorNormFreqDerivatives, |
290 gOscBanks[gCurrentOscBank]->oscillatorAmplitudeDerivatives, | 286 gOscBanks[gCurrentOscBank]->oscillatorAmplitudeDerivatives, |
291 gDynamicWavetable/*gOscBanks[gCurrentOscBank]->lookupTable*/); | 287 gDynamicWavetable/*gOscBanks[gCurrentOscBank]->lookupTable*/); |
292 framesRemaining -= gOscBanks[gCurrentOscBank]->hopCounter; | 288 framesRemaining -= gOscBanks[gCurrentOscBank]->hopCounter; |
293 audioOutWithOffset += gNumAudioChannels * gOscBanks[gCurrentOscBank]->hopCounter; | 289 audioOutWithOffset += * gOscBanks[gCurrentOscBank]->hopCounter; |
294 gOscBanks[gCurrentOscBank]->sampleCount += gOscBanks[gCurrentOscBank]->hopCounter; | 290 gOscBanks[gCurrentOscBank]->sampleCount += gOscBanks[gCurrentOscBank]->hopCounter; |
295 gOscBanks[gCurrentOscBank]->nextHop(); | 291 gOscBanks[gCurrentOscBank]->nextHop(); |
296 } | 292 } |
297 } | 293 } |
298 #else | 294 #else |
299 for(int n = 0; n < numAudioFrames; n++) { | 295 for(unsigned int n = 0; n < context->audioFrames; n++) { |
300 audioOut[2*n] = gOscillatorBufferRead[gOscillatorBufferReadPointer++]+audioIn[2*n]*audioInStatus; | 296 context->audioOut[2*n] = gOscillatorBufferRead[gOscillatorBufferReadPointer++]+context->audioIn[2*n]*audioInStatus; |
301 audioOut[2*n + 1] = gOscillatorBufferRead[gOscillatorBufferReadPointer++]+audioIn[2*n+1]*audioInStatus; | 297 context->audioOut[2*n + 1] = gOscillatorBufferRead[gOscillatorBufferReadPointer++]+context->audioIn[2*n+1]*audioInStatus; |
302 | 298 |
303 filterIn[0][n] = fabs(audioIn[2*n]); // rectify for peak detection in 1 | 299 filterIn[0][n] = fabs(context->audioIn[2*n]); // rectify for peak detection in 1 |
304 filterIn[1][n] = fabs(audioIn[2*n+1]); // rectify for peak detection in 2 | 300 filterIn[1][n] = fabs(context->audioIn[2*n+1]); // rectify for peak detection in 2 |
305 | 301 |
306 /* FIXME why doesn't this work? */ | 302 /* FIXME why doesn't this work? */ |
307 /* | 303 /* |
308 if(gOscillatorBufferReadPointer == gOscillatorBufferCurrentSize/2) { | 304 if(gOscillatorBufferReadPointer == gOscillatorBufferCurrentSize/2) { |
309 gOscillatorNeedsRender = true; | 305 gOscillatorNeedsRender = true; |
324 // New buffer size is whatever finished writing last hop | 320 // New buffer size is whatever finished writing last hop |
325 gOscillatorBufferReadCurrentSize = gOscillatorBufferWriteCurrentSize; | 321 gOscillatorBufferReadCurrentSize = gOscillatorBufferWriteCurrentSize; |
326 gOscillatorBufferReadPointer = 0; | 322 gOscillatorBufferReadPointer = 0; |
327 | 323 |
328 gOscillatorNeedsRender = true; | 324 gOscillatorNeedsRender = true; |
329 scheduleAuxiliaryTask(gMediumPriorityRender); | 325 BeagleRT_scheduleAuxiliaryTask(gMediumPriorityRender); |
330 } | 326 } |
331 } | 327 } |
332 #endif | 328 #endif |
333 } | 329 } |
334 else | 330 else |
335 { | 331 { |
336 for(int n = 0; n < numAudioFrames; n++) { | 332 for(unsigned int n = 0; n < context->audioFrames; n++) { |
337 audioOut[2*n] = audioIn[2*n]*audioInStatus; | 333 context->audioOut[2*n] = context->audioIn[2*n]*audioInStatus; |
338 audioOut[2*n + 1] = audioIn[2*n+1]*audioInStatus; | 334 context->audioOut[2*n + 1] = context->audioIn[2*n+1]*audioInStatus; |
339 | 335 |
340 filterIn[0][n] = fabs(audioIn[2*n]); // rectify for peak detection in 1 | 336 filterIn[0][n] = fabs(context->audioIn[2*n]); // rectify for peak detection in 1 |
341 filterIn[1][n] = fabs(audioIn[2*n+1]); // rectify for peak detection in 2 | 337 filterIn[1][n] = fabs(context->audioIn[2*n+1]); // rectify for peak detection in 2 |
342 } | 338 } |
343 } | 339 } |
344 | 340 |
345 // low pass filter audio in 1 and 2 for peak detection | 341 // low pass filter audio in 1 and 2 for peak detection |
346 ne10_fir_float_neon(&filter[0], filterIn[0], filterOut[0], blockSize); | 342 ne10_fir_float_neon(&filter[0], filterIn[0], filterOut[0], blockSize); |
347 ne10_fir_float_neon(&filter[1], filterIn[1], filterOut[1], blockSize); | 343 ne10_fir_float_neon(&filter[1], filterIn[1], filterOut[1], blockSize); |
348 | 344 |
349 for(int n = 0; n < numMatrixFrames; n++) { | 345 for(unsigned int n = 0; n < context->analogFrames; n++) { |
350 | 346 |
351 | 347 |
352 /* Matrix Out 0, In 0 | 348 /* Matrix Out 0, In 0 |
353 * | 349 * |
354 * CV loop | 350 * CV loop |
355 * Controls pitch of sound | 351 * Controls pitch of sound |
356 */ | 352 */ |
357 int touchPosInt = gSensor0LatestTouchPos * 65536.0; | 353 float touchPosInt = gSensor0LatestTouchPos; |
358 if(touchPosInt < 0) touchPosInt = 0; | 354 if(touchPosInt < 0) touchPosInt = 0; |
359 if(touchPosInt > 65535) touchPosInt = 65535; | 355 if(touchPosInt > 1.0) touchPosInt = 1.0; |
360 matrixOut[n*8 + DAC_PIN0] = touchPosInt; | 356 context->analogOut[n*8 + DAC_PIN0] = touchPosInt; |
361 | 357 |
362 gPitchLatestInput = matrixIn[n*8 + ADC_PIN0]; | 358 gPitchLatestInput = context->analogIn[n*8 + ADC_PIN0]; |
363 | 359 |
364 | 360 |
365 /* Matrix Out 7 | 361 /* Matrix Out 7 |
366 * | 362 * |
367 * Loop feedback with Matrix In 0 | 363 * Loop feedback with Matrix In 0 |
370 float deltaTarget = 0; | 366 float deltaTarget = 0; |
371 int semitoneIndex = 0; | 367 int semitoneIndex = 0; |
372 if(gSensor0LatestTouchNum>0) | 368 if(gSensor0LatestTouchNum>0) |
373 { | 369 { |
374 // current pitch is gPitchLatestInput, already retrieved | 370 // current pitch is gPitchLatestInput, already retrieved |
375 semitoneIndex = ( ( (float)gPitchLatestInput / 65535)*12*N_OCT )+0.5; // closest semitone | 371 semitoneIndex = ( gPitchLatestInput * 12 * N_OCT )+0.5; // closest semitone |
376 deltaTarget = (semitones[semitoneIndex]-gPitchLatestInput); // delta between pitch and target | 372 deltaTarget = (semitones[semitoneIndex]-gPitchLatestInput); // delta between pitch and target |
377 deltaTouch += deltaTarget*deltaWeightI; // update feedback [previous + current] | 373 deltaTouch += deltaTarget*deltaWeightI; // update feedback [previous + current] |
378 } | 374 } |
379 else | 375 else |
380 deltaTouch = 0; | 376 deltaTouch = 0; |
381 | 377 |
382 int nextOut = touchPosInt + deltaTarget*deltaWeightP + deltaTouch; // add feedback to touch -> next out | 378 float nextOut = touchPosInt + deltaTarget*deltaWeightP + deltaTouch; // add feedback to touch -> next out |
383 if(nextOut < 0) nextOut = 0; // clamp | 379 if(nextOut < 0) nextOut = 0; // clamp |
384 if(nextOut > 65535) nextOut = 65535; // clamp | 380 if(nextOut > 1.0) nextOut = 1.0; // clamp |
385 matrixOut[n*8 + DAC_PIN7] = nextOut; // send next nextOut | 381 context->analogOut[n*8 + DAC_PIN7] = nextOut; // send next nextOut |
386 | 382 |
387 | 383 |
388 /* | 384 /* |
389 * Matrix Out 1, In 1 | 385 * Matrix Out 1, In 1 |
390 * | 386 * |
391 * Hysteresis (comparator) oscillator | 387 * Hysteresis (comparator) oscillator |
392 * Controls speed of playback | 388 * Controls speed of playback |
393 */ | 389 */ |
394 bool wasRising = gSpeedHysteresisOscillatorRising; | 390 bool wasRising = gSpeedHysteresisOscillatorRising; |
395 matrixOut[n*8 + DAC_PIN1] = hysteresis_oscillator(matrixIn[n*8 + ADC_PIN1], 48000, 16000, &gSpeedHysteresisOscillatorRising); | 391 context->analogOut[n*8 + DAC_PIN1] = hysteresis_oscillator(context->analogIn[n*8 + ADC_PIN1], 48000.0/65536.0, |
392 16000.0/65536.0, &gSpeedHysteresisOscillatorRising); | |
396 | 393 |
397 // Find interval of zero crossing | 394 // Find interval of zero crossing |
398 if(wasRising && !gSpeedHysteresisOscillatorRising) { | 395 if(wasRising && !gSpeedHysteresisOscillatorRising) { |
399 int interval = gMatrixSampleCount - gSpeedHysteresisLastTrigger; | 396 int interval = gMatrixSampleCount - gSpeedHysteresisLastTrigger; |
400 | 397 |
413 * | 410 * |
414 * Feedback (phase shift) oscillator | 411 * Feedback (phase shift) oscillator |
415 * Controls wavetable used for oscillator bank | 412 * Controls wavetable used for oscillator bank |
416 */ | 413 */ |
417 | 414 |
418 int tableLength = gFeedbackOscillator.process(matrixIn[n*8 + ADC_PIN2], &matrixOut[n*8 + DAC_PIN2]); | 415 int tableLength = gFeedbackOscillator.process(context->analogIn[n*8 + ADC_PIN2], &context->analogOut[n*8 + DAC_PIN2]); |
419 if(tableLength != 0) { | 416 if(tableLength != 0) { |
420 gFeedbackOscillatorTableLength = tableLength; | 417 gFeedbackOscillatorTableLength = tableLength; |
421 gFeedbackOscillatorTable = gFeedbackOscillator.wavetable(); | 418 gFeedbackOscillatorTable = gFeedbackOscillator.wavetable(); |
422 gDynamicWavetableNeedsRender = true; | 419 gDynamicWavetableNeedsRender = true; |
423 scheduleAuxiliaryTask(gLowPriorityRender); | 420 BeagleRT_scheduleAuxiliaryTask(gLowPriorityRender); |
424 } | 421 } |
425 | 422 |
426 /* | 423 /* |
427 * Matrix Out 3, In 3 | 424 * Matrix Out 3, In 3 |
428 * | 425 * |
430 * Touch positions from sensor 1 | 427 * Touch positions from sensor 1 |
431 * Change every 32 samples (ca. 1.5 ms) | 428 * Change every 32 samples (ca. 1.5 ms) |
432 */ | 429 */ |
433 volatile int touchCount = gSensor1LatestTouchCount; | 430 volatile int touchCount = gSensor1LatestTouchCount; |
434 if(touchCount == 0) | 431 if(touchCount == 0) |
435 matrixOut[n*8 + DAC_PIN3] = 0; | 432 context->analogOut[n*8 + DAC_PIN3] = 0; |
436 else { | 433 else { |
437 int touchIndex = (gMatrixSampleCount >> 5) % touchCount; | 434 int touchIndex = (gMatrixSampleCount >> 5) % touchCount; |
438 matrixOut[n*8 + DAC_PIN3] = gSensor1LatestTouchPos[touchIndex] * 56000.0f; | 435 context->analogOut[n*8 + DAC_PIN3] = gSensor1LatestTouchPos[touchIndex] * 56000.0f / 65536.0f; |
439 if(touchIndex != gSensor1LastTouchIndex) { | 436 if(touchIndex != gSensor1LastTouchIndex) { |
440 // Just changed to a new touch output. Reset the counter. | 437 // Just changed to a new touch output. Reset the counter. |
441 // It will take 2*matrixFrames samples for this output to come back to the | 438 // It will take 2*matrixFrames samples for this output to come back to the |
442 // ADC input. But we also want to read near the end of the 32 sample block; | 439 // ADC input. But we also want to read near the end of the 32 sample block; |
443 // let's say 24 samples into it. | 440 // let's say 24 samples into it. |
444 | 441 |
445 // FIXME this won't work for p > 2 | 442 // FIXME this won't work for p > 2 |
446 gSensor1InputDelayCounter = 24 + 2*numMatrixFrames; | 443 gSensor1InputDelayCounter = 24 + 2*context->analogFrames; |
447 gSensor1InputIndex = touchIndex; | 444 gSensor1InputIndex = touchIndex; |
448 } | 445 } |
449 gSensor1LastTouchIndex = touchIndex; | 446 gSensor1LastTouchIndex = touchIndex; |
450 } | 447 } |
451 | 448 |
452 if(gSensor1InputDelayCounter-- >= 0 && touchCount > 0) { | 449 if(gSensor1InputDelayCounter-- >= 0 && touchCount > 0) { |
453 gSensor1MatrixTouchPos[gSensor1InputIndex] = (float)matrixIn[n*8 + ADC_PIN3] / 65536.0f; | 450 gSensor1MatrixTouchPos[gSensor1InputIndex] = context->analogIn[n*8 + ADC_PIN3]; |
454 } | 451 } |
455 | 452 |
456 /* Matrix Out 4 | 453 /* Matrix Out 4 |
457 * | 454 * |
458 * Sensor 1 last pos | 455 * Sensor 1 last pos |
459 */ | 456 */ |
460 touchPosInt = gSensor1LatestTouchPos[gSensor1LatestTouchIndex] * 65536.0; | 457 touchPosInt = gSensor1LatestTouchPos[gSensor1LatestTouchIndex]; |
461 if(touchPosInt < 0) touchPosInt = 0; | 458 if(touchPosInt < 0) touchPosInt = 0; |
462 if(touchPosInt > 65535) touchPosInt = 65535; | 459 if(touchPosInt > 1.0) touchPosInt = 1.0; |
463 matrixOut[n*8 + DAC_PIN4] = touchPosInt; | 460 context->analogOut[n*8 + DAC_PIN4] = touchPosInt; |
464 | 461 |
465 /* Matrix In 4 | 462 /* Matrix In 4 |
466 * | 463 * |
467 * Loop points selector | 464 * Loop points selector |
468 */ | 465 */ |
469 gLoopPointsInputBuffer[gLoopPointsInputBufferPointer++] = matrixIn[n*8 + ADC_PIN4]; | 466 gLoopPointsInputBuffer[gLoopPointsInputBufferPointer++] = context->analogIn[n*8 + ADC_PIN4]; |
470 if(gLoopPointsInputBufferPointer >= gLoopPointsInputBufferSize) { | 467 if(gLoopPointsInputBufferPointer >= gLoopPointsInputBufferSize) { |
471 // Find min and max values | 468 // Find min and max values |
472 uint16_t loopMax = 0, loopMin = 65535; | 469 float loopMax = 0, loopMin = 1.0; |
473 for(int i = 0; i < gLoopPointsInputBufferSize; i++) { | 470 for(int i = 0; i < gLoopPointsInputBufferSize; i++) { |
474 if(gLoopPointsInputBuffer[i] < loopMin) | 471 if(gLoopPointsInputBuffer[i] < loopMin) |
475 loopMin = gLoopPointsInputBuffer[i]; | 472 loopMin = gLoopPointsInputBuffer[i]; |
476 if(gLoopPointsInputBuffer[i] > loopMax/* && gLoopPointsInputBuffer[i] != 65535*/) | 473 if(gLoopPointsInputBuffer[i] > loopMax/* && gLoopPointsInputBuffer[i] != 65535*/) |
477 loopMax = gLoopPointsInputBuffer[i]; | 474 loopMax = gLoopPointsInputBuffer[i]; |
501 } | 498 } |
502 } | 499 } |
503 | 500 |
504 PeakBurst[0].process(1); | 501 PeakBurst[0].process(1); |
505 | 502 |
506 int convAudio = burstOut*peak[0]*65535; | 503 float convAudio = burstOut*peak[0]; |
507 matrixOut[n*8 + DAC_PIN5] = convAudio; | 504 context->analogOut[n*8 + DAC_PIN5] = convAudio; |
508 prevFiltered[0] = filterOut[0][n*2+1]; | 505 prevFiltered[0] = filterOut[0][n*2+1]; |
509 if(prevFiltered[0]>1) | 506 if(prevFiltered[0]>1) |
510 prevFiltered[0] = 1; | 507 prevFiltered[0] = 1; |
511 | 508 |
512 /* Matrix In 5 | 509 /* Matrix In 5 |
513 * | 510 * |
514 * Dissonance, via changing frequency motion of partials | 511 * Dissonance, via changing frequency motion of partials |
515 */ | 512 */ |
516 float amount = (float)matrixIn[n*8 + ADC_PIN5] / 65536.0f; | 513 float amount = (float)context->analogIn[n*8 + ADC_PIN5]; |
517 gOscBanks[gCurrentOscBank]->freqMovement = 1-amount; | 514 gOscBanks[gCurrentOscBank]->freqMovement = 1.0 - amount; |
518 | 515 |
519 | 516 |
520 | 517 |
521 | 518 |
522 /* Matrix Out 6 | 519 /* Matrix Out 6 |
535 } | 532 } |
536 } | 533 } |
537 | 534 |
538 PeakBurst[1].process(1); | 535 PeakBurst[1].process(1); |
539 | 536 |
540 convAudio = burstOut*peak[1]*65535; | 537 convAudio = burstOut*peak[1]; |
541 matrixOut[n*8 + DAC_PIN6] = convAudio; | 538 context->analogOut[n*8 + DAC_PIN6] = convAudio; |
542 prevFiltered[1] = filterOut[1][n*2+1]; | 539 prevFiltered[1] = filterOut[1][n*2+1]; |
543 if(prevFiltered[1]>1) | 540 if(prevFiltered[1]>1) |
544 prevFiltered[1] = 1; | 541 prevFiltered[1] = 1; |
545 | 542 |
546 /* Matrix In 6 | 543 /* Matrix In 6 |
548 * Sound selector | 545 * Sound selector |
549 */ | 546 */ |
550 if(!gIsLoading) { | 547 if(!gIsLoading) { |
551 // Use hysteresis to avoid jumping back and forth between sounds | 548 // Use hysteresis to avoid jumping back and forth between sounds |
552 if(gOscBanks.size() > 1) { | 549 if(gOscBanks.size() > 1) { |
553 int input = matrixIn[n*8 + ADC_PIN6]; | 550 float input = context->analogIn[n*8 + ADC_PIN6]; |
554 const int hystValue = 16000; | 551 const float hystValue = 16000.0 / 65536.0; |
555 | 552 |
556 int upHysteresisValue = ((gCurrentOscBank + 1) * 65536 + hystValue) / gOscBanks.size(); | 553 float upHysteresisValue = ((gCurrentOscBank + 1) + hystValue) / gOscBanks.size(); |
557 int downHysteresisValue = (gCurrentOscBank * 65536 - hystValue) / gOscBanks.size(); | 554 float downHysteresisValue = (gCurrentOscBank - hystValue) / gOscBanks.size(); |
558 | 555 |
559 if(input > upHysteresisValue || input < downHysteresisValue) { | 556 if(input > upHysteresisValue || input < downHysteresisValue) { |
560 gNextOscBank = input * gOscBanks.size() / 65536; | 557 gNextOscBank = input * gOscBanks.size(); |
561 if(gNextOscBank < 0) | 558 if(gNextOscBank < 0) |
562 gNextOscBank = 0; | 559 gNextOscBank = 0; |
563 if((unsigned)gNextOscBank >= gOscBanks.size()) | 560 if((unsigned)gNextOscBank >= gOscBanks.size()) |
564 gNextOscBank = gOscBanks.size() - 1; | 561 gNextOscBank = gOscBanks.size() - 1; |
565 } | 562 } |
570 * Matrix In 7 | 567 * Matrix In 7 |
571 * | 568 * |
572 * FSR from primary touch sensor | 569 * FSR from primary touch sensor |
573 * Value ranges from 0-1799 | 570 * Value ranges from 0-1799 |
574 */ | 571 */ |
575 gLastFSRValue = matrixIn[n*8 + ADC_PIN7] * (1799.0 / 65535.0); | 572 gLastFSRValue = context->analogIn[n*8 + ADC_PIN7] * 1799.0; |
576 //gLastFSRValue = 1799 - matrixIn[n*8 + ADC_PIN7] * (1799.0 / 65535.0); | 573 //gLastFSRValue = 1799 - context->analogIn[n*8 + ADC_PIN7] * (1799.0 / 65535.0); |
577 //dbox_printf("%i\n",gLastFSRValue); | 574 //dbox_printf("%i\n",gLastFSRValue); |
578 | 575 |
579 gMatrixSampleCount++; | 576 gMatrixSampleCount++; |
580 } | 577 } |
581 | 578 |
588 | 585 |
589 if(gOscillatorNeedsRender) { | 586 if(gOscillatorNeedsRender) { |
590 gOscillatorNeedsRender = false; | 587 gOscillatorNeedsRender = false; |
591 | 588 |
592 /* Render one frame into the write buffer */ | 589 /* Render one frame into the write buffer */ |
593 memset(gOscillatorBufferWrite, 0, gOscBanks[gCurrentOscBank]->hopCounter * gNumAudioChannels * sizeof(float)); | 590 memset(gOscillatorBufferWrite, 0, gOscBanks[gCurrentOscBank]->hopCounter * 2 * sizeof(float)); /* assumes 2 audio channels */ |
594 | 591 |
595 oscillator_bank_neon(gOscBanks[gCurrentOscBank]->hopCounter, gOscillatorBufferWrite, | 592 oscillator_bank_neon(gOscBanks[gCurrentOscBank]->hopCounter, gOscillatorBufferWrite, |
596 gOscBanks[gCurrentOscBank]->actPartNum, gOscBanks[gCurrentOscBank]->lookupTableSize, | 593 gOscBanks[gCurrentOscBank]->actPartNum, gOscBanks[gCurrentOscBank]->lookupTableSize, |
597 gOscBanks[gCurrentOscBank]->oscillatorPhases, gOscBanks[gCurrentOscBank]->oscillatorNormFrequencies, | 594 gOscBanks[gCurrentOscBank]->oscillatorPhases, gOscBanks[gCurrentOscBank]->oscillatorNormFrequencies, |
598 gOscBanks[gCurrentOscBank]->oscillatorAmplitudes, | 595 gOscBanks[gCurrentOscBank]->oscillatorAmplitudes, |
599 gOscBanks[gCurrentOscBank]->oscillatorNormFreqDerivatives, | 596 gOscBanks[gCurrentOscBank]->oscillatorNormFreqDerivatives, |
600 gOscBanks[gCurrentOscBank]->oscillatorAmplitudeDerivatives, | 597 gOscBanks[gCurrentOscBank]->oscillatorAmplitudeDerivatives, |
601 /*gOscBanks[gCurrentOscBank]->lookupTable*/gDynamicWavetable); | 598 /*gOscBanks[gCurrentOscBank]->lookupTable*/gDynamicWavetable); |
602 | 599 |
603 gOscillatorBufferWriteCurrentSize = gOscBanks[gCurrentOscBank]->hopCounter * gNumAudioChannels; | 600 gOscillatorBufferWriteCurrentSize = gOscBanks[gCurrentOscBank]->hopCounter * 2; |
604 | 601 |
605 /* Update the pitch right before the hop | 602 /* Update the pitch right before the hop |
606 * Total CV range +/- N_OCT octaves | 603 * Total CV range +/- N_OCT octaves |
607 */ | 604 */ |
608 float pitch = (float)gPitchLatestInput / octaveSplitter - N_OCT/2; | 605 float pitch = (float)gPitchLatestInput / octaveSplitter - N_OCT/2; |
679 wavetable_interpolate(gFeedbackOscillatorTableLength, gDynamicWavetableLength, | 676 wavetable_interpolate(gFeedbackOscillatorTableLength, gDynamicWavetableLength, |
680 gFeedbackOscillatorTable, gDynamicWavetable, | 677 gFeedbackOscillatorTable, gDynamicWavetable, |
681 gOscBanks[gCurrentOscBank]->lookupTable, sineMix); | 678 gOscBanks[gCurrentOscBank]->lookupTable, sineMix); |
682 } | 679 } |
683 | 680 |
684 if(gLoopPointMin >= 60000 && gLoopPointMax >= 60000) { | 681 if(gLoopPointMin >= 60000.0/65536.0 && gLoopPointMax >= 60000.0/65536.0) { |
685 // KLUDGE! | 682 // KLUDGE! |
686 if(gCurrentOscBank == 0) | 683 if(gCurrentOscBank == 0) |
687 gOscBanks[gCurrentOscBank]->setLoopHops(50, ((float)gOscBanks[gCurrentOscBank]->getLastHop() * 0.6) - 1); | 684 gOscBanks[gCurrentOscBank]->setLoopHops(50, ((float)gOscBanks[gCurrentOscBank]->getLastHop() * 0.6) - 1); |
688 else | 685 else |
689 gOscBanks[gCurrentOscBank]->setLoopHops(5, ((float)gOscBanks[gCurrentOscBank]->getLastHop() * 0.7) - 1); | 686 gOscBanks[gCurrentOscBank]->setLoopHops(5, ((float)gOscBanks[gCurrentOscBank]->getLastHop() * 0.7) - 1); |
690 } | 687 } |
691 else { | 688 else { |
692 float normLoopPointMin = (float)gLoopPointMin * gOscBanks[gCurrentOscBank]->getLastHop() / 65535.0; | 689 float normLoopPointMin = (float)gLoopPointMin * gOscBanks[gCurrentOscBank]->getLastHop(); |
693 float normLoopPointMax = (float)gLoopPointMax * gOscBanks[gCurrentOscBank]->getLastHop() / 65535.0; | 690 float normLoopPointMax = (float)gLoopPointMax * gOscBanks[gCurrentOscBank]->getLastHop(); |
694 | 691 |
695 int intLoopPointMin = normLoopPointMin; | 692 int intLoopPointMin = normLoopPointMin; |
696 if(intLoopPointMin < 1) | 693 if(intLoopPointMin < 1) |
697 intLoopPointMin = 1; | 694 intLoopPointMin = 1; |
698 int intLoopPointMax = normLoopPointMax; | 695 int intLoopPointMax = normLoopPointMax; |
731 | 728 |
732 //dbox_printf("min %d max %d\n", gLoopPointMin, gLoopPointMax); | 729 //dbox_printf("min %d max %d\n", gLoopPointMin, gLoopPointMax); |
733 } | 730 } |
734 | 731 |
735 // Clean up at the end of render | 732 // Clean up at the end of render |
736 void cleanup_render() | 733 void cleanup_render(BeagleRTContext *context, void *userData) |
737 { | 734 { |
738 free(gOscillatorBuffer1); | 735 free(gOscillatorBuffer1); |
739 free(gOscillatorBuffer2); | 736 free(gOscillatorBuffer2); |
740 free(gDynamicWavetable); | 737 free(gDynamicWavetable); |
741 } | 738 } |
763 | 760 |
764 tableOut[numSamplesOut] = tableOut[0]; | 761 tableOut[numSamplesOut] = tableOut[0]; |
765 } | 762 } |
766 | 763 |
767 // Create a hysteresis oscillator with a matrix input and output | 764 // Create a hysteresis oscillator with a matrix input and output |
768 inline uint16_t hysteresis_oscillator(uint16_t input, uint16_t risingThreshold, uint16_t fallingThreshold, bool *rising) | 765 inline float hysteresis_oscillator(float input, float risingThreshold, float fallingThreshold, bool *rising) |
769 { | 766 { |
770 uint16_t value; | 767 float value; |
771 | 768 |
772 if(*rising) { | 769 if(*rising) { |
773 if(input > risingThreshold) { | 770 if(input > risingThreshold) { |
774 *rising = false; | 771 *rising = false; |
775 value = 0; | 772 value = 0; |
776 } | 773 } |
777 else | 774 else |
778 value = 65535; | 775 value = 1.0; |
779 } | 776 } |
780 else { | 777 else { |
781 if(input < fallingThreshold) { | 778 if(input < fallingThreshold) { |
782 *rising = true; | 779 *rising = true; |
783 value = 65535; | 780 value = 1.0; |
784 } | 781 } |
785 else | 782 else |
786 value = 0; | 783 value = 0; |
787 } | 784 } |
788 | 785 |