These files demonstrate the ultra-efficient oscillator bank class.
OscillatorBank::init() allocates the needed buffers.
OscillatorBank::getWavetable() gives access to the wavetable. The user has to populate it with one period of the desired waveform. Note that the length of the waveform is (getWavetableLength() + 1) and the last sample must be the same as the first sample.
OscillatorBank::setAmplitude() and OscillatorBank::setFrequency() can be used to set the amplitude and frequency of individual oscillators. These can be changed at any point during the execution of the program.
OscillatorBank::process(int frames, float* output) writes frames values to the output array.
This program can run with a large number of oscillators (> 500, depending on the settings in use). Updating the frequencies of a large number of oscillators from within render(), for every sample or for every block would add significatively to the computational load. For this reason, we factored out the frequency update in an AuxiliaryTask which runs at most every 128 samples. If needed, the AuxiliaryTask will split the load over time across multiple calls to render(), thus avoiding audio dropouts.
#include <stdlib.h>
#include <math.h>
#include <time.h>
#include <libraries/OscillatorBank/OscillatorBank.h>
const float kMinimumFrequency = 20.0f;
const float kMaximumFrequency = 8000.0f;
int gSampleCount;
float gNewMinFrequency;
float gNewMaxFrequency;
int gNumOscillators = 500;
int gWavetableLength = 1024;
void recalculate_frequencies(void*);
{
rt_printf("Error: this example needs stereo audio enabled\n");
return false;
}
srandom(time(NULL));
}
float freq = kMinimumFrequency;
float increment = (kMaximumFrequency - kMinimumFrequency) / (float)gNumOscillators;
for(int n = 0; n < gNumOscillators; n++) {
osc.
setFrequency(n, kMinimumFrequency + (kMaximumFrequency - kMinimumFrequency) * ((
float)random() / (
float)RAND_MAX));
}
else {
freq += increment;
}
osc.
setAmplitude(n, (
float)random() / (
float)RAND_MAX / (
float)gNumOscillators);
}
increment = 0;
freq = 440.0;
for(int n = 0; n < gNumOscillators; n++) {
float randScale = 0.99 + .02 * (float)random() / (float)RAND_MAX;
float newFreq = freq * randScale;
freq += increment;
}
return false;
gSampleCount = 0;
return true;
}
{
for(
unsigned int n = 0; n < context->
audioFrames; ++n){
}
gSampleCount = 0;
gNewMinFrequency =
map(context->
analogIn[0], 0, 1.0, 1000.0f, 8000.0f);
gNewMaxFrequency =
map(context->
analogIn[1], 0, 1.0, 1000.0f, 8000.0f);
if(gNewMaxFrequency < gNewMinFrequency) {
float temp = gNewMaxFrequency;
gNewMaxFrequency = gNewMinFrequency;
gNewMinFrequency = temp;
}
}
}
void recalculate_frequencies(void*)
{
float freq = gNewMinFrequency;
float increment = (gNewMaxFrequency - gNewMinFrequency) / (float)gNumOscillators;
for(int n = 0; n < gNumOscillators; n++) {
float randScale = 0.99 + .02 * (float)random() / (float)RAND_MAX;
float newFreq = freq * randScale;
freq += increment;
}
}
{}