comparison 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
comparison
equal deleted inserted replaced
90:c74006ef86ca 91:241d4d5df929
10 #include <Utilities.h> 10 #include <Utilities.h>
11 #include <cmath> 11 #include <cmath>
12 12
13 int gBufferSize = 8192; 13 int gBufferSize = 8192;
14 14
15 // Buffers to hold samples for noise analysis 15 // Double buffers to hold samples for noise analysis
16 float* gBuffers[10]; 16 float *gReadBuffers[10], *gWriteBuffers[10];
17 int gBufferPointers[10]; 17 float *gBuffers0[10], *gBuffers1[10];
18 18
19 // Outputs to display 19 int gWriteBufferPointers[10], gReadBufferPointers[10];
20 float gDCLevels[10];
21 float gNoiseLevels[10];
22 float gNumSamplesAnalysed[10];
23 20
24 // Task to print results which would otherwise be too slow for render() 21 // Task to analyse and print results which would otherwise be too slow for render()
25 AuxiliaryTask gPrintTask; 22 AuxiliaryTask gAnalysisTask;
26 23
27 void printResults(); 24 void analyseResults();
28 25
29 // setup() is called once before the audio rendering starts. 26 // setup() is called once before the audio rendering starts.
30 // Use it to perform any initialisation and allocation which is dependent 27 // Use it to perform any initialisation and allocation which is dependent
31 // on the period size or sample rate. 28 // on the period size or sample rate.
32 // 29 //
37 34
38 bool setup(BeagleRTContext *context, void *userData) 35 bool setup(BeagleRTContext *context, void *userData)
39 { 36 {
40 // Clear the filter data structures 37 // Clear the filter data structures
41 for(int i = 0; i < 10; i++) { 38 for(int i = 0; i < 10; i++) {
42 gBufferPointers[i] = 0; 39 gReadBufferPointers[i] = gWriteBufferPointers[i] = 0;
43 gBuffers[i] = new float[gBufferSize]; 40 gBuffers0[i] = new float[gBufferSize];
44 if(gBuffers[i] == 0) { 41 gBuffers1[i] = new float[gBufferSize];
42 gWriteBuffers[i] = gBuffers0[i];
43 gReadBuffers[i] = gBuffers1[i];
44 if(gBuffers0[i] == 0 || gBuffers1[i] == 0) {
45 rt_printf("Error allocating buffer %d\n", i); 45 rt_printf("Error allocating buffer %d\n", i);
46 return false; 46 return false;
47 } 47 }
48 } 48 }
49 49
50 gPrintTask = BeagleRT_createAuxiliaryTask(printResults, 50, "beaglert-print-results"); 50 gAnalysisTask = BeagleRT_createAuxiliaryTask(analyseResults, 50, "beaglert-analyse-results");
51 51
52 return true; 52 return true;
53 } 53 }
54 54
55 // render() is called regularly at the highest priority by the audio engine. 55 // render() is called regularly at the highest priority by the audio engine.
62 bool bufferIsFull = false; // Whether at least one buffer has filled 62 bool bufferIsFull = false; // Whether at least one buffer has filled
63 63
64 for(unsigned int n = 0; n < context->audioFrames; n++) { 64 for(unsigned int n = 0; n < context->audioFrames; n++) {
65 // Store audio inputs in buffer 65 // Store audio inputs in buffer
66 for(unsigned int ch = 0; ch < context->audioChannels; ch++) { 66 for(unsigned int ch = 0; ch < context->audioChannels; ch++) {
67 if(gBufferPointers[ch] < gBufferSize) { 67 if(gWriteBufferPointers[ch] < gBufferSize) {
68 gBuffers[ch][gBufferPointers[ch]] = 68 gWriteBuffers[ch][gWriteBufferPointers[ch]] =
69 context->audioIn[n * context->audioChannels + ch]; 69 context->audioIn[n * context->audioChannels + ch];
70 gBufferPointers[ch]++; 70 gWriteBufferPointers[ch]++;
71 if(gBufferPointers[ch] >= gBufferSize) 71 if(gWriteBufferPointers[ch] >= gBufferSize)
72 bufferIsFull = true; 72 bufferIsFull = true;
73 } 73 }
74 } 74 }
75 } 75 }
76 76
77 if(context->analogChannels != 0) { 77 if(context->analogChannels != 0) {
78 for(unsigned int n = 0; n < context->analogFrames; n++) { 78 for(unsigned int n = 0; n < context->analogFrames; n++) {
79 // Store analog inputs in buffer, starting at channel 2 79 // Store analog inputs in buffer, starting at channel 2
80 for(unsigned int ch = 0; ch < context->analogChannels; ch++) { 80 for(unsigned int ch = 0; ch < context->analogChannels; ch++) {
81 if(gBufferPointers[ch + 2] < gBufferSize) { 81 if(gWriteBufferPointers[ch + 2] < gBufferSize) {
82 gBuffers[ch + 2][gBufferPointers[ch + 2]] = 82 gWriteBuffers[ch + 2][gWriteBufferPointers[ch + 2]] =
83 context->analogIn[n * context->analogChannels + ch]; 83 context->analogIn[n * context->analogChannels + ch];
84 gBufferPointers[ch + 2]++; 84 gWriteBufferPointers[ch + 2]++;
85 if(gBufferPointers[ch + 2] >= gBufferSize) 85 if(gWriteBufferPointers[ch + 2] >= gBufferSize)
86 bufferIsFull = true; 86 bufferIsFull = true;
87 } 87 }
88
89 // Set all analog outputs to halfway point so they can be more
90 // easily measured for noise
91 context->analogOut[n * context->analogChannels + ch] = 0.5;
88 } 92 }
89 } 93 }
90 } 94 }
95
91 96
92 if(bufferIsFull) { 97 if(bufferIsFull) {
93 // Analyse all active channels at once 98 // Swap buffers and reset write pointers
94 for(int ch = 0; ch < 10; ch++) { 99 for(int ch = 0; ch < 10; ch++) {
95 // gBufferPointers[ch] tells us how many samples were stored in the buffer 100 gReadBufferPointers[ch] = gWriteBufferPointers[ch];
96 gNumSamplesAnalysed[ch] = gBufferPointers[ch]; 101 gWriteBufferPointers[ch] = 0;
97 102
98 if(gBufferPointers[ch] != 0) { 103 if(gReadBuffers[ch] == gBuffers0[ch]) {
99 float mean = 0; 104 gReadBuffers[ch] = gBuffers1[ch];
100 for(int n = 0; n < gBufferPointers[ch]; n++) { 105 gWriteBuffers[ch] = gBuffers0[ch];
101 mean += gBuffers[ch][n];
102 }
103 mean /= (float)gBufferPointers[ch];
104
105 float rms = 0;
106 for(int n = 0; n < gBufferPointers[ch]; n++) {
107 rms += (gBuffers[ch][n] - mean) * (gBuffers[ch][n] - mean);
108 }
109 rms = sqrtf(rms / (float)gBufferPointers[ch]);
110
111 gDCLevels[ch] = mean;
112 gNoiseLevels[ch] = rms;
113 } 106 }
114 107 else {
115 // Reset pointer to 0 for next time 108 gReadBuffers[ch] = gBuffers0[ch];
116 gBufferPointers[ch] = 0; 109 gWriteBuffers[ch] = gBuffers1[ch];
110 }
117 } 111 }
118 112
119 BeagleRT_scheduleAuxiliaryTask(gPrintTask); 113 BeagleRT_scheduleAuxiliaryTask(gAnalysisTask);
120 } 114 }
121 } 115 }
122 116
123 void printResults() 117 void analyseResults()
124 { 118 {
125 rt_printf("\e[1;1H\e[2J"); // Command to clear the screen 119 rt_printf("\e[1;1H\e[2J"); // Command to clear the screen
126 120
127 // Print the analysis results. channels 0-1 are audio, channels 2-9 are analog 121 // Print the analysis results. channels 0-1 are audio, channels 2-9 are analog
128 for(int ch = 0; ch < 10; ch++) { 122 for(int ch = 0; ch < 10; ch++) {
129 int samples = gNumSamplesAnalysed[ch]; 123 // Skip unused channels
130 if(samples == 0) 124 if(gReadBufferPointers[ch] == 0)
131 continue; 125 continue;
126
127 float mean = 0;
128 for(int n = 0; n < gReadBufferPointers[ch]; n++) {
129 mean += gReadBuffers[ch][n];
130 }
131 mean /= (float)gReadBufferPointers[ch];
132
133 float rms = 0;
134 for(int n = 0; n < gReadBufferPointers[ch]; n++) {
135 rms += (gReadBuffers[ch][n] - mean) * (gReadBuffers[ch][n] - mean);
136 }
137 rms = sqrtf(rms / (float)gReadBufferPointers[ch]);
132 138
133 if(ch == 0) 139 if(ch == 0)
134 rt_printf("Audio In L: "); 140 rt_printf("Audio In L: ");
135 else if(ch == 1) 141 else if(ch == 1)
136 rt_printf("Audio In R: "); 142 rt_printf("Audio In R: ");
137 else 143 else
138 rt_printf("Analog In %d: ", ch - 2); 144 rt_printf("Analog In %d: ", ch - 2);
139 145
140 rt_printf("Noise %6.1fdB DC offset %6.4f (%6.1fdB) window size: %d\n", 146 rt_printf("Noise %6.1fdB DC offset %6.4f (%6.1fdB) window size: %d\n",
141 20.0f * log10f(gNoiseLevels[ch]), 147 20.0f * log10f(rms),
142 gDCLevels[ch], 148 mean,
143 20.0f * log10f(fabsf(gDCLevels[ch])), 149 20.0f * log10f(fabsf(mean)),
144 samples); 150 gReadBufferPointers[ch]);
145 } 151 }
146 } 152 }
147 153
148 // cleanup() is called once at the end, after the audio has stopped. 154 // cleanup() is called once at the end, after the audio has stopped.
149 // Release any resources that were allocated in setup(). 155 // Release any resources that were allocated in setup().
150 156
151 void cleanup(BeagleRTContext *context, void *userData) 157 void cleanup(BeagleRTContext *context, void *userData)
152 { 158 {
153 for(int i = 0; i < 10; i++) 159 for(int i = 0; i < 10; i++) {
154 delete gBuffers[i]; 160 delete gBuffers0[i];
161 delete gBuffers1[i];
162 }
155 } 163 }