annotate projects/filter_IIR/render.cpp @ 24:ad5cd8dd99b3 bbb_network

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