Mercurial > hg > beaglert
diff 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 |
line wrap: on
line diff
--- a/projects/d-box/render.cpp Thu May 28 17:48:42 2015 -0400 +++ b/projects/d-box/render.cpp Sat May 30 12:34:32 2015 -0500 @@ -5,7 +5,7 @@ * Author: Victor Zappi */ -#include "../../include/RTAudio.h" +#include "../../include/BeagleRT.h" #include "../../include/PRU.h" #include "StatusLED.h" #include "config.h" @@ -39,7 +39,6 @@ #define ADC_PIN6 6 #define ADC_PIN7 7 - #define N_OCT 4.0 // maximum number of octaves on sensor 1 extern vector<OscillatorBank*> gOscBanks; @@ -49,7 +48,6 @@ extern StatusLED gStatusLED; extern bool gIsLoading; extern bool gAudioIn; -extern int gPeriodSize; float *gOscillatorBuffer1, *gOscillatorBuffer2; float *gOscillatorBufferRead, *gOscillatorBufferWrite; @@ -78,7 +76,7 @@ // sensor 0. extern float gSensor0LatestTouchPos; extern int gSensor0LatestTouchNum; -uint16_t gPitchLatestInput = 0; +float gPitchLatestInput = 0; extern float gSensor1LatestTouchPos[]; //extern float gSensor1LatestTouchSizes[]; @@ -94,9 +92,9 @@ // Loop points from matrix input 4 const int gLoopPointsInputBufferSize = 256; -uint16_t gLoopPointsInputBuffer[gLoopPointsInputBufferSize]; +float gLoopPointsInputBuffer[gLoopPointsInputBufferSize]; int gLoopPointsInputBufferPointer = 0; -int gLoopPointMin = 0, gLoopPointMax = 0; +float gLoopPointMin = 0, gLoopPointMax = 0; // multiplier to activate or mute audio in int audioInStatus = 0; @@ -106,7 +104,7 @@ // pitch vars float octaveSplitter; -u_int16_t semitones[((int)N_OCT*12)+1]; +float semitones[((int)N_OCT*12)+1]; float deltaTouch = 0; float deltaWeightP = 0.5; float deltaWeightI = 0.0005; @@ -143,22 +141,21 @@ float *tableIn, float *tableOut, float *sineTable, float sineMix); -inline uint16_t hysteresis_oscillator(uint16_t input, uint16_t risingThreshold, - uint16_t fallingThreshold, bool *rising); +inline float hysteresis_oscillator(float input, float risingThreshold, + float fallingThreshold, bool *rising); + +void render_medium_prio(); +void render_low_prio(); #ifdef DBOX_CAPE_TEST void render_capetest(int numMatrixFrames, int numAudioFrames, float *audioIn, float *audioOut, uint16_t *matrixIn, uint16_t *matrixOut); #endif -bool initialise_render(int numMatrixChannels, int numAudioChannels, - int numMatrixFramesPerPeriod, - int numAudioFramesPerPeriod, - float matrixSampleRate, float audioSampleRate, - void *userData) { +bool initialise_render(BeagleRTContext *context, void *userData) { int oscBankHopSize = *(int *)userData; - if(numMatrixChannels != 8) { + if(context->analogChannels != 8) { printf("Error: D-Box needs matrix enabled with 8 channels.\n"); return false; } @@ -166,19 +163,19 @@ // Allocate two buffers for rendering oscillator bank samples // One will be used for writing in the background while the other is used for reading // on the audio thread. 8-byte alignment needed for the NEON code. - if(posix_memalign((void **)&gOscillatorBuffer1, 8, oscBankHopSize * gNumAudioChannels * sizeof(float))) { + if(posix_memalign((void **)&gOscillatorBuffer1, 8, oscBankHopSize * context->audioChannels * sizeof(float))) { printf("Error allocating render buffers\n"); return false; } - if(posix_memalign((void **)&gOscillatorBuffer2, 8, oscBankHopSize * gNumAudioChannels * sizeof(float))) { + if(posix_memalign((void **)&gOscillatorBuffer2, 8, oscBankHopSize * context->audioChannels * sizeof(float))) { printf("Error allocating render buffers\n"); return false; } gOscillatorBufferWrite = gOscillatorBuffer1; gOscillatorBufferRead = gOscillatorBuffer2; - memset(gOscillatorBuffer1, 0, oscBankHopSize * gNumAudioChannels * sizeof(float)); - memset(gOscillatorBuffer2, 0, oscBankHopSize * gNumAudioChannels * sizeof(float)); + memset(gOscillatorBuffer1, 0, oscBankHopSize * context->audioChannels * sizeof(float)); + memset(gOscillatorBuffer2, 0, oscBankHopSize * context->audioChannels * sizeof(float)); // Initialise the dynamic wavetable used by the oscillator bank // It should match the size of the static one already allocated in the OscillatorBank object @@ -189,18 +186,18 @@ return false; } - gFeedbackOscillator.initialise(8192, 10.0, matrixSampleRate); + gFeedbackOscillator.initialise(8192, 10.0, context->analogSampleRate); for(int n = 0; n < gDynamicWavetableLength + 1; n++) gDynamicWavetable[n] = 0; // pitch - float midPos = (float)65535/2.0; - octaveSplitter = round((float)65535/(N_OCT)); + float midPos = 0.5; + octaveSplitter = 1.0 / N_OCT; int numOfSemi = 12*N_OCT; int middleSemitone = 12*N_OCT/2; int lastSemitone = middleSemitone+numOfSemi/2; - float inc = (float)65535/(N_OCT*12.0); + float inc = 1.0 / (N_OCT*12.0); int i = -1; for(int semi=middleSemitone; semi<=lastSemitone; semi++) semitones[semi] = ( midPos + (++i)*inc) + 0.5; @@ -212,7 +209,7 @@ audioInStatus = 1; // filter - blockSize = 2*gPeriodSize; + blockSize = context->audioFrames; filterState[0] = (ne10_float32_t *) NE10_MALLOC ((FILTER_TAP_NUM+blockSize-1) * sizeof (ne10_float32_t)); filterState[1] = (ne10_float32_t *) NE10_MALLOC ((FILTER_TAP_NUM+blockSize-1) * sizeof (ne10_float32_t)); filterIn[0] = (ne10_float32_t *) NE10_MALLOC (blockSize * sizeof (ne10_float32_t)); @@ -223,24 +220,23 @@ ne10_fir_init_float(&filter[1], FILTER_TAP_NUM, filterTaps, filterState[1], blockSize); // peak outputs - PeakBurst[0].setAttackRate(.00001 * matrixSampleRate); - PeakBurst[1].setAttackRate(.00001 * matrixSampleRate); - PeakBurst[0].setDecayRate(.5 * matrixSampleRate); - PeakBurst[1].setDecayRate(.5 * matrixSampleRate); + PeakBurst[0].setAttackRate(.00001 * context->analogSampleRate); + PeakBurst[1].setAttackRate(.00001 * context->analogSampleRate); + PeakBurst[0].setDecayRate(.5 * context->analogSampleRate); + PeakBurst[1].setDecayRate(.5 * context->analogSampleRate); PeakBurst[0].setSustainLevel(0.0); PeakBurst[1].setSustainLevel(0.0); // Initialise auxiliary tasks - if((gMediumPriorityRender = createAuxiliaryTaskLoop(&render_medium_prio, 90, "dbox-calculation-medium")) == 0) + if((gMediumPriorityRender = BeagleRT_createAuxiliaryTask(&render_medium_prio, BEAGLERT_AUDIO_PRIORITY - 10, "dbox-calculation-medium")) == 0) return false; - if((gLowPriorityRender = createAuxiliaryTaskLoop(&render_low_prio, 85, "dbox-calculation-low")) == 0) + if((gLowPriorityRender = BeagleRT_createAuxiliaryTask(&render_low_prio, BEAGLERT_AUDIO_PRIORITY - 15, "dbox-calculation-low")) == 0) return false; return true; } -void render(int numMatrixFrames, int numAudioFrames, float *audioIn, float *audioOut, - uint16_t *matrixIn, uint16_t *matrixOut) +void render(BeagleRTContext *context, void *userData) { #ifdef DBOX_CAPE_TEST render_capetest(numMatrixFrames, numAudioFrames, audioIn, audioOut, matrixIn, matrixOut); @@ -250,10 +246,10 @@ if(gOscBanks[gCurrentOscBank]->state==bank_playing) { - assert(gNumAudioChannels == 2); + assert(context->audioChannels == 2); #ifdef OLD_OSCBANK - memset(audioOut, 0, numAudioFrames * gNumAudioChannels * sizeof(float)); + memset(audioOut, 0, numAudioFrames * * sizeof(float)); /* Render the oscillator bank. The oscillator bank function is written in NEON assembly * and it strips out all extra checks, so find out in advance whether we can render a whole @@ -290,18 +286,18 @@ gOscBanks[gCurrentOscBank]->oscillatorAmplitudeDerivatives, gDynamicWavetable/*gOscBanks[gCurrentOscBank]->lookupTable*/); framesRemaining -= gOscBanks[gCurrentOscBank]->hopCounter; - audioOutWithOffset += gNumAudioChannels * gOscBanks[gCurrentOscBank]->hopCounter; + audioOutWithOffset += * gOscBanks[gCurrentOscBank]->hopCounter; gOscBanks[gCurrentOscBank]->sampleCount += gOscBanks[gCurrentOscBank]->hopCounter; gOscBanks[gCurrentOscBank]->nextHop(); } } #else - for(int n = 0; n < numAudioFrames; n++) { - audioOut[2*n] = gOscillatorBufferRead[gOscillatorBufferReadPointer++]+audioIn[2*n]*audioInStatus; - audioOut[2*n + 1] = gOscillatorBufferRead[gOscillatorBufferReadPointer++]+audioIn[2*n+1]*audioInStatus; + for(unsigned int n = 0; n < context->audioFrames; n++) { + context->audioOut[2*n] = gOscillatorBufferRead[gOscillatorBufferReadPointer++]+context->audioIn[2*n]*audioInStatus; + context->audioOut[2*n + 1] = gOscillatorBufferRead[gOscillatorBufferReadPointer++]+context->audioIn[2*n+1]*audioInStatus; - filterIn[0][n] = fabs(audioIn[2*n]); // rectify for peak detection in 1 - filterIn[1][n] = fabs(audioIn[2*n+1]); // rectify for peak detection in 2 + filterIn[0][n] = fabs(context->audioIn[2*n]); // rectify for peak detection in 1 + filterIn[1][n] = fabs(context->audioIn[2*n+1]); // rectify for peak detection in 2 /* FIXME why doesn't this work? */ /* @@ -326,19 +322,19 @@ gOscillatorBufferReadPointer = 0; gOscillatorNeedsRender = true; - scheduleAuxiliaryTask(gMediumPriorityRender); + BeagleRT_scheduleAuxiliaryTask(gMediumPriorityRender); } } #endif } else { - for(int n = 0; n < numAudioFrames; n++) { - audioOut[2*n] = audioIn[2*n]*audioInStatus; - audioOut[2*n + 1] = audioIn[2*n+1]*audioInStatus; + for(unsigned int n = 0; n < context->audioFrames; n++) { + context->audioOut[2*n] = context->audioIn[2*n]*audioInStatus; + context->audioOut[2*n + 1] = context->audioIn[2*n+1]*audioInStatus; - filterIn[0][n] = fabs(audioIn[2*n]); // rectify for peak detection in 1 - filterIn[1][n] = fabs(audioIn[2*n+1]); // rectify for peak detection in 2 + filterIn[0][n] = fabs(context->audioIn[2*n]); // rectify for peak detection in 1 + filterIn[1][n] = fabs(context->audioIn[2*n+1]); // rectify for peak detection in 2 } } @@ -346,7 +342,7 @@ ne10_fir_float_neon(&filter[0], filterIn[0], filterOut[0], blockSize); ne10_fir_float_neon(&filter[1], filterIn[1], filterOut[1], blockSize); - for(int n = 0; n < numMatrixFrames; n++) { + for(unsigned int n = 0; n < context->analogFrames; n++) { /* Matrix Out 0, In 0 @@ -354,12 +350,12 @@ * CV loop * Controls pitch of sound */ - int touchPosInt = gSensor0LatestTouchPos * 65536.0; + float touchPosInt = gSensor0LatestTouchPos; if(touchPosInt < 0) touchPosInt = 0; - if(touchPosInt > 65535) touchPosInt = 65535; - matrixOut[n*8 + DAC_PIN0] = touchPosInt; + if(touchPosInt > 1.0) touchPosInt = 1.0; + context->analogOut[n*8 + DAC_PIN0] = touchPosInt; - gPitchLatestInput = matrixIn[n*8 + ADC_PIN0]; + gPitchLatestInput = context->analogIn[n*8 + ADC_PIN0]; /* Matrix Out 7 @@ -372,17 +368,17 @@ if(gSensor0LatestTouchNum>0) { // current pitch is gPitchLatestInput, already retrieved - semitoneIndex = ( ( (float)gPitchLatestInput / 65535)*12*N_OCT )+0.5; // closest semitone + semitoneIndex = ( gPitchLatestInput * 12 * N_OCT )+0.5; // closest semitone deltaTarget = (semitones[semitoneIndex]-gPitchLatestInput); // delta between pitch and target deltaTouch += deltaTarget*deltaWeightI; // update feedback [previous + current] } else deltaTouch = 0; - int nextOut = touchPosInt + deltaTarget*deltaWeightP + deltaTouch; // add feedback to touch -> next out + float nextOut = touchPosInt + deltaTarget*deltaWeightP + deltaTouch; // add feedback to touch -> next out if(nextOut < 0) nextOut = 0; // clamp - if(nextOut > 65535) nextOut = 65535; // clamp - matrixOut[n*8 + DAC_PIN7] = nextOut; // send next nextOut + if(nextOut > 1.0) nextOut = 1.0; // clamp + context->analogOut[n*8 + DAC_PIN7] = nextOut; // send next nextOut /* @@ -392,7 +388,8 @@ * Controls speed of playback */ bool wasRising = gSpeedHysteresisOscillatorRising; - matrixOut[n*8 + DAC_PIN1] = hysteresis_oscillator(matrixIn[n*8 + ADC_PIN1], 48000, 16000, &gSpeedHysteresisOscillatorRising); + context->analogOut[n*8 + DAC_PIN1] = hysteresis_oscillator(context->analogIn[n*8 + ADC_PIN1], 48000.0/65536.0, + 16000.0/65536.0, &gSpeedHysteresisOscillatorRising); // Find interval of zero crossing if(wasRising && !gSpeedHysteresisOscillatorRising) { @@ -415,12 +412,12 @@ * Controls wavetable used for oscillator bank */ - int tableLength = gFeedbackOscillator.process(matrixIn[n*8 + ADC_PIN2], &matrixOut[n*8 + DAC_PIN2]); + int tableLength = gFeedbackOscillator.process(context->analogIn[n*8 + ADC_PIN2], &context->analogOut[n*8 + DAC_PIN2]); if(tableLength != 0) { gFeedbackOscillatorTableLength = tableLength; gFeedbackOscillatorTable = gFeedbackOscillator.wavetable(); gDynamicWavetableNeedsRender = true; - scheduleAuxiliaryTask(gLowPriorityRender); + BeagleRT_scheduleAuxiliaryTask(gLowPriorityRender); } /* @@ -432,10 +429,10 @@ */ volatile int touchCount = gSensor1LatestTouchCount; if(touchCount == 0) - matrixOut[n*8 + DAC_PIN3] = 0; + context->analogOut[n*8 + DAC_PIN3] = 0; else { int touchIndex = (gMatrixSampleCount >> 5) % touchCount; - matrixOut[n*8 + DAC_PIN3] = gSensor1LatestTouchPos[touchIndex] * 56000.0f; + context->analogOut[n*8 + DAC_PIN3] = gSensor1LatestTouchPos[touchIndex] * 56000.0f / 65536.0f; if(touchIndex != gSensor1LastTouchIndex) { // Just changed to a new touch output. Reset the counter. // It will take 2*matrixFrames samples for this output to come back to the @@ -443,33 +440,33 @@ // let's say 24 samples into it. // FIXME this won't work for p > 2 - gSensor1InputDelayCounter = 24 + 2*numMatrixFrames; + gSensor1InputDelayCounter = 24 + 2*context->analogFrames; gSensor1InputIndex = touchIndex; } gSensor1LastTouchIndex = touchIndex; } if(gSensor1InputDelayCounter-- >= 0 && touchCount > 0) { - gSensor1MatrixTouchPos[gSensor1InputIndex] = (float)matrixIn[n*8 + ADC_PIN3] / 65536.0f; + gSensor1MatrixTouchPos[gSensor1InputIndex] = context->analogIn[n*8 + ADC_PIN3]; } /* Matrix Out 4 * * Sensor 1 last pos */ - touchPosInt = gSensor1LatestTouchPos[gSensor1LatestTouchIndex] * 65536.0; + touchPosInt = gSensor1LatestTouchPos[gSensor1LatestTouchIndex]; if(touchPosInt < 0) touchPosInt = 0; - if(touchPosInt > 65535) touchPosInt = 65535; - matrixOut[n*8 + DAC_PIN4] = touchPosInt; + if(touchPosInt > 1.0) touchPosInt = 1.0; + context->analogOut[n*8 + DAC_PIN4] = touchPosInt; /* Matrix In 4 * * Loop points selector */ - gLoopPointsInputBuffer[gLoopPointsInputBufferPointer++] = matrixIn[n*8 + ADC_PIN4]; + gLoopPointsInputBuffer[gLoopPointsInputBufferPointer++] = context->analogIn[n*8 + ADC_PIN4]; if(gLoopPointsInputBufferPointer >= gLoopPointsInputBufferSize) { // Find min and max values - uint16_t loopMax = 0, loopMin = 65535; + float loopMax = 0, loopMin = 1.0; for(int i = 0; i < gLoopPointsInputBufferSize; i++) { if(gLoopPointsInputBuffer[i] < loopMin) loopMin = gLoopPointsInputBuffer[i]; @@ -503,8 +500,8 @@ PeakBurst[0].process(1); - int convAudio = burstOut*peak[0]*65535; - matrixOut[n*8 + DAC_PIN5] = convAudio; + float convAudio = burstOut*peak[0]; + context->analogOut[n*8 + DAC_PIN5] = convAudio; prevFiltered[0] = filterOut[0][n*2+1]; if(prevFiltered[0]>1) prevFiltered[0] = 1; @@ -513,8 +510,8 @@ * * Dissonance, via changing frequency motion of partials */ - float amount = (float)matrixIn[n*8 + ADC_PIN5] / 65536.0f; - gOscBanks[gCurrentOscBank]->freqMovement = 1-amount; + float amount = (float)context->analogIn[n*8 + ADC_PIN5]; + gOscBanks[gCurrentOscBank]->freqMovement = 1.0 - amount; @@ -537,8 +534,8 @@ PeakBurst[1].process(1); - convAudio = burstOut*peak[1]*65535; - matrixOut[n*8 + DAC_PIN6] = convAudio; + convAudio = burstOut*peak[1]; + context->analogOut[n*8 + DAC_PIN6] = convAudio; prevFiltered[1] = filterOut[1][n*2+1]; if(prevFiltered[1]>1) prevFiltered[1] = 1; @@ -550,14 +547,14 @@ if(!gIsLoading) { // Use hysteresis to avoid jumping back and forth between sounds if(gOscBanks.size() > 1) { - int input = matrixIn[n*8 + ADC_PIN6]; - const int hystValue = 16000; + float input = context->analogIn[n*8 + ADC_PIN6]; + const float hystValue = 16000.0 / 65536.0; - int upHysteresisValue = ((gCurrentOscBank + 1) * 65536 + hystValue) / gOscBanks.size(); - int downHysteresisValue = (gCurrentOscBank * 65536 - hystValue) / gOscBanks.size(); + float upHysteresisValue = ((gCurrentOscBank + 1) + hystValue) / gOscBanks.size(); + float downHysteresisValue = (gCurrentOscBank - hystValue) / gOscBanks.size(); if(input > upHysteresisValue || input < downHysteresisValue) { - gNextOscBank = input * gOscBanks.size() / 65536; + gNextOscBank = input * gOscBanks.size(); if(gNextOscBank < 0) gNextOscBank = 0; if((unsigned)gNextOscBank >= gOscBanks.size()) @@ -572,8 +569,8 @@ * FSR from primary touch sensor * Value ranges from 0-1799 */ - gLastFSRValue = matrixIn[n*8 + ADC_PIN7] * (1799.0 / 65535.0); - //gLastFSRValue = 1799 - matrixIn[n*8 + ADC_PIN7] * (1799.0 / 65535.0); + gLastFSRValue = context->analogIn[n*8 + ADC_PIN7] * 1799.0; + //gLastFSRValue = 1799 - context->analogIn[n*8 + ADC_PIN7] * (1799.0 / 65535.0); //dbox_printf("%i\n",gLastFSRValue); gMatrixSampleCount++; @@ -590,7 +587,7 @@ gOscillatorNeedsRender = false; /* Render one frame into the write buffer */ - memset(gOscillatorBufferWrite, 0, gOscBanks[gCurrentOscBank]->hopCounter * gNumAudioChannels * sizeof(float)); + memset(gOscillatorBufferWrite, 0, gOscBanks[gCurrentOscBank]->hopCounter * 2 * sizeof(float)); /* assumes 2 audio channels */ oscillator_bank_neon(gOscBanks[gCurrentOscBank]->hopCounter, gOscillatorBufferWrite, gOscBanks[gCurrentOscBank]->actPartNum, gOscBanks[gCurrentOscBank]->lookupTableSize, @@ -600,7 +597,7 @@ gOscBanks[gCurrentOscBank]->oscillatorAmplitudeDerivatives, /*gOscBanks[gCurrentOscBank]->lookupTable*/gDynamicWavetable); - gOscillatorBufferWriteCurrentSize = gOscBanks[gCurrentOscBank]->hopCounter * gNumAudioChannels; + gOscillatorBufferWriteCurrentSize = gOscBanks[gCurrentOscBank]->hopCounter * 2; /* Update the pitch right before the hop * Total CV range +/- N_OCT octaves @@ -681,7 +678,7 @@ gOscBanks[gCurrentOscBank]->lookupTable, sineMix); } - if(gLoopPointMin >= 60000 && gLoopPointMax >= 60000) { + if(gLoopPointMin >= 60000.0/65536.0 && gLoopPointMax >= 60000.0/65536.0) { // KLUDGE! if(gCurrentOscBank == 0) gOscBanks[gCurrentOscBank]->setLoopHops(50, ((float)gOscBanks[gCurrentOscBank]->getLastHop() * 0.6) - 1); @@ -689,8 +686,8 @@ gOscBanks[gCurrentOscBank]->setLoopHops(5, ((float)gOscBanks[gCurrentOscBank]->getLastHop() * 0.7) - 1); } else { - float normLoopPointMin = (float)gLoopPointMin * gOscBanks[gCurrentOscBank]->getLastHop() / 65535.0; - float normLoopPointMax = (float)gLoopPointMax * gOscBanks[gCurrentOscBank]->getLastHop() / 65535.0; + float normLoopPointMin = (float)gLoopPointMin * gOscBanks[gCurrentOscBank]->getLastHop(); + float normLoopPointMax = (float)gLoopPointMax * gOscBanks[gCurrentOscBank]->getLastHop(); int intLoopPointMin = normLoopPointMin; if(intLoopPointMin < 1) @@ -733,7 +730,7 @@ } // Clean up at the end of render -void cleanup_render() +void cleanup_render(BeagleRTContext *context, void *userData) { free(gOscillatorBuffer1); free(gOscillatorBuffer2); @@ -765,9 +762,9 @@ } // Create a hysteresis oscillator with a matrix input and output -inline uint16_t hysteresis_oscillator(uint16_t input, uint16_t risingThreshold, uint16_t fallingThreshold, bool *rising) +inline float hysteresis_oscillator(float input, float risingThreshold, float fallingThreshold, bool *rising) { - uint16_t value; + float value; if(*rising) { if(input > risingThreshold) { @@ -775,12 +772,12 @@ value = 0; } else - value = 65535; + value = 1.0; } else { if(input < fallingThreshold) { *rising = true; - value = 65535; + value = 1.0; } else value = 0;