andrewm@0: /* andrewm@0: * FeedbackOscillator.cpp andrewm@0: * andrewm@0: * Recursive phase-shift oscillator implemented andrewm@0: * on the matrix andrewm@0: * andrewm@0: * Andrew McPherson 2014 andrewm@0: */ andrewm@0: andrewm@0: #include "FeedbackOscillator.h" andrewm@0: #include andrewm@0: #include andrewm@0: andrewm@0: #define COEFF_B0 0 andrewm@0: #define COEFF_B1 1 andrewm@0: #define COEFF_A1 2 andrewm@0: andrewm@0: FeedbackOscillator::FeedbackOscillator() andrewm@0: : wavetable1(0), wavetable2(0) andrewm@0: { andrewm@0: andrewm@0: } andrewm@0: andrewm@0: FeedbackOscillator::~FeedbackOscillator() { andrewm@0: if(wavetable1 != 0) andrewm@0: free(wavetable1); andrewm@0: if(wavetable2 != 0) andrewm@0: free(wavetable2); andrewm@0: andrewm@0: } andrewm@0: andrewm@0: // Initialise the settings for the feedback oscillator andrewm@0: void FeedbackOscillator::initialise(int maxTableSize, float hpfCutoffFrequency, float matrixSampleRate) { andrewm@0: wavetableMaxLength = maxTableSize; andrewm@0: if(wavetable1 != 0) andrewm@0: free(wavetable1); andrewm@0: if(wavetable2 != 0) andrewm@0: free(wavetable2); andrewm@0: andrewm@0: wavetable1 = (float *)malloc(maxTableSize * sizeof(float)); andrewm@0: wavetable2 = (float *)malloc(maxTableSize * sizeof(float)); andrewm@0: andrewm@0: float omega = tan(M_PI * hpfCutoffFrequency / matrixSampleRate); andrewm@0: float n = 1.0f / (1.0f + omega); andrewm@0: andrewm@0: coeffs[COEFF_A1] = (omega - 1.0f) * n; andrewm@0: coeffs[COEFF_B0] = n; andrewm@0: coeffs[COEFF_B1] = -n; andrewm@0: andrewm@0: for(int n = 0; n < maxTableSize; n++) andrewm@0: wavetable1[n] = wavetable2[n] = 0; andrewm@0: andrewm@0: wavetableRead = wavetable1; andrewm@0: wavetableWrite = wavetable2; andrewm@0: wavetableWritePointer = 0; andrewm@0: sampleCount = lastTriggerCount = 0; andrewm@0: } andrewm@0: andrewm@0: // Process one sample and store the output value andrewm@0: // Returns true if the wavetable needs rendering andrewm@50: int FeedbackOscillator::process(float input, float *output) { andrewm@50: float outFloat = coeffs[COEFF_B0] * input + coeffs[COEFF_B1] * lastInput - coeffs[COEFF_A1] * lastOutput; andrewm@0: int requestRenderLength = 0; andrewm@0: andrewm@51: if(outFloat < -0.5) andrewm@51: *output = 0; andrewm@51: else if(outFloat > 0.5) andrewm@51: *output = 1; andrewm@51: else andrewm@51: *output = outFloat + 0.5; andrewm@0: andrewm@0: if(canTrigger && outFloat > 0 && lastOutput <= 0) { andrewm@0: triggered = true; andrewm@0: requestRenderLength = wavetableWritePointer; // How many samples stored thus far? andrewm@0: if(requestRenderLength < 4) andrewm@0: requestRenderLength = 0; // Ignore anything with fewer than 4 points andrewm@0: andrewm@0: lastTriggerCount = sampleCount; andrewm@0: canTrigger = false; andrewm@0: wavetableWritePointer = 0; andrewm@0: andrewm@0: // Swap buffers andrewm@0: float *temp = wavetableWrite; andrewm@0: wavetableWrite = wavetableRead; andrewm@0: wavetableRead = temp; andrewm@0: } andrewm@0: andrewm@0: if(triggered) { andrewm@0: wavetableWrite[wavetableWritePointer] = outFloat; andrewm@0: if(++wavetableWritePointer >= wavetableMaxLength) { andrewm@0: triggered = false; andrewm@0: wavetableWritePointer = 0; andrewm@0: } andrewm@0: } andrewm@0: andrewm@0: if(sampleCount - lastTriggerCount > 40) andrewm@0: canTrigger = true; andrewm@0: andrewm@0: sampleCount++; andrewm@0: andrewm@0: lastOutput = outFloat; andrewm@50: lastInput = input; andrewm@0: andrewm@0: return requestRenderLength; andrewm@0: }