comparison examples/04-Audio/measure-noisefloor/render.cpp @ 464:8fcfbfb32aa0 prerelease

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