Mercurial > hg > beaglert
comparison examples/level_meter/render.cpp @ 300:dbeed520b014 prerelease
Renamed projects to examples
author | Giulio Moro <giuliomoro@yahoo.it> |
---|---|
date | Fri, 27 May 2016 13:58:20 +0100 |
parents | projects/level_meter/render.cpp@8d80eda512cd |
children | e4392164b458 |
comparison
equal
deleted
inserted
replaced
297:a3d83ebdf49b | 300:dbeed520b014 |
---|---|
1 /* | |
2 * render.cpp | |
3 * | |
4 * Created on: Oct 24, 2014 | |
5 * Author: parallels | |
6 */ | |
7 | |
8 | |
9 #include <BeagleRT.h> | |
10 #include <Utilities.h> | |
11 #include <cmath> | |
12 | |
13 #define NUMBER_OF_SEGMENTS 10 | |
14 | |
15 // Two levels of audio: one follows current value, the other holds | |
16 // peaks for longer | |
17 float gAudioLocalLevel = 0, gAudioPeakLevel = 0; | |
18 | |
19 // Decay rates for detecting levels | |
20 float gLocalDecayRate = 0.99, gPeakDecayRate = 0.999; | |
21 | |
22 // Thresholds for LEDs: set in setup() | |
23 float gThresholds[NUMBER_OF_SEGMENTS + 1]; | |
24 int gSamplesToLight[NUMBER_OF_SEGMENTS]; | |
25 | |
26 // High-pass filter on the input | |
27 float gLastX[2] = {0}; | |
28 float gLastY[2] = {0}; | |
29 | |
30 // These coefficients make a high-pass filter at 5Hz for 44.1kHz sample rate | |
31 double gB0 = 0.99949640; | |
32 double gB1 = -1.99899280; | |
33 double gB2 = gB0; | |
34 double gA1 = -1.99899254; | |
35 double gA2 = 0.99899305; | |
36 | |
37 // setup() is called once before the audio rendering starts. | |
38 // Use it to perform any initialisation and allocation which is dependent | |
39 // on the period size or sample rate. | |
40 // | |
41 // userData holds an opaque pointer to a data structure that was passed | |
42 // in from the call to initAudio(). | |
43 // | |
44 // Return true on success; returning false halts the program. | |
45 | |
46 bool setup(BeagleRTContext *context, void *userData) | |
47 { | |
48 // This project makes the assumption that the audio and digital | |
49 // sample rates are the same. But check it to be sure! | |
50 if(context->audioFrames != context->digitalFrames) { | |
51 rt_printf("Error: this project needs the audio and digital sample rates to be the same.\n"); | |
52 return false; | |
53 } | |
54 | |
55 // Initialise threshold levels in -3dB steps. One extra for efficiency in render() | |
56 // Level = 10^(dB/20) | |
57 for(int i = 0; i < NUMBER_OF_SEGMENTS + 1; i++) { | |
58 gThresholds[i] = powf(10.0f, (-1.0 * (NUMBER_OF_SEGMENTS - i)) * .05); | |
59 } | |
60 | |
61 for(int i = 0; i < NUMBER_OF_SEGMENTS; i++) { | |
62 gSamplesToLight[i] = 0; | |
63 pinModeFrame(context, 0, i, OUTPUT); | |
64 } | |
65 | |
66 return true; | |
67 } | |
68 | |
69 // render() is called regularly at the highest priority by the audio engine. | |
70 // Input and output are given from the audio hardware and the other | |
71 // ADCs and DACs (if available). If only audio is available, numMatrixFrames | |
72 // will be 0. | |
73 | |
74 void render(BeagleRTContext *context, void *userData) | |
75 { | |
76 for(unsigned int n = 0; n < context->audioFrames; n++) { | |
77 // Get average of audio input channels | |
78 float sample = 0; | |
79 for(unsigned int ch = 0; ch < context->audioChannels; ch++) { | |
80 context->audioOut[n * context->audioChannels + ch] = | |
81 context->audioIn[n * context->audioChannels + ch]; | |
82 sample += context->audioIn[n * context->audioChannels + ch]; | |
83 } | |
84 | |
85 // Do DC-blocking on the sum | |
86 float out = gB0 * sample + gB1 * gLastX[0] + gB2 * gLastX[1] | |
87 - gA1 * gLastY[0] - gA2 * gLastY[1]; | |
88 | |
89 gLastX[1] = gLastX[0]; | |
90 gLastX[0] = sample; | |
91 gLastY[1] = gLastY[0]; | |
92 gLastY[0] = out; | |
93 | |
94 out = fabsf(out / (float)context->audioChannels); | |
95 | |
96 // Do peak detection: fast-responding local level | |
97 if(out > gAudioLocalLevel) | |
98 gAudioLocalLevel = out; | |
99 else | |
100 gAudioLocalLevel *= gLocalDecayRate; | |
101 | |
102 // Do peak detection: slow-responding peak level | |
103 if(out > gAudioPeakLevel) | |
104 gAudioPeakLevel = out; | |
105 else { | |
106 // Make peak decay slowly by only multiplying | |
107 // every few samples | |
108 if(((context->audioSampleCount + n) & 31) == 0) | |
109 gAudioPeakLevel *= gPeakDecayRate; | |
110 } | |
111 // LED bargraph on digital outputs 0-9 | |
112 for(int led = 0; led < NUMBER_OF_SEGMENTS; led++) { | |
113 // All LEDs up to the local level light up. The LED | |
114 // for the peak level also remains lit. | |
115 int state = LOW; | |
116 | |
117 if(gAudioLocalLevel > gThresholds[led]) { | |
118 state = HIGH; | |
119 gSamplesToLight[led] = 1000; | |
120 } | |
121 /*else if(gAudioPeakLevel > gThresholds[led] && gAudioPeakLevel <= gThresholds[led + 1]) { | |
122 state = HIGH; | |
123 gSamplesToLight[led] = 1000; | |
124 }*/ | |
125 else if(--gSamplesToLight[led] > 0) | |
126 state = HIGH; | |
127 | |
128 // Write LED | |
129 digitalWriteFrameOnce(context, n, led, state); | |
130 } | |
131 } | |
132 } | |
133 | |
134 // cleanup() is called once at the end, after the audio has stopped. | |
135 // Release any resources that were allocated in setup(). | |
136 | |
137 void cleanup(BeagleRTContext *context, void *userData) | |
138 { | |
139 | |
140 } |