annotate examples/level_meter/render.cpp @ 310:02c4ca0e3718 prerelease

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