Mercurial > hg > beaglert
comparison examples/02-Digital/level-meter/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 | 8f8809c77dda |
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 #define NUMBER_OF_SEGMENTS 10 | |
29 | |
30 // Two levels of audio: one follows current value, the other holds | |
31 // peaks for longer | |
32 float gAudioLocalLevel = 0, gAudioPeakLevel = 0; | |
33 | |
34 // Decay rates for detecting levels | |
35 float gLocalDecayRate = 0.99, gPeakDecayRate = 0.999; | |
36 | |
37 // Thresholds for LEDs: set in setup() | |
38 float gThresholds[NUMBER_OF_SEGMENTS + 1]; | |
39 int gSamplesToLight[NUMBER_OF_SEGMENTS]; | |
40 | |
41 // High-pass filter on the input | |
42 float gLastX[2] = {0}; | |
43 float gLastY[2] = {0}; | |
44 | |
45 // These coefficients make a high-pass filter at 5Hz for 44.1kHz sample rate | |
46 double gB0 = 0.99949640; | |
47 double gB1 = -1.99899280; | |
48 double gB2 = gB0; | |
49 double gA1 = -1.99899254; | |
50 double gA2 = 0.99899305; | |
51 | |
52 bool setup(BelaContext *context, void *userData) | |
53 { | |
54 // This project makes the assumption that the audio and digital | |
55 // sample rates are the same. But check it to be sure! | |
56 if(context->audioFrames != context->digitalFrames) { | |
57 rt_printf("Error: this project needs the audio and digital sample rates to be the same.\n"); | |
58 return false; | |
59 } | |
60 | |
61 // Initialise threshold levels in -3dB steps. One extra for efficiency in render() | |
62 // Level = 10^(dB/20) | |
63 for(int i = 0; i < NUMBER_OF_SEGMENTS + 1; i++) { | |
64 gThresholds[i] = powf(10.0f, (-1.0 * (NUMBER_OF_SEGMENTS - i)) * .05); | |
65 } | |
66 | |
67 for(int i = 0; i < NUMBER_OF_SEGMENTS; i++) { | |
68 gSamplesToLight[i] = 0; | |
69 pinMode(context, 0, i, OUTPUT); | |
70 } | |
71 | |
72 return true; | |
73 } | |
74 | |
75 void render(BelaContext *context, void *userData) | |
76 { | |
77 for(unsigned int n = 0; n < context->audioFrames; n++) { | |
78 // Get average of audio input channels | |
79 float sample = 0; | |
80 for(unsigned int ch = 0; ch < context->audioChannels; ch++) { | |
81 context->audioOut[n * context->audioChannels + ch] = | |
82 context->audioIn[n * context->audioChannels + ch]; | |
83 sample += context->audioIn[n * context->audioChannels + ch]; | |
84 } | |
85 | |
86 // Do DC-blocking on the sum | |
87 float out = gB0 * sample + gB1 * gLastX[0] + gB2 * gLastX[1] | |
88 - gA1 * gLastY[0] - gA2 * gLastY[1]; | |
89 | |
90 gLastX[1] = gLastX[0]; | |
91 gLastX[0] = sample; | |
92 gLastY[1] = gLastY[0]; | |
93 gLastY[0] = out; | |
94 | |
95 out = fabsf(out / (float)context->audioChannels); | |
96 | |
97 // Do peak detection: fast-responding local level | |
98 if(out > gAudioLocalLevel) | |
99 gAudioLocalLevel = out; | |
100 else | |
101 gAudioLocalLevel *= gLocalDecayRate; | |
102 | |
103 // Do peak detection: slow-responding peak level | |
104 if(out > gAudioPeakLevel) | |
105 gAudioPeakLevel = out; | |
106 else { | |
107 // Make peak decay slowly by only multiplying | |
108 // every few samples | |
109 if(((context->audioFramesElapsed + n) & 31) == 0) | |
110 gAudioPeakLevel *= gPeakDecayRate; | |
111 } | |
112 // LED bargraph on digital outputs 0-9 | |
113 for(int led = 0; led < NUMBER_OF_SEGMENTS; led++) { | |
114 // All LEDs up to the local level light up. The LED | |
115 // for the peak level also remains lit. | |
116 int state = LOW; | |
117 | |
118 if(gAudioLocalLevel > gThresholds[led]) { | |
119 state = HIGH; | |
120 gSamplesToLight[led] = 1000; | |
121 } | |
122 /*else if(gAudioPeakLevel > gThresholds[led] && gAudioPeakLevel <= gThresholds[led + 1]) { | |
123 state = HIGH; | |
124 gSamplesToLight[led] = 1000; | |
125 }*/ | |
126 else if(--gSamplesToLight[led] > 0) | |
127 state = HIGH; | |
128 | |
129 // Write LED | |
130 digitalWriteOnce(context, n, led, state); | |
131 } | |
132 } | |
133 } | |
134 | |
135 void cleanup(BelaContext *context, void *userData) | |
136 { | |
137 | |
138 } |