Mercurial > hg > beaglert
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 } |