annotate examples/filter_IIR/render.cpp @ 460:f96238bdbb18 prerelease

updateunsafe now does doxygen
author Giulio Moro <giuliomoro@yahoo.it>
date Mon, 20 Jun 2016 03:27:16 +0100
parents db2fe4e1b88e
children
rev   line source
robert@372 1 /*
robert@372 2 ____ _____ _ _
robert@372 3 | __ )| ____| | / \
robert@372 4 | _ \| _| | | / _ \
robert@372 5 | |_) | |___| |___ / ___ \
robert@372 6 |____/|_____|_____/_/ \_\.io
robert@372 7
robert@372 8 */
robert@372 9
victor@3 10 /*
victor@3 11 * render.cpp
victor@3 12 *
victor@3 13 * Created on: Oct 24, 2014
victor@3 14 * Author: Andrew McPherson and Victor Zappi
victor@3 15 */
victor@3 16
robert@372 17 /**
robert@372 18 \example 4_filter_IIR
robert@372 19
robert@372 20 Infinite Impulse Response Filter
robert@372 21 ------------------------------
robert@372 22
robert@372 23 This is an example of a infinite impulse response filter implementation.
robert@372 24 */
victor@3 25
giuliomoro@301 26 #include <Bela.h> // to schedule lower prio parallel process
victor@3 27 #include <rtdk.h>
victor@3 28 #include <cmath>
victor@3 29 #include <stdio.h>
victor@3 30 #include "SampleData.h"
victor@3 31
victor@3 32 SampleData gSampleData; // User defined structure to get complex data from main
victor@3 33 int gReadPtr; // Position of last read sample from file
victor@3 34
victor@3 35 // filter vars
victor@3 36 float gLastX[2];
victor@3 37 float gLastY[2];
victor@3 38 double lb0, lb1, lb2, la1, la2 = 0.0;
victor@3 39
victor@3 40 // communication vars between the 2 auxiliary tasks
victor@3 41 int gChangeCoeff = 0;
victor@3 42 int gFreqDelta = 0;
victor@3 43
victor@3 44 void initialise_filter(float freq);
victor@3 45
victor@3 46 void calculate_coeff(float cutFreq);
victor@3 47
victor@3 48 bool initialise_aux_tasks();
victor@3 49
victor@3 50 // Task for handling the update of the frequencies using the matrix
victor@3 51 AuxiliaryTask gChangeCoeffTask;
victor@3 52
victor@3 53 void check_coeff();
victor@3 54
victor@3 55 // Task for handling the update of the frequencies using the matrix
victor@3 56 AuxiliaryTask gInputTask;
victor@3 57
victor@3 58 void read_input();
victor@3 59
victor@3 60
victor@3 61 extern float gCutFreq;
victor@3 62
victor@3 63
andrewm@56 64 // setup() is called once before the audio rendering starts.
victor@3 65 // Use it to perform any initialisation and allocation which is dependent
victor@3 66 // on the period size or sample rate.
victor@3 67 //
victor@3 68 // userData holds an opaque pointer to a data structure that was passed
victor@3 69 // in from the call to initAudio().
victor@3 70 //
victor@3 71 // Return true on success; returning false halts the program.
victor@3 72
giuliomoro@301 73 bool setup(BelaContext *context, void *userData)
victor@3 74 {
victor@3 75
victor@3 76 // Retrieve a parameter passed in from the initAudio() call
victor@3 77 gSampleData = *(SampleData *)userData;
victor@3 78
victor@3 79 gReadPtr = -1;
victor@3 80
victor@3 81 initialise_filter(200);
victor@3 82
victor@3 83 // Initialise auxiliary tasks
victor@3 84 if(!initialise_aux_tasks())
victor@3 85 return false;
victor@3 86
victor@3 87 return true;
victor@3 88 }
victor@3 89
victor@3 90 // render() is called regularly at the highest priority by the audio engine.
victor@3 91 // Input and output are given from the audio hardware and the other
victor@3 92 // ADCs and DACs (if available). If only audio is available, numMatrixFrames
victor@3 93 // will be 0.
victor@3 94
giuliomoro@301 95 void render(BelaContext *context, void *userData)
victor@3 96 {
andrewm@52 97 for(unsigned int n = 0; n < context->audioFrames; n++) {
victor@3 98 float sample = 0;
victor@3 99 float out = 0;
victor@3 100
victor@3 101 // If triggered...
victor@3 102 if(gReadPtr != -1)
victor@3 103 sample += gSampleData.samples[gReadPtr++]; // ...read each sample...
victor@3 104
victor@3 105 if(gReadPtr >= gSampleData.sampleLen)
victor@3 106 gReadPtr = -1;
victor@3 107
victor@3 108 out = lb0*sample+lb1*gLastX[0]+lb2*gLastX[1]-la1*gLastY[0]-la2*gLastY[1];
victor@3 109
victor@3 110 gLastX[1] = gLastX[0];
victor@3 111 gLastX[0] = out;
victor@3 112 gLastY[1] = gLastY[0];
victor@3 113 gLastY[0] = out;
victor@3 114
andrewm@52 115 for(unsigned int channel = 0; channel < context->audioChannels; channel++)
andrewm@52 116 context->audioOut[n * context->audioChannels + channel] = out; // ...and put it in both left and right channel
victor@3 117
victor@3 118 }
victor@3 119
victor@3 120 // Request that the lower-priority tasks run at next opportunity
giuliomoro@301 121 Bela_scheduleAuxiliaryTask(gChangeCoeffTask);
giuliomoro@301 122 Bela_scheduleAuxiliaryTask(gInputTask);
victor@3 123 }
victor@3 124
victor@3 125 // First calculation of coefficients
victor@3 126
victor@3 127 void initialise_filter(float freq)
victor@3 128 {
victor@3 129 calculate_coeff(freq);
victor@3 130 }
victor@3 131
victor@3 132
victor@3 133 // Calculate the filter coefficients
victor@3 134 // second order low pass butterworth filter
victor@3 135
victor@3 136 void calculate_coeff(float cutFreq)
victor@3 137 {
victor@3 138 // Initialise any previous state (clearing buffers etc.)
victor@3 139 // to prepare for calls to render()
victor@3 140 float sampleRate = 44100;
victor@3 141 double f = 2*M_PI*cutFreq/sampleRate;
victor@3 142 double denom = 4+2*sqrt(2)*f+f*f;
victor@3 143 lb0 = f*f/denom;
victor@3 144 lb1 = 2*lb0;
victor@3 145 lb2 = lb0;
victor@3 146 la1 = (2*f*f-8)/denom;
victor@3 147 la2 = (f*f+4-2*sqrt(2)*f)/denom;
victor@3 148 gLastX[0] = gLastX [1] = 0;
victor@3 149 gLastY[0] = gLastY[1] = 0;
victor@3 150
victor@3 151 }
victor@3 152
victor@3 153
victor@3 154 // Initialise the auxiliary tasks
victor@3 155 // and print info
victor@3 156
victor@3 157 bool initialise_aux_tasks()
victor@3 158 {
andrewm@303 159 if((gChangeCoeffTask = Bela_createAuxiliaryTask(&check_coeff, 90, "bela-check-coeff")) == 0)
victor@3 160 return false;
victor@3 161
andrewm@303 162 if((gInputTask = Bela_createAuxiliaryTask(&read_input, 50, "bela-read-input")) == 0)
victor@3 163 return false;
victor@3 164
victor@3 165 rt_printf("Press 'a' to trigger sample, 's' to stop\n");
victor@3 166 rt_printf("Press 'z' to low down cut-off freq of 100 Hz, 'x' to raise it up\n");
victor@3 167 rt_printf("Press 'q' to quit\n");
victor@3 168
victor@3 169 return true;
victor@3 170 }
victor@3 171
victor@3 172 // Check if cut-off freq has been changed
victor@3 173 // and new coefficients are needed
victor@3 174
victor@3 175 void check_coeff()
victor@3 176 {
victor@3 177 if(gChangeCoeff == 1)
victor@3 178 {
victor@3 179 gCutFreq += gFreqDelta;
victor@3 180 gCutFreq = gCutFreq < 0 ? 0 : gCutFreq;
victor@3 181 gCutFreq = gCutFreq > 22050 ? 22050 : gCutFreq;
victor@3 182
victor@3 183 rt_printf("Cut-off frequency: %f\n", gCutFreq);
victor@3 184
victor@3 185 calculate_coeff(gCutFreq);
victor@3 186 gChangeCoeff = 0;
victor@3 187 }
victor@3 188 }
victor@3 189
victor@3 190 // This is a lower-priority call to periodically read keyboard input
victor@3 191 // and trigger samples. By placing it at a lower priority,
victor@3 192 // it has minimal effect on the audio performance but it will take longer to
victor@3 193 // complete if the system is under heavy audio load.
victor@3 194
victor@3 195 void read_input()
victor@3 196 {
victor@3 197 // This is not a real-time task!
victor@3 198 // Cos getchar is a system call, not handled by Xenomai.
victor@3 199 // This task will be automatically down graded.
victor@3 200
victor@3 201 char keyStroke = '.';
victor@3 202
victor@3 203 keyStroke = getchar();
victor@3 204 while(getchar()!='\n'); // to read the first stroke
victor@3 205
victor@3 206 switch (keyStroke)
victor@3 207 {
victor@3 208 case 'a':
victor@3 209 gReadPtr = 0;
victor@3 210 break;
victor@3 211 case 's':
victor@3 212 gReadPtr = -1;
victor@3 213 break;
victor@3 214 case 'z':
victor@3 215 gChangeCoeff = 1;
victor@3 216 gFreqDelta = -100;
victor@3 217 break;
victor@3 218 case 'x':
victor@3 219 gChangeCoeff = 1;
victor@3 220 gFreqDelta = 100;
victor@3 221 break;
victor@3 222 case 'q':
victor@3 223 gShouldStop = true;
victor@3 224 break;
victor@3 225 default:
victor@3 226 break;
victor@3 227 }
victor@3 228 }
victor@3 229
victor@3 230
victor@3 231
andrewm@56 232 // cleanup() is called once at the end, after the audio has stopped.
andrewm@56 233 // Release any resources that were allocated in setup().
victor@3 234
giuliomoro@301 235 void cleanup(BelaContext *context, void *userData)
victor@3 236 {
victor@3 237 delete[] gSampleData.samples;
victor@3 238 }