annotate examples/filter_IIR/render.cpp @ 303:421a69d42943 prerelease

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