annotate examples/level_meter/render.cpp @ 380:9dc5a0ccad25 prerelease

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