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