comparison projects/level_meter/render.cpp @ 108:3068421c0737 ultra-staging

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