annotate projects/filter_IIR/render.cpp @ 322:dde921ea256b Doxy prerelease

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