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++) {