annotate projects/filter_IIR/render.cpp @ 269:ac8eb07afcf5

Oxygen text added to each render.cpp file for the default projects. Text includes project explanation from Wiki, edited in places. Empty project added as a default project. Doxyfile updated. Each of the project locations added to INPUT configuration option. Consider just watching the whole project file so all new projects are automatically pulled through.
author Robert Jack <robert.h.jack@gmail.com>
date Tue, 17 May 2016 15:40:16 +0100
parents 3c3a1357657d
children 5433c83ce04e
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
andrewm@56 9 #include <BeagleRT.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
andrewm@56 56 bool setup(BeagleRTContext *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
andrewm@52 78 void render(BeagleRTContext *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
andrewm@52 104 BeagleRT_scheduleAuxiliaryTask(gChangeCoeffTask);
andrewm@52 105 BeagleRT_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@52 142 if((gChangeCoeffTask = BeagleRT_createAuxiliaryTask(&check_coeff, 90, "beaglert-check-coeff")) == 0)
victor@3 143 return false;
victor@3 144
andrewm@52 145 if((gInputTask = BeagleRT_createAuxiliaryTask(&read_input, 50, "beaglert-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
andrewm@56 218 void cleanup(BeagleRTContext *context, void *userData)
victor@3 219 {
victor@3 220 delete[] gSampleData.samples;
victor@3 221 }