annotate projects/oscillator_bank/render.cpp @ 151:e9c9404e3d1f ClockSync

Pff partially working. No PID. When setting the audio clock on the bbb to 44098 the master and slave clock keep diverging instead of converging ...
author Giulio Moro <giuliomoro@yahoo.it>
date Tue, 22 Sep 2015 04:10:07 +0100
parents 3c3a1357657d
children ac8eb07afcf5
rev   line source
andrewm@0 1 /*
andrewm@0 2 * render.cpp
andrewm@0 3 *
andrewm@0 4 * Created on: Oct 24, 2014
andrewm@0 5 * Author: parallels
andrewm@0 6 */
andrewm@0 7
andrewm@0 8
andrewm@56 9 #include <BeagleRT.h>
andrewm@56 10 #include <Utilities.h>
andrewm@0 11 #include <rtdk.h>
andrewm@0 12 #include <cstdlib>
andrewm@0 13 #include <cmath>
andrewm@0 14 #include <cstring>
andrewm@0 15 #include <time.h>
andrewm@0 16
andrewm@0 17 const float kMinimumFrequency = 20.0f;
andrewm@0 18 const float kMaximumFrequency = 8000.0f;
andrewm@0 19
andrewm@0 20 float *gWavetable; // Buffer holding the precalculated sine lookup table
andrewm@0 21 float *gPhases; // Buffer holding the phase of each oscillator
andrewm@0 22 float *gFrequencies; // Buffer holding the frequencies of each oscillator
andrewm@0 23 float *gAmplitudes; // Buffer holding the amplitudes of each oscillator
andrewm@0 24 float *gDFrequencies; // Buffer holding the derivatives of frequency
andrewm@0 25 float *gDAmplitudes; // Buffer holding the derivatives of amplitude
andrewm@0 26
andrewm@0 27 float gAudioSampleRate;
andrewm@0 28 int gSampleCount; // Sample counter for indicating when to update frequencies
andrewm@0 29 float gNewMinFrequency;
andrewm@0 30 float gNewMaxFrequency;
andrewm@0 31
andrewm@0 32 // Task for handling the update of the frequencies using the matrix
andrewm@0 33 AuxiliaryTask gFrequencyUpdateTask;
andrewm@0 34
andrewm@0 35 // These settings are carried over from main.cpp
andrewm@0 36 // Setting global variables is an alternative approach
andrewm@56 37 // to passing a structure to userData in setup()
andrewm@0 38
andrewm@0 39 extern int gNumOscillators;
andrewm@0 40 extern int gWavetableLength;
andrewm@0 41
andrewm@0 42 void recalculate_frequencies();
andrewm@0 43
andrewm@0 44 extern "C" {
andrewm@0 45 // Function prototype for ARM assembly implementation of oscillator bank
andrewm@0 46 void oscillator_bank_neon(int numAudioFrames, float *audioOut,
andrewm@0 47 int activePartialNum, int lookupTableSize,
andrewm@0 48 float *phases, float *frequencies, float *amplitudes,
andrewm@0 49 float *freqDerivatives, float *ampDerivatives,
andrewm@0 50 float *lookupTable);
andrewm@0 51 }
andrewm@0 52
andrewm@56 53 // setup() is called once before the audio rendering starts.
andrewm@0 54 // Use it to perform any initialisation and allocation which is dependent
andrewm@0 55 // on the period size or sample rate.
andrewm@0 56 //
andrewm@0 57 // userData holds an opaque pointer to a data structure that was passed
andrewm@0 58 // in from the call to initAudio().
andrewm@0 59 //
andrewm@0 60 // Return true on success; returning false halts the program.
andrewm@56 61 bool setup(BeagleRTContext *context, void *userData)
andrewm@0 62 {
andrewm@0 63 srandom(time(NULL));
andrewm@0 64
andrewm@52 65 if(context->audioChannels != 2) {
andrewm@14 66 rt_printf("Error: this example needs stereo audio enabled\n");
andrewm@14 67 return false;
andrewm@14 68 }
andrewm@14 69
andrewm@0 70 // Initialise the sine wavetable
andrewm@0 71 if(posix_memalign((void **)&gWavetable, 8, (gWavetableLength + 1) * sizeof(float))) {
andrewm@0 72 rt_printf("Error allocating wavetable\n");
andrewm@0 73 return false;
andrewm@0 74 }
andrewm@0 75 for(int n = 0; n < gWavetableLength + 1; n++)
andrewm@0 76 gWavetable[n] = sinf(2.0 * M_PI * (float)n / (float)gWavetableLength);
andrewm@0 77
andrewm@0 78 // Allocate the other buffers
andrewm@0 79 if(posix_memalign((void **)&gPhases, 16, gNumOscillators * sizeof(float))) {
andrewm@0 80 rt_printf("Error allocating phase buffer\n");
andrewm@0 81 return false;
andrewm@0 82 }
andrewm@0 83 if(posix_memalign((void **)&gFrequencies, 16, gNumOscillators * sizeof(float))) {
andrewm@0 84 rt_printf("Error allocating frequency buffer\n");
andrewm@0 85 return false;
andrewm@0 86 }
andrewm@0 87 if(posix_memalign((void **)&gAmplitudes, 16, gNumOscillators * sizeof(float))) {
andrewm@0 88 rt_printf("Error allocating amplitude buffer\n");
andrewm@0 89 return false;
andrewm@0 90 }
andrewm@0 91 if(posix_memalign((void **)&gDFrequencies, 16, gNumOscillators * sizeof(float))) {
andrewm@0 92 rt_printf("Error allocating frequency derivative buffer\n");
andrewm@0 93 return false;
andrewm@0 94 }
andrewm@0 95 if(posix_memalign((void **)&gDAmplitudes, 16, gNumOscillators * sizeof(float))) {
andrewm@0 96 rt_printf("Error allocating amplitude derivative buffer\n");
andrewm@0 97 return false;
andrewm@0 98 }
andrewm@0 99
andrewm@0 100 // Initialise buffer contents
andrewm@0 101
andrewm@0 102 float freq = kMinimumFrequency;
andrewm@0 103 float increment = (kMaximumFrequency - kMinimumFrequency) / (float)gNumOscillators;
andrewm@0 104
andrewm@0 105 for(int n = 0; n < gNumOscillators; n++) {
andrewm@0 106 gPhases[n] = 0.0;
andrewm@0 107
andrewm@52 108 if(context->analogFrames == 0) {
andrewm@0 109 // Random frequencies when used without matrix
andrewm@0 110 gFrequencies[n] = kMinimumFrequency + (kMaximumFrequency - kMinimumFrequency) * ((float)random() / (float)RAND_MAX);
andrewm@0 111 }
andrewm@0 112 else {
andrewm@0 113 // Constant spread of frequencies when used with matrix
andrewm@0 114 gFrequencies[n] = freq;
andrewm@0 115 freq += increment;
andrewm@0 116 }
andrewm@0 117
andrewm@0 118 // For efficiency, frequency is expressed in change in wavetable position per sample, not Hz or radians
andrewm@52 119 gFrequencies[n] *= (float)gWavetableLength / context->audioSampleRate;
andrewm@0 120 gAmplitudes[n] = ((float)random() / (float)RAND_MAX) / (float)gNumOscillators;
andrewm@0 121 gDFrequencies[n] = gDAmplitudes[n] = 0.0;
andrewm@0 122 }
andrewm@0 123
andrewm@45 124 increment = 0;
andrewm@45 125 freq = 440.0;
andrewm@45 126
andrewm@45 127 for(int n = 0; n < gNumOscillators; n++) {
andrewm@45 128 // Update the frequencies to a regular spread, plus a small amount of randomness
andrewm@45 129 // to avoid weird phase effects
andrewm@45 130 float randScale = 0.99 + .02 * (float)random() / (float)RAND_MAX;
andrewm@45 131 float newFreq = freq * randScale;
andrewm@45 132
andrewm@45 133 // For efficiency, frequency is expressed in change in wavetable position per sample, not Hz or radians
andrewm@52 134 gFrequencies[n] = newFreq * (float)gWavetableLength / context->audioSampleRate;
andrewm@45 135
andrewm@45 136 freq += increment;
andrewm@45 137 }
andrewm@45 138
andrewm@0 139 // Initialise auxiliary tasks
andrewm@52 140 if((gFrequencyUpdateTask = BeagleRT_createAuxiliaryTask(&recalculate_frequencies, 85, "beaglert-update-frequencies")) == 0)
andrewm@0 141 return false;
andrewm@0 142
andrewm@52 143 //for(int n = 0; n < gNumOscillators; n++)
andrewm@52 144 // rt_printf("%f\n", gFrequencies[n]);
andrewm@45 145
andrewm@52 146 gAudioSampleRate = context->audioSampleRate;
andrewm@0 147 gSampleCount = 0;
andrewm@0 148
andrewm@0 149 return true;
andrewm@0 150 }
andrewm@0 151
andrewm@0 152 // render() is called regularly at the highest priority by the audio engine.
andrewm@0 153 // Input and output are given from the audio hardware and the other
andrewm@0 154 // ADCs and DACs (if available). If only audio is available, numMatrixFrames
andrewm@0 155 // will be 0.
andrewm@0 156
andrewm@52 157 void render(BeagleRTContext *context, void *userData)
andrewm@0 158 {
andrewm@0 159 // Initialise buffer to 0
andrewm@52 160 memset(context->audioOut, 0, 2 * context->audioFrames * sizeof(float));
andrewm@0 161
andrewm@0 162 // Render audio frames
andrewm@52 163 oscillator_bank_neon(context->audioFrames, context->audioOut,
andrewm@0 164 gNumOscillators, gWavetableLength,
andrewm@0 165 gPhases, gFrequencies, gAmplitudes,
andrewm@0 166 gDFrequencies, gDAmplitudes,
andrewm@0 167 gWavetable);
andrewm@0 168
andrewm@52 169 if(context->analogFrames != 0 && (gSampleCount += context->audioFrames) >= 128) {
andrewm@0 170 gSampleCount = 0;
andrewm@52 171 gNewMinFrequency = map(context->analogIn[0], 0, 1.0, 1000.0f, 8000.0f);
andrewm@52 172 gNewMaxFrequency = map(context->analogIn[1], 0, 1.0, 1000.0f, 8000.0f);
andrewm@0 173
andrewm@0 174 // Make sure max >= min
andrewm@0 175 if(gNewMaxFrequency < gNewMinFrequency) {
andrewm@0 176 float temp = gNewMaxFrequency;
andrewm@0 177 gNewMaxFrequency = gNewMinFrequency;
andrewm@0 178 gNewMinFrequency = temp;
andrewm@0 179 }
andrewm@0 180
andrewm@0 181 // Request that the lower-priority task run at next opportunity
andrewm@52 182 //BeagleRT_scheduleAuxiliaryTask(gFrequencyUpdateTask);
andrewm@0 183 }
andrewm@0 184 }
andrewm@0 185
andrewm@0 186 // This is a lower-priority call to update the frequencies which will happen
andrewm@0 187 // periodically when the matrix is enabled. By placing it at a lower priority,
andrewm@0 188 // it has minimal effect on the audio performance but it will take longer to
andrewm@0 189 // complete if the system is under heavy audio load.
andrewm@0 190
andrewm@0 191 void recalculate_frequencies()
andrewm@0 192 {
andrewm@0 193 float freq = gNewMinFrequency;
andrewm@0 194 float increment = (gNewMaxFrequency - gNewMinFrequency) / (float)gNumOscillators;
andrewm@0 195
andrewm@0 196 for(int n = 0; n < gNumOscillators; n++) {
andrewm@0 197 // Update the frequencies to a regular spread, plus a small amount of randomness
andrewm@0 198 // to avoid weird phase effects
andrewm@0 199 float randScale = 0.99 + .02 * (float)random() / (float)RAND_MAX;
andrewm@0 200 float newFreq = freq * randScale;
andrewm@0 201
andrewm@0 202 // For efficiency, frequency is expressed in change in wavetable position per sample, not Hz or radians
andrewm@0 203 gFrequencies[n] = newFreq * (float)gWavetableLength / gAudioSampleRate;
andrewm@0 204
andrewm@0 205 freq += increment;
andrewm@0 206 }
andrewm@0 207 }
andrewm@0 208
andrewm@0 209
andrewm@56 210 // cleanup() is called once at the end, after the audio has stopped.
andrewm@56 211 // Release any resources that were allocated in setup().
andrewm@0 212
andrewm@56 213 void cleanup(BeagleRTContext *context, void *userData)
andrewm@0 214 {
andrewm@0 215 free(gWavetable);
andrewm@0 216 free(gPhases);
andrewm@0 217 free(gFrequencies);
andrewm@0 218 free(gAmplitudes);
andrewm@0 219 free(gDFrequencies);
andrewm@0 220 free(gDAmplitudes);
andrewm@0 221 }