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@0: int FeedbackOscillator::process(uint16_t input, uint16_t *output) { andrewm@0: float inFloat = input / 65536.0; andrewm@0: float outFloat = coeffs[COEFF_B0] * inFloat + coeffs[COEFF_B1] * lastInput - coeffs[COEFF_A1] * lastOutput; andrewm@0: int requestRenderLength = 0; andrewm@0: andrewm@0: //outFloat *= 2.0; andrewm@0: andrewm@0: int intOut = outFloat * 65536.0 + 32768; andrewm@0: if(intOut > 65535) andrewm@0: intOut = 65535; andrewm@0: if(intOut < 0) andrewm@0: intOut = 0; andrewm@0: //intOut = (intOut & 0xFF) << 8; andrewm@0: //if(intOut > 65535) andrewm@0: // intOut = 65535; andrewm@0: andrewm@0: *output = (uint16_t)intOut; 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@0: lastInput = inFloat; andrewm@0: andrewm@0: return requestRenderLength; andrewm@0: }