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