annotate examples/04-Audio/measure-noisefloor/render.cpp @ 544:cdabbaf3a252 prerelease

Updated Audio examples for audioOutChannels etc.
author Robert Jack <robert.h.jack@gmail.com>
date Fri, 24 Jun 2016 13:32:07 +0100
parents 8fcfbfb32aa0
children
rev   line source
robert@464 1 /*
robert@464 2 ____ _____ _ _
robert@464 3 | __ )| ____| | / \
robert@464 4 | _ \| _| | | / _ \
robert@464 5 | |_) | |___| |___ / ___ \
robert@464 6 |____/|_____|_____/_/ \_\
robert@464 7
robert@464 8 The platform for ultra-low latency audio and sensor processing
robert@464 9
robert@464 10 http://bela.io
robert@464 11
robert@464 12 A project of the Augmented Instruments Laboratory within the
robert@464 13 Centre for Digital Music at Queen Mary University of London.
robert@464 14 http://www.eecs.qmul.ac.uk/~andrewm
robert@464 15
robert@464 16 (c) 2016 Augmented Instruments Laboratory: Andrew McPherson,
robert@464 17 Astrid Bin, Liam Donovan, Christian Heinrichs, Robert Jack,
robert@464 18 Giulio Moro, Laurel Pardue, Victor Zappi. All rights reserved.
robert@464 19
robert@464 20 The Bela software is distributed under the GNU Lesser General Public License
robert@464 21 (LGPL 3.0), available here: https://www.gnu.org/licenses/lgpl-3.0.txt
robert@464 22 */
robert@464 23
robert@464 24
robert@464 25 #include <Bela.h>
robert@464 26 #include <cmath>
robert@464 27
robert@464 28 int gBufferSize = 8192;
robert@464 29
robert@464 30 // Double buffers to hold samples for noise analysis
robert@464 31 float *gReadBuffers[10], *gWriteBuffers[10];
robert@464 32 float *gBuffers0[10], *gBuffers1[10];
robert@464 33
robert@464 34 int gWriteBufferPointers[10], gReadBufferPointers[10];
robert@464 35
robert@464 36 // Task to analyse and print results which would otherwise be too slow for render()
robert@464 37 AuxiliaryTask gAnalysisTask;
robert@464 38
robert@464 39 void analyseResults();
robert@464 40
robert@464 41 // setup() is called once before the audio rendering starts.
robert@464 42 // Use it to perform any initialisation and allocation which is dependent
robert@464 43 // on the period size or sample rate.
robert@464 44 //
robert@464 45 // userData holds an opaque pointer to a data structure that was passed
robert@464 46 // in from the call to initAudio().
robert@464 47 //
robert@464 48 // Return true on success; returning false halts the program.
robert@464 49
robert@464 50 bool setup(BelaContext *context, void *userData)
robert@464 51 {
robert@544 52
robert@544 53 // Check that we have the same number of inputs and outputs.
robert@544 54 if(context->audioInChannels != context->audioOutChannels ||
robert@544 55 context->analogInChannels != context-> analogOutChannels){
robert@544 56 printf("Error: for this project, you need the same number of input and output channels.\n");
robert@544 57 return false;
robert@544 58 }
robert@544 59
robert@464 60 // Clear the filter data structures
robert@464 61 for(int i = 0; i < 10; i++) {
robert@464 62 gReadBufferPointers[i] = gWriteBufferPointers[i] = 0;
robert@464 63 gBuffers0[i] = new float[gBufferSize];
robert@464 64 gBuffers1[i] = new float[gBufferSize];
robert@464 65 gWriteBuffers[i] = gBuffers0[i];
robert@464 66 gReadBuffers[i] = gBuffers1[i];
robert@464 67 if(gBuffers0[i] == 0 || gBuffers1[i] == 0) {
robert@464 68 rt_printf("Error allocating buffer %d\n", i);
robert@464 69 return false;
robert@464 70 }
robert@464 71 }
robert@464 72
robert@464 73 gAnalysisTask = Bela_createAuxiliaryTask(analyseResults, 50, "bela-analyse-results");
robert@464 74
robert@464 75 return true;
robert@464 76 }
robert@464 77
robert@464 78 // render() is called regularly at the highest priority by the audio engine.
robert@464 79 // Input and output are given from the audio hardware and the other
robert@464 80 // ADCs and DACs (if available). If only audio is available, numMatrixFrames
robert@464 81 // will be 0.
robert@464 82
robert@464 83 void render(BelaContext *context, void *userData)
robert@464 84 {
robert@464 85 bool bufferIsFull = false; // Whether at least one buffer has filled
robert@464 86
robert@464 87 for(unsigned int n = 0; n < context->audioFrames; n++) {
robert@464 88 // Store audio inputs in buffer
robert@544 89 for(unsigned int ch = 0; ch < context->audioOutChannels; ch++) {
robert@464 90 if(gWriteBufferPointers[ch] < gBufferSize) {
robert@464 91 gWriteBuffers[ch][gWriteBufferPointers[ch]] =
robert@544 92 context->audioIn[n * context->audioOutChannels + ch];
robert@464 93 gWriteBufferPointers[ch]++;
robert@464 94 if(gWriteBufferPointers[ch] >= gBufferSize)
robert@464 95 bufferIsFull = true;
robert@464 96 }
robert@464 97 }
robert@464 98 }
robert@464 99
robert@544 100 if(context->analogOutChannels != 0) {
robert@464 101 for(unsigned int n = 0; n < context->analogFrames; n++) {
robert@464 102 // Store analog inputs in buffer, starting at channel 2
robert@544 103 for(unsigned int ch = 0; ch < context->analogOutChannels; ch++) {
robert@464 104 if(gWriteBufferPointers[ch + 2] < gBufferSize) {
robert@464 105 gWriteBuffers[ch + 2][gWriteBufferPointers[ch + 2]] =
robert@544 106 context->analogIn[n * context->analogOutChannels + ch];
robert@464 107 gWriteBufferPointers[ch + 2]++;
robert@464 108 if(gWriteBufferPointers[ch + 2] >= gBufferSize)
robert@464 109 bufferIsFull = true;
robert@464 110 }
robert@464 111
robert@464 112 // Set all analog outputs to halfway point so they can be more
robert@464 113 // easily measured for noise
robert@544 114 context->analogOut[n * context->analogOutChannels + ch] = 0.5;
robert@464 115 }
robert@464 116 }
robert@464 117 }
robert@464 118
robert@464 119
robert@464 120 if(bufferIsFull) {
robert@464 121 // Swap buffers and reset write pointers
robert@464 122 for(int ch = 0; ch < 10; ch++) {
robert@464 123 gReadBufferPointers[ch] = gWriteBufferPointers[ch];
robert@464 124 gWriteBufferPointers[ch] = 0;
robert@464 125
robert@464 126 if(gReadBuffers[ch] == gBuffers0[ch]) {
robert@464 127 gReadBuffers[ch] = gBuffers1[ch];
robert@464 128 gWriteBuffers[ch] = gBuffers0[ch];
robert@464 129 }
robert@464 130 else {
robert@464 131 gReadBuffers[ch] = gBuffers0[ch];
robert@464 132 gWriteBuffers[ch] = gBuffers1[ch];
robert@464 133 }
robert@464 134 }
robert@464 135
robert@464 136 Bela_scheduleAuxiliaryTask(gAnalysisTask);
robert@464 137 }
robert@464 138 }
robert@464 139
robert@464 140 void analyseResults()
robert@464 141 {
robert@464 142 rt_printf("\e[1;1H\e[2J"); // Command to clear the screen
robert@464 143
robert@464 144 // Print the analysis results. channels 0-1 are audio, channels 2-9 are analog
robert@464 145 for(int ch = 0; ch < 10; ch++) {
robert@464 146 // Skip unused channels
robert@464 147 if(gReadBufferPointers[ch] == 0)
robert@464 148 continue;
robert@464 149
robert@464 150 float mean = 0;
robert@464 151 for(int n = 0; n < gReadBufferPointers[ch]; n++) {
robert@464 152 mean += gReadBuffers[ch][n];
robert@464 153 }
robert@464 154 mean /= (float)gReadBufferPointers[ch];
robert@464 155
robert@464 156 float rms = 0;
robert@464 157 for(int n = 0; n < gReadBufferPointers[ch]; n++) {
robert@464 158 rms += (gReadBuffers[ch][n] - mean) * (gReadBuffers[ch][n] - mean);
robert@464 159 }
robert@464 160 rms = sqrtf(rms / (float)gReadBufferPointers[ch]);
robert@464 161
robert@464 162 if(ch == 0)
robert@464 163 rt_printf("Audio In L: ");
robert@464 164 else if(ch == 1)
robert@464 165 rt_printf("Audio In R: ");
robert@464 166 else
robert@464 167 rt_printf("Analog In %d: ", ch - 2);
robert@464 168
robert@464 169 rt_printf("Noise %6.1fdB DC offset %6.4f (%6.1fdB) window size: %d\n",
robert@464 170 20.0f * log10f(rms),
robert@464 171 mean,
robert@464 172 20.0f * log10f(fabsf(mean)),
robert@464 173 gReadBufferPointers[ch]);
robert@464 174 }
robert@464 175 }
robert@464 176
robert@464 177 // cleanup() is called once at the end, after the audio has stopped.
robert@464 178 // Release any resources that were allocated in setup().
robert@464 179
robert@464 180 void cleanup(BelaContext *context, void *userData)
robert@464 181 {
robert@464 182 for(int i = 0; i < 10; i++) {
robert@464 183 delete gBuffers0[i];
robert@464 184 delete gBuffers1[i];
robert@464 185 }
robert@464 186 }