annotate examples/cape_test/render.cpp @ 447:86591d203c78 prerelease

Updated scripts to use "." instead of source, for sh compatibility
author Giulio Moro <giuliomoro@yahoo.it>
date Sun, 19 Jun 2016 16:33:05 +0100
parents 493a07f6ec09
children
rev   line source
andrewm@55 1 /*
andrewm@55 2 * render.cpp
andrewm@55 3 *
andrewm@55 4 * Created on: Oct 24, 2014
andrewm@55 5 * Author: parallels
andrewm@55 6 */
andrewm@55 7
andrewm@55 8
giuliomoro@301 9 #include <Bela.h>
andrewm@55 10 #include <cmath>
andrewm@55 11
andrewm@55 12 #define ANALOG_LOW (2048.0 / 65536.0)
andrewm@55 13 #define ANALOG_HIGH (50000.0 / 65536.0)
andrewm@55 14
andrewm@55 15 const int gDACPinOrder[] = {6, 4, 2, 0, 1, 3, 5, 7};
andrewm@55 16
andrewm@268 17 enum {
andrewm@268 18 kStateTestingAudioLeft = 0,
andrewm@268 19 kStateTestingAudioRight,
andrewm@268 20 kStateTestingAudioDone
andrewm@268 21 };
andrewm@268 22
andrewm@55 23 uint64_t gLastErrorFrame = 0;
andrewm@55 24 uint32_t gEnvelopeSampleCount = 0;
andrewm@268 25 float gEnvelopeValueL = 0.5, gEnvelopeValueR = 0.5;
andrewm@55 26 float gEnvelopeDecayRate = 0.9995;
andrewm@268 27 int gEnvelopeLastChannel = 0;
andrewm@268 28
andrewm@268 29 float gPositivePeakLevels[2] = {0, 0};
andrewm@268 30 float gNegativePeakLevels[2] = {0, 0};
andrewm@268 31 float gPeakLevelDecayRate = 0.999;
andrewm@268 32 const float gPeakLevelLowThreshold = 0.02;
andrewm@268 33 const float gPeakLevelHighThreshold = 0.2;
andrewm@268 34 const float gDCOffsetThreshold = 0.1;
andrewm@268 35 int gAudioTestState = kStateTestingAudioLeft;
andrewm@268 36 int gAudioTestStateSampleCount = 0;
andrewm@268 37 int gAudioTestSuccessCounter = 0;
andrewm@268 38 const int gAudioTestSuccessCounterThreshold = 64;
andrewm@268 39 const int gAudioTestStateSampleThreshold = 16384;
andrewm@55 40
andrewm@56 41 // setup() is called once before the audio rendering starts.
andrewm@55 42 // Use it to perform any initialisation and allocation which is dependent
andrewm@55 43 // on the period size or sample rate.
andrewm@55 44 //
andrewm@55 45 // userData holds an opaque pointer to a data structure that was passed
andrewm@55 46 // in from the call to initAudio().
andrewm@55 47 //
andrewm@55 48 // Return true on success; returning false halts the program.
andrewm@55 49
giuliomoro@301 50 bool setup(BelaContext *context, void *userData)
andrewm@55 51 {
andrewm@55 52 return true;
andrewm@55 53 }
andrewm@55 54
andrewm@55 55 // render() is called regularly at the highest priority by the audio engine.
andrewm@55 56 // Input and output are given from the audio hardware and the other
andrewm@55 57 // ADCs and DACs (if available). If only audio is available, numMatrixFrames
andrewm@55 58 // will be 0.
andrewm@55 59
giuliomoro@301 60 void render(BelaContext *context, void *userData)
andrewm@55 61 {
andrewm@55 62 static float phase = 0.0;
andrewm@55 63 static int sampleCounter = 0;
andrewm@55 64 static int invertChannel = 0;
andrewm@55 65 float frequency = 0;
andrewm@55 66
andrewm@55 67 // Play a sine wave on the audio output
andrewm@55 68 for(unsigned int n = 0; n < context->audioFrames; n++) {
andrewm@268 69
andrewm@268 70 // Peak detection on the audio inputs, with offset to catch
andrewm@268 71 // DC errors
andrewm@268 72 for(int ch = 0; ch < 2; ch++) {
andrewm@268 73 if(context->audioIn[2*n + ch] > gPositivePeakLevels[ch])
andrewm@268 74 gPositivePeakLevels[ch] = context->audioIn[2*n + ch];
andrewm@268 75 gPositivePeakLevels[ch] += 0.1;
andrewm@268 76 gPositivePeakLevels[ch] *= gPeakLevelDecayRate;
andrewm@268 77 gPositivePeakLevels[ch] -= 0.1;
andrewm@268 78 if(context->audioIn[2*n + ch] < gNegativePeakLevels[ch])
andrewm@268 79 gNegativePeakLevels[ch] = context->audioIn[2*n + ch];
andrewm@268 80 gNegativePeakLevels[ch] -= 0.1;
andrewm@268 81 gNegativePeakLevels[ch] *= gPeakLevelDecayRate;
andrewm@268 82 gNegativePeakLevels[ch] += 0.1;
andrewm@268 83 }
andrewm@268 84
andrewm@268 85 if(gAudioTestState == kStateTestingAudioLeft) {
andrewm@268 86 context->audioOut[2*n] = 0.2 * sinf(phase);
andrewm@268 87 context->audioOut[2*n + 1] = 0;
andrewm@268 88
andrewm@268 89 frequency = 3000.0;
andrewm@268 90 phase += 2.0 * M_PI * frequency / 44100.0;
andrewm@268 91 if(phase >= 2.0 * M_PI)
andrewm@268 92 phase -= 2.0 * M_PI;
andrewm@268 93
andrewm@268 94 gAudioTestStateSampleCount++;
andrewm@268 95 if(gAudioTestStateSampleCount >= gAudioTestStateSampleThreshold) {
andrewm@268 96 // Check if we have the expected input: signal on the left but not
andrewm@268 97 // on the right. Also check that there is not too much DC offset on the
andrewm@268 98 // inactive signal
andrewm@268 99 if((gPositivePeakLevels[0] - gNegativePeakLevels[0]) >= gPeakLevelHighThreshold
andrewm@268 100 && (gPositivePeakLevels[1] - gNegativePeakLevels[1]) <= gPeakLevelLowThreshold &&
andrewm@268 101 fabsf(gPositivePeakLevels[1]) < gDCOffsetThreshold &&
andrewm@268 102 fabsf(gNegativePeakLevels[1]) < gDCOffsetThreshold) {
andrewm@268 103 // Successful test: increment counter
andrewm@268 104 gAudioTestSuccessCounter++;
andrewm@268 105 if(gAudioTestSuccessCounter >= gAudioTestSuccessCounterThreshold) {
andrewm@268 106 gAudioTestState = kStateTestingAudioRight;
andrewm@268 107 gAudioTestStateSampleCount = 0;
andrewm@268 108 gAudioTestSuccessCounter = 0;
andrewm@268 109 }
andrewm@55 110
andrewm@268 111 }
andrewm@268 112 else {
andrewm@311 113 if(!((context->audioFramesElapsed + n) % 22050)) {
andrewm@268 114 // Debugging print messages
andrewm@268 115 if((gPositivePeakLevels[0] - gNegativePeakLevels[0]) < gPeakLevelHighThreshold)
andrewm@268 116 rt_printf("Left Audio In FAIL: insufficient signal: %f\n",
andrewm@268 117 gPositivePeakLevels[0] - gNegativePeakLevels[0]);
andrewm@268 118 else if(gPositivePeakLevels[1] - gNegativePeakLevels[1] > gPeakLevelLowThreshold)
andrewm@268 119 rt_printf("Right Audio In FAIL: signal present when it should not be: %f\n",
andrewm@268 120 gPositivePeakLevels[1] - gNegativePeakLevels[1]);
andrewm@268 121 else if(fabsf(gPositivePeakLevels[1]) >= gDCOffsetThreshold ||
andrewm@268 122 fabsf(gNegativePeakLevels[1]) >= gDCOffsetThreshold)
andrewm@268 123 rt_printf("Right Audio In FAIL: DC offset: (%f, %f)\n",
andrewm@268 124 gPositivePeakLevels[1], gNegativePeakLevels[1]);
andrewm@268 125 }
andrewm@268 126 gAudioTestSuccessCounter--;
andrewm@268 127 if(gAudioTestSuccessCounter <= 0)
andrewm@268 128 gAudioTestSuccessCounter = 0;
andrewm@268 129 }
andrewm@55 130 }
andrewm@268 131 }
andrewm@268 132 else if(gAudioTestState == kStateTestingAudioRight) {
andrewm@268 133 context->audioOut[2*n] = 0;
andrewm@268 134 context->audioOut[2*n + 1] = 0.2 * sinf(phase);
andrewm@268 135
andrewm@268 136 frequency = 3000.0;
andrewm@268 137 phase += 2.0 * M_PI * frequency / 44100.0;
andrewm@268 138 if(phase >= 2.0 * M_PI)
andrewm@268 139 phase -= 2.0 * M_PI;
andrewm@268 140
andrewm@268 141 gAudioTestStateSampleCount++;
andrewm@268 142 if(gAudioTestStateSampleCount >= gAudioTestStateSampleThreshold) {
andrewm@268 143 // Check if we have the expected input: signal on the left but not
andrewm@268 144 // on the right
andrewm@268 145 if((gPositivePeakLevels[1] - gNegativePeakLevels[1]) >= gPeakLevelHighThreshold
andrewm@268 146 && (gPositivePeakLevels[0] - gNegativePeakLevels[0]) <= gPeakLevelLowThreshold &&
andrewm@268 147 fabsf(gPositivePeakLevels[0]) < gDCOffsetThreshold &&
andrewm@268 148 fabsf(gNegativePeakLevels[0]) < gDCOffsetThreshold) {
andrewm@268 149 // Successful test: increment counter
andrewm@268 150 gAudioTestSuccessCounter++;
andrewm@268 151 if(gAudioTestSuccessCounter >= gAudioTestSuccessCounterThreshold) {
andrewm@268 152 gAudioTestSuccessCounter = 0;
andrewm@268 153 gAudioTestStateSampleCount = 0;
andrewm@268 154 gAudioTestState = kStateTestingAudioDone;
andrewm@268 155 }
andrewm@268 156 }
andrewm@268 157 else {
andrewm@311 158 if(!((context->audioFramesElapsed + n) % 22050)) {
andrewm@268 159 // Debugging print messages
andrewm@268 160 if((gPositivePeakLevels[1] - gNegativePeakLevels[1]) < gPeakLevelHighThreshold)
andrewm@268 161 rt_printf("Right Audio In FAIL: insufficient signal: %f\n",
andrewm@268 162 gPositivePeakLevels[1] - gNegativePeakLevels[1]);
andrewm@268 163 else if(gPositivePeakLevels[0] - gNegativePeakLevels[0] > gPeakLevelLowThreshold)
andrewm@268 164 rt_printf("Left Audio In FAIL: signal present when it should not be: %f\n",
andrewm@268 165 gPositivePeakLevels[0] - gNegativePeakLevels[0]);
andrewm@268 166 else if(fabsf(gPositivePeakLevels[0]) >= gDCOffsetThreshold ||
andrewm@268 167 fabsf(gNegativePeakLevels[0]) >= gDCOffsetThreshold)
andrewm@268 168 rt_printf("Left Audio In FAIL: DC offset: (%f, %f)\n",
andrewm@268 169 gPositivePeakLevels[0], gNegativePeakLevels[0]);
andrewm@268 170 }
andrewm@268 171 gAudioTestSuccessCounter--;
andrewm@268 172 if(gAudioTestSuccessCounter <= 0)
andrewm@268 173 gAudioTestSuccessCounter = 0;
andrewm@268 174 }
andrewm@268 175 }
andrewm@55 176 }
andrewm@55 177 else {
andrewm@268 178 // Audio input testing finished. Play tones depending on status of
andrewm@268 179 // analog testing
andrewm@268 180 context->audioOut[2*n] = gEnvelopeValueL * sinf(phase);
andrewm@268 181 context->audioOut[2*n + 1] = gEnvelopeValueR * sinf(phase);
andrewm@268 182
andrewm@268 183 // If one second has gone by with no error, play one sound, else
andrewm@268 184 // play another
andrewm@311 185 if(context->audioFramesElapsed + n - gLastErrorFrame > 44100) {
andrewm@268 186 gEnvelopeValueL *= gEnvelopeDecayRate;
andrewm@268 187 gEnvelopeValueR *= gEnvelopeDecayRate;
andrewm@268 188 gEnvelopeSampleCount++;
andrewm@268 189 if(gEnvelopeSampleCount > 22050) {
andrewm@268 190 if(gEnvelopeLastChannel == 0)
andrewm@268 191 gEnvelopeValueR = 0.5;
andrewm@268 192 else
andrewm@268 193 gEnvelopeValueL = 0.5;
andrewm@268 194 gEnvelopeLastChannel = !gEnvelopeLastChannel;
andrewm@268 195 gEnvelopeSampleCount = 0;
andrewm@268 196 }
andrewm@268 197 frequency = 880.0;
andrewm@268 198 }
andrewm@268 199 else {
andrewm@268 200 gEnvelopeValueL = gEnvelopeValueR = 0.5;
andrewm@268 201 gEnvelopeLastChannel = 0;
andrewm@268 202 frequency = 220.0;
andrewm@268 203 }
andrewm@268 204
andrewm@268 205 phase += 2.0 * M_PI * frequency / 44100.0;
andrewm@268 206 if(phase >= 2.0 * M_PI)
andrewm@268 207 phase -= 2.0 * M_PI;
andrewm@55 208 }
andrewm@55 209 }
andrewm@55 210
andrewm@55 211 for(unsigned int n = 0; n < context->analogFrames; n++) {
andrewm@55 212 // Change outputs every 512 samples
andrewm@55 213 if(sampleCounter < 512) {
andrewm@55 214 for(int k = 0; k < 8; k++) {
andrewm@55 215 if(k == invertChannel)
andrewm@55 216 context->analogOut[n*8 + gDACPinOrder[k]] = ANALOG_HIGH;
andrewm@55 217 else
andrewm@55 218 context->analogOut[n*8 + gDACPinOrder[k]] = 0;
andrewm@55 219 }
andrewm@55 220 }
andrewm@55 221 else {
andrewm@55 222 for(int k = 0; k < 8; k++) {
andrewm@55 223 if(k == invertChannel)
andrewm@55 224 context->analogOut[n*8 + gDACPinOrder[k]] = 0;
andrewm@55 225 else
andrewm@55 226 context->analogOut[n*8 + gDACPinOrder[k]] = ANALOG_HIGH;
andrewm@55 227 }
andrewm@55 228 }
andrewm@55 229
andrewm@55 230 // Read after 256 samples: input should be low
andrewm@55 231 if(sampleCounter == 256) {
andrewm@55 232 for(int k = 0; k < 8; k++) {
andrewm@55 233 if(k == invertChannel) {
andrewm@55 234 if(context->analogIn[n*8 + k] < ANALOG_HIGH) {
andrewm@55 235 rt_printf("FAIL [output %d, input %d] -- output HIGH input %f (inverted)\n", gDACPinOrder[k], k, context->analogIn[n*8 + k]);
andrewm@311 236 gLastErrorFrame = context->audioFramesElapsed + n;
andrewm@55 237 }
andrewm@55 238 }
andrewm@55 239 else {
andrewm@55 240 if(context->analogIn[n*8 + k] > ANALOG_LOW) {
andrewm@55 241 rt_printf("FAIL [output %d, input %d] -- output LOW --> input %f\n", gDACPinOrder[k], k, context->analogIn[n*8 + k]);
andrewm@311 242 gLastErrorFrame = context->audioFramesElapsed + n;
andrewm@55 243 }
andrewm@55 244 }
andrewm@55 245 }
andrewm@55 246 }
andrewm@55 247 else if(sampleCounter == 768) {
andrewm@55 248 for(int k = 0; k < 8; k++) {
andrewm@55 249 if(k == invertChannel) {
andrewm@55 250 if(context->analogIn[n*8 + k] > ANALOG_LOW) {
andrewm@55 251 rt_printf("FAIL [output %d, input %d] -- output LOW input %f (inverted)\n", gDACPinOrder[k], k, context->analogIn[n*8 + k]);
andrewm@311 252 gLastErrorFrame = context->audioFramesElapsed + n;
andrewm@55 253 }
andrewm@55 254 }
andrewm@55 255 else {
andrewm@55 256 if(context->analogIn[n*8 + k] < ANALOG_HIGH) {
andrewm@55 257 rt_printf("FAIL [output %d, input %d] -- output HIGH input %f\n", gDACPinOrder[k], k, context->analogIn[n*8 + k]);
andrewm@311 258 gLastErrorFrame = context->audioFramesElapsed + n;
andrewm@55 259 }
andrewm@55 260 }
andrewm@55 261 }
andrewm@55 262 }
andrewm@55 263
andrewm@55 264 if(++sampleCounter >= 1024) {
andrewm@55 265 sampleCounter = 0;
andrewm@55 266 invertChannel++;
andrewm@55 267 if(invertChannel >= 8)
andrewm@55 268 invertChannel = 0;
andrewm@55 269 }
andrewm@55 270 }
andrewm@55 271 }
andrewm@55 272
andrewm@56 273 // cleanup() is called once at the end, after the audio has stopped.
andrewm@56 274 // Release any resources that were allocated in setup().
andrewm@55 275
giuliomoro@301 276 void cleanup(BelaContext *context, void *userData)
andrewm@55 277 {
andrewm@55 278
andrewm@55 279 }