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