Mercurial > hg > beaglert
diff projects/cape_test/render.cpp @ 268:8d80eda512cd prerelease
Added new overlay for using PRU0 or PRU1, a script to halt board on button press, and several example projects
author | andrewm |
---|---|
date | Tue, 17 May 2016 14:46:26 +0100 |
parents | 3c3a1357657d |
children |
line wrap: on
line diff
--- a/projects/cape_test/render.cpp Tue May 17 14:38:03 2016 +0100 +++ b/projects/cape_test/render.cpp Tue May 17 14:46:26 2016 +0100 @@ -14,10 +14,29 @@ const int gDACPinOrder[] = {6, 4, 2, 0, 1, 3, 5, 7}; +enum { + kStateTestingAudioLeft = 0, + kStateTestingAudioRight, + kStateTestingAudioDone +}; + uint64_t gLastErrorFrame = 0; uint32_t gEnvelopeSampleCount = 0; -float gEnvelopeValue = 0.5; +float gEnvelopeValueL = 0.5, gEnvelopeValueR = 0.5; float gEnvelopeDecayRate = 0.9995; +int gEnvelopeLastChannel = 0; + +float gPositivePeakLevels[2] = {0, 0}; +float gNegativePeakLevels[2] = {0, 0}; +float gPeakLevelDecayRate = 0.999; +const float gPeakLevelLowThreshold = 0.02; +const float gPeakLevelHighThreshold = 0.2; +const float gDCOffsetThreshold = 0.1; +int gAudioTestState = kStateTestingAudioLeft; +int gAudioTestStateSampleCount = 0; +int gAudioTestSuccessCounter = 0; +const int gAudioTestSuccessCounterThreshold = 64; +const int gAudioTestStateSampleThreshold = 16384; // setup() is called once before the audio rendering starts. // Use it to perform any initialisation and allocation which is dependent @@ -47,27 +66,146 @@ // Play a sine wave on the audio output for(unsigned int n = 0; n < context->audioFrames; n++) { - context->audioOut[2*n] = context->audioOut[2*n + 1] = gEnvelopeValue * sinf(phase); + + // Peak detection on the audio inputs, with offset to catch + // DC errors + for(int ch = 0; ch < 2; ch++) { + if(context->audioIn[2*n + ch] > gPositivePeakLevels[ch]) + gPositivePeakLevels[ch] = context->audioIn[2*n + ch]; + gPositivePeakLevels[ch] += 0.1; + gPositivePeakLevels[ch] *= gPeakLevelDecayRate; + gPositivePeakLevels[ch] -= 0.1; + if(context->audioIn[2*n + ch] < gNegativePeakLevels[ch]) + gNegativePeakLevels[ch] = context->audioIn[2*n + ch]; + gNegativePeakLevels[ch] -= 0.1; + gNegativePeakLevels[ch] *= gPeakLevelDecayRate; + gNegativePeakLevels[ch] += 0.1; + } + + if(gAudioTestState == kStateTestingAudioLeft) { + context->audioOut[2*n] = 0.2 * sinf(phase); + context->audioOut[2*n + 1] = 0; + + frequency = 3000.0; + phase += 2.0 * M_PI * frequency / 44100.0; + if(phase >= 2.0 * M_PI) + phase -= 2.0 * M_PI; + + gAudioTestStateSampleCount++; + if(gAudioTestStateSampleCount >= gAudioTestStateSampleThreshold) { + // Check if we have the expected input: signal on the left but not + // on the right. Also check that there is not too much DC offset on the + // inactive signal + if((gPositivePeakLevels[0] - gNegativePeakLevels[0]) >= gPeakLevelHighThreshold + && (gPositivePeakLevels[1] - gNegativePeakLevels[1]) <= gPeakLevelLowThreshold && + fabsf(gPositivePeakLevels[1]) < gDCOffsetThreshold && + fabsf(gNegativePeakLevels[1]) < gDCOffsetThreshold) { + // Successful test: increment counter + gAudioTestSuccessCounter++; + if(gAudioTestSuccessCounter >= gAudioTestSuccessCounterThreshold) { + gAudioTestState = kStateTestingAudioRight; + gAudioTestStateSampleCount = 0; + gAudioTestSuccessCounter = 0; + } - // If one second has gone by with no error, play one sound, else - // play another - if(context->audioSampleCount + n - gLastErrorFrame > 44100) { - gEnvelopeValue *= gEnvelopeDecayRate; - gEnvelopeSampleCount++; - if(gEnvelopeSampleCount > 22050) { - gEnvelopeValue = 0.5; - gEnvelopeSampleCount = 0; + } + else { + if(!((context->audioSampleCount + n) % 22050)) { + // Debugging print messages + if((gPositivePeakLevels[0] - gNegativePeakLevels[0]) < gPeakLevelHighThreshold) + rt_printf("Left Audio In FAIL: insufficient signal: %f\n", + gPositivePeakLevels[0] - gNegativePeakLevels[0]); + else if(gPositivePeakLevels[1] - gNegativePeakLevels[1] > gPeakLevelLowThreshold) + rt_printf("Right Audio In FAIL: signal present when it should not be: %f\n", + gPositivePeakLevels[1] - gNegativePeakLevels[1]); + else if(fabsf(gPositivePeakLevels[1]) >= gDCOffsetThreshold || + fabsf(gNegativePeakLevels[1]) >= gDCOffsetThreshold) + rt_printf("Right Audio In FAIL: DC offset: (%f, %f)\n", + gPositivePeakLevels[1], gNegativePeakLevels[1]); + } + gAudioTestSuccessCounter--; + if(gAudioTestSuccessCounter <= 0) + gAudioTestSuccessCounter = 0; + } } - frequency = 880.0; + } + else if(gAudioTestState == kStateTestingAudioRight) { + context->audioOut[2*n] = 0; + context->audioOut[2*n + 1] = 0.2 * sinf(phase); + + frequency = 3000.0; + phase += 2.0 * M_PI * frequency / 44100.0; + if(phase >= 2.0 * M_PI) + phase -= 2.0 * M_PI; + + gAudioTestStateSampleCount++; + if(gAudioTestStateSampleCount >= gAudioTestStateSampleThreshold) { + // Check if we have the expected input: signal on the left but not + // on the right + if((gPositivePeakLevels[1] - gNegativePeakLevels[1]) >= gPeakLevelHighThreshold + && (gPositivePeakLevels[0] - gNegativePeakLevels[0]) <= gPeakLevelLowThreshold && + fabsf(gPositivePeakLevels[0]) < gDCOffsetThreshold && + fabsf(gNegativePeakLevels[0]) < gDCOffsetThreshold) { + // Successful test: increment counter + gAudioTestSuccessCounter++; + if(gAudioTestSuccessCounter >= gAudioTestSuccessCounterThreshold) { + gAudioTestSuccessCounter = 0; + gAudioTestStateSampleCount = 0; + gAudioTestState = kStateTestingAudioDone; + } + } + else { + if(!((context->audioSampleCount + n) % 22050)) { + // Debugging print messages + if((gPositivePeakLevels[1] - gNegativePeakLevels[1]) < gPeakLevelHighThreshold) + rt_printf("Right Audio In FAIL: insufficient signal: %f\n", + gPositivePeakLevels[1] - gNegativePeakLevels[1]); + else if(gPositivePeakLevels[0] - gNegativePeakLevels[0] > gPeakLevelLowThreshold) + rt_printf("Left Audio In FAIL: signal present when it should not be: %f\n", + gPositivePeakLevels[0] - gNegativePeakLevels[0]); + else if(fabsf(gPositivePeakLevels[0]) >= gDCOffsetThreshold || + fabsf(gNegativePeakLevels[0]) >= gDCOffsetThreshold) + rt_printf("Left Audio In FAIL: DC offset: (%f, %f)\n", + gPositivePeakLevels[0], gNegativePeakLevels[0]); + } + gAudioTestSuccessCounter--; + if(gAudioTestSuccessCounter <= 0) + gAudioTestSuccessCounter = 0; + } + } } else { - gEnvelopeValue = 0.5; - frequency = 220.0; + // Audio input testing finished. Play tones depending on status of + // analog testing + context->audioOut[2*n] = gEnvelopeValueL * sinf(phase); + context->audioOut[2*n + 1] = gEnvelopeValueR * sinf(phase); + + // If one second has gone by with no error, play one sound, else + // play another + if(context->audioSampleCount + n - gLastErrorFrame > 44100) { + gEnvelopeValueL *= gEnvelopeDecayRate; + gEnvelopeValueR *= gEnvelopeDecayRate; + gEnvelopeSampleCount++; + if(gEnvelopeSampleCount > 22050) { + if(gEnvelopeLastChannel == 0) + gEnvelopeValueR = 0.5; + else + gEnvelopeValueL = 0.5; + gEnvelopeLastChannel = !gEnvelopeLastChannel; + gEnvelopeSampleCount = 0; + } + frequency = 880.0; + } + else { + gEnvelopeValueL = gEnvelopeValueR = 0.5; + gEnvelopeLastChannel = 0; + frequency = 220.0; + } + + phase += 2.0 * M_PI * frequency / 44100.0; + if(phase >= 2.0 * M_PI) + phase -= 2.0 * M_PI; } - - phase += 2.0 * M_PI * frequency / 44100.0; - if(phase >= 2.0 * M_PI) - phase -= 2.0 * M_PI; } for(unsigned int n = 0; n < context->analogFrames; n++) {