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