diff --git a/src/filters/filters.cpp b/src/filters/filters.cpp index 7877c63..60c32e0 100644 --- a/src/filters/filters.cpp +++ b/src/filters/filters.cpp @@ -22,12 +22,11 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -#include "SC_PlugIn.h" #include "fir.hpp" InterfaceTable *ft; PluginLoad(flex_filters) { ft = inTable; - registerUnit(ft, "FIR", false); + registerUnit(ft, "FIR", false); } diff --git a/src/filters/fir.cpp b/src/filters/fir.cpp index c4216e1..73f5a0c 100644 --- a/src/filters/fir.cpp +++ b/src/filters/fir.cpp @@ -25,7 +25,7 @@ along with this program. If not, see . #include "fir.hpp" extern InterfaceTable *ft; -FIR::FIR() { +FlexPlugins::FIR::FIR() { m_z = static_cast(RTAlloc(mWorld, fullBufferSize() * sizeof(float))); for (size_t i = 0; i < fullBufferSize(); i++) { m_z[i] = 0.f; @@ -34,26 +34,26 @@ FIR::FIR() { next(1); } -FIR::~FIR() { +FlexPlugins::FIR::~FIR() { if (m_z) RTFree(mWorld, m_z); } -void FIR::next(int inNumSamples) { +void FlexPlugins::FIR::next(int inNumSamples) { size_t numCoefs = static_cast(mNumInputs - 1); numCoefs = sc_clip(numCoefs, 0, static_cast(fullBufferSize())); const float *inBuf = in(0); float *outBuf = out(0); - for (size_t xxi = 0; xxi < inNumSamples; xxi++) { + for (size_t i = 0; i < inNumSamples; i++) { float convResult = 0.f; // unit delay - for (size_t xxj = fullBufferSize() - 1; xxj > 0; xxj--) { - m_z[xxj] = m_z[xxj-1]; + for (size_t j = fullBufferSize() - 1; j > 0; j--) { + m_z[j] = m_z[j-1]; } - m_z[0] = inBuf[xxi]; + m_z[0] = inBuf[i]; // convolve - for (size_t xxk = 0; xxk < numCoefs; xxk++) { - convResult += in0(1+xxk) * m_z[xxk]; + for (size_t k = 0; k < numCoefs; k++) { + convResult += in0(1+k) * m_z[k]; } - outBuf[xxi] = convResult; + outBuf[i] = convResult; } } \ No newline at end of file diff --git a/src/filters/fir.hpp b/src/filters/fir.hpp index 17368b7..552caef 100644 --- a/src/filters/fir.hpp +++ b/src/filters/fir.hpp @@ -26,13 +26,15 @@ along with this program. If not, see . #include "SC_PlugIn.hpp" -class FIR : public SCUnit { -public: - FIR(); - ~FIR(); - -private: - void next(int inNumSamples); - float *m_z; - size_t m_delaySize; -}; \ No newline at end of file +namespace FlexPlugins { + class FIR : public SCUnit { + public: + FIR(); + ~FIR(); + + private: + void next(int inNumSamples); + float *m_z; + size_t m_delaySize; + }; +} \ No newline at end of file diff --git a/src/generators/LoopPhasor.schelp b/src/generators/LoopPhasor.schelp index b73e35e..053ae46 100644 --- a/src/generators/LoopPhasor.schelp +++ b/src/generators/LoopPhasor.schelp @@ -67,27 +67,29 @@ b = Buffer.read(s, p); x = Bus.audio(s, 1); SynthDef(\ptr, { - var sig; - sig = LoopPhasor.ar(\t_start.tr(0.0), \t_end.tr(0.0), \rate.kr(1.0) * BufRateScale.ir(b), 0.0, BufFrames.kr(b), \loopStart.ir(0), \loopEnd.ir(1)); - Out.ar(\out.kr(0), sig); + arg rate=1, loopStart=0, loopEnd=1, out=0, trigEnd=0.0; + var sig; + sig = LoopPhasor.ar(0.0, trigEnd, 1 * BufRateScale.ir(b), 0.0, BufFrames.ir(b), loopStart, loopEnd); + sig.poll; + Out.ar(out, sig); }).add; SynthDef(\player, { - var sig, ptr_in; - ptr_in = In.ar(\ptr.kr(0)); - sig = BufRd.ar(1, b, ptr_in, 0); - Out.ar(0, sig); + arg ptr; + var sig, ptr_in; + ptr_in = In.ar(ptr); + sig = BufRd.ar(1, b, ptr_in, 0); + Out.ar(0, sig); }).add; +) // we need two synths: a pointer synth and a player synth -y = Synth(\ptr, [\out, x, \loopStart, 80e3, \loopEnd, 120e3]); +y = Synth(\ptr, [\out, x, \loopStart, 8e4, \loopEnd, 9e4]); z = Synth(\player, [\ptr, x], addAction: \addToTail); // to stop looping and end naturally -y.set(\t_end, 1.0); +y.set(\trigEnd, 1.0); -// free the synths z.free; y.free; -) :: \ No newline at end of file diff --git a/src/generators/generators.cpp b/src/generators/generators.cpp index 90cdf2a..c9b0435 100644 --- a/src/generators/generators.cpp +++ b/src/generators/generators.cpp @@ -22,7 +22,7 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -#include "SC_PlugIn.h" +#include "SC_PlugIn.hpp" #include "loopPhasor.hpp" #include "impulseDropout.hpp" #include "impulseJitter.hpp" @@ -31,7 +31,7 @@ InterfaceTable *ft; PluginLoad(flexplugin_generators) { ft = inTable; - DefineSimpleUnit(ImpulseDropout); - DefineDtorUnit(ImpulseJitter); - DefineSimpleUnit(LoopPhasor); + registerUnit(ft, "ImpulseDropout", false); + registerUnit(ft, "ImpulseJitter", false); + registerUnit(ft, "LoopPhasor", false); } diff --git a/src/generators/impulseDropout.cpp b/src/generators/impulseDropout.cpp index 64d217d..7cd0a90 100644 --- a/src/generators/impulseDropout.cpp +++ b/src/generators/impulseDropout.cpp @@ -51,86 +51,147 @@ static inline float testWrapPhase(double prev_inc, double& phase) { } } -void ImpulseDropout_next_aa(ImpulseDropout* unit, int inNumSamples) { - float* out = OUT(0); - float* freqIn = IN(0); - float* offIn = IN(1); - float dropProbIn = IN0(2); +FlexPlugins::ImpulseDropout::ImpulseDropout() { + mPhaseIncrement = in0(0) * mFreqMul; + mPhaseOffset = in0(1); + mFreqMul = static_cast(mRate->mSampleDur); + + double initOff = mPhaseOffset; + double initInc = mPhaseIncrement; + double initPhase = sc_wrap(initOff, 0.0, 1.0); + + // Initial phase offset of 0 means output of 1 on first sample. + // Set phase to wrap point to trigger impulse on first sample + if (initPhase == 0.0 && initInc >= 0.0) { + initPhase = 1.0; // positive frequency trigger/wrap position + } + mPhase = initPhase; + + UnitCalcFunc func; + switch (inRate(0)) { + case calc_FullRate: + switch (inRate(1)) { + case calc_ScalarRate: + set_calc_function(); + next_ai(1); + break; + case calc_BufRate: + set_calc_function(); + next_ak(1); + break; + case calc_FullRate: + set_calc_function(); + next_aa(1); + break; + } + break; + case calc_BufRate: + case calc_ScalarRate: + if (inRate(1) == calc_ScalarRate) { + set_calc_function(); + next_ki(1); + } else { + set_calc_function(); + next_ki(1); + } + break; + } + + mPhase = initPhase; + mPhaseOffset = initOff; + mPhaseIncrement = initInc; +} + +void FlexPlugins::ImpulseDropout::next_aa(int inNumSamples) { + float* outBuf = out(0); + const float* freqIn = in(0); + const float* offIn = in(1); + float dropProbIn = in0(2); // Collect UGen state - double phase = unit->mPhase; - double inc = unit->mPhaseIncrement; - float freqMul = unit->mFreqMul; - double prevOff = unit->mPhaseOffset; + double phase = mPhase; + double inc = mPhaseIncrement; + float freqMul = mFreqMul; + double prevOff = mPhaseOffset; - RGET - for (int xxn = 0; xxn < inNumSamples; xxn++) { + RGen* rgen = mParent->mRGen; + uint32 s1 = rgen->s1; \ + uint32 s2 = rgen->s2; \ + uint32 s3 = rgen->s3; + + for (int i = 0; i < inNumSamples; i++) { float impulseResult = testWrapPhase(inc, phase); // Drop the impulse if necessary - if (impulseResult > 0.5f && rgen.frand() < dropProbIn) { + if (impulseResult > 0.5f && rgen->frand() < dropProbIn) { impulseResult = 0.f; } - double off = static_cast(offIn[xxn]); + double off = static_cast(offIn[i]); double offInc = off - prevOff; phase += offInc; testWrapPhase(inc, phase); - inc = freqIn[xxn] * freqMul; - out[xxn] = impulseResult; + inc = freqIn[i] * freqMul; + outBuf[i] = impulseResult; phase += inc; prevOff = off; } - unit->mPhase = phase; - unit->mPhaseOffset = prevOff; - unit->mPhaseIncrement = inc; + mPhase = phase; + mPhaseOffset = prevOff; + mPhaseIncrement = inc; } -void ImpulseDropout_next_ai(ImpulseDropout* unit, int inNumSamples) { - float* out = OUT(0); - float freqIn = IN0(0); - float dropProbIn = IN0(2); +void FlexPlugins::ImpulseDropout::next_ai(int inNumSamples) { + float* outBuf = out(0); + float freqIn = in0(0); + float dropProbIn = in0(2); // Collect UGen state - double phase = unit->mPhase; - double inc = unit->mPhaseIncrement; - float freqMul = unit->mFreqMul; - - RGET - for (int xxn = 0; xxn < inNumSamples; xxn++) { + double phase = mPhase; + double inc = mPhaseIncrement; + float freqMul = mFreqMul; + + RGen* rgen = mParent->mRGen; + uint32 s1 = rgen->s1; \ + uint32 s2 = rgen->s2; \ + uint32 s3 = rgen->s3; + for (int i = 0; i < inNumSamples; i++) { float impulseResult = testWrapPhase(inc, phase); // Drop the impulse if necessary - if (impulseResult > 0.5f && rgen.frand() < dropProbIn) { + if (impulseResult > 0.5f && rgen->frand() < dropProbIn) { impulseResult = 0.f; } inc = freqIn * freqMul; - out[xxn] = impulseResult; + outBuf[i] = impulseResult; phase += inc; } - unit->mPhase = phase; - unit->mPhaseIncrement = inc; + mPhase = phase; + mPhaseIncrement = inc; } -void ImpulseDropout_next_ak(ImpulseDropout* unit, int inNumSamples) { - float* out = OUT(0); - float freqIn = IN0(0); - double off = IN0(1); - float dropProbIn = IN0(2); +void FlexPlugins::ImpulseDropout::next_ak(int inNumSamples) { + float* outBuf = out(0); + float freqIn = in0(0); + double off = in0(1); + float dropProbIn = in0(2); // Collect UGen state - double phase = unit->mPhase; - double inc = unit->mPhaseIncrement; - float freqMul = unit->mFreqMul; - double prevOff = unit->mPhaseOffset; + double phase = mPhase; + double inc = mPhaseIncrement; + float freqMul = mFreqMul; + double prevOff = mPhaseOffset; - double offSlope = CALCSLOPE(off, prevOff); + double offSlope = calcSlope(off, prevOff); bool offChanged = offSlope != 0.f; - RGET - for (int xxn = 0; xxn < inNumSamples; xxn++) { + RGen* rgen = mParent->mRGen; + uint32 s1 = rgen->s1; \ + uint32 s2 = rgen->s2; \ + uint32 s3 = rgen->s3; + for (int i = 0; i < inNumSamples; i++) { float impulseResult = testWrapPhase(inc, phase); // Drop the impulse if necessary - if (impulseResult > 0.5f && rgen.frand() < dropProbIn) { + if (impulseResult > 0.5f && rgen->frand() < dropProbIn) { impulseResult = 0.f; } if (offChanged) { @@ -138,183 +199,80 @@ void ImpulseDropout_next_ak(ImpulseDropout* unit, int inNumSamples) { testWrapPhase(inc, phase); } inc = freqIn * freqMul; - out[xxn] = impulseResult; + outBuf[i] = impulseResult; phase += inc; } - unit->mPhase = phase; - unit->mPhaseOffset = off; - unit->mPhaseIncrement = inc; + mPhase = phase; + mPhaseOffset = off; + mPhaseIncrement = inc; } -void ImpulseDropout_next_ki(ImpulseDropout* unit, int inNumSamples) { - float* out = OUT(0); - double inc = IN0(0) * unit->mFreqMul; - float dropProbIn = IN0(2); +void FlexPlugins::ImpulseDropout::next_ki(int inNumSamples) { + float* outBuf = out(0); + double inc = in0(0) * mFreqMul; + float dropProbIn = in0(2); // Collect UGen state - double phase = unit->mPhase; - double prevInc = unit->mPhaseIncrement; + double phase = mPhase; + double prevInc = mPhaseIncrement; - double incSlope = CALCSLOPE(inc, prevInc); + double incSlope = calcSlope(inc, prevInc); - RGET - for (int xxn = 0; xxn < inNumSamples; xxn++) { + RGen* rgen = mParent->mRGen; + uint32 s1 = rgen->s1; \ + uint32 s2 = rgen->s2; \ + uint32 s3 = rgen->s3; + for (int i = 0; i < inNumSamples; i++) { float impulseResult = testWrapPhase(prevInc, phase); // Drop the impulse if necessary - if (impulseResult > 0.5f && rgen.frand() < dropProbIn) { + if (impulseResult > 0.5f && rgen->frand() < dropProbIn) { impulseResult = 0.f; } - out[xxn] = impulseResult; + outBuf[i] = impulseResult; prevInc += incSlope; phase += prevInc; } - unit->mPhase = phase; - unit->mPhaseIncrement = inc; + mPhase = phase; + mPhaseIncrement = inc; } -void ImpulseDropout_next_kk(ImpulseDropout* unit, int inNumSamples) { - float* out = OUT(0); - double inc = IN0(0) * unit->mFreqMul; - double off = IN0(1); - float dropProbIn = IN0(2); +void FlexPlugins::ImpulseDropout::next_kk(int inNumSamples) { + float* outBuf = out(0); + double inc = in0(0) * mFreqMul; + double off = in0(1); + float dropProbIn = in0(2); // Collect UGen state - double phase = unit->mPhase; - double prevInc = unit->mPhaseIncrement; - double prevOff = unit->mPhaseOffset; + double phase = mPhase; + double prevInc = mPhaseIncrement; + double prevOff = mPhaseOffset; - double incSlope = CALCSLOPE(inc, prevInc); - double phaseSlope = CALCSLOPE(off, prevOff); + double incSlope = calcSlope(inc, prevInc); + double phaseSlope = calcSlope(off, prevOff); bool phOffChanged = phaseSlope != 0.f; - RGET - for (int xxn = 0; xxn < inNumSamples; xxn++) { + RGen* rgen = mParent->mRGen; + uint32 s1 = rgen->s1; \ + uint32 s2 = rgen->s2; \ + uint32 s3 = rgen->s3; + for (int i = 0; i < inNumSamples; i++) { float impulseResult = testWrapPhase(prevInc, phase); // Drop the impulse if necessary - if (impulseResult > 0.5f && rgen.frand() < dropProbIn) { + if (impulseResult > 0.5f && rgen->frand() < dropProbIn) { impulseResult = 0.f; } if (phOffChanged) { phase += phaseSlope; testWrapPhase(prevInc, phase); } - out[xxn] = impulseResult; + outBuf[i] = impulseResult; prevInc += incSlope; phase += prevInc; } - unit->mPhase = phase; - unit->mPhaseOffset = off; - unit->mPhaseIncrement = inc; -} - -void ImpulseDropout_next_ii(ImpulseDropout* unit, int inNumSamples) { - float* out = OUT(0); - float dropProbIn = IN0(2); - - // Collect UGen state - double inc = unit->mPhaseIncrement; - double phase = unit->mPhase; - - RGET - for (int xxn = 0; xxn < inNumSamples; xxn++) { - float impulseResult = testWrapPhase(inc, phase); - // Drop the impulse if necessary - if (impulseResult > 0.5f && rgen.frand() < dropProbIn) { - impulseResult = 0.f; - } - out[xxn] = impulseResult; - phase += inc; - } - - unit->mPhase = phase; + mPhase = phase; + mPhaseOffset = off; + mPhaseIncrement = inc; } - -void ImpulseDropout_next_ik(ImpulseDropout* unit, int inNumSamples) { - float* out = OUT(0); - double off = IN0(1); - float dropProbIn = IN0(2); - - // Collect UGen state - double phase = unit->mPhase; - double inc = unit->mPhaseIncrement; - double prevOff = unit->mPhaseOffset; - - double phaseSlope = CALCSLOPE(off, prevOff); - bool phOffChanged = phaseSlope != 0.f; - - RGET - for (int xxn = 0; xxn < inNumSamples; xxn++) { - float impulseResult = testWrapPhase(inc, phase); - // Drop the impulse if necessary - if (impulseResult > 0.5f && rgen.frand() < dropProbIn) { - impulseResult = 0.f; - } - if (phOffChanged) { - phase += phaseSlope; - testWrapPhase(inc, phase); - } - out[xxn] = impulseResult; - phase += inc; - } - - unit->mPhase = phase; - unit->mPhaseOffset = off; -} - -// Construct the ImpulseDropout -void ImpulseDropout_Ctor(ImpulseDropout* unit) { - unit->mPhaseIncrement = IN0(0) * unit->mFreqMul; - unit->mPhaseOffset = IN0(1); - unit->mFreqMul = static_cast(unit->mRate->mSampleDur); - - double initOff = unit->mPhaseOffset; - double initInc = unit->mPhaseIncrement; - double initPhase = sc_wrap(initOff, 0.0, 1.0); - - // Initial phase offset of 0 means output of 1 on first sample. - // Set phase to wrap point to trigger impulse on first sample - if (initPhase == 0.0 && initInc >= 0.0) { - initPhase = 1.0; // positive frequency trigger/wrap position - } - unit->mPhase = initPhase; - - UnitCalcFunc func; - switch (INRATE(0)) { - case calc_FullRate: - switch (INRATE(1)) { - case calc_ScalarRate: - func = (UnitCalcFunc)ImpulseDropout_next_ai; - break; - case calc_BufRate: - func = (UnitCalcFunc)ImpulseDropout_next_ak; - break; - case calc_FullRate: - func = (UnitCalcFunc)ImpulseDropout_next_aa; - break; - } - break; - case calc_BufRate: - if (INRATE(1) == calc_ScalarRate) { - func = (UnitCalcFunc)ImpulseDropout_next_ki; - } else { - func = (UnitCalcFunc)ImpulseDropout_next_kk; - } - break; - case calc_ScalarRate: - if (INRATE(1) == calc_ScalarRate) { - func = (UnitCalcFunc)ImpulseDropout_next_ki; - } else { - func = (UnitCalcFunc)ImpulseDropout_next_kk; - } - break; - } - unit->mCalcFunc = func; - func(unit, 1); - - unit->mPhase = initPhase; - unit->mPhaseOffset = initOff; - unit->mPhaseIncrement = initInc; -} \ No newline at end of file diff --git a/src/generators/impulseDropout.hpp b/src/generators/impulseDropout.hpp index eb79286..4098c9a 100644 --- a/src/generators/impulseDropout.hpp +++ b/src/generators/impulseDropout.hpp @@ -23,18 +23,20 @@ along with this program. If not, see . */ #pragma once -#include "SC_PlugIn.h" -#define HEAP_MAX_SIZE 1024 - -// Represents an ImpulseDropout UGen. -struct ImpulseDropout : public Unit { - double mPhase, mPhaseOffset, mPhaseIncrement; - float mFreqMul; -}; - -void ImpulseDropout_Ctor(ImpulseDropout* unit); -void ImpulseDropout_next_aa(ImpulseDropout* unit, int inNumSamples); -void ImpulseDropout_next_ai(ImpulseDropout* unit, int inNumSamples); -void ImpulseDropout_next_ak(ImpulseDropout* unit, int inNumSamples); -void ImpulseDropout_next_ki(ImpulseDropout* unit, int inNumSamples); -void ImpulseDropout_next_kk(ImpulseDropout* unit, int inNumSamples); +#include "SC_PlugIn.hpp" + +namespace FlexPlugins { + // Represents an ImpulseDropout UGen. + class ImpulseDropout : public SCUnit { + public: + ImpulseDropout(); + private: + void next_aa(int inNumSamples); + void next_ai(int inNumSamples); + void next_ak(int inNumSamples); + void next_ki(int inNumSamples); + void next_kk(int inNumSamples); + double mPhase, mPhaseOffset, mPhaseIncrement; + float mFreqMul; + }; +} \ No newline at end of file diff --git a/src/generators/impulseJitter.cpp b/src/generators/impulseJitter.cpp index 95ebfc0..ed4a6c0 100644 --- a/src/generators/impulseJitter.cpp +++ b/src/generators/impulseJitter.cpp @@ -23,6 +23,7 @@ along with this program. If not, see . */ #include "impulseJitter.hpp" +#include "SC_Rate.h" extern InterfaceTable *ft; // This is a copy of the static function from LFUGens.cpp in server/plugins. @@ -52,153 +53,224 @@ static inline float testWrapPhase(double prev_inc, double& phase) { } -void ImpulseJitter_next_aa(ImpulseJitter* unit, int inNumSamples) { - float* out = OUT(0); - float* freq = IN(0); - float* offIn = IN(1); - float jitterFracIn = IN0(2); +// Construct the ImpulseJitter +FlexPlugins::ImpulseJitter::ImpulseJitter() { + mPhaseIncrement = in0(0) * mFreqMul; + mPhaseOffset = in0(1); + mFreqMul = static_cast(mRate->mSampleDur); + mImpulseHeap.maxSize = HEAP_MAX_SIZE; // hard coded for now + mImpulseHeap.size = 1; + mImpulseHeap.heap = (int*)RTAlloc(mWorld, HEAP_MAX_SIZE * sizeof(int)); + + double initOff = mPhaseOffset; + double initInc = mPhaseIncrement; + double initPhase = sc_wrap(initOff, 0.0, 1.0); + + // Initial phase offset of 0 means output of 1 on first sample. + // Set phase to wrap point to trigger impulse on first sample + if (initPhase == 0.0 && initInc >= 0.0) { + initPhase = 1.0; // positive frequency trigger/wrap position + } + mPhase = initPhase; + + UnitCalcFunc func; + switch (inRate(0)) { + case calc_FullRate: + switch (inRate(1)) { + case calc_ScalarRate: + set_calc_function(); + next_ai(1); + break; + case calc_BufRate: + set_calc_function(); + next_ak(1); + break; + case calc_FullRate: + set_calc_function(); + next_aa(1); + break; + } + break; + case calc_ScalarRate: + case calc_BufRate: + if (inRate(1) == calc_ScalarRate) { + set_calc_function(); + next_ki(1); + } else { + set_calc_function(); + next_kk(1); + } + break; + } + + mPhase = initPhase; + mPhaseOffset = initOff; + mPhaseIncrement = initInc; +} + +FlexPlugins::ImpulseJitter::~ImpulseJitter() { + RTFree(mWorld, mImpulseHeap.heap); +} + +void FlexPlugins::ImpulseJitter::next_aa(int inNumSamples) { + float* outBuf = out(0); + const float* freq = in(0); + const float* offIn = in(1); + float jitterFracIn = in0(2); // Collect UGen state - double phase = unit->mPhase; - double inc = unit->mPhaseIncrement; - float freqMul = unit->mFreqMul; - double prevOff = unit->mPhaseOffset; + double phase = mPhase; + double inc = mPhaseIncrement; + float freqMul = mFreqMul; + double prevOff = mPhaseOffset; // The maximum distance an impulse can be displaced - int jitterWidth = static_cast(jitterFracIn * unit->mImpulseHeap.maxSize); + int jitterWidth = static_cast(jitterFracIn * mImpulseHeap.maxSize); // Zero out the output buffer - for (int xxn = 0; xxn < inNumSamples; xxn++) { - out[xxn] = 0.f; + for (int i = 0; i < inNumSamples; i++) { + outBuf[i] = 0.f; } // Update the impulse table indices - for (int xxn = 1; xxn < unit->mImpulseHeap.size; xxn++) { - unit->mImpulseHeap.heap[xxn] -= inNumSamples; + for (int i = 1; i < mImpulseHeap.size; i++) { + mImpulseHeap.heap[i] -= inNumSamples; } // Retrieve impulses for this block - while (heapPeek(&unit->mImpulseHeap) < inNumSamples && unit->mImpulseHeap.size > 1) { - out[heapPop(&unit->mImpulseHeap)] = 1.f; + while (heapPeek(&mImpulseHeap) < inNumSamples && mImpulseHeap.size > 1) { + outBuf[heapPop(&mImpulseHeap)] = 1.f; } - RGET - for (int xxn = 0; xxn < inNumSamples; xxn++) { - size_t heapEffectiveSize = static_cast(HEAP_MAX_SIZE / (12 * sc_log2(freq[xxn]))); + RGen* rgen = mParent->mRGen; + uint32 s1 = rgen->s1; \ + uint32 s2 = rgen->s2; \ + uint32 s3 = rgen->s3; + + for (int i = 0; i < inNumSamples; i++) { + size_t heapEffectiveSize = static_cast(HEAP_MAX_SIZE / (12 * sc_log2(freq[i]))); float impulseResult = testWrapPhase(inc, phase); if (impulseResult > 0.5f) { - int idx = rgen.irand(jitterWidth) + xxn; + int idx = rgen->irand(jitterWidth) + i; if (idx < inNumSamples) { - out[idx] = 1.f; - } else if (unit->mImpulseHeap.size < heapEffectiveSize) { - heapInsert(&unit->mImpulseHeap, idx); + outBuf[idx] = 1.f; + } else if (mImpulseHeap.size < heapEffectiveSize) { + heapInsert(&mImpulseHeap, idx); } } - double off = static_cast(offIn[xxn]); + double off = static_cast(offIn[i]); double offInc = off - prevOff; phase += offInc; testWrapPhase(inc, phase); - inc = freq[xxn] * freqMul; + inc = freq[i] * freqMul; phase += inc; prevOff = off; } - unit->mPhase = phase; - unit->mPhaseOffset = prevOff; - unit->mPhaseIncrement = inc; + mPhase = phase; + mPhaseOffset = prevOff; + mPhaseIncrement = inc; } -void ImpulseJitter_next_ai(ImpulseJitter* unit, int inNumSamples) { - float* out = OUT(0); - float freq = IN0(0); - float jitterFracIn = IN0(2); +void FlexPlugins::ImpulseJitter::next_ai(int inNumSamples) { + float* outBuf = out(0); + float freq = in0(0); + float jitterFracIn = in0(2); size_t heapEffectiveSize = static_cast(HEAP_MAX_SIZE / (12 * sc_log2(freq))); // Collect UGen state - double phase = unit->mPhase; - double inc = unit->mPhaseIncrement; - float freqMul = unit->mFreqMul; + double phase = mPhase; + double inc = mPhaseIncrement; + float freqMul = mFreqMul; // The maximum distance an impulse can be displaced - int jitterWidth = static_cast(jitterFracIn * unit->mImpulseHeap.maxSize); + int jitterWidth = static_cast(jitterFracIn * mImpulseHeap.maxSize); // Zero out the output buffer - for (int xxn = 0; xxn < inNumSamples; xxn++) { - out[xxn] = 0.f; + for (int i = 0; i < inNumSamples; i++) { + outBuf[i] = 0.f; } // Update the impulse table indices - for (int xxn = 1; xxn < unit->mImpulseHeap.size; xxn++) { - unit->mImpulseHeap.heap[xxn] -= inNumSamples; + for (int i = 1; i < mImpulseHeap.size; i++) { + mImpulseHeap.heap[i] -= inNumSamples; } // Retrieve impulses for this block - while (heapPeek(&unit->mImpulseHeap) < inNumSamples && unit->mImpulseHeap.size > 1) { - out[heapPop(&unit->mImpulseHeap)] = 1.f; + while (heapPeek(&mImpulseHeap) < inNumSamples && mImpulseHeap.size > 1) { + outBuf[heapPop(&mImpulseHeap)] = 1.f; } - RGET - for (int xxn = 0; xxn < inNumSamples; xxn++) { + RGen* rgen = mParent->mRGen; + uint32 s1 = rgen->s1; \ + uint32 s2 = rgen->s2; \ + uint32 s3 = rgen->s3; + + for (int i = 0; i < inNumSamples; i++) { float impulseResult = testWrapPhase(inc, phase); if (impulseResult > 0.5f) { - int idx = rgen.irand(jitterWidth) + xxn; + int idx = rgen->irand(jitterWidth) + i; if (idx < inNumSamples) { - out[idx] = 1.f; - } else if (unit->mImpulseHeap.size < heapEffectiveSize) { - heapInsert(&unit->mImpulseHeap, idx); + outBuf[idx] = 1.f; + } else if (mImpulseHeap.size < heapEffectiveSize) { + heapInsert(&mImpulseHeap, idx); } } inc = freq * freqMul; phase += inc; } - unit->mPhase = phase; - unit->mPhaseIncrement = inc; + mPhase = phase; + mPhaseIncrement = inc; } -void ImpulseJitter_next_ak(ImpulseJitter* unit, int inNumSamples) { - float* out = OUT(0); - float freq = IN0(0); - double off = IN0(1); - float jitterFracIn = IN0(2); +void FlexPlugins::ImpulseJitter::next_ak(int inNumSamples) { + float* outBuf = out(0); + float freq = in0(0); + double off = in0(1); + float jitterFracIn = in0(2); size_t heapEffectiveSize = static_cast(HEAP_MAX_SIZE / (12 * sc_log2(freq))); // Collect UGen state - double phase = unit->mPhase; - double inc = unit->mPhaseIncrement; - float freqMul = unit->mFreqMul; - double prevOff = unit->mPhaseOffset; + double phase = mPhase; + double inc = mPhaseIncrement; + float freqMul = mFreqMul; + double prevOff = mPhaseOffset; - double offSlope = CALCSLOPE(off, prevOff); + double offSlope = calcSlope(off, prevOff); bool offChanged = offSlope != 0.f; // The maximum distance an impulse can be displaced - int jitterWidth = static_cast(jitterFracIn * unit->mImpulseHeap.maxSize); + int jitterWidth = static_cast(jitterFracIn * mImpulseHeap.maxSize); // Zero out the output buffer - for (int xxn = 0; xxn < inNumSamples; xxn++) { - out[xxn] = 0.f; + for (int i = 0; i < inNumSamples; i++) { + outBuf[i] = 0.f; } // Update the impulse table indices - for (int xxn = 1; xxn < unit->mImpulseHeap.size; xxn++) { - unit->mImpulseHeap.heap[xxn] -= inNumSamples; + for (int i = 1; i < mImpulseHeap.size; i++) { + mImpulseHeap.heap[i] -= inNumSamples; } // Retrieve impulses for this block - while (heapPeek(&unit->mImpulseHeap) < inNumSamples && unit->mImpulseHeap.size > 1) { - out[heapPop(&unit->mImpulseHeap)] = 1.f; + while (heapPeek(&mImpulseHeap) < inNumSamples && mImpulseHeap.size > 1) { + outBuf[heapPop(&mImpulseHeap)] = 1.f; } - RGET - for (int xxn = 0; xxn < inNumSamples; xxn++) { + RGen* rgen = mParent->mRGen; + uint32 s1 = rgen->s1; \ + uint32 s2 = rgen->s2; \ + uint32 s3 = rgen->s3; + + for (int i = 0; i < inNumSamples; i++) { float impulseResult = testWrapPhase(inc, phase); if (impulseResult > 0.5f) { - int idx = rgen.irand(jitterWidth) + xxn; + int idx = rgen->irand(jitterWidth) + i; if (idx < inNumSamples) { - out[idx] = 1.f; - } else if (unit->mImpulseHeap.size < heapEffectiveSize) { - heapInsert(&unit->mImpulseHeap, idx); + outBuf[idx] = 1.f; + } else if (mImpulseHeap.size < heapEffectiveSize) { + heapInsert(&mImpulseHeap, idx); } } if (offChanged) { @@ -209,105 +281,113 @@ void ImpulseJitter_next_ak(ImpulseJitter* unit, int inNumSamples) { phase += inc; } - unit->mPhase = phase; - unit->mPhaseOffset = off; - unit->mPhaseIncrement = inc; + mPhase = phase; + mPhaseOffset = off; + mPhaseIncrement = inc; } -void ImpulseJitter_next_ki(ImpulseJitter* unit, int inNumSamples) { - float* out = OUT(0); - double freq = IN0(0); - double inc = freq * unit->mFreqMul; - float jitterFracIn = IN0(2); +void FlexPlugins::ImpulseJitter::next_ki(int inNumSamples) { + float* outBuf = out(0); + double freq = in0(0); + double inc = freq * mFreqMul; + float jitterFracIn = in0(2); size_t heapEffectiveSize = static_cast(HEAP_MAX_SIZE / (12 * sc_log2(freq))); // Collect UGen state - double phase = unit->mPhase; - double prevInc = unit->mPhaseIncrement; + double phase = mPhase; + double prevInc = mPhaseIncrement; - double incSlope = CALCSLOPE(inc, prevInc); + double incSlope = calcSlope(inc, prevInc); // The maximum distance an impulse can be displaced - int jitterWidth = static_cast(jitterFracIn * unit->mImpulseHeap.maxSize); + int jitterWidth = static_cast(jitterFracIn * mImpulseHeap.maxSize); // Zero out the output buffer - for (int xxn = 0; xxn < inNumSamples; xxn++) { - out[xxn] = 0.f; + for (int i = 0; i < inNumSamples; i++) { + outBuf[i] = 0.f; } // Update the impulse table indices - for (int xxn = 1; xxn < unit->mImpulseHeap.size; xxn++) { - unit->mImpulseHeap.heap[xxn] -= inNumSamples; + for (int i = 1; i < mImpulseHeap.size; i++) { + mImpulseHeap.heap[i] -= inNumSamples; } // Retrieve impulses for this block - while (heapPeek(&unit->mImpulseHeap) < inNumSamples && unit->mImpulseHeap.size > 1) { - out[heapPop(&unit->mImpulseHeap)] = 1.f; + while (heapPeek(&mImpulseHeap) < inNumSamples && mImpulseHeap.size > 1) { + outBuf[heapPop(&mImpulseHeap)] = 1.f; } - RGET - for (int xxn = 0; xxn < inNumSamples; xxn++) { + RGen* rgen = mParent->mRGen; + uint32 s1 = rgen->s1; \ + uint32 s2 = rgen->s2; \ + uint32 s3 = rgen->s3; + + for (int i = 0; i < inNumSamples; i++) { float impulseResult = testWrapPhase(prevInc, phase); if (impulseResult > 0.5f) { - int idx = rgen.irand(jitterWidth) + xxn; + int idx = rgen->irand(jitterWidth) + i; if (idx < inNumSamples) { - out[idx] = 1.f; - } else if (unit->mImpulseHeap.size < heapEffectiveSize) { - heapInsert(&unit->mImpulseHeap, idx); + outBuf[idx] = 1.f; + } else if (mImpulseHeap.size < heapEffectiveSize) { + heapInsert(&mImpulseHeap, idx); } } prevInc += incSlope; phase += prevInc; } - unit->mPhase = phase; - unit->mPhaseIncrement = inc; + mPhase = phase; + mPhaseIncrement = inc; } -void ImpulseJitter_next_kk(ImpulseJitter* unit, int inNumSamples) { - float* out = OUT(0); - double freq = IN0(0); - double inc = freq * unit->mFreqMul; - double off = IN0(1); - float jitterFracIn = IN0(2); +void FlexPlugins::ImpulseJitter::next_kk(int inNumSamples) { + float* outBuf = out(0); + double freq = in0(0); + double inc = freq * mFreqMul; + double off = in0(1); + float jitterFracIn = in0(2); size_t heapEffectiveSize = static_cast(HEAP_MAX_SIZE / (12 * sc_log2(freq))); // Collect UGen state - double phase = unit->mPhase; - double prevInc = unit->mPhaseIncrement; - double prevOff = unit->mPhaseOffset; + double phase = mPhase; + double prevInc = mPhaseIncrement; + double prevOff = mPhaseOffset; - double incSlope = CALCSLOPE(inc, prevInc); - double phaseSlope = CALCSLOPE(off, prevOff); + double incSlope = calcSlope(inc, prevInc); + double phaseSlope = calcSlope(off, prevOff); bool phOffChanged = phaseSlope != 0.f; // The maximum distance an impulse can be displaced - int jitterWidth = static_cast(jitterFracIn * unit->mImpulseHeap.maxSize); + int jitterWidth = static_cast(jitterFracIn * mImpulseHeap.maxSize); // Zero out the output buffer - for (int xxn = 0; xxn < inNumSamples; xxn++) { - out[xxn] = 0.f; + for (int i = 0; i < inNumSamples; i++) { + outBuf[i] = 0.f; } // Update the impulse table indices - for (int xxn = 1; xxn < unit->mImpulseHeap.size; xxn++) { - unit->mImpulseHeap.heap[xxn] -= inNumSamples; + for (int i = 1; i < mImpulseHeap.size; i++) { + mImpulseHeap.heap[i] -= inNumSamples; } // Retrieve impulses for this block - while (heapPeek(&unit->mImpulseHeap) < inNumSamples && unit->mImpulseHeap.size > 1) { - out[heapPop(&unit->mImpulseHeap)] = 1.f; + while (heapPeek(&mImpulseHeap) < inNumSamples && mImpulseHeap.size > 1) { + outBuf[heapPop(&mImpulseHeap)] = 1.f; } - RGET - for (int xxn = 0; xxn < inNumSamples; xxn++) { + RGen* rgen = mParent->mRGen; + uint32 s1 = rgen->s1; \ + uint32 s2 = rgen->s2; \ + uint32 s3 = rgen->s3; + + for (int i = 0; i < inNumSamples; i++) { float impulseResult = testWrapPhase(prevInc, phase); if (impulseResult > 0.5f) { - int idx = rgen.irand(jitterWidth) + xxn; + int idx = rgen->irand(jitterWidth) + i; if (idx < inNumSamples) { - out[idx] = 1.f; - } else if (unit->mImpulseHeap.size < heapEffectiveSize) { - heapInsert(&unit->mImpulseHeap, idx); + outBuf[idx] = 1.f; + } else if (mImpulseHeap.size < heapEffectiveSize) { + heapInsert(&mImpulseHeap, idx); } } if (phOffChanged) { @@ -318,76 +398,7 @@ void ImpulseJitter_next_kk(ImpulseJitter* unit, int inNumSamples) { phase += prevInc; } - unit->mPhase = phase; - unit->mPhaseOffset = off; - unit->mPhaseIncrement = inc; + mPhase = phase; + mPhaseOffset = off; + mPhaseIncrement = inc; } - -// Construct the ImpulseJitter -void ImpulseJitter_Ctor(ImpulseJitter* unit) { - unit->mPhaseIncrement = IN0(0) * unit->mFreqMul; - unit->mPhaseOffset = IN0(1); - unit->mFreqMul = static_cast(unit->mRate->mSampleDur); - unit->mImpulseHeap.maxSize = HEAP_MAX_SIZE; // hard coded for now - unit->mImpulseHeap.size = 1; - unit->mImpulseHeap.heap = (int*)RTAlloc(unit->mWorld, HEAP_MAX_SIZE * sizeof(int)); - - double initOff = unit->mPhaseOffset; - double initInc = unit->mPhaseIncrement; - double initPhase = sc_wrap(initOff, 0.0, 1.0); - - // Initial phase offset of 0 means output of 1 on first sample. - // Set phase to wrap point to trigger impulse on first sample - if (initPhase == 0.0 && initInc >= 0.0) { - initPhase = 1.0; // positive frequency trigger/wrap position - } - unit->mPhase = initPhase; - - UnitCalcFunc func; - switch (INRATE(0)) { - case calc_FullRate: - switch (INRATE(1)) { - case calc_ScalarRate: - func = (UnitCalcFunc)ImpulseJitter_next_ai; - //printf("Calc function set to ai\n"); - break; - case calc_BufRate: - func = (UnitCalcFunc)ImpulseJitter_next_ak; - //printf("Calc function set to ak\n"); - break; - case calc_FullRate: - func = (UnitCalcFunc)ImpulseJitter_next_aa; - //printf("Calc function set to aa\n"); - break; - } - break; - case calc_BufRate: - if (INRATE(1) == calc_ScalarRate) { - func = (UnitCalcFunc)ImpulseJitter_next_ki; - //printf("Calc function set to ki\n"); - } else { - func = (UnitCalcFunc)ImpulseJitter_next_kk; - //printf("Calc function set to kk\n"); - } - break; - case calc_ScalarRate: - if (INRATE(1) == calc_ScalarRate) { - func = (UnitCalcFunc)ImpulseJitter_next_ki; - //printf("Calc function set to ki\n"); - } else { - func = (UnitCalcFunc)ImpulseJitter_next_kk; - //printf("Calc function set to kk\n"); - } - break; - } - unit->mCalcFunc = func; - func(unit, 1); - - unit->mPhase = initPhase; - unit->mPhaseOffset = initOff; - unit->mPhaseIncrement = initInc; -} - -void ImpulseJitter_Dtor(ImpulseJitter* unit) { - RTFree(unit->mWorld, unit->mImpulseHeap.heap); -} \ No newline at end of file diff --git a/src/generators/impulseJitter.hpp b/src/generators/impulseJitter.hpp index d1deaf6..e876710 100644 --- a/src/generators/impulseJitter.hpp +++ b/src/generators/impulseJitter.hpp @@ -23,21 +23,25 @@ along with this program. If not, see . */ #pragma once -#include "SC_PlugIn.h" +#include "SC_PlugIn.hpp" #include "arrayheap.hpp" #define HEAP_MAX_SIZE 1024 -// Represents an ImpulseJitter UGen. -struct ImpulseJitter : public Unit { - double mPhase, mPhaseOffset, mPhaseIncrement; - float mFreqMul; - IntMinHeap mImpulseHeap; -}; - -void ImpulseJitter_Ctor(ImpulseJitter* unit); -void ImpulseJitter_Dtor(ImpulseJitter* unit); -void ImpulseJitter_next_aa(ImpulseJitter* unit, int inNumSamples); -void ImpulseJitter_next_ai(ImpulseJitter* unit, int inNumSamples); -void ImpulseJitter_next_ak(ImpulseJitter* unit, int inNumSamples); -void ImpulseJitter_next_ki(ImpulseJitter* unit, int inNumSamples); -void ImpulseJitter_next_kk(ImpulseJitter* unit, int inNumSamples); + +namespace FlexPlugins { + // Represents an ImpulseJitter UGen. + class ImpulseJitter : public SCUnit { + public: + ImpulseJitter(); + ~ImpulseJitter(); + private: + void next_aa(int inNumSamples); + void next_ai(int inNumSamples); + void next_ak(int inNumSamples); + void next_ki(int inNumSamples); + void next_kk(int inNumSamples); + double mPhase, mPhaseOffset, mPhaseIncrement; + float mFreqMul; + IntMinHeap mImpulseHeap; + }; +} diff --git a/src/generators/loopPhasor.cpp b/src/generators/loopPhasor.cpp index d00107c..166fc4c 100644 --- a/src/generators/loopPhasor.cpp +++ b/src/generators/loopPhasor.cpp @@ -23,210 +23,174 @@ along with this program. If not, see . */ #include "loopPhasor.hpp" +#include "SC_Rate.h" extern InterfaceTable *ft; // Construct the LoopPhasor -void LoopPhasor_Ctor(LoopPhasor* unit) { +FlexPlugins::LoopPhasor::LoopPhasor() { // Set the calculation function - if (unit->mCalcRate == calc_FullRate) { - if (INRATE(0) == calc_FullRate) { - if (INRATE(1) == calc_FullRate) { - SETCALC(LoopPhasor_next_aa); - } else { - SETCALC(LoopPhasor_next_ak); - } + if (inRate(2) == calc_FullRate) { + if (inRate(0) == calc_FullRate) { + set_calc_function(); + Print("Set aa\n"); + next_aa(1); } else { - SETCALC(LoopPhasor_next_kk); + Print("Set ak\n"); + set_calc_function(); + next_ak(1); } } else { - SETCALC(LoopPhasor_next_ak); + Print("Set kk\n"); + set_calc_function(); + next_k(1); } // Initialize the triggers - unit->m_prevTriggerStart = IN0(0); - unit->m_prevTriggerFinish = IN0(1); - unit->m_triggerFinishState = false; + m_prevTriggerStart = in0(0); + m_prevTriggerFinish = in0(1); + m_loopState = false; // Initialize the output - unit->m_level = IN0(3); - ZOUT0(0) = static_cast(unit->m_level); + m_level = in0(3); } -// Calculates samples for a LoopPhasor.kr UGen -void LoopPhasor_next_kk(LoopPhasor* unit, int inNumSamples) { +// all parameters are control rate +void FlexPlugins::LoopPhasor::next_k(int inNumSamples) { // Pointer to output array - float* out = OUT(0); + float* outBuf = out(0); // Get new parameters of the LoopPhasor - float triggerReturnToStart = IN0(0); - float triggerFinish = IN0(1); - double rate = IN0(2); - double startPosition = IN0(3); - double endPosition = IN0(4); - double loopStart = IN0(5); - double loopEnd = IN0(6); - - // Get current state of the LoopPhasor - float previousTriggerReturnToStart = unit->m_prevTriggerStart; // trigger return to start - float previousTriggerFinish = unit->m_prevTriggerFinish; // trigger finish - double level = unit->m_level; + const float triggerReturnToStart = in0(0); + const float triggerFinish = in0(1); + const float rate = in0(2); + const float startPosition = in0(3); + const float endPosition = in0(4); + const float loopStart = in0(5); + const float loopEnd = in0(6); // Handle trigger return to start - if (previousTriggerReturnToStart <= 0.f && triggerReturnToStart > 0.f) { - level = startPosition; + if (m_prevTriggerStart <= 0.f && triggerReturnToStart > 0.f) { + m_level = startPosition; } - // Handle trigger finish. This just flips the finish trigger. - if (previousTriggerFinish <= 0.f && triggerFinish > 0.f) { - unit->m_triggerFinishState = !(unit->m_triggerFinishState); + // Handle trigger finish. This just flips the loop state. + if (m_prevTriggerFinish <= 0.f && triggerFinish > 0.f) { + m_triggerFinishState = !m_triggerFinishState; } // Compute output block - for (int xxn = 0; xxn < inNumSamples; xxn++) { - // If we haven't triggered completion - if (!unit->m_triggerFinishState) { - // If we're inside the looping part of the LoopPhasor - if (level >= loopStart && level <= loopEnd) { - level = sc_wrap(level, loopStart, loopEnd); - } else { - level = sc_wrap(level, startPosition, endPosition); + for (int i = 0; i < inNumSamples; i++) { + if (!m_triggerFinishState) { + if (m_level >= loopStart) { + m_loopState = true; + } + if (m_loopState) { + m_level = sc_wrap(m_level, loopStart, loopEnd); } } - // Otherwise we wrap up else { - level = sc_max(level, startPosition); - level = sc_min(level, endPosition); + m_loopState = false; + m_level = sc_clip(m_level, startPosition, endPosition); } - out[xxn] = static_cast(level); - level += rate; + outBuf[i] = static_cast(m_level); + m_level += rate; } // Update the state of the LoopPhasor - unit->m_prevTriggerStart = triggerReturnToStart; - unit->m_prevTriggerFinish = triggerFinish; - unit->m_level = level; + m_prevTriggerStart = triggerReturnToStart; + m_prevTriggerFinish = triggerFinish; } -// Calculates samples for a LoopPhasor.ar ugen with .kr parameters -void LoopPhasor_next_ak(LoopPhasor* unit, int inNumSamples) { +// rate parameter is audio rate +void FlexPlugins::LoopPhasor::next_ak(int inNumSamples) { // Pointer to output array - float* out = OUT(0); + float* outBuf = out(0); // Get new parameters of the LoopPhasor - float *triggerReturnToStart = IN(0); - float *triggerFinish = IN(1); - double rate = IN0(2); - double startPosition = IN0(3); - double endPosition = IN0(4); - double loopStart = IN0(5); - double loopEnd = IN0(6); - - // Get current state of the LoopPhasor - float previousTriggerReturnToStart = unit->m_prevTriggerStart; - float previousTriggerFinish = unit->m_prevTriggerFinish; - double level = unit->m_level; + const float triggerReturnToStart = in0(0); + const float triggerFinish = in0(1); + const float *rate = in(2); + const float startPosition = in0(3); + const float endPosition = in0(4); + const float loopStart = in0(5); + const float loopEnd = in0(6); - // Compute output block - for (int xxn = 0; xxn < inNumSamples; xxn++) { - // If we reset to start - if (previousTriggerReturnToStart <= 0.f && triggerReturnToStart[xxn] > 0.f) { - float frac = 1.f - previousTriggerReturnToStart / (triggerReturnToStart[xxn] - previousTriggerReturnToStart); - level = startPosition + frac * rate; - } + // Handle trigger return to start + if (m_prevTriggerStart <= 0.f && triggerReturnToStart > 0.f) { + m_level = startPosition; + } - // Handle trigger finish. This just flips the finish trigger. - if (previousTriggerFinish <= 0.f && triggerFinish[xxn] > 0.f) { - unit->m_triggerFinishState = !(unit->m_triggerFinishState); - } + // Handle trigger finish. This just flips the finish trigger. + if (m_prevTriggerFinish <= 0.f && triggerFinish > 0.f) { + m_triggerFinishState = !(m_triggerFinishState); + } - // Wrapping: if we haven't triggered completion - if (!unit->m_triggerFinishState) { - // if we're inside the looping part of the LoopPhasor - if (level >= loopStart && level <= loopEnd) { - level = sc_wrap(level, loopStart, loopEnd); - } else { - level = sc_wrap(level, startPosition, endPosition); + // Compute output block + for (int i = 0; i < inNumSamples; i++) { + if (!m_triggerFinishState) { + if (m_level >= loopStart) { + m_loopState = true; + } + if (m_loopState) { + m_level = sc_wrap(m_level, loopStart, loopEnd); } } - // Wrapping: if we have triggered completion else { - level = sc_max(level, startPosition); - level = sc_min(level, endPosition); + m_level = sc_clip(m_level, startPosition, endPosition); } - out[xxn] = static_cast(level); - level += rate; - previousTriggerReturnToStart = triggerReturnToStart[xxn]; - previousTriggerFinish = triggerFinish[xxn]; + outBuf[i] = static_cast(m_level); + m_level += rate[i]; } - - // update the state of the LoopPhasor - unit->m_prevTriggerStart = previousTriggerReturnToStart; - unit->m_prevTriggerFinish = previousTriggerFinish; - unit->m_level = level; + m_prevTriggerStart = triggerReturnToStart; + m_prevTriggerFinish = triggerFinish; } -// Calculates samples for a LoopPhasor.ar UGen with .ar parameters -void LoopPhasor_next_aa(LoopPhasor* unit, int inNumSamples) { - float* out = OUT(0); +// first two parameters are audio rate +void FlexPlugins::LoopPhasor::next_aa(int inNumSamples) { + float* outBuf = out(0); // Get new parameters of the LoopPhasor - float *triggerReturnToStart = IN(0); - float *triggerFinish = IN(1); - float *rate = IN(2); - double startPosition = IN0(3); - double endPosition = IN0(4); - double loopStart = IN0(5); - double loopEnd = IN0(6); - - // Get current state of the LoopPhasor - float previousTriggerReturnToStart = unit->m_prevTriggerStart; - float previousTriggerFinish = unit->m_prevTriggerFinish; - double level = unit->m_level; - - float *in = triggerReturnToStart; - float previn = previousTriggerReturnToStart; + const float *triggerReturnToStart = in(0); + const float triggerFinish = in0(1); + const float *rate = in(2); + const float startPosition = in0(3); + const float endPosition = in0(4); + const float loopStart = in0(5); + const float loopEnd = in0(6); + + // Handle trigger finish. This just flips the finish trigger. + if (m_prevTriggerFinish <= 0.f && triggerFinish > 0.f) { + m_triggerFinishState = !(m_triggerFinishState); + } // Compute output block - for (int xxn = 0; xxn < inNumSamples; xxn++) { + for (int i = 0; i < inNumSamples; i++) { // Handle trigger return to start - if (previousTriggerReturnToStart <= 0.f && triggerReturnToStart[xxn] > 0.f) { - float frac = 1.f - previousTriggerReturnToStart / (triggerReturnToStart[xxn] - previousTriggerReturnToStart); - level = startPosition + frac * rate[xxn]; - } - - // Handle trigger finish. This just flips the finish trigger. - if (previousTriggerFinish <= 0.f && triggerFinish[xxn] > 0.f) { - unit->m_triggerFinishState = !(unit->m_triggerFinishState); + if (m_prevTriggerStart <= 0.f && triggerReturnToStart[i] > 0.f) { + float frac = 1.f - m_prevTriggerStart / (triggerReturnToStart[i] - m_prevTriggerStart); + m_level = startPosition + frac * rate[i]; } - // Wrapping: if we haven't triggered completion - if (!unit->m_triggerFinishState) { - // If we're inside the looping part of the LoopPhasor - if (level >= loopStart && level <= loopEnd) { - level = sc_wrap(level, loopStart, loopEnd); - } else { - level = sc_wrap(level, startPosition, endPosition); + if (!m_triggerFinishState) { + if (m_level >= loopStart) { + m_loopState = true; + } + if (m_loopState) { + m_level = sc_wrap(m_level, loopStart, loopEnd); } } - // Wrapping: if we have triggered completion else { - level = sc_max(level, startPosition); - level = sc_min(level, endPosition); + m_level = sc_clip(m_level, startPosition, endPosition); } - out[xxn] = static_cast(level); - level += rate[xxn]; - previousTriggerReturnToStart = triggerReturnToStart[xxn]; - previousTriggerFinish = triggerFinish[xxn]; + outBuf[i] = static_cast(m_level); + m_level += rate[i]; + m_prevTriggerStart = triggerReturnToStart[i]; } - - // update the state of the LoopPhasor at the end of the calculation block - unit->m_prevTriggerStart = previousTriggerReturnToStart; - unit->m_prevTriggerFinish = previousTriggerFinish; - unit->m_level = level; + m_prevTriggerFinish = triggerFinish; } diff --git a/src/generators/loopPhasor.hpp b/src/generators/loopPhasor.hpp index d710fdd..7277df0 100644 --- a/src/generators/loopPhasor.hpp +++ b/src/generators/loopPhasor.hpp @@ -23,17 +23,22 @@ along with this program. If not, see . */ #pragma once -#include "SC_PlugIn.h" - -// Represents a LoopPhasor UGen. -struct LoopPhasor : public Unit { - double m_level; // LoopPhasor output level (position of the phasor between `start` and `end`) - float m_prevTriggerStart; // previous value of trigger to return to start position - float m_prevTriggerFinish; // previous value of trigger to finish - bool m_triggerFinishState; // current state of finish trigger (true - finish; false - continue looping) -}; - -void LoopPhasor_Ctor(LoopPhasor* unit); -void LoopPhasor_next_aa(LoopPhasor* unit, int inNumSamples); -void LoopPhasor_next_ak(LoopPhasor* unit, int inNumSamples); -void LoopPhasor_next_kk(LoopPhasor* unit, int inNumSamples); +#include "SC_PlugIn.hpp" + +namespace FlexPlugins { + // Represents a LoopPhasor UGen. + class LoopPhasor : public SCUnit { + public: + LoopPhasor(); + + private: + void next_ak(int inNumSamples); + void next_aa(int inNumSamples); + void next_k(int inNumSamples); + float m_level; // LoopPhasor output level (position of the phasor between `start` and `end`) + float m_prevTriggerStart; // previous value of trigger to return to start position + float m_prevTriggerFinish; // previous value of trigger to finish + bool m_triggerFinishState; // current state of finish trigger (true - finish; false - continue looping) + float m_loopState; // Tracks if we are currently looping + }; +} diff --git a/src/pv/pv.cpp b/src/pv/pv.cpp index ba9adb3..f7fe46f 100644 --- a/src/pv/pv.cpp +++ b/src/pv/pv.cpp @@ -22,7 +22,6 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -#include "SC_InterfaceTable.h" #include "pvCFreeze.hpp" #include "pvOther.hpp" #include "pvStretch.hpp" @@ -31,9 +30,9 @@ InterfaceTable *ft; PluginLoad(PV_flexplugins) { ft = inTable; - DefineSimpleUnit(PV_MagMirror); - DefineSimpleUnit(PV_MagSqueeze); - DefineSimpleUnit(PV_MagXFade); - DefineDtorUnit(PV_PlayBufStretch); - DefineDtorUnit(PV_CFreeze); + registerUnit(ft, "PV_MagSqueeze", false); + registerUnit(ft, "PV_MagMirror", false); + registerUnit(ft, "PV_MagXFade", false); + registerUnit(ft, "PV_PlayBufStretch", false); + registerUnit(ft, "PV_CFreeze", false); } diff --git a/src/pv/pvCFreeze.cpp b/src/pv/pvCFreeze.cpp index 67700a1..1458c15 100644 --- a/src/pv/pvCFreeze.cpp +++ b/src/pv/pvCFreeze.cpp @@ -27,30 +27,31 @@ along with this program. If not, see . extern InterfaceTable *ft; -void PV_CFreeze_next(PV_CFreeze *unit, int inNumSamples) { +void FlexPlugins::PV_CFreeze::next(int inNumSamples) { + PV_CFreeze *unit = this; PV_GET_BUF - float freezeState = IN0(1); + float freezeState = in0(1); // allocate the buffers - if (!unit->mMags) { + if (!mMags) { // MxN where N is num bins, and M is num frames. Acts as a circular buffer. - unit->mMags = (float*)RTAlloc(unit->mWorld, numbins * sizeof(float) * unit->mNumFrames); + mMags = (float*)RTAlloc(mWorld, numbins * sizeof(float) * mNumFrames); // M (num frames) - unit->mDc = (float*)RTAlloc(unit->mWorld, sizeof(float) * unit->mNumFrames); + mDc = (float*)RTAlloc(mWorld, sizeof(float) * mNumFrames); // M (num frames) - unit->mNyq = (float*)RTAlloc(unit->mWorld, sizeof(float) * unit->mNumFrames); + mNyq = (float*)RTAlloc(mWorld, sizeof(float) * mNumFrames); // N (num bins) - unit->mPhase = (float*)RTAlloc(unit->mWorld, numbins * sizeof(float)); + mPhase = (float*)RTAlloc(mWorld, numbins * sizeof(float)); // MxN where N is num bins, and M is num frames. - // Acts as a circular buffer corresponding to unit->mMags. - unit->mPhaseDiffs = (float*)RTAlloc(unit->mWorld, numbins * sizeof(float) * unit->mNumFrames); - ClearFFTUnitIfMemFailed(unit->mMags); - ClearFFTUnitIfMemFailed(unit->mDc); - ClearFFTUnitIfMemFailed(unit->mNyq); - ClearFFTUnitIfMemFailed(unit->mPhase); - ClearFFTUnitIfMemFailed(unit->mPhaseDiffs); - unit->mNumBins = numbins; - unit->mWritePtr = 0; - } else if (numbins != unit->mNumBins) { + // Acts as a circular buffer corresponding to mMags. + mPhaseDiffs = (float*)RTAlloc(mWorld, numbins * sizeof(float) * mNumFrames); + ClearFFTUnitIfMemFailed(mMags); + ClearFFTUnitIfMemFailed(mDc); + ClearFFTUnitIfMemFailed(mNyq); + ClearFFTUnitIfMemFailed(mPhase); + ClearFFTUnitIfMemFailed(mPhaseDiffs); + mNumBins = numbins; + mWritePtr = 0; + } else if (numbins != mNumBins) { // Cannot allow the FFT size to change return; } @@ -60,64 +61,64 @@ void PV_CFreeze_next(PV_CFreeze *unit, int inNumSamples) { if (freezeState > 0.f) { RGET // Pull random DC and nyquist magnitudes - p->dc = unit->mDc[rgen.irand(unit->mNumFrames)]; - p->nyq = unit->mNyq[rgen.irand(unit->mNumFrames)]; - for (int xxn = 0; xxn < unit->mNumBins; xxn++) { + p->dc = mDc[rgen.irand(mNumFrames)]; + p->nyq = mNyq[rgen.irand(mNumFrames)]; + for (int xxn = 0; xxn < mNumBins; xxn++) { // For each bin, grab a random magnitude and phase diff pair - int idx = rgen.irand(unit->mNumFrames); - idx = idx * unit->mNumBins + xxn; - p->bin[xxn].mag = unit->mMags[idx]; - unit->mPhase[xxn] = sc_wrap(unit->mPhase[xxn] + unit->mPhaseDiffs[idx], 0.f, static_cast(twopi)); - p->bin[xxn].phase = unit->mPhase[xxn]; + int idx = rgen.irand(mNumFrames); + idx = idx * mNumBins + xxn; + p->bin[xxn].mag = mMags[idx]; + mPhase[xxn] = sc_wrap(mPhase[xxn] + mPhaseDiffs[idx], 0.f, static_cast(twopi)); + p->bin[xxn].phase = mPhase[xxn]; } } else { // We're writing to a circular buffer, so pull the current magnitude and phase diff arrays - float *currentMagArr = unit->mMags + (unit->mWritePtr * unit->mNumBins); - float *currentPhaseDiffArr = unit->mPhaseDiffs + (unit->mWritePtr * unit->mNumBins); + float *currentMagArr = mMags + (mWritePtr * mNumBins); + float *currentPhaseDiffArr = mPhaseDiffs + (mWritePtr * mNumBins); for (int xxn = 0; xxn < numbins; xxn++) { currentMagArr[xxn] = p->bin[xxn].mag; - currentPhaseDiffArr[xxn] = sc_wrap(p->bin[xxn].phase - unit->mPhase[xxn], 0.f, static_cast(twopi)); - unit->mPhase[xxn] = p->bin[xxn].phase; + currentPhaseDiffArr[xxn] = sc_wrap(p->bin[xxn].phase - mPhase[xxn], 0.f, static_cast(twopi)); + mPhase[xxn] = p->bin[xxn].phase; } - unit->mDc[unit->mWritePtr] = p->dc; - unit->mNyq[unit->mWritePtr] = p->nyq; - unit->mWritePtr++; - unit->mWritePtr %= unit->mNumFrames; + mDc[mWritePtr] = p->dc; + mNyq[mWritePtr] = p->nyq; + mWritePtr++; + mWritePtr %= mNumFrames; } } -void PV_CFreeze_Ctor(PV_CFreeze *unit) { - SETCALC(PV_CFreeze_next); - OUT0(0) = IN0(0); - unit->mMags = nullptr; - unit->mDc = nullptr; - unit->mNyq = nullptr; - unit->mPhase = nullptr; - unit->mPhaseDiffs = nullptr; - int numFrames = static_cast(IN0(2)); +FlexPlugins::PV_CFreeze::PV_CFreeze() { + mMags = nullptr; + mDc = nullptr; + mNyq = nullptr; + mPhase = nullptr; + mPhaseDiffs = nullptr; + int numFrames = static_cast(in0(2)); // prevent the user from doing something nuts - unit->mNumFrames = sc_clip(numFrames, 1, 64); + mNumFrames = sc_clip(numFrames, 1, 64); + set_calc_function(); + next(1); } -void PV_CFreeze_Dtor(PV_CFreeze *unit) { - if (unit->mMags) { - RTFree(unit->mWorld, unit->mMags); - unit->mMags = nullptr; +FlexPlugins::PV_CFreeze::~PV_CFreeze() { + if (mMags) { + RTFree(mWorld, mMags); + mMags = nullptr; } - if (unit->mDc) { - RTFree(unit->mWorld, unit->mDc); - unit->mDc = nullptr; + if (mDc) { + RTFree(mWorld, mDc); + mDc = nullptr; } - if (unit->mNyq) { - RTFree(unit->mWorld, unit->mNyq); - unit->mNyq = nullptr; + if (mNyq) { + RTFree(mWorld, mNyq); + mNyq = nullptr; } - if (unit->mPhase) { - RTFree(unit->mWorld, unit->mPhase); - unit->mPhase = nullptr; + if (mPhase) { + RTFree(mWorld, mPhase); + mPhase = nullptr; } - if (unit->mPhaseDiffs) { - RTFree(unit->mWorld, unit->mPhaseDiffs); - unit->mPhaseDiffs = nullptr; + if (mPhaseDiffs) { + RTFree(mWorld, mPhaseDiffs); + mPhaseDiffs = nullptr; } } diff --git a/src/pv/pvCFreeze.hpp b/src/pv/pvCFreeze.hpp index 9d76180..bd8b0b1 100644 --- a/src/pv/pvCFreeze.hpp +++ b/src/pv/pvCFreeze.hpp @@ -23,19 +23,24 @@ along with this program. If not, see . */ #pragma once -#include "SC_Unit.h" - -struct PV_CFreeze : public Unit { - int mNumBins; // The number of FFT bins - int mNumFrames; // The number of candidate FFT frames to maintain - float *mMags; // The 2D array of FFT mags - float *mDc; // The 1D array of FFT DC values - float *mNyq; // The 1D array of FFT Nyquist values - float *mPhase; // The most recent phase array - float *mPhaseDiffs; // The 2D array of FFT phase differences - size_t mWritePtr; // The write pointer -}; - -void PV_CFreeze_next(PV_CFreeze *unit, int inNumSamples); -void PV_CFreeze_Ctor(PV_CFreeze *unit); -void PV_CFreeze_Dtor(PV_CFreeze *unit); \ No newline at end of file +#include "SC_PlugIn.hpp" + +namespace FlexPlugins { + class PV_CFreeze : public SCUnit { + public: + PV_CFreeze(); + ~PV_CFreeze(); + + private: + void next(int inNumSamples); + + int mNumBins; // The number of FFT bins + int mNumFrames; // The number of candidate FFT frames to maintain + float *mMags; // The 2D array of FFT mags + float *mDc; // The 1D array of FFT DC values + float *mNyq; // The 1D array of FFT Nyquist values + float *mPhase; // The most recent phase array + float *mPhaseDiffs; // The 2D array of FFT phase differences + size_t mWritePtr; // The write pointer + }; +} diff --git a/src/pv/pvOther.cpp b/src/pv/pvOther.cpp index 55f1efa..4f20a68 100644 --- a/src/pv/pvOther.cpp +++ b/src/pv/pvOther.cpp @@ -27,10 +27,11 @@ along with this program. If not, see . extern InterfaceTable *ft; -void PV_MagSqueeze_next(PV_MagSqueeze *unit, int inNumSamples) { +void FlexPlugins::PV_MagSqueeze::next(int inNumSamples) { + PV_MagSqueeze *unit = this; PV_GET_BUF - float low = IN0(1); - float high = IN0(2); + float low = in0(1); + float high = in0(2); SCPolarBuf *p = ToPolarApx(buf); float min = p->dc; float max = p->dc; @@ -52,12 +53,13 @@ void PV_MagSqueeze_next(PV_MagSqueeze *unit, int inNumSamples) { } } -void PV_MagSqueeze_Ctor(PV_MagSqueeze *unit) { - SETCALC(PV_MagSqueeze_next); - OUT0(0) = IN0(0); +FlexPlugins::PV_MagSqueeze::PV_MagSqueeze() { + set_calc_function(); + next(1); } -void PV_MagMirror_next(PV_MagMirror *unit, int inNumSamples) { +void FlexPlugins::PV_MagMirror::next(int inNumSamples) { + PV_MagMirror *unit = this; PV_GET_BUF SCPolarBuf *p = ToPolarApx(buf); float min = p->dc; @@ -79,14 +81,15 @@ void PV_MagMirror_next(PV_MagMirror *unit, int inNumSamples) { } } -void PV_MagMirror_Ctor(PV_MagMirror *unit) { - SETCALC(PV_MagMirror_next); - OUT0(0) = IN0(0); +FlexPlugins::PV_MagMirror::PV_MagMirror() { + set_calc_function(); + next(1); } -void PV_MagXFade_next(PV_MagXFade *unit, int inNumSamples) { +void FlexPlugins::PV_MagXFade::next(int inNumSamples) { + PV_MagXFade *unit = this; PV_GET_BUF2 - float crossfade = IN0(2); + float crossfade = in0(2); crossfade = sc_clip(crossfade, 0.f, 1.f); SCPolarBuf *p = ToPolarApx(buf1); SCPolarBuf *q = ToPolarApx(buf2); @@ -106,7 +109,7 @@ void PV_MagXFade_next(PV_MagXFade *unit, int inNumSamples) { } } -void PV_MagXFade_Ctor(PV_MagXFade *unit) { - SETCALC(PV_MagXFade_next); - OUT0(0) = IN0(0); +FlexPlugins::PV_MagXFade::PV_MagXFade() { + set_calc_function(); + next(1); } \ No newline at end of file diff --git a/src/pv/pvOther.hpp b/src/pv/pvOther.hpp index 899d6b2..1921ae5 100644 --- a/src/pv/pvOther.hpp +++ b/src/pv/pvOther.hpp @@ -23,16 +23,27 @@ along with this program. If not, see . */ #pragma once -#include "SC_Unit.h" - -struct PV_MagSqueeze : public Unit {}; -void PV_MagSqueeze_next(PV_MagSqueeze *unit, int inNumSamples); -void PV_MagSqueeze_Ctor(PV_MagSqueeze *unit); - -struct PV_MagMirror : public Unit {}; -void PV_MagMirror_next(PV_MagMirror *unit, int inNumSamples); -void PV_MagMirror_Ctor(PV_MagMirror *unit); - -struct PV_MagXFade : public Unit {}; -void PV_MagXFade_next(PV_MagXFade *unit, int inNumSamples); -void PV_MagXFade_Ctor(PV_MagXFade *unit); \ No newline at end of file +#include "SC_PlugIn.hpp" + +namespace FlexPlugins { + class PV_MagSqueeze : public SCUnit { + public: + PV_MagSqueeze(); + private: + void next(int inNumSamples); + }; + + class PV_MagMirror : public SCUnit { + public: + PV_MagMirror(); + private: + void next(int inNumSamples); + }; + + class PV_MagXFade : public SCUnit { + public: + PV_MagXFade(); + private: + void next(int inNumSamples); + }; +} \ No newline at end of file diff --git a/src/pv/pvStretch.cpp b/src/pv/pvStretch.cpp index 9db9cc1..f994baa 100644 --- a/src/pv/pvStretch.cpp +++ b/src/pv/pvStretch.cpp @@ -30,76 +30,77 @@ along with this program. If not, see . extern InterfaceTable *ft; -void PV_PlayBufStretch_Ctor(PV_PlayBufStretch *unit) { +FlexPlugins::PV_PlayBufStretch::PV_PlayBufStretch() { + PV_PlayBufStretch *unit = this; PV_GET_BUF // Connect to the STFT buffer. For now, we only allow this in the constructor. - float fstftbufnum = IN0(1); + float fstftbufnum = in0(1); uint32 stftbufnum = static_cast(fstftbufnum); - if (stftbufnum >= unit->mWorld->mNumSndBufs) stftbufnum = 0; - unit->m_fbufnum = fstftbufnum; - unit->m_buf = unit->mWorld->mSndBufs + stftbufnum; - unit->m_outFramePrev = nullptr; - unit->m_frameNext = nullptr; - unit->m_framePrev1 = nullptr; - unit->m_framePrev2 = nullptr; - size_t peakRadius = static_cast(sc_clip(IN0(6), 1.f, 32.f)); - unit->m_peakFinder = (PeakFinder*)RTAlloc(unit->mWorld, sizeof(PeakFinder)); - new (unit->m_peakFinder) PeakFinder(static_cast(buf->samples), peakRadius); - unit->m_peakFinder->memLoad(RTAlloc(unit->mWorld, unit->m_peakFinder->memSize())); + if (stftbufnum >= mWorld->mNumSndBufs) stftbufnum = 0; + m_fbufnum = fstftbufnum; + m_buf = mWorld->mSndBufs + stftbufnum; + m_outFramePrev = nullptr; + m_frameNext = nullptr; + m_framePrev1 = nullptr; + m_framePrev2 = nullptr; + size_t peakRadius = static_cast(sc_clip(in0(6), 1.f, 32.f)); + m_peakFinder = (PeakFinder*)RTAlloc(mWorld, sizeof(PeakFinder)); + new (m_peakFinder) PeakFinder(static_cast(buf->samples), peakRadius); + m_peakFinder->memLoad(RTAlloc(mWorld, m_peakFinder->memSize())); // Configure position - float startPos = sc_clip(IN0(2), 0.0, 1.0); - unit->m_pos = 0.f; - unit->m_startPos = startPos; - unit->m_firstFrame = true; + float startPos = sc_clip(in0(2), 0.0, 1.0); + m_pos = 0.f; + m_startPos = startPos; + m_firstFrame = true; - SETCALC(PV_PlayBufStretch_next); - OUT0(0) = IN0(0); + set_calc_function(); + next(1); } -void PV_PlayBufStretch_Dtor(PV_PlayBufStretch *unit) { - if (unit->m_peakFinder) { - void *reservedMem = unit->m_peakFinder->memRetrieve(); +FlexPlugins::PV_PlayBufStretch::~PV_PlayBufStretch() { + if (m_peakFinder) { + void *reservedMem = m_peakFinder->memRetrieve(); if (reservedMem) { - RTFree(unit->mWorld, reservedMem); + RTFree(mWorld, reservedMem); } - RTFree(unit->mWorld, unit->m_peakFinder); + RTFree(mWorld, m_peakFinder); } - if (unit->m_outFramePrev) { - RTFree(unit->mWorld, unit->m_outFramePrev); + if (m_outFramePrev) { + RTFree(mWorld, m_outFramePrev); } - if (unit->m_frameNext) { - RTFree(unit->mWorld, unit->m_frameNext); + if (m_frameNext) { + RTFree(mWorld, m_frameNext); } - if (unit->m_framePrev1) { - RTFree(unit->mWorld, unit->m_framePrev1); + if (m_framePrev1) { + RTFree(mWorld, m_framePrev1); } - if (unit->m_framePrev2) { - RTFree(unit->mWorld, unit->m_framePrev2); + if (m_framePrev2) { + RTFree(mWorld, m_framePrev2); } } -void PV_PlayBufStretch_next(PV_PlayBufStretch *unit, int inNumSamples) { +void FlexPlugins::PV_PlayBufStretch::next(int inNumSamples) { + PV_PlayBufStretch *unit = this; PV_GET_BUF // This section of the code is for acquiring the STFT buffer and information about it. // It has to be run every time because we cannot be sure the user has not freed the buffer. // We also have to verify important details about the buffer to make sure we can read from it at all. - const SndBuf *stftBuf = unit->m_buf; - if (!stftBuf) { + if (!m_buf) { OUT0(0) = -1.f; std::cout << "WARNING: The stftBuffer could not be accessed. Aborting.\n"; return; } ACQUIRE_SNDBUF_SHARED(stftBuf); - const float* bufData __attribute__((__unused__)) = stftBuf->data; - const float* stftData __attribute__((__unused__)) = stftBuf->data + 3; - const uint32 bufChannels __attribute__((__unused__)) = stftBuf->channels; - const uint32 bufSamples __attribute__((__unused__)) = stftBuf->samples; - const uint32 bufFrames = stftBuf->frames; + const float* bufData __attribute__((__unused__)) = m_buf->data; + const float* stftData __attribute__((__unused__)) = m_buf->data + 3; + const uint32 bufChannels __attribute__((__unused__)) = m_buf->channels; + const uint32 bufSamples __attribute__((__unused__)) = m_buf->samples; + const uint32 bufFrames = m_buf->frames; // first 3 frames have analysis parameters - const int stftFrames = (static_cast(stftBuf->samples) - 3) / static_cast(buf->samples); + const int stftFrames = (static_cast(m_buf->samples) - 3) / static_cast(buf->samples); // If the buffer is improperly configured, we cannot use it. if (bufChannels != 1) { @@ -133,64 +134,66 @@ void PV_PlayBufStretch_next(PV_PlayBufStretch *unit, int inNumSamples) { } // The first time through, we need to allocate the SCPolarBuf storage in the UGen. - if (!unit->m_outFramePrev) { + if (!m_outFramePrev) { // This is an annoying way to have to allocate memory, // but it seems to be necessary based on how SCPolarBuf is defined. - float *outFramePrev = (float*)RTAlloc(unit->mWorld, stftBufFftSize * sizeof(float)); - float *frameNext = (float*)RTAlloc(unit->mWorld, stftBufFftSize * sizeof(float)); - float *framePrev1 = (float*)RTAlloc(unit->mWorld, stftBufFftSize * sizeof(float)); - float *framePrev2 = (float*)RTAlloc(unit->mWorld, stftBufFftSize * sizeof(float)); - unit->m_outFramePrev = (SCPolarBuf*)outFramePrev; - unit->m_frameNext = (SCPolarBuf*)frameNext; - unit->m_framePrev1 = (SCPolarBuf*)framePrev1; - unit->m_framePrev2 = (SCPolarBuf*)framePrev2; + float *outFramePrev = (float*)RTAlloc(mWorld, stftBufFftSize * sizeof(float)); + float *frameNext = (float*)RTAlloc(mWorld, stftBufFftSize * sizeof(float)); + float *framePrev1 = (float*)RTAlloc(mWorld, stftBufFftSize * sizeof(float)); + float *framePrev2 = (float*)RTAlloc(mWorld, stftBufFftSize * sizeof(float)); + m_outFramePrev = (SCPolarBuf*)outFramePrev; + m_frameNext = (SCPolarBuf*)frameNext; + m_framePrev1 = (SCPolarBuf*)framePrev1; + m_framePrev2 = (SCPolarBuf*)framePrev2; } - float startPos = sc_clip(IN0(2), 0.0, 1.0); - const float rate = IN0(3); - const float loop = IN0(4); + float startPos = sc_clip(in0(2), 0.0, 1.0); + const float rate = in0(3); + const float loop = in0(4); - if (startPos != unit->m_startPos) { - unit->m_startPos = startPos; - unit->m_firstFrame = true; + if (startPos != m_startPos) { + m_startPos = startPos; + m_firstFrame = true; // std::cout << "Start pos changed\n"; } // Now that we've run setup, we're ready to read STFT data and perform phase vocoder stretching. // First we need to figure out where we are, and if that means we need to loop or quit. - float newPos = unit->m_pos + rate; + float newPos = m_pos + rate; if (newPos > stftFrames - 1) { if (loop && rate > 0) { - unit->m_firstFrame = true; + m_firstFrame = true; startPos = 0; } else if (rate <= 0) { // clip it to the last possible frame if we're working backwards newPos = stftFrames - 1; } else { - OUT0(0) = -1.f; + float *outBuf = out(0); + outBuf[0] = -1.f; RELEASE_SNDBUF_SHARED(stftBuf); - DoneAction(static_cast(IN0(7)), unit); + DoneAction(static_cast(in0(7)), this); return; } } else if (newPos < 0) { if (loop && rate < 0) { - unit->m_firstFrame = true; + m_firstFrame = true; startPos = 1; } else if (rate >= 0) { // clip it to the first frame if we're working forwards newPos = 0; } else { - OUT0(0) = -1.f; + float *outBuf = out(0); + outBuf[0] = -1.f; RELEASE_SNDBUF_SHARED(stftBuf); - DoneAction(static_cast(IN0(7)), unit); + DoneAction(static_cast(in0(7)), this); return; } } // The first frame has to be cloned directly from the STFT buffer with no phase adjustments. // This is essential to make sure that subsequent phase calculations are correctly aligned. - if (unit->m_firstFrame) { + if (m_firstFrame) { // Compute the index of the first frame size_t firstFrameIdx = static_cast(std::round(startPos * (stftFrames-1))); @@ -203,16 +206,16 @@ void PV_PlayBufStretch_next(PV_PlayBufStretch *unit, int inNumSamples) { // We always need to store the resultant FFT frame in the UGen. // It is used in the next call to PV_PlayBufStretch_next, for // phase vocoder calculations. - fillPolarBuf(currentFftFrame, unit->m_outFramePrev, stftBufFftSize); + fillPolarBuf(currentFftFrame, m_outFramePrev, stftBufFftSize); // We have to advance by one frame because we need to be able to compute frequency for time stretching. - unit->m_pos = static_cast(firstFrameIdx + 1); - unit->m_firstFrame = false; + m_pos = static_cast(firstFrameIdx + 1); + m_firstFrame = false; } // For frames other than the first frame, we'll need to perform phase computation. else { - size_t phaseLock = sc_clip(static_cast(IN0(5)), 0, 2); + size_t phaseLock = sc_clip(static_cast(in0(5)), 0, 2); SCPolarBuf *p = ToPolarApx(buf); size_t roundedPos = static_cast(std::round(newPos)); @@ -226,37 +229,37 @@ void PV_PlayBufStretch_next(PV_PlayBufStretch *unit, int inNumSamples) { } else if (lastPos >= stftFrames) { lastPos = roundedPos - 1; } - fillPolarBuf(stftData + (roundedPos * stftBufFftSize), unit->m_frameNext, stftBufFftSize); - fillPolarBuf(stftData + (lastPos * stftBufFftSize), unit->m_framePrev1, stftBufFftSize); + fillPolarBuf(stftData + (roundedPos * stftBufFftSize), m_frameNext, stftBufFftSize); + fillPolarBuf(stftData + (lastPos * stftBufFftSize), m_framePrev1, stftBufFftSize); // Render the output FFT frame switch (phaseLock) { case 1: Stretch2Puckette( - unit->m_frameNext, - unit->m_framePrev1, + m_frameNext, + m_framePrev1, p, - unit->m_outFramePrev, + m_outFramePrev, stftBufFftSize, stftBufHopSize ); break; case 2: Stretch2LarocheDolson( - unit->m_frameNext, - unit->m_framePrev1, + m_frameNext, + m_framePrev1, p, - unit->m_outFramePrev, - unit->m_peakFinder, + m_outFramePrev, + m_peakFinder, stftBufFftSize, stftBufHopSize ); break; default: Stretch2( - unit->m_frameNext, - unit->m_framePrev1, + m_frameNext, + m_framePrev1, p, - unit->m_outFramePrev, + m_outFramePrev, stftBufFftSize, stftBufHopSize ); @@ -277,19 +280,19 @@ void PV_PlayBufStretch_next(PV_PlayBufStretch *unit, int inNumSamples) { } // We are in between these two frames - fillPolarBuf(stftData + (hi * stftBufFftSize), unit->m_frameNext, stftBufFftSize); - fillPolarBuf(stftData + (lo * stftBufFftSize), unit->m_framePrev1, stftBufFftSize); + fillPolarBuf(stftData + (hi * stftBufFftSize), m_frameNext, stftBufFftSize); + fillPolarBuf(stftData + (lo * stftBufFftSize), m_framePrev1, stftBufFftSize); // This is the frame right before that. It's needed to compute the previous instantaneous frequencies. - fillPolarBuf(stftData + (loprev * stftBufFftSize), unit->m_framePrev2, stftBufFftSize); + fillPolarBuf(stftData + (loprev * stftBufFftSize), m_framePrev2, stftBufFftSize); // Render the output FFT frame switch (phaseLock) { case 1: Stretch3Puckette( - unit->m_frameNext, - unit->m_framePrev1, - unit->m_framePrev2, + m_frameNext, + m_framePrev1, + m_framePrev2, p, - unit->m_outFramePrev, + m_outFramePrev, newPos-static_cast(lo), stftBufFftSize, stftBufHopSize @@ -297,12 +300,12 @@ void PV_PlayBufStretch_next(PV_PlayBufStretch *unit, int inNumSamples) { break; case 2: Stretch3LarocheDolson( - unit->m_frameNext, - unit->m_framePrev1, - unit->m_framePrev2, + m_frameNext, + m_framePrev1, + m_framePrev2, p, - unit->m_outFramePrev, - unit->m_peakFinder, + m_outFramePrev, + m_peakFinder, newPos-static_cast(lo), stftBufFftSize, stftBufHopSize @@ -310,11 +313,11 @@ void PV_PlayBufStretch_next(PV_PlayBufStretch *unit, int inNumSamples) { break; default: Stretch3( - unit->m_frameNext, - unit->m_framePrev1, - unit->m_framePrev2, + m_frameNext, + m_framePrev1, + m_framePrev2, p, - unit->m_outFramePrev, + m_outFramePrev, newPos-static_cast(lo), stftBufFftSize, stftBufHopSize @@ -324,8 +327,8 @@ void PV_PlayBufStretch_next(PV_PlayBufStretch *unit, int inNumSamples) { // We always need to store the resultant FFT frame in the UGen. // It is used in the next call to PV_PlayBufStretch_next, for // phase vocoder calculations. - copyPolarBuf(p, unit->m_outFramePrev, static_cast(numbins)); - unit->m_pos = newPos; + copyPolarBuf(p, m_outFramePrev, static_cast(numbins)); + m_pos = newPos; } RELEASE_SNDBUF_SHARED(stftBuf); @@ -342,7 +345,7 @@ void PV_PlayBufStretch_next(PV_PlayBufStretch *unit, int inNumSamples) { /// \param outFramePrev The previously computed output STFT frame /// \param fftSize The FFT size /// \param hopSize The hop size -void Stretch2( +void FlexPlugins::PV_PlayBufStretch::Stretch2( const SCPolarBuf *frame, const SCPolarBuf *framePrev, SCPolarBuf *outFrame, @@ -381,7 +384,7 @@ void Stretch2( /// \param outFramePrev The previously computed output STFT frame /// \param fftSize The FFT size /// \param hopSize The hop size -void Stretch2Puckette( +void FlexPlugins::PV_PlayBufStretch::Stretch2Puckette( const SCPolarBuf *frame, const SCPolarBuf *framePrev, SCPolarBuf *outFrame, @@ -434,7 +437,7 @@ void Stretch2Puckette( /// \param peakFinder The PeakFinder instance for determining peak locations in the magnitude spectrum /// \param fftSize The FFT size /// \param hopSize The hop size -void Stretch2LarocheDolson( +void FlexPlugins::PV_PlayBufStretch::Stretch2LarocheDolson( const SCPolarBuf *frame, const SCPolarBuf *framePrev, SCPolarBuf *outFrame, @@ -550,7 +553,7 @@ void Stretch2LarocheDolson( /// \param pos The position between framePrev1 and frameNext (0 < pos < 1) /// \param fftSize The FFT size /// \param hopSize The hop size -void Stretch3( +void FlexPlugins::PV_PlayBufStretch::Stretch3( const SCPolarBuf *frameNext, const SCPolarBuf *framePrev1, const SCPolarBuf *framePrev2, @@ -602,7 +605,7 @@ void Stretch3( /// \param pos The position between framePrev1 and frameNext (0 < pos < 1) /// \param fftSize The FFT size /// \param hopSize The hop size -void Stretch3Puckette( +void FlexPlugins::PV_PlayBufStretch::Stretch3Puckette( const SCPolarBuf *frameNext, const SCPolarBuf *framePrev1, const SCPolarBuf *framePrev2, @@ -668,7 +671,7 @@ void Stretch3Puckette( /// \param pos The position between framePrev1 and frameNext (0 < pos < 1) /// \param fftSize The FFT size /// \param hopSize The hop size -static void Stretch3LarocheDolson( +void FlexPlugins::PV_PlayBufStretch::Stretch3LarocheDolson( const SCPolarBuf *frameNext, const SCPolarBuf *framePrev1, const SCPolarBuf *framePrev2, @@ -821,7 +824,7 @@ static void Stretch3LarocheDolson( /// \param fftBuf The FFT frame from the STFT buffer /// \param [out] polarBuf The SCPolarBuf to copy to /// \param fftSize The FFT size -void fillPolarBuf(const float *fftBuf, SCPolarBuf *polarBuf, size_t fftSize) { +void FlexPlugins::PV_PlayBufStretch::fillPolarBuf(const float *fftBuf, SCPolarBuf *polarBuf, size_t fftSize) { polarBuf->dc = fftBuf[0]; polarBuf->nyq = fftBuf[1]; for (size_t xxn = 2, xxk = 0; xxn < fftSize; xxn+=2, xxk++) { @@ -837,7 +840,7 @@ void fillPolarBuf(const float *fftBuf, SCPolarBuf *polarBuf, size_t fftSize) { /// \param sourceBuf The source buffer /// \param [out] destBuf The destination buffer /// \param numbins The number of bins in the SCPolarBuf (fftSize/2-1) -void copyPolarBuf(const SCPolarBuf *sourceBuf, SCPolarBuf *destBuf, size_t numbins) { +void FlexPlugins::PV_PlayBufStretch::copyPolarBuf(const SCPolarBuf *sourceBuf, SCPolarBuf *destBuf, size_t numbins) { destBuf->dc = sourceBuf->dc; destBuf->nyq = sourceBuf->nyq; for (size_t xxn = 0; xxn < numbins; xxn++) { @@ -846,11 +849,10 @@ void copyPolarBuf(const SCPolarBuf *sourceBuf, SCPolarBuf *destBuf, size_t numbi } } +FlexPlugins::Peak::Peak(size_t peak) : peak(peak) {} +FlexPlugins::Peak::Peak(size_t peak, size_t leftValley, size_t rightValley) : peak(peak), leftValley(leftValley), rightValley(rightValley) {} -Peak::Peak(size_t peak) : peak(peak) {} -Peak::Peak(size_t peak, size_t leftValley, size_t rightValley) : peak(peak), leftValley(leftValley), rightValley(rightValley) {} - -PeakFinder::PeakFinder(size_t fftSize, size_t radius) { +FlexPlugins::PeakFinder::PeakFinder(size_t fftSize, size_t radius) { m_maxSize = fftSize/2-1; m_radius = radius; m_size = 0; @@ -859,34 +861,34 @@ PeakFinder::PeakFinder(size_t fftSize, size_t radius) { m_queueR = nullptr; } -void PeakFinder::memLoad(void* arr) { +void FlexPlugins::PeakFinder::memLoad(void* arr) { size_t *data = (size_t*)arr; m_queueL = data; m_queueR = data + m_radius; peaks = (Peak*)(data + 2 * m_radius); } -size_t PeakFinder::memSize() const { +size_t FlexPlugins::PeakFinder::memSize() const { return m_radius * 2 * sizeof(size_t) + m_maxSize * sizeof(Peak); } -void* PeakFinder::memRetrieve() { +void* FlexPlugins::PeakFinder::memRetrieve() { return (void*)m_queueL; } -void PeakFinder::clear() { +void FlexPlugins::PeakFinder::clear() { m_size = 0; } -size_t PeakFinder::maxSize() const { +size_t FlexPlugins::PeakFinder::maxSize() const { return m_maxSize; } -size_t PeakFinder::size() const { +size_t FlexPlugins::PeakFinder::size() const { return m_size; } -void PeakFinder::analyze(const SCPolarBuf *buf) { +void FlexPlugins::PeakFinder::analyze(const SCPolarBuf *buf) { // We can only perform the analysis if we have enough bins if (m_queueL && m_maxSize > m_radius * 2 + 1) { m_size = 0; // clear any existing data diff --git a/src/pv/pvStretch.hpp b/src/pv/pvStretch.hpp index fe70e1a..29f83d3 100644 --- a/src/pv/pvStretch.hpp +++ b/src/pv/pvStretch.hpp @@ -22,256 +22,256 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ #pragma once -#include "SC_Unit.h" +#include "SC_PlugIn.hpp" #include "FFT_UGens.h" -class Peak { -public: - Peak(size_t peak); - Peak(size_t peak, size_t leftValley, size_t rightValley); - size_t peak, leftValley, rightValley; -}; - -class PeakFinder { -public: - /// Constructs the PeakFinder - /// - /// \param fftSize The FFT size - PeakFinder(size_t fftSize, size_t radius); - - /// Finds peaks in the provided SCPolarBuf. Note that this buffer must correspond - /// to the original FFT size provided for the PeakFinder--otherwise memory errors may occur. - /// - /// \param buf The buffer to analyze - void analyze(const SCPolarBuf *buf); - - /// Loads memory from the external SuperCollider allocator. Memory is allocated - /// using RTAlloc() and the size is specified by the memSize() method. - /// - /// \param arr The allocated memory - void memLoad(void *arr); - - /// Gets the memory size required for the PeakFinder - size_t memSize() const; - - /// Gets the max size of the PeakFinder - /// - /// \returns The max size - size_t maxSize() const; - - /// Gets the current size of the PeakFinder (the number of peaks stored) - /// - /// \returns The current size - size_t size() const; - - /// Clears the PeakFinder - void clear(); - - /// Gets a pointer to the memory that was allocated for the PeakFinder - /// so that it can be deallocated - /// - /// \return The memory pointer - void* memRetrieve(); - - Peak *peaks; -private: - size_t m_maxSize, m_size, m_radius; - size_t *m_queueL, *m_queueR; -}; - -/// Stores the state of a PV_PlayBufStretch UGen instance -struct PV_PlayBufStretch : public Unit { - /// The index of the buffer with STFT data - float m_fbufnum; - - /// The buffer with STFT data - SndBuf *m_buf; - - /// The most recent output STFT frame - SCPolarBuf *m_outFramePrev; - - /// The next STFT frame after the current position - SCPolarBuf *m_frameNext; - - /// The STFT frame right before the current position - SCPolarBuf *m_framePrev1; - - /// The STFT frame two positions before the current position - SCPolarBuf *m_framePrev2; - - /// The peak finding utility for the Laroche/Dolson stretching algorithm - PeakFinder *m_peakFinder; - - /// Between 0 and 1; represents the start position of playback. - /// If it jumps during playback, playback will be restarted - /// at the new m_startPos. - float m_startPos; - - /// A fractional STFT frame index. Unlike m_startPos, it corresponds to the - /// integer index of the current STFT frame (from 0 to M-1). - /// Used for interpolating position. - float m_pos; - - /// For the first frame, we need to read phase data directly - /// instead of computing it. - bool m_firstFrame; -}; - -/// Initializes a new PV_PlayBufStretch UGen -void PV_PlayBufStretch_Ctor(PV_PlayBufStretch *unit); - -/// Frees memory created by the PV_PlayBufStretch UGen -void PV_PlayBufStretch_Dtor(PV_PlayBufStretch *unit); - -/// Computes the next FFT frame requested by the PV_PlayBufStretch UGen -void PV_PlayBufStretch_next(PV_PlayBufStretch *unit, int inNumSamples); - -/// Computes a single frame of STFT data for time stretching. -/// The assumption is that we are positioned exactly at `frame`, and we therefore -/// just need framePrev to compute the instantaneous frequency. We also do not -/// need to perform any magnitude or frequency interpolation. -/// -/// \param frame The current STFT frame -/// \param framePrev The previous STFT frame -/// \param [out] outFrame The output STFT frame -/// \param outFramePrev The previously computed output STFT frame -/// \param fftSize The FFT size -/// \param hopSize The hop size -void Stretch2( - const SCPolarBuf *frame, - const SCPolarBuf *framePrev, - SCPolarBuf *outFrame, - const SCPolarBuf *outFramePrev, - size_t fftSize, - size_t hopSize); - -/// Computes a single frame of STFT data for time stretching. -/// The assumption is that we are positioned exactly at `frame`, and we therefore -/// just need framePrev to compute the instantaneous frequency. We also do not -/// need to perform any magnitude or frequency interpolation. -/// -/// This version uses Miller Puckette's phase locking. -/// -/// \param frame The current STFT frame -/// \param framePrev The previous STFT frame -/// \param [out] outFrame The output STFT frame -/// \param outFramePrev The previously computed output STFT frame -/// \param fftSize The FFT size -/// \param hopSize The hop size -void Stretch2Puckette( - const SCPolarBuf *frame, - const SCPolarBuf *framePrev, - SCPolarBuf *outFrame, - const SCPolarBuf *outFramePrev, - size_t fftSize, - size_t hopSize); - -/// Computes a single frame of STFT data for time stretching, -/// using the Laroche/Dolson identity phase locking scheme. -/// The assumption is that we are positioned exactly at `frame`, and we therefore -/// just need framePrev to compute the instantaneous frequency. We also do not -/// need to perform any magnitude or frequency interpolation. -/// -/// \param frame The current STFT frame -/// \param framePrev The previous STFT frame -/// \param [out] outFrame The output STFT frame -/// \param outFramePrev The previously computed output STFT frame -/// \param peakFinder The PeakFinder instance for determining peak locations in the magnitude spectrum -/// \param fftSize The FFT size -/// \param hopSize The hop size -void Stretch2LarocheDolson( - const SCPolarBuf *frame, - const SCPolarBuf *framePrev, - SCPolarBuf *outFrame, - const SCPolarBuf *outFramePrev, - PeakFinder *peakFinder, - size_t fftSize, - size_t hopSize); - -/// Computes a single frame of STFT data for time stretching. -/// The assumption is that we are positioned between framePrev1 and frameNext. -/// This means we will need to interpolate frequency data. So we will need to -/// compute two frequencies for each bin, and that means we need three STFT frames. -/// -/// \param frameNext The next STFT frame -/// \param framePrev1 The previous STFT frame -/// \param framePrev2 The previous STFT frame before that (required for instantaneous frequency interpolation) -/// \param [out] outFrame The output STFT frame -/// \param outFramePrev The previously computed output STFT frame -/// \param pos The position between framePrev1 and frameNext (0 < pos < 1) -/// \param fftSize The FFT size -/// \param hopSize The hop size -void Stretch3( - const SCPolarBuf *frameNext, - const SCPolarBuf *framePrev1, - const SCPolarBuf *framePrev2, - SCPolarBuf *outFrame, - const SCPolarBuf *outFramePrev, - float pos, - size_t fftSize, - size_t hopSize); - -/// Computes a single frame of STFT data for time stretching. -/// The assumption is that we are positioned between framePrev1 and frameNext. -/// This means we will need to interpolate frequency data. So we will need to -/// compute two frequencies for each bin, and that means we need three STFT frames. -/// -/// This version uses Miller Puckette's phase locking. -/// -/// \param frameNext The next STFT frame -/// \param framePrev1 The previous STFT frame -/// \param framePrev2 The previous STFT frame before that (required for instantaneous frequency interpolation) -/// \param [out] outFrame The output STFT frame -/// \param outFramePrev The previously computed output STFT frame -/// \param pos The position between framePrev1 and frameNext (0 < pos < 1) -/// \param fftSize The FFT size -/// \param hopSize The hop size -void Stretch3Puckette( - const SCPolarBuf *frameNext, - const SCPolarBuf *framePrev1, - const SCPolarBuf *framePrev2, - SCPolarBuf *outFrame, - const SCPolarBuf *outFramePrev, - float pos, - size_t fftSize, - size_t hopSize); - -/// Computes a single frame of STFT data for time stretching, -/// using the Laroche/Dolson identity phase locking scheme. -/// The assumption is that we are positioned exactly at `frame`, and we therefore -/// just need framePrev to compute the instantaneous frequency. We also do not -/// need to perform any magnitude or frequency interpolation. -/// -/// \param frameNext The next STFT frame -/// \param framePrev1 The previous STFT frame -/// \param framePrev2 The previous STFT frame before that (required for instantaneous frequency interpolation) -/// \param [out] outFrame The output STFT frame -/// \param outFramePrev The previously computed output STFT frame -/// \param peakFinder The PeakFinder instance for determining peak locations in the magnitude spectrum -/// \param pos The position between framePrev1 and frameNext (0 < pos < 1) -/// \param fftSize The FFT size -/// \param hopSize The hop size -static void Stretch3LarocheDolson( - const SCPolarBuf *frameNext, - const SCPolarBuf *framePrev1, - const SCPolarBuf *framePrev2, - SCPolarBuf *outFrame, - const SCPolarBuf *outFramePrev, - PeakFinder *peakFinder, - double pos, - size_t fftSize, - size_t hopSize); - -/// Fills a SCPolarBuf with saved STFT data from a single frame -/// -/// \param fftBuf The FFT frame from the STFT buffer -/// \param [out] polarBuf The SCPolarBuf to copy to -/// \param fftSize The FFT size -void fillPolarBuf(const float *fftBuf, SCPolarBuf *polarBuf, size_t fftSize); - -/// Copies data from one SCPolarBuf to another -/// -/// \param sourceBuf The source buffer -/// \param [out] destBuf The destination buffer -/// \param numbins The number of bins in the SCPolarBuf (fftSize/2-1) -void copyPolarBuf(const SCPolarBuf *sourceBuf, SCPolarBuf *destBuf, size_t numbins); \ No newline at end of file +namespace FlexPlugins { + class Peak { + public: + Peak(size_t peak); + Peak(size_t peak, size_t leftValley, size_t rightValley); + size_t peak, leftValley, rightValley; + }; + + class PeakFinder { + public: + /// Constructs the PeakFinder + /// + /// \param fftSize The FFT size + PeakFinder(size_t fftSize, size_t radius); + + /// Finds peaks in the provided SCPolarBuf. Note that this buffer must correspond + /// to the original FFT size provided for the PeakFinder--otherwise memory errors may occur. + /// + /// \param buf The buffer to analyze + void analyze(const SCPolarBuf *buf); + + /// Loads memory from the external SuperCollider allocator. Memory is allocated + /// using RTAlloc() and the size is specified by the memSize() method. + /// + /// \param arr The allocated memory + void memLoad(void *arr); + + /// Gets the memory size required for the PeakFinder + size_t memSize() const; + + /// Gets the max size of the PeakFinder + /// + /// \returns The max size + size_t maxSize() const; + + /// Gets the current size of the PeakFinder (the number of peaks stored) + /// + /// \returns The current size + size_t size() const; + + /// Clears the PeakFinder + void clear(); + + /// Gets a pointer to the memory that was allocated for the PeakFinder + /// so that it can be deallocated + /// + /// \return The memory pointer + void* memRetrieve(); + + Peak *peaks; + private: + size_t m_maxSize, m_size, m_radius; + size_t *m_queueL, *m_queueR; + }; + + /// Stores the state of a PV_PlayBufStretch UGen instance + class PV_PlayBufStretch : public SCUnit { + public: + PV_PlayBufStretch(); + ~PV_PlayBufStretch(); + + private: + void next(int inNumSamples); + + /// Computes a single frame of STFT data for time stretching. + /// The assumption is that we are positioned exactly at `frame`, and we therefore + /// just need framePrev to compute the instantaneous frequency. We also do not + /// need to perform any magnitude or frequency interpolation. + /// + /// \param frame The current STFT frame + /// \param framePrev The previous STFT frame + /// \param [out] outFrame The output STFT frame + /// \param outFramePrev The previously computed output STFT frame + /// \param fftSize The FFT size + /// \param hopSize The hop size + void Stretch2( + const SCPolarBuf *frame, + const SCPolarBuf *framePrev, + SCPolarBuf *outFrame, + const SCPolarBuf *outFramePrev, + size_t fftSize, + size_t hopSize); + + /// Computes a single frame of STFT data for time stretching. + /// The assumption is that we are positioned exactly at `frame`, and we therefore + /// just need framePrev to compute the instantaneous frequency. We also do not + /// need to perform any magnitude or frequency interpolation. + /// + /// This version uses Miller Puckette's phase locking. + /// + /// \param frame The current STFT frame + /// \param framePrev The previous STFT frame + /// \param [out] outFrame The output STFT frame + /// \param outFramePrev The previously computed output STFT frame + /// \param fftSize The FFT size + /// \param hopSize The hop size + void Stretch2Puckette( + const SCPolarBuf *frame, + const SCPolarBuf *framePrev, + SCPolarBuf *outFrame, + const SCPolarBuf *outFramePrev, + size_t fftSize, + size_t hopSize); + + /// Computes a single frame of STFT data for time stretching, + /// using the Laroche/Dolson identity phase locking scheme. + /// The assumption is that we are positioned exactly at `frame`, and we therefore + /// just need framePrev to compute the instantaneous frequency. We also do not + /// need to perform any magnitude or frequency interpolation. + /// + /// \param frame The current STFT frame + /// \param framePrev The previous STFT frame + /// \param [out] outFrame The output STFT frame + /// \param outFramePrev The previously computed output STFT frame + /// \param peakFinder The PeakFinder instance for determining peak locations in the magnitude spectrum + /// \param fftSize The FFT size + /// \param hopSize The hop size + void Stretch2LarocheDolson( + const SCPolarBuf *frame, + const SCPolarBuf *framePrev, + SCPolarBuf *outFrame, + const SCPolarBuf *outFramePrev, + PeakFinder *peakFinder, + size_t fftSize, + size_t hopSize); + + /// Computes a single frame of STFT data for time stretching. + /// The assumption is that we are positioned between framePrev1 and frameNext. + /// This means we will need to interpolate frequency data. So we will need to + /// compute two frequencies for each bin, and that means we need three STFT frames. + /// + /// \param frameNext The next STFT frame + /// \param framePrev1 The previous STFT frame + /// \param framePrev2 The previous STFT frame before that (required for instantaneous frequency interpolation) + /// \param [out] outFrame The output STFT frame + /// \param outFramePrev The previously computed output STFT frame + /// \param pos The position between framePrev1 and frameNext (0 < pos < 1) + /// \param fftSize The FFT size + /// \param hopSize The hop size + void Stretch3( + const SCPolarBuf *frameNext, + const SCPolarBuf *framePrev1, + const SCPolarBuf *framePrev2, + SCPolarBuf *outFrame, + const SCPolarBuf *outFramePrev, + float pos, + size_t fftSize, + size_t hopSize); + + /// Computes a single frame of STFT data for time stretching. + /// The assumption is that we are positioned between framePrev1 and frameNext. + /// This means we will need to interpolate frequency data. So we will need to + /// compute two frequencies for each bin, and that means we need three STFT frames. + /// + /// This version uses Miller Puckette's phase locking. + /// + /// \param frameNext The next STFT frame + /// \param framePrev1 The previous STFT frame + /// \param framePrev2 The previous STFT frame before that (required for instantaneous frequency interpolation) + /// \param [out] outFrame The output STFT frame + /// \param outFramePrev The previously computed output STFT frame + /// \param pos The position between framePrev1 and frameNext (0 < pos < 1) + /// \param fftSize The FFT size + /// \param hopSize The hop size + void Stretch3Puckette( + const SCPolarBuf *frameNext, + const SCPolarBuf *framePrev1, + const SCPolarBuf *framePrev2, + SCPolarBuf *outFrame, + const SCPolarBuf *outFramePrev, + float pos, + size_t fftSize, + size_t hopSize); + + /// Computes a single frame of STFT data for time stretching, + /// using the Laroche/Dolson identity phase locking scheme. + /// The assumption is that we are positioned exactly at `frame`, and we therefore + /// just need framePrev to compute the instantaneous frequency. We also do not + /// need to perform any magnitude or frequency interpolation. + /// + /// \param frameNext The next STFT frame + /// \param framePrev1 The previous STFT frame + /// \param framePrev2 The previous STFT frame before that (required for instantaneous frequency interpolation) + /// \param [out] outFrame The output STFT frame + /// \param outFramePrev The previously computed output STFT frame + /// \param peakFinder The PeakFinder instance for determining peak locations in the magnitude spectrum + /// \param pos The position between framePrev1 and frameNext (0 < pos < 1) + /// \param fftSize The FFT size + /// \param hopSize The hop size + static void Stretch3LarocheDolson( + const SCPolarBuf *frameNext, + const SCPolarBuf *framePrev1, + const SCPolarBuf *framePrev2, + SCPolarBuf *outFrame, + const SCPolarBuf *outFramePrev, + PeakFinder *peakFinder, + double pos, + size_t fftSize, + size_t hopSize); + + /// Fills a SCPolarBuf with saved STFT data from a single frame + /// + /// \param fftBuf The FFT frame from the STFT buffer + /// \param [out] polarBuf The SCPolarBuf to copy to + /// \param fftSize The FFT size + void fillPolarBuf(const float *fftBuf, SCPolarBuf *polarBuf, size_t fftSize); + + /// Copies data from one SCPolarBuf to another + /// + /// \param sourceBuf The source buffer + /// \param [out] destBuf The destination buffer + /// \param numbins The number of bins in the SCPolarBuf (fftSize/2-1) + void copyPolarBuf(const SCPolarBuf *sourceBuf, SCPolarBuf *destBuf, size_t numbins); + + /// The index of the buffer with STFT data + float m_fbufnum; + + /// The buffer with STFT data + SndBuf *m_buf; + + /// The most recent output STFT frame + SCPolarBuf *m_outFramePrev; + + /// The next STFT frame after the current position + SCPolarBuf *m_frameNext; + + /// The STFT frame right before the current position + SCPolarBuf *m_framePrev1; + + /// The STFT frame two positions before the current position + SCPolarBuf *m_framePrev2; + + /// The peak finding utility for the Laroche/Dolson stretching algorithm + PeakFinder *m_peakFinder; + + /// Between 0 and 1; represents the start position of playback. + /// If it jumps during playback, playback will be restarted + /// at the new m_startPos. + float m_startPos; + + /// A fractional STFT frame index. Unlike m_startPos, it corresponds to the + /// integer index of the current STFT frame (from 0 to M-1). + /// Used for interpolating position. + float m_pos; + + /// For the first frame, we need to read phase data directly + /// instead of computing it. + bool m_firstFrame; + }; +} diff --git a/src/rubberband/ringbuffer.hpp b/src/rubberband/ringbuffer.hpp index 09f9c7d..eefca00 100644 --- a/src/rubberband/ringbuffer.hpp +++ b/src/rubberband/ringbuffer.hpp @@ -21,16 +21,16 @@ class RingBuffer { void initialize(T* buffer, size_t size); /// Determines if the buffer is ready to read `length` samples - bool isReadReady(size_t length); + bool isReadReady(size_t length) const; /// Reads a block of specified length void readBlock(T* destination, size_t length); /// Retrieves the size - size_t size(); + size_t size() const; /// Writes a block of specified length - void writeBlock(T* samples, size_t length); + void writeBlock(const T* samples, size_t length); /// Zeros out the buffer void zero(); @@ -60,7 +60,7 @@ void RingBuffer::initialize(T* buffer, size_t size) { } template -void RingBuffer::writeBlock(T* samples, size_t length) { +void RingBuffer::writeBlock(const T* samples, size_t length) { if (m_buffer && m_size > 0) { size_t startPos = m_inputPointer; for (size_t i = 0; i < length; i++) { @@ -90,7 +90,7 @@ void RingBuffer::readBlock(T* destination, size_t length) { } template -bool RingBuffer::isReadReady(size_t length) { +bool RingBuffer::isReadReady(size_t length) const { if (m_newSamples >= length) { return true; } else { @@ -99,7 +99,7 @@ bool RingBuffer::isReadReady(size_t length) { } template -size_t RingBuffer::size() { +size_t RingBuffer::size() const { return m_size; } diff --git a/src/rubberband/rubberBandPS.cpp b/src/rubberband/rubberBandPS.cpp index 1c9b23b..3f9c041 100644 --- a/src/rubberband/rubberBandPS.cpp +++ b/src/rubberband/rubberBandPS.cpp @@ -23,96 +23,107 @@ along with this program. If not, see . */ #include "rubberBandPS.hpp" -#include "SC_PlugIn.h" extern InterfaceTable *ft; -void RubberBandPS_Ctor(RubberBandPS *unit) { - float pitchRatio = IN0(1); +FlexPlugins::RubberBandPS::RubberBandPS() { + float pitchRatio = in0(1); // Initialize the shifter // 0x01000000 // formant preserving // 0x00000000 // no formant preservation - unit->m_shifter = (RubberBand::RubberBandLiveShifter*)RTAlloc(unit->mWorld, sizeof(RubberBand::RubberBandLiveShifter)); - new (unit->m_shifter) RubberBand::RubberBandLiveShifter(static_cast(SAMPLERATE), 1, 0x01000000); - unit->m_shifter->setPitchScale(sc_clip(pitchRatio, 1e-2, 64)); - unit->m_blockSize = BUFLENGTH; - unit->m_shifterBlockSize = unit->m_shifter->getBlockSize(); + m_shifter = (RubberBand::RubberBandLiveShifter*)RTAlloc(mWorld, sizeof(RubberBand::RubberBandLiveShifter)); + new (m_shifter) RubberBand::RubberBandLiveShifter(static_cast(sampleRate()), 1, 0x01000000); + m_shifter->setPitchScale(sc_clip(pitchRatio, 1e-2, 64)); + m_blockSize = fullBufferSize(); + m_shifterBlockSize = m_shifter->getBlockSize(); // Buffers for holding the samples to feed in and out of the shifter. // These buffers need to have the block size specified by the RubberBand shifter. - unit->m_shiftBufferIn = (float*)RTAlloc(unit->mWorld, unit->m_shifter->getBlockSize() * sizeof(float)); - unit->m_shiftBufferOut = (float*)RTAlloc(unit->mWorld, unit->m_shifter->getBlockSize() * sizeof(float)); + m_shiftBufferIn = (float*)RTAlloc(mWorld, m_shifter->getBlockSize() * sizeof(float)); + m_shiftBufferOut = (float*)RTAlloc(mWorld, m_shifter->getBlockSize() * sizeof(float)); // Make the ring buffers - unit->m_sendBuffer = (RingBuffer*)RTAlloc(unit->mWorld, sizeof(RingBuffer)); - new (unit->m_sendBuffer) RingBuffer; - unit->m_sendBuffer->initialize( + m_sendBuffer = (RingBuffer*)RTAlloc(mWorld, sizeof(RingBuffer)); + new (m_sendBuffer) RingBuffer; + m_sendBuffer->initialize( (float*)RTAlloc( - unit->mWorld, - (BUFLENGTH + unit->m_shifter->getBlockSize()) * 3 * sizeof(float)), - (BUFLENGTH + unit->m_shifter->getBlockSize()) * 3 + mWorld, + (fullBufferSize() + m_shifter->getBlockSize()) * 3 * sizeof(float)), + (fullBufferSize() + m_shifter->getBlockSize()) * 3 ); - unit->m_receiveBuffer = (RingBuffer*)RTAlloc(unit->mWorld, sizeof(RingBuffer)); - new (unit->m_receiveBuffer) RingBuffer; - unit->m_receiveBuffer->initialize( + m_receiveBuffer = (RingBuffer*)RTAlloc(mWorld, sizeof(RingBuffer)); + new (m_receiveBuffer) RingBuffer; + m_receiveBuffer->initialize( (float*)RTAlloc( - unit->mWorld, - (BUFLENGTH + unit->m_shifter->getBlockSize()) * 3 * sizeof(float)), - (BUFLENGTH + unit->m_shifter->getBlockSize()) * 3 + mWorld, + (fullBufferSize() + m_shifter->getBlockSize()) * 3 * sizeof(float)), + (fullBufferSize() + m_shifter->getBlockSize()) * 3 ); // Initialize output ring buffer with zeros. If there's trouble, you might need to do this twice. - for (size_t i = 0; i < unit->m_shifter->getBlockSize(); i++) { - unit->m_shiftBufferIn[i] = 0.f; + for (size_t i = 0; i < m_shifter->getBlockSize(); i++) { + m_shiftBufferIn[i] = 0.f; } - // Initialize first out sample - OUT0(0) = 0; - - SETCALC(RubberBandPS_next); + set_calc_function(); + next(1); } -void RubberBandPS_Dtor(RubberBandPS *unit) { - RTFree(unit->mWorld, unit->m_sendBuffer->m_buffer); - RTFree(unit->mWorld, unit->m_receiveBuffer->m_buffer); - RTFree(unit->mWorld, unit->m_shifter); - RTFree(unit->mWorld, unit->m_sendBuffer); - RTFree(unit->mWorld, unit->m_receiveBuffer); - RTFree(unit->mWorld, unit->m_shiftBufferIn); - RTFree(unit->mWorld, unit->m_shiftBufferOut); +FlexPlugins::RubberBandPS::~RubberBandPS() { + if (m_sendBuffer) { + if (m_sendBuffer->m_buffer) { + RTFree(mWorld, m_sendBuffer->m_buffer); + } + RTFree(mWorld, m_sendBuffer); + } + if (m_receiveBuffer) { + if (m_receiveBuffer->m_buffer) { + RTFree(mWorld, m_receiveBuffer->m_buffer); + } + RTFree(mWorld, m_receiveBuffer); + } + if (m_shifter) { + RTFree(mWorld, m_shifter); + } + if (m_shiftBufferIn) { + RTFree(mWorld, m_shiftBufferIn); + } + if (m_shiftBufferOut) { + RTFree(mWorld, m_shiftBufferOut); + } } -void RubberBandPS_next(RubberBandPS *unit, int inNumSamples) { - float pitchRatio = IN0(1); - float formantRatio = IN0(2); - float* in = IN(0); - float* out = OUT(0); +void FlexPlugins::RubberBandPS::next(int inNumSamples) { + float pitchRatio = in0(1); + float formantRatio = in0(2); + const float* inBuf = in(0); + float* outBuf = out(0); // Prepare the shifter, clipping the pitch and formant ratios for safety - unit->m_shifter->setPitchScale(sc_clip(pitchRatio, 1e-2, 64)); + m_shifter->setPitchScale(sc_clip(pitchRatio, 1e-2, 64)); if (formantRatio) { - unit->m_shifter->setFormantScale(sc_clip(formantRatio, 1e-2, 64)); + m_shifter->setFormantScale(sc_clip(formantRatio, 1e-2, 64)); } else { - unit->m_shifter->setFormantScale(0.f); + m_shifter->setFormantScale(0.f); } // Feed the input into the shifter - unit->m_sendBuffer->writeBlock(in, inNumSamples); + m_sendBuffer->writeBlock(inBuf, inNumSamples); - if (unit->m_sendBuffer->isReadReady(unit->m_shifterBlockSize)) { - unit->m_sendBuffer->readBlock(unit->m_shiftBufferIn, unit->m_shifterBlockSize); - unit->m_shifter->shift(&(unit->m_shiftBufferIn), &(unit->m_shiftBufferOut)); - unit->m_receiveBuffer->writeBlock(unit->m_shiftBufferOut, unit->m_shifterBlockSize); + if (m_sendBuffer->isReadReady(m_shifterBlockSize)) { + m_sendBuffer->readBlock(m_shiftBufferIn, m_shifterBlockSize); + m_shifter->shift(&m_shiftBufferIn, &m_shiftBufferOut); + m_receiveBuffer->writeBlock(m_shiftBufferOut, m_shifterBlockSize); } // If there is a block of output samples ready, read it. (There should always be a block ready.) - if (unit->m_receiveBuffer->isReadReady(inNumSamples)) { - unit->m_receiveBuffer->readBlock(out, inNumSamples); + if (m_receiveBuffer->isReadReady(inNumSamples)) { + m_receiveBuffer->readBlock(outBuf, inNumSamples); } else { // Zero out the output buffer for (size_t i = 0; i < inNumSamples; i++) { - out[i] = 0.f; + outBuf[i] = 0.f; } } } \ No newline at end of file diff --git a/src/rubberband/rubberBandPS.hpp b/src/rubberband/rubberBandPS.hpp index 82024ac..b4af1ae 100644 --- a/src/rubberband/rubberBandPS.hpp +++ b/src/rubberband/rubberBandPS.hpp @@ -23,20 +23,24 @@ along with this program. If not, see . */ #pragma once -#include "SC_Unit.h" +#include "SC_PlugIn.hpp" #include "rubberband/RubberBandLiveShifter.h" #include "ringbuffer.hpp" -struct RubberBandPS : public Unit { - RubberBand::RubberBandLiveShifter* m_shifter; - RingBuffer* m_sendBuffer; - RingBuffer* m_receiveBuffer; - float *m_shiftBufferIn; - float *m_shiftBufferOut; - size_t m_blockSize; - size_t m_shifterBlockSize; -}; - -void RubberBandPS_Ctor(RubberBandPS *unit); -void RubberBandPS_Dtor(RubberBandPS *unit); -void RubberBandPS_next(RubberBandPS *unit, int inNumSamples); \ No newline at end of file +namespace FlexPlugins { + class RubberBandPS : public SCUnit { + public: + RubberBandPS(); + ~RubberBandPS(); + + private: + void next(int inNumSamples); + RubberBand::RubberBandLiveShifter* m_shifter; + RingBuffer* m_sendBuffer; + RingBuffer* m_receiveBuffer; + float *m_shiftBufferIn; + float *m_shiftBufferOut; + size_t m_blockSize; + size_t m_shifterBlockSize; + }; +} diff --git a/src/rubberband/rubberBandStretcher.cpp b/src/rubberband/rubberBandStretcher.cpp index c9295dd..87019f2 100644 --- a/src/rubberband/rubberBandStretcher.cpp +++ b/src/rubberband/rubberBandStretcher.cpp @@ -24,29 +24,28 @@ along with this program. If not, see . #include "rubberBandStretcher.hpp" #include -#include "SC_PlugIn.h" extern InterfaceTable *ft; -void RubberBandStretcher_Ctor(RubberBandStretcher *unit) { - float timeRatio = IN0(1); - float pitchRatio = IN0(2); - float formantRatio = IN0(3); - int transientsMode = static_cast(IN0(4)); - int detector = static_cast(IN0(5)); - int phaseOption = static_cast(IN0(6)); - int pitchQuality = static_cast(IN0(7)); - int windowOption = static_cast(IN0(8)); - int smoothing = static_cast(IN0(9)); - int engine = static_cast(IN0(10)); +FlexPlugins::RubberBandStretcher::RubberBandStretcher() { + float timeRatio = in0(1); + float pitchRatio = in0(2); + float formantRatio = in0(3); + int transientsMode = static_cast(in0(4)); + int detector = static_cast(in0(5)); + int phaseOption = static_cast(in0(6)); + int pitchQuality = static_cast(in0(7)); + int windowOption = static_cast(in0(8)); + int smoothing = static_cast(in0(9)); + int engine = static_cast(in0(10)); - unit->m_timeRatio = timeRatio; - unit->m_pitchRatio = pitchRatio; - unit->m_formantRatio = formantRatio; - unit->m_transientsMode = transientsMode; - unit->m_detectorOption = detector; - unit->m_phaseOption = phaseOption; - unit->m_pitchQuality = pitchQuality; + m_timeRatio = timeRatio; + m_pitchRatio = pitchRatio; + m_formantRatio = formantRatio; + m_transientsMode = transientsMode; + m_detectorOption = detector; + m_phaseOption = phaseOption; + m_pitchQuality = pitchQuality; // Set up RubberBandStretcher initial options int options = 0x01000001; // formant-preserving, real-time options set @@ -98,130 +97,128 @@ void RubberBandStretcher_Ctor(RubberBandStretcher *unit) { } // Allocate the shifter with the given options - unit->m_stretcher = (RubberBand::RubberBandStretcher*)RTAlloc(unit->mWorld, sizeof(RubberBand::RubberBandStretcher)); - new (unit->m_stretcher) RubberBand::RubberBandStretcher(static_cast(SAMPLERATE), 1, options, timeRatio, pitchRatio); + m_stretcher = (RubberBand::RubberBandStretcher*)RTAlloc(mWorld, sizeof(RubberBand::RubberBandStretcher)); + new (m_stretcher) RubberBand::RubberBandStretcher(static_cast(sampleRate()), 1, options, timeRatio, pitchRatio); // Initialize the shifter // The shifter accepts a block size (which must be set before the first process() // call and not after), which avoids the need to use local RingBuffers. - unit->m_stretcher->setMaxProcessSize(BUFLENGTH); - unit->m_stretcher->setTimeRatio(sc_clip(timeRatio, 1.f, std::numeric_limits::infinity())); - unit->m_stretcher->setPitchScale(sc_clip(pitchRatio, 1e-2, 64)); - unit->m_stretcher->setFormantScale(sc_clip(formantRatio, 1e-2, 64)); + m_stretcher->setMaxProcessSize(fullBufferSize()); + m_stretcher->setTimeRatio(sc_clip(timeRatio, 1.f, std::numeric_limits::infinity())); + m_stretcher->setPitchScale(sc_clip(pitchRatio, 1e-2, 64)); + m_stretcher->setFormantScale(sc_clip(formantRatio, 1e-2, 64)); // Feed samples in until the shifter is ready to start producing valid output. // This is necessary because the shifter isn't ready to produce valid output // as soon as it is initialized--it requires padded 0s to be fed in for some // number of samples specified by the shifter. - float *zeroBuf = (float*)RTAlloc(unit->mWorld, BUFLENGTH * sizeof(float)); - for (size_t i = 0; i < BUFLENGTH; i++) { + float *zeroBuf = (float*)RTAlloc(mWorld, fullBufferSize() * sizeof(float)); + for (size_t i = 0; i < fullBufferSize(); i++) { zeroBuf[i] = 0.f; } // The number of initial zeros required - size_t startPad = unit->m_stretcher->getPreferredStartPad(); + size_t startPad = m_stretcher->getPreferredStartPad(); // The number of samples to discard at the beginning of the stretcher output. // This is handled in the RubberBandStretcher_next() method. - unit->m_samplesToDiscard = unit->m_stretcher->getStartDelay(); + m_samplesToDiscard = m_stretcher->getStartDelay(); // Feed in the start pad samples while (startPad > 0) { - unit->m_stretcher->process(&zeroBuf, BUFLENGTH, false); - startPad -= BUFLENGTH; + m_stretcher->process(&zeroBuf, fullBufferSize(), false); + startPad -= fullBufferSize(); } - RTFree(unit->mWorld, zeroBuf); + RTFree(mWorld, zeroBuf); - // Initialize first out sample - OUT0(0) = 0; - - SETCALC(RubberBandStretcher_next); + set_calc_function(); + next(1); } -void RubberBandStretcher_Dtor(RubberBandStretcher *unit) { - RTFree(unit->mWorld, unit->m_stretcher); +FlexPlugins::RubberBandStretcher::~RubberBandStretcher() { + if (m_stretcher) RTFree(mWorld, m_stretcher); } -void RubberBandStretcher_next(RubberBandStretcher *unit, int inNumSamples) { - float *in = IN(0); - float *out = OUT(0); - float timeRatio = IN0(1); - float pitchRatio = IN0(2); - float formantRatio = IN0(3); - int transientsMode = static_cast(IN0(4)); - int detector = static_cast(IN0(5)); - int phaseOption = static_cast(IN0(6)); - int pitchQuality = static_cast(IN0(7)); +void FlexPlugins::RubberBandStretcher::next(int inNumSamples) { + const float *inBuf = in(0); + float *outBuf = out(0); + float timeRatio = in0(1); + float pitchRatio = in0(2); + float formantRatio = in0(3); + int transientsMode = static_cast(in0(4)); + int detector = static_cast(in0(5)); + int phaseOption = static_cast(in0(6)); + int pitchQuality = static_cast(in0(7)); // Update shifter options only if something has changed - if (timeRatio != unit->m_timeRatio) { - unit->m_stretcher->setTimeRatio(sc_clip(timeRatio, 1.f, std::numeric_limits::infinity())); + if (timeRatio != m_timeRatio) { + m_stretcher->setTimeRatio(sc_clip(timeRatio, 1.f, std::numeric_limits::infinity())); } - if (pitchRatio != unit->m_pitchRatio) { - unit->m_stretcher->setPitchScale(sc_clip(pitchRatio, 1e-2, 64)); + if (pitchRatio != m_pitchRatio) { + m_stretcher->setPitchScale(sc_clip(pitchRatio, 1e-2, 64)); } - if (formantRatio != unit->m_formantRatio) { - unit->m_stretcher->setFormantScale(sc_clip(formantRatio, 1e-2, 64)); + if (formantRatio != m_formantRatio) { + m_stretcher->setFormantScale(sc_clip(formantRatio, 1e-2, 64)); } // QUESTION: Will this method of setting options override all existing options, // or just the option provided? May need to compute all options from scratch. - if (transientsMode != unit->m_transientsMode) { + if (transientsMode != m_transientsMode) { switch (transientsMode) { case 1: - unit->m_stretcher->setTransientsOption(0x00000100); + m_stretcher->setTransientsOption(0x00000100); break; case 2: - unit->m_stretcher->setTransientsOption(0x00000200); + m_stretcher->setTransientsOption(0x00000200); break; default: - unit->m_stretcher->setTransientsOption(0x00000000); + m_stretcher->setTransientsOption(0x00000000); } } - if (detector != unit->m_detectorOption) { + if (detector != m_detectorOption) { switch (detector) { case 1: - unit->m_stretcher->setDetectorOption(0x00000400); + m_stretcher->setDetectorOption(0x00000400); break; case 2: - unit->m_stretcher->setDetectorOption(0x00000800); + m_stretcher->setDetectorOption(0x00000800); break; default: - unit->m_stretcher->setDetectorOption(0x00000000); + m_stretcher->setDetectorOption(0x00000000); } } - if (phaseOption != unit->m_phaseOption) { + if (phaseOption != m_phaseOption) { switch (phaseOption) { case 1: - unit->m_stretcher->setPhaseOption(0x00002000); + m_stretcher->setPhaseOption(0x00002000); break; default: - unit->m_stretcher->setPhaseOption(0x00000000); + m_stretcher->setPhaseOption(0x00000000); } } - if (pitchQuality != unit->m_pitchQuality) { + if (pitchQuality != m_pitchQuality) { switch (pitchQuality) { case 1: - unit->m_stretcher->setPitchOption(0x02000000); + m_stretcher->setPitchOption(0x02000000); break; case 2: - unit->m_stretcher->setPitchOption(0x04000000); + m_stretcher->setPitchOption(0x04000000); break; default: - unit->m_stretcher->setPitchOption(0x00000000); + m_stretcher->setPitchOption(0x00000000); } } - unit->m_stretcher->process(&in, BUFLENGTH, false); + m_stretcher->process(&inBuf, inNumSamples, false); // If we can retrieve a full block worth of audio - if (unit->m_stretcher->available() >= BUFLENGTH) { - unit->m_stretcher->retrieve(&out, BUFLENGTH); + if (m_stretcher->available() >= inNumSamples) { + m_stretcher->retrieve(&outBuf, inNumSamples); // Clear initial samples if necessary - if (unit->m_samplesToDiscard > 0) { + if (m_samplesToDiscard > 0) { size_t i = 0; - while (i < BUFLENGTH && unit->m_samplesToDiscard > 0) { - out[i] = 0.f; - unit->m_samplesToDiscard--; + while (i < inNumSamples && m_samplesToDiscard > 0) { + outBuf[i] = 0.f; + m_samplesToDiscard--; i++; } } @@ -229,8 +226,6 @@ void RubberBandStretcher_next(RubberBandStretcher *unit, int inNumSamples) { // Output zeros if the shifter has no new samples available else { - for (size_t i = 0; i < BUFLENGTH; i++) { - out[i] = 0.f; - } + ClearUnitOutputs(this, inNumSamples); } } diff --git a/src/rubberband/rubberBandStretcher.hpp b/src/rubberband/rubberBandStretcher.hpp index 31b3302..690ad55 100644 --- a/src/rubberband/rubberBandStretcher.hpp +++ b/src/rubberband/rubberBandStretcher.hpp @@ -23,26 +23,31 @@ along with this program. If not, see . */ #pragma once -#include "SC_Unit.h" +#include "SC_PlugIn.hpp" #include "rubberband/RubberBandStretcher.h" -struct RubberBandStretcher : public Unit { - /// The stretcher - RubberBand::RubberBandStretcher* m_stretcher; - - /// The number of initial output samples to discard - size_t m_samplesToDiscard; - - // A collection of settings for the RubberBand stretcher - float m_timeRatio; - float m_pitchRatio; - float m_formantRatio; - int m_transientsMode; - int m_detectorOption; - int m_phaseOption; - int m_pitchQuality; -}; - -void RubberBandStretcher_Ctor(RubberBandStretcher *unit); -void RubberBandStretcher_Dtor(RubberBandStretcher *unit); -void RubberBandStretcher_next(RubberBandStretcher *unit, int inNumSamples); \ No newline at end of file +namespace FlexPlugins { + class RubberBandStretcher : public SCUnit { + public: + RubberBandStretcher(); + ~RubberBandStretcher(); + + private: + void next(int inNumSamples); + + /// The stretcher + RubberBand::RubberBandStretcher* m_stretcher; + + /// The number of initial output samples to discard + size_t m_samplesToDiscard; + + // A collection of settings for the RubberBand stretcher + float m_timeRatio; + float m_pitchRatio; + float m_formantRatio; + int m_transientsMode; + int m_detectorOption; + int m_phaseOption; + int m_pitchQuality; + }; +} diff --git a/src/rubberband/rubberBandStretcherBuf.cpp b/src/rubberband/rubberBandStretcherBuf.cpp index 8445966..cabe67c 100644 --- a/src/rubberband/rubberBandStretcherBuf.cpp +++ b/src/rubberband/rubberBandStretcherBuf.cpp @@ -24,38 +24,37 @@ along with this program. If not, see . #include "rubberBandStretcherBuf.hpp" #include -#include "SC_PlugIn.h" extern InterfaceTable *ft; -void RubberBandStretcherBuf_Ctor(RubberBandStretcherBuf *unit) { - float timeRatio = IN0(8); - float pitchRatio = IN0(9); - float formantRatio = IN0(10); - int transientsMode = static_cast(IN0(11)); - int detector = static_cast(IN0(12)); - int phaseOption = static_cast(IN0(13)); - int pitchQuality = static_cast(IN0(14)); - int windowOption = static_cast(IN0(15)); - int smoothing = static_cast(IN0(16)); - int engine = static_cast(IN0(17)); +FlexPlugins::RubberBandStretcherBuf::RubberBandStretcherBuf() { + float timeRatio = in0(8); + float pitchRatio = in0(9); + float formantRatio = in0(10); + int transientsMode = static_cast(in0(11)); + int detector = static_cast(in0(12)); + int phaseOption = static_cast(in0(13)); + int pitchQuality = static_cast(in0(14)); + int windowOption = static_cast(in0(15)); + int smoothing = static_cast(in0(16)); + int engine = static_cast(in0(17)); - unit->m_timeRatio = timeRatio; - unit->m_pitchRatio = pitchRatio; - unit->m_formantRatio = formantRatio; - unit->m_transientsMode = transientsMode; - unit->m_detectorOption = detector; - unit->m_phaseOption = phaseOption; - unit->m_pitchQuality = pitchQuality; + m_timeRatio = timeRatio; + m_pitchRatio = pitchRatio; + m_formantRatio = formantRatio; + m_transientsMode = transientsMode; + m_detectorOption = detector; + m_phaseOption = phaseOption; + m_pitchQuality = pitchQuality; // Acquire the sound buffer - float fbufnum = IN0(1); + float fbufnum = in0(1); uint32 bufnum = static_cast(fbufnum); - if (bufnum >= unit->mWorld->mNumSndBufs) bufnum = 0; - unit->m_fbufnum = fbufnum; - unit->m_buf = unit->mWorld->mSndBufs + bufnum; - unit->m_writePtr = static_cast(IN0(2)); // initial offset - unit->m_prevTrigger = 0.f; + if (bufnum >= mWorld->mNumSndBufs) bufnum = 0; + m_fbufnum = fbufnum; + m_buf = mWorld->mSndBufs + bufnum; + m_writePtr = static_cast(in0(2)); // initial offset + m_prevTrigger = 0.f; // Set up RubberBandStretcher initial options int options = 0x01000001; // formant-preserving, real-time options set @@ -107,56 +106,55 @@ void RubberBandStretcherBuf_Ctor(RubberBandStretcherBuf *unit) { } // Allocate the shifter with the given options - unit->m_stretcher = (RubberBand::RubberBandStretcher*)RTAlloc(unit->mWorld, sizeof(RubberBand::RubberBandStretcher)); - new (unit->m_stretcher) RubberBand::RubberBandStretcher(static_cast(SAMPLERATE), 1, options, timeRatio, pitchRatio); + m_stretcher = (RubberBand::RubberBandStretcher*)RTAlloc(mWorld, sizeof(RubberBand::RubberBandStretcher)); + new (m_stretcher) RubberBand::RubberBandStretcher(static_cast(sampleRate()), 1, options, timeRatio, pitchRatio); // Initialize the shifter // The shifter accepts a block size (which must be set before the first process() // call and not after), which avoids the need to use local RingBuffers. - unit->m_stretcher->setMaxProcessSize(BUFLENGTH); - unit->m_stretcher->setTimeRatio(sc_clip(timeRatio, 1e-5, 1e5)); - unit->m_stretcher->setPitchScale(sc_clip(pitchRatio, 1e-2, 64)); - unit->m_stretcher->setFormantScale(sc_clip(formantRatio, 1e-2, 64)); + m_stretcher->setMaxProcessSize(fullBufferSize()); + m_stretcher->setTimeRatio(sc_clip(timeRatio, 1e-5, 1e5)); + m_stretcher->setPitchScale(sc_clip(pitchRatio, 1e-2, 64)); + m_stretcher->setFormantScale(sc_clip(formantRatio, 1e-2, 64)); // Feed samples in until the shifter is ready to start producing valid output. // This is necessary because the shifter isn't ready to produce valid output // as soon as it is initialized--it requires padded 0s to be fed in for some // number of samples specified by the shifter. - unit->m_localBuf = (float*)RTAlloc(unit->mWorld, BUFLENGTH * sizeof(float)); - for (size_t i = 0; i < BUFLENGTH; i++) { - unit->m_localBuf[i] = 0.f; + m_localBuf = (float*)RTAlloc(mWorld, fullBufferSize() * sizeof(float)); + for (size_t i = 0; i < fullBufferSize(); i++) { + m_localBuf[i] = 0.f; } // The number of initial zeros required - size_t startPad = unit->m_stretcher->getPreferredStartPad(); + size_t startPad = m_stretcher->getPreferredStartPad(); // The number of samples to discard at the beginning of the stretcher output. // This is handled in the RubberBandStretcher_next() method. - unit->m_samplesToDiscard = unit->m_stretcher->getStartDelay(); + m_samplesToDiscard = m_stretcher->getStartDelay(); // Feed in the start pad samples while (startPad > 0) { - unit->m_stretcher->process(&unit->m_localBuf, BUFLENGTH, false); - startPad -= BUFLENGTH; + m_stretcher->process(&m_localBuf, fullBufferSize(), false); + startPad -= fullBufferSize(); } // Initialize first out sample - OUT0(0) = 0; - - SETCALC(RubberBandStretcherBuf_next); + set_calc_function(); + next(1); } -void RubberBandStretcherBuf_Dtor(RubberBandStretcherBuf *unit) { - if (unit->m_stretcher) RTFree(unit->mWorld, unit->m_stretcher); - if (unit->m_localBuf) RTFree(unit->mWorld, unit->m_localBuf); +FlexPlugins::RubberBandStretcherBuf::~RubberBandStretcherBuf() { + if (m_stretcher) RTFree(mWorld, m_stretcher); + if (m_localBuf) RTFree(mWorld, m_localBuf); } -void RubberBandStretcherBuf_next(RubberBandStretcherBuf *unit, int inNumSamples) { +void FlexPlugins::RubberBandStretcherBuf::next(int inNumSamples) { // Step 1: acquire the sound buffer - const SndBuf *writeBuf = unit->m_buf; + const SndBuf *writeBuf = m_buf; if (!writeBuf) { std::cout << "WARNING: The stftBuffer could not be accessed. Aborting.\n"; - ClearUnitOutputs(unit, inNumSamples); + ClearUnitOutputs(this, inNumSamples); return; } ACQUIRE_SNDBUF_SHARED(writeBuf); @@ -168,116 +166,122 @@ void RubberBandStretcherBuf_next(RubberBandStretcherBuf *unit, int inNumSamples) if (bufChannels != 1) { std::cout << "WARNING: The buffer has " << bufChannels << " channels, but the " << "RubberBandStretcherBuf only supports mono buffers. Aborting.\n"; - ClearUnitOutputs(unit, inNumSamples); + ClearUnitOutputs(this, inNumSamples); RELEASE_SNDBUF_SHARED(writeBuf); return; } // 2. Update unit parameters if required - float timeRatio = IN0(8); - float pitchRatio = IN0(9); - float formantRatio = IN0(10); - int transientsMode = static_cast(IN0(11)); - int detector = static_cast(IN0(12)); - int phaseOption = static_cast(IN0(13)); - int pitchQuality = static_cast(IN0(14)); + float timeRatio = in0(8); + float pitchRatio = in0(9); + float formantRatio = in0(10); + int transientsMode = static_cast(in0(11)); + int detector = static_cast(in0(12)); + int phaseOption = static_cast(in0(13)); + int pitchQuality = static_cast(in0(14)); // Update shifter options only if something has changed - if (timeRatio != unit->m_timeRatio) { - unit->m_stretcher->setTimeRatio(sc_clip(timeRatio, 1e-5, 1e5)); + if (timeRatio != m_timeRatio) { + m_stretcher->setTimeRatio(sc_clip(timeRatio, 1e-5, 1e5)); } - if (pitchRatio != unit->m_pitchRatio) { - unit->m_stretcher->setPitchScale(sc_clip(pitchRatio, 1e-2, 64)); + if (pitchRatio != m_pitchRatio) { + m_stretcher->setPitchScale(sc_clip(pitchRatio, 1e-2, 64)); } - if (formantRatio != unit->m_formantRatio) { - unit->m_stretcher->setFormantScale(sc_clip(formantRatio, 1e-2, 64)); + if (formantRatio != m_formantRatio) { + m_stretcher->setFormantScale(sc_clip(formantRatio, 1e-2, 64)); } // QUESTION: Will this method of setting options override all existing options, // or just the option provided? May need to compute all options from scratch. - if (transientsMode != unit->m_transientsMode) { + if (transientsMode != m_transientsMode) { switch (transientsMode) { case 1: - unit->m_stretcher->setTransientsOption(0x00000100); + m_stretcher->setTransientsOption(0x00000100); break; case 2: - unit->m_stretcher->setTransientsOption(0x00000200); + m_stretcher->setTransientsOption(0x00000200); break; default: - unit->m_stretcher->setTransientsOption(0x00000000); + m_stretcher->setTransientsOption(0x00000000); } } - if (detector != unit->m_detectorOption) { + if (detector != m_detectorOption) { switch (detector) { case 1: - unit->m_stretcher->setDetectorOption(0x00000400); + m_stretcher->setDetectorOption(0x00000400); break; case 2: - unit->m_stretcher->setDetectorOption(0x00000800); + m_stretcher->setDetectorOption(0x00000800); break; default: - unit->m_stretcher->setDetectorOption(0x00000000); + m_stretcher->setDetectorOption(0x00000000); } } - if (phaseOption != unit->m_phaseOption) { + if (phaseOption != m_phaseOption) { switch (phaseOption) { case 1: - unit->m_stretcher->setPhaseOption(0x00002000); + m_stretcher->setPhaseOption(0x00002000); break; default: - unit->m_stretcher->setPhaseOption(0x00000000); + m_stretcher->setPhaseOption(0x00000000); } } - if (pitchQuality != unit->m_pitchQuality) { + if (pitchQuality != m_pitchQuality) { switch (pitchQuality) { case 1: - unit->m_stretcher->setPitchOption(0x02000000); + m_stretcher->setPitchOption(0x02000000); break; case 2: - unit->m_stretcher->setPitchOption(0x04000000); + m_stretcher->setPitchOption(0x04000000); break; default: - unit->m_stretcher->setPitchOption(0x00000000); + m_stretcher->setPitchOption(0x00000000); } } // 3. Handle the trigger functionality - float trigger = IN0(7); - if (trigger > 0.f && unit->m_prevTrigger <= 0.f) { - unit->m_writePtr = 0; + float trigger = in0(7); + if (trigger > 0.f && m_prevTrigger <= 0.f) { + m_writePtr = 0; } - unit->m_prevTrigger = trigger; + m_prevTrigger = trigger; // 4. Process input audio. - float *in = IN(0); - float recLevel = IN0(3); - float preLevel = IN0(4); - float loop = IN0(6); + const float *inBuf = in(0); + float recLevel = in0(3); + float preLevel = in0(4); + float loop = in0(6); - unit->m_stretcher->process(&in, BUFLENGTH, false); + m_stretcher->process(&inBuf, inNumSamples, false); - while (unit->m_stretcher->available() > 0) { - size_t numRetrieve = static_cast(std::min(BUFLENGTH, unit->m_stretcher->available())); - unit->m_stretcher->retrieve(&unit->m_localBuf, numRetrieve); + while (m_stretcher->available() > 0) { + size_t numRetrieve = static_cast(std::min(inNumSamples, m_stretcher->available())); + m_stretcher->retrieve(&m_localBuf, numRetrieve); // 5. While we run the audio through the stretcher regardless, we only store it to the buffer if "run" is set. - if (IN0(5) > 0.f) { - for (size_t xxi = 0; xxi < numRetrieve; xxi++) { - if (unit->m_writePtr >= bufSamples) { + if (in0(5) > 0.f) { + for (size_t i = 0; i < numRetrieve; i++) { + if (m_writePtr >= bufSamples) { if (loop > 0.f) { - unit->m_writePtr = 0; + m_writePtr = 0; } else { RELEASE_SNDBUF_SHARED(writeBuf); - ClearUnitOutputs(unit, inNumSamples); - DoneAction(static_cast(IN0(18)), unit); + ClearUnitOutputs(this, inNumSamples); + DoneAction(static_cast(in0(18)), this); return; } } - bufData[unit->m_writePtr] = preLevel * bufData[unit->m_writePtr] + recLevel * unit->m_localBuf[xxi]; - unit->m_writePtr++; + // We need to ignore the initial samples output by the stretcher + if (m_samplesToDiscard > 0) { + m_samplesToDiscard--; + } else { + bufData[m_writePtr] = preLevel * bufData[m_writePtr] + recLevel * m_localBuf[i]; + } + + m_writePtr++; } } } - ClearUnitOutputs(unit, inNumSamples); + ClearUnitOutputs(this, inNumSamples); RELEASE_SNDBUF_SHARED(writeBuf); } \ No newline at end of file diff --git a/src/rubberband/rubberBandStretcherBuf.hpp b/src/rubberband/rubberBandStretcherBuf.hpp index 6148b34..909bbd6 100644 --- a/src/rubberband/rubberBandStretcherBuf.hpp +++ b/src/rubberband/rubberBandStretcherBuf.hpp @@ -24,41 +24,45 @@ along with this program. If not, see . #pragma once -#include "SC_Unit.h" +#include "SC_PlugIn.hpp" #include "rubberband/RubberBandStretcher.h" -struct RubberBandStretcherBuf : public Unit { - /// The stretcher - RubberBand::RubberBandStretcher* m_stretcher; - - /// A buffer - float *m_localBuf; - - /// The number of initial output samples to discard - size_t m_samplesToDiscard; - - // A collection of settings for the RubberBand stretcher - float m_timeRatio; - float m_pitchRatio; - float m_formantRatio; - int m_transientsMode; - int m_detectorOption; - int m_phaseOption; - int m_pitchQuality; - - /// The index of the buffer with STFT data - float m_fbufnum; - - /// The audio buffer to write the stretched audio to - SndBuf *m_buf; - - /// The next sample to write to - size_t m_writePtr; - - /// The previous trigger - float m_prevTrigger; -}; - -void RubberBandStretcherBuf_Ctor(RubberBandStretcherBuf *unit); -void RubberBandStretcherBuf_Dtor(RubberBandStretcherBuf *unit); -void RubberBandStretcherBuf_next(RubberBandStretcherBuf *unit, int inNumSamples); \ No newline at end of file +namespace FlexPlugins { + class RubberBandStretcherBuf : public SCUnit { + public: + RubberBandStretcherBuf(); + ~RubberBandStretcherBuf(); + + private: + void next(int inNumSamples); + /// The stretcher + RubberBand::RubberBandStretcher* m_stretcher; + + /// A buffer + float *m_localBuf; + + /// The number of initial output samples to discard + size_t m_samplesToDiscard; + + // A collection of settings for the RubberBand stretcher + float m_timeRatio; + float m_pitchRatio; + float m_formantRatio; + int m_transientsMode; + int m_detectorOption; + int m_phaseOption; + int m_pitchQuality; + + /// The index of the buffer with STFT data + float m_fbufnum; + + /// The audio buffer to write the stretched audio to + SndBuf *m_buf; + + /// The next sample to write to + size_t m_writePtr; + + /// The previous trigger + float m_prevTrigger; + }; +} diff --git a/src/rubberband/rubberband.cpp b/src/rubberband/rubberband.cpp index 51fc551..5ec7b6c 100644 --- a/src/rubberband/rubberband.cpp +++ b/src/rubberband/rubberband.cpp @@ -22,7 +22,6 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -#include "SC_PlugIn.h" #include "rubberBandPS.hpp" #include "rubberBandStretcher.hpp" #include "rubberBandStretcherBuf.hpp" @@ -31,7 +30,7 @@ InterfaceTable *ft; PluginLoad(RubberBandPlugins) { ft = inTable; - DefineDtorUnit(RubberBandPS); - DefineDtorUnit(RubberBandStretcher); - DefineDtorUnit(RubberBandStretcherBuf); + registerUnit(ft, "RubberBandPS", false); + registerUnit(ft, "RubberBandStretcher", false); + registerUnit(ft, "RubberBandStretcherBuf", false); }