annotate projects/measure_noisefloor/render.cpp @ 91:241d4d5df929

Double buffered the noise floor project; works without glitches now
author andrewm
date Sun, 19 Jul 2015 23:19:27 +0100
parents d41631e0fe0e
children
rev   line source
andrewm@89 1 /*
andrewm@89 2 * render.cpp
andrewm@89 3 *
andrewm@89 4 * Created on: Oct 24, 2014
andrewm@89 5 * Author: parallels
andrewm@89 6 */
andrewm@89 7
andrewm@89 8
andrewm@89 9 #include <BeagleRT.h>
andrewm@89 10 #include <Utilities.h>
andrewm@89 11 #include <cmath>
andrewm@89 12
andrewm@89 13 int gBufferSize = 8192;
andrewm@89 14
andrewm@91 15 // Double buffers to hold samples for noise analysis
andrewm@91 16 float *gReadBuffers[10], *gWriteBuffers[10];
andrewm@91 17 float *gBuffers0[10], *gBuffers1[10];
andrewm@89 18
andrewm@91 19 int gWriteBufferPointers[10], gReadBufferPointers[10];
andrewm@89 20
andrewm@91 21 // Task to analyse and print results which would otherwise be too slow for render()
andrewm@91 22 AuxiliaryTask gAnalysisTask;
andrewm@89 23
andrewm@91 24 void analyseResults();
andrewm@89 25
andrewm@89 26 // setup() is called once before the audio rendering starts.
andrewm@89 27 // Use it to perform any initialisation and allocation which is dependent
andrewm@89 28 // on the period size or sample rate.
andrewm@89 29 //
andrewm@89 30 // userData holds an opaque pointer to a data structure that was passed
andrewm@89 31 // in from the call to initAudio().
andrewm@89 32 //
andrewm@89 33 // Return true on success; returning false halts the program.
andrewm@89 34
andrewm@89 35 bool setup(BeagleRTContext *context, void *userData)
andrewm@89 36 {
andrewm@89 37 // Clear the filter data structures
andrewm@89 38 for(int i = 0; i < 10; i++) {
andrewm@91 39 gReadBufferPointers[i] = gWriteBufferPointers[i] = 0;
andrewm@91 40 gBuffers0[i] = new float[gBufferSize];
andrewm@91 41 gBuffers1[i] = new float[gBufferSize];
andrewm@91 42 gWriteBuffers[i] = gBuffers0[i];
andrewm@91 43 gReadBuffers[i] = gBuffers1[i];
andrewm@91 44 if(gBuffers0[i] == 0 || gBuffers1[i] == 0) {
andrewm@89 45 rt_printf("Error allocating buffer %d\n", i);
andrewm@89 46 return false;
andrewm@89 47 }
andrewm@89 48 }
andrewm@89 49
andrewm@91 50 gAnalysisTask = BeagleRT_createAuxiliaryTask(analyseResults, 50, "beaglert-analyse-results");
andrewm@89 51
andrewm@89 52 return true;
andrewm@89 53 }
andrewm@89 54
andrewm@89 55 // render() is called regularly at the highest priority by the audio engine.
andrewm@89 56 // Input and output are given from the audio hardware and the other
andrewm@89 57 // ADCs and DACs (if available). If only audio is available, numMatrixFrames
andrewm@89 58 // will be 0.
andrewm@89 59
andrewm@89 60 void render(BeagleRTContext *context, void *userData)
andrewm@89 61 {
andrewm@89 62 bool bufferIsFull = false; // Whether at least one buffer has filled
andrewm@89 63
andrewm@89 64 for(unsigned int n = 0; n < context->audioFrames; n++) {
andrewm@89 65 // Store audio inputs in buffer
andrewm@89 66 for(unsigned int ch = 0; ch < context->audioChannels; ch++) {
andrewm@91 67 if(gWriteBufferPointers[ch] < gBufferSize) {
andrewm@91 68 gWriteBuffers[ch][gWriteBufferPointers[ch]] =
andrewm@89 69 context->audioIn[n * context->audioChannels + ch];
andrewm@91 70 gWriteBufferPointers[ch]++;
andrewm@91 71 if(gWriteBufferPointers[ch] >= gBufferSize)
andrewm@89 72 bufferIsFull = true;
andrewm@89 73 }
andrewm@89 74 }
andrewm@89 75 }
andrewm@89 76
andrewm@89 77 if(context->analogChannels != 0) {
andrewm@89 78 for(unsigned int n = 0; n < context->analogFrames; n++) {
andrewm@89 79 // Store analog inputs in buffer, starting at channel 2
andrewm@89 80 for(unsigned int ch = 0; ch < context->analogChannels; ch++) {
andrewm@91 81 if(gWriteBufferPointers[ch + 2] < gBufferSize) {
andrewm@91 82 gWriteBuffers[ch + 2][gWriteBufferPointers[ch + 2]] =
andrewm@89 83 context->analogIn[n * context->analogChannels + ch];
andrewm@91 84 gWriteBufferPointers[ch + 2]++;
andrewm@91 85 if(gWriteBufferPointers[ch + 2] >= gBufferSize)
andrewm@89 86 bufferIsFull = true;
andrewm@89 87 }
andrewm@91 88
andrewm@91 89 // Set all analog outputs to halfway point so they can be more
andrewm@91 90 // easily measured for noise
andrewm@91 91 context->analogOut[n * context->analogChannels + ch] = 0.5;
andrewm@89 92 }
andrewm@89 93 }
andrewm@89 94 }
andrewm@91 95
andrewm@89 96
andrewm@89 97 if(bufferIsFull) {
andrewm@91 98 // Swap buffers and reset write pointers
andrewm@89 99 for(int ch = 0; ch < 10; ch++) {
andrewm@91 100 gReadBufferPointers[ch] = gWriteBufferPointers[ch];
andrewm@91 101 gWriteBufferPointers[ch] = 0;
andrewm@89 102
andrewm@91 103 if(gReadBuffers[ch] == gBuffers0[ch]) {
andrewm@91 104 gReadBuffers[ch] = gBuffers1[ch];
andrewm@91 105 gWriteBuffers[ch] = gBuffers0[ch];
andrewm@89 106 }
andrewm@91 107 else {
andrewm@91 108 gReadBuffers[ch] = gBuffers0[ch];
andrewm@91 109 gWriteBuffers[ch] = gBuffers1[ch];
andrewm@91 110 }
andrewm@89 111 }
andrewm@89 112
andrewm@91 113 BeagleRT_scheduleAuxiliaryTask(gAnalysisTask);
andrewm@89 114 }
andrewm@89 115 }
andrewm@89 116
andrewm@91 117 void analyseResults()
andrewm@89 118 {
andrewm@89 119 rt_printf("\e[1;1H\e[2J"); // Command to clear the screen
andrewm@91 120
andrewm@89 121 // Print the analysis results. channels 0-1 are audio, channels 2-9 are analog
andrewm@89 122 for(int ch = 0; ch < 10; ch++) {
andrewm@91 123 // Skip unused channels
andrewm@91 124 if(gReadBufferPointers[ch] == 0)
andrewm@89 125 continue;
andrewm@89 126
andrewm@91 127 float mean = 0;
andrewm@91 128 for(int n = 0; n < gReadBufferPointers[ch]; n++) {
andrewm@91 129 mean += gReadBuffers[ch][n];
andrewm@91 130 }
andrewm@91 131 mean /= (float)gReadBufferPointers[ch];
andrewm@91 132
andrewm@91 133 float rms = 0;
andrewm@91 134 for(int n = 0; n < gReadBufferPointers[ch]; n++) {
andrewm@91 135 rms += (gReadBuffers[ch][n] - mean) * (gReadBuffers[ch][n] - mean);
andrewm@91 136 }
andrewm@91 137 rms = sqrtf(rms / (float)gReadBufferPointers[ch]);
andrewm@91 138
andrewm@89 139 if(ch == 0)
andrewm@89 140 rt_printf("Audio In L: ");
andrewm@89 141 else if(ch == 1)
andrewm@89 142 rt_printf("Audio In R: ");
andrewm@89 143 else
andrewm@89 144 rt_printf("Analog In %d: ", ch - 2);
andrewm@89 145
andrewm@89 146 rt_printf("Noise %6.1fdB DC offset %6.4f (%6.1fdB) window size: %d\n",
andrewm@91 147 20.0f * log10f(rms),
andrewm@91 148 mean,
andrewm@91 149 20.0f * log10f(fabsf(mean)),
andrewm@91 150 gReadBufferPointers[ch]);
andrewm@89 151 }
andrewm@89 152 }
andrewm@89 153
andrewm@89 154 // cleanup() is called once at the end, after the audio has stopped.
andrewm@89 155 // Release any resources that were allocated in setup().
andrewm@89 156
andrewm@89 157 void cleanup(BeagleRTContext *context, void *userData)
andrewm@89 158 {
andrewm@91 159 for(int i = 0; i < 10; i++) {
andrewm@91 160 delete gBuffers0[i];
andrewm@91 161 delete gBuffers1[i];
andrewm@91 162 }
andrewm@89 163 }