andrewm@89: /* andrewm@89: * render.cpp andrewm@89: * andrewm@89: * Created on: Oct 24, 2014 andrewm@89: * Author: parallels andrewm@89: */ andrewm@89: andrewm@89: andrewm@89: #include andrewm@89: #include andrewm@89: #include andrewm@89: andrewm@89: int gBufferSize = 8192; andrewm@89: andrewm@89: // Buffers to hold samples for noise analysis andrewm@89: float* gBuffers[10]; andrewm@89: int gBufferPointers[10]; andrewm@89: andrewm@89: // Outputs to display andrewm@89: float gDCLevels[10]; andrewm@89: float gNoiseLevels[10]; andrewm@89: float gNumSamplesAnalysed[10]; andrewm@89: andrewm@89: // Task to print results which would otherwise be too slow for render() andrewm@89: AuxiliaryTask gPrintTask; andrewm@89: andrewm@89: void printResults(); andrewm@89: andrewm@89: // setup() is called once before the audio rendering starts. andrewm@89: // Use it to perform any initialisation and allocation which is dependent andrewm@89: // on the period size or sample rate. andrewm@89: // andrewm@89: // userData holds an opaque pointer to a data structure that was passed andrewm@89: // in from the call to initAudio(). andrewm@89: // andrewm@89: // Return true on success; returning false halts the program. andrewm@89: andrewm@89: bool setup(BeagleRTContext *context, void *userData) andrewm@89: { andrewm@89: // Clear the filter data structures andrewm@89: for(int i = 0; i < 10; i++) { andrewm@89: gBufferPointers[i] = 0; andrewm@89: gBuffers[i] = new float[gBufferSize]; andrewm@89: if(gBuffers[i] == 0) { andrewm@89: rt_printf("Error allocating buffer %d\n", i); andrewm@89: return false; andrewm@89: } andrewm@89: } andrewm@89: andrewm@89: gPrintTask = BeagleRT_createAuxiliaryTask(printResults, 50, "beaglert-print-results"); andrewm@89: andrewm@89: return true; andrewm@89: } andrewm@89: andrewm@89: // render() is called regularly at the highest priority by the audio engine. andrewm@89: // Input and output are given from the audio hardware and the other andrewm@89: // ADCs and DACs (if available). If only audio is available, numMatrixFrames andrewm@89: // will be 0. andrewm@89: andrewm@89: void render(BeagleRTContext *context, void *userData) andrewm@89: { andrewm@89: bool bufferIsFull = false; // Whether at least one buffer has filled andrewm@89: andrewm@89: for(unsigned int n = 0; n < context->audioFrames; n++) { andrewm@89: // Store audio inputs in buffer andrewm@89: for(unsigned int ch = 0; ch < context->audioChannels; ch++) { andrewm@89: if(gBufferPointers[ch] < gBufferSize) { andrewm@89: gBuffers[ch][gBufferPointers[ch]] = andrewm@89: context->audioIn[n * context->audioChannels + ch]; andrewm@89: gBufferPointers[ch]++; andrewm@89: if(gBufferPointers[ch] >= gBufferSize) andrewm@89: bufferIsFull = true; andrewm@89: } andrewm@89: } andrewm@89: } andrewm@89: andrewm@89: if(context->analogChannels != 0) { andrewm@89: for(unsigned int n = 0; n < context->analogFrames; n++) { andrewm@89: // Store analog inputs in buffer, starting at channel 2 andrewm@89: for(unsigned int ch = 0; ch < context->analogChannels; ch++) { andrewm@89: if(gBufferPointers[ch + 2] < gBufferSize) { andrewm@89: gBuffers[ch + 2][gBufferPointers[ch + 2]] = andrewm@89: context->analogIn[n * context->analogChannels + ch]; andrewm@89: gBufferPointers[ch + 2]++; andrewm@89: if(gBufferPointers[ch + 2] >= gBufferSize) andrewm@89: bufferIsFull = true; andrewm@89: } andrewm@89: } andrewm@89: } andrewm@89: } andrewm@89: andrewm@89: if(bufferIsFull) { andrewm@89: // Analyse all active channels at once andrewm@89: for(int ch = 0; ch < 10; ch++) { andrewm@89: // gBufferPointers[ch] tells us how many samples were stored in the buffer andrewm@89: gNumSamplesAnalysed[ch] = gBufferPointers[ch]; andrewm@89: andrewm@89: if(gBufferPointers[ch] != 0) { andrewm@89: float mean = 0; andrewm@89: for(int n = 0; n < gBufferPointers[ch]; n++) { andrewm@89: mean += gBuffers[ch][n]; andrewm@89: } andrewm@89: mean /= (float)gBufferPointers[ch]; andrewm@89: andrewm@89: float rms = 0; andrewm@89: for(int n = 0; n < gBufferPointers[ch]; n++) { andrewm@89: rms += (gBuffers[ch][n] - mean) * (gBuffers[ch][n] - mean); andrewm@89: } andrewm@89: rms = sqrtf(rms / (float)gBufferPointers[ch]); andrewm@89: andrewm@89: gDCLevels[ch] = mean; andrewm@89: gNoiseLevels[ch] = rms; andrewm@89: } andrewm@89: andrewm@89: // Reset pointer to 0 for next time andrewm@89: gBufferPointers[ch] = 0; andrewm@89: } andrewm@89: andrewm@89: BeagleRT_scheduleAuxiliaryTask(gPrintTask); andrewm@89: } andrewm@89: } andrewm@89: andrewm@89: void printResults() andrewm@89: { andrewm@89: rt_printf("\e[1;1H\e[2J"); // Command to clear the screen andrewm@89: andrewm@89: // Print the analysis results. channels 0-1 are audio, channels 2-9 are analog andrewm@89: for(int ch = 0; ch < 10; ch++) { andrewm@89: int samples = gNumSamplesAnalysed[ch]; andrewm@89: if(samples == 0) andrewm@89: continue; andrewm@89: andrewm@89: if(ch == 0) andrewm@89: rt_printf("Audio In L: "); andrewm@89: else if(ch == 1) andrewm@89: rt_printf("Audio In R: "); andrewm@89: else andrewm@89: rt_printf("Analog In %d: ", ch - 2); andrewm@89: andrewm@89: rt_printf("Noise %6.1fdB DC offset %6.4f (%6.1fdB) window size: %d\n", andrewm@89: 20.0f * log10f(gNoiseLevels[ch]), andrewm@89: gDCLevels[ch], andrewm@89: 20.0f * log10f(fabsf(gDCLevels[ch])), andrewm@89: samples); andrewm@89: } andrewm@89: } andrewm@89: andrewm@89: // cleanup() is called once at the end, after the audio has stopped. andrewm@89: // Release any resources that were allocated in setup(). andrewm@89: andrewm@89: void cleanup(BeagleRTContext *context, void *userData) andrewm@89: { andrewm@89: for(int i = 0; i < 10; i++) andrewm@89: delete gBuffers[i]; andrewm@89: }