annotate projects/level_meter/render.cpp @ 277:4b3ae93ab102 prerelease

build_project.sh allows to pass a custom project name
author Giulio Moro <giuliomoro@yahoo.it>
date Tue, 17 May 2016 16:07:35 +0100
parents 3a5823f7a11f
children 8d80eda512cd
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
andrewm@88 9 #include <BeagleRT.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@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
andrewm@88 45 bool setup(BeagleRTContext *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@88 60 for(int i = 0; i < NUMBER_OF_SEGMENTS; i++)
andrewm@88 61 pinModeFrame(context, 0, i, OUTPUT);
andrewm@88 62
andrewm@88 63 return true;
andrewm@88 64 }
andrewm@88 65
andrewm@88 66 // render() is called regularly at the highest priority by the audio engine.
andrewm@88 67 // Input and output are given from the audio hardware and the other
andrewm@88 68 // ADCs and DACs (if available). If only audio is available, numMatrixFrames
andrewm@88 69 // will be 0.
andrewm@88 70
andrewm@88 71 void render(BeagleRTContext *context, void *userData)
andrewm@88 72 {
andrewm@88 73 for(unsigned int n = 0; n < context->audioFrames; n++) {
andrewm@88 74 // Get average of audio input channels
andrewm@88 75 float sample = 0;
andrewm@88 76 for(unsigned int ch = 0; ch < context->audioChannels; ch++) {
andrewm@88 77 context->audioOut[n * context->audioChannels + ch] =
andrewm@88 78 context->audioIn[n * context->audioChannels + ch];
andrewm@88 79 sample += context->audioIn[n * context->audioChannels + ch];
andrewm@88 80 }
andrewm@88 81
andrewm@88 82 // Do DC-blocking on the sum
andrewm@88 83 float out = gB0 * sample + gB1 * gLastX[0] + gB2 * gLastX[1]
andrewm@88 84 - gA1 * gLastY[0] - gA2 * gLastY[1];
andrewm@88 85
andrewm@88 86 gLastX[1] = gLastX[0];
andrewm@88 87 gLastX[0] = sample;
andrewm@88 88 gLastY[1] = gLastY[0];
andrewm@88 89 gLastY[0] = out;
andrewm@88 90
andrewm@88 91 out = fabsf(out / (float)context->audioChannels);
andrewm@88 92
andrewm@88 93 // Do peak detection: fast-responding local level
andrewm@88 94 if(out > gAudioLocalLevel)
andrewm@88 95 gAudioLocalLevel = out;
andrewm@88 96 else
andrewm@88 97 gAudioLocalLevel *= gLocalDecayRate;
andrewm@88 98
andrewm@88 99 // Do peak detection: slow-responding peak level
andrewm@88 100 if(out > gAudioPeakLevel)
andrewm@88 101 gAudioPeakLevel = out;
andrewm@88 102 else {
andrewm@88 103 // Make peak decay slowly by only multiplying
andrewm@88 104 // every few samples
andrewm@88 105 if(((context->audioSampleCount + n) & 31) == 0)
andrewm@88 106 gAudioPeakLevel *= gPeakDecayRate;
andrewm@88 107 }
andrewm@88 108 // LED bargraph on digital outputs 0-9
andrewm@88 109 for(int led = 0; led < NUMBER_OF_SEGMENTS; led++) {
andrewm@88 110 // All LEDs up to the local level light up. The LED
andrewm@88 111 // for the peak level also remains lit.
andrewm@88 112 int state = LOW;
andrewm@88 113
andrewm@88 114 if(gAudioLocalLevel > gThresholds[led])
andrewm@88 115 state = HIGH;
andrewm@88 116 else if(gAudioPeakLevel > gThresholds[led] && gAudioPeakLevel <= gThresholds[led + 1])
andrewm@88 117 state = HIGH;
andrewm@88 118
andrewm@88 119 // Write LED
andrewm@88 120 digitalWriteFrameOnce(context, n, led, state);
andrewm@88 121 }
andrewm@88 122 }
andrewm@88 123 }
andrewm@88 124
andrewm@88 125 // cleanup() is called once at the end, after the audio has stopped.
andrewm@88 126 // Release any resources that were allocated in setup().
andrewm@88 127
andrewm@88 128 void cleanup(BeagleRTContext *context, void *userData)
andrewm@88 129 {
andrewm@88 130
andrewm@88 131 }