From e7b24dd7da9de84e218f7d7be623f0cf8b9d1b9c Mon Sep 17 00:00:00 2001 From: "N.N." Date: Mon, 17 Feb 2003 14:12:16 +0000 Subject: This commit was generated by cvs2svn to compensate for changes in r415, which included commits to RCS files with non-trunk default branches. svn path=/trunk/externals/dfx/; revision=416 --- dfx-library/FIRfilter.cpp | 97 +++++++++++++++++++++ dfx-library/FIRfilter.h | 37 ++++++++ dfx-library/IIRfilter.cpp | 61 +++++++++++++ dfx-library/IIRfilter.h | 156 +++++++++++++++++++++++++++++++++ dfx-library/MultiKick.cpp | 114 ++++++++++++++++++++++++ dfx-library/MultiKick.hpp | 42 +++++++++ dfx-library/TempoRateTable.cpp | 72 +++++++++++++++ dfx-library/TempoRateTable.h | 47 ++++++++++ dfx-library/dfxmisc.cpp | 77 ++++++++++++++++ dfx-library/dfxmisc.h | 194 +++++++++++++++++++++++++++++++++++++++++ dfx-library/lfo.cpp | 178 +++++++++++++++++++++++++++++++++++++ dfx-library/lfo.h | 150 +++++++++++++++++++++++++++++++ 12 files changed, 1225 insertions(+) create mode 100755 dfx-library/FIRfilter.cpp create mode 100755 dfx-library/FIRfilter.h create mode 100755 dfx-library/IIRfilter.cpp create mode 100755 dfx-library/IIRfilter.h create mode 100644 dfx-library/MultiKick.cpp create mode 100644 dfx-library/MultiKick.hpp create mode 100755 dfx-library/TempoRateTable.cpp create mode 100755 dfx-library/TempoRateTable.h create mode 100755 dfx-library/dfxmisc.cpp create mode 100755 dfx-library/dfxmisc.h create mode 100755 dfx-library/lfo.cpp create mode 100755 dfx-library/lfo.h (limited to 'dfx-library') diff --git a/dfx-library/FIRfilter.cpp b/dfx-library/FIRfilter.cpp new file mode 100755 index 0000000..d020dc8 --- /dev/null +++ b/dfx-library/FIRfilter.cpp @@ -0,0 +1,97 @@ +#ifndef __FIRfilter +#include "FIRfilter.h" +#endif + +//----------------------------------------------------------------------------- +// you're supposed to use use an odd number of taps +void calculateFIRidealLowpassCoefficients(float cutoff, float samplerate, + int numTaps, float *coefficients) +{ + int middleCoeff; + float corner, value; + + // get the cutoff as a ratio of cutoff to Nyquist, scaled from 0 to Pi + corner = (cutoff / (samplerate*0.5f)) * PI; + + if (numTaps%2) + { + middleCoeff = (numTaps-1) / 2; + coefficients[middleCoeff] = corner/PI; + } + else + middleCoeff = numTaps/2; + + for (int n=0; n < middleCoeff; n++) + { + value = (float)n - ((float)(numTaps-1) * 0.5f); + coefficients[n] = sinf(value*corner) / (value*PI); + coefficients[numTaps-1-n] = coefficients[n]; + } +} + +//----------------------------------------------------------------------------- +void applyKaiserWindow(int numTaps, float *coefficients, float attenuation) +{ + int halfLength; + + + // beta is 0 if the attenuation is less than 21 dB + float beta = 0.0f; + if (attenuation >= 50.0f) + beta = 0.1102f * (attenuation - 8.71f); + else if ( (attenuation < 50.0f) && (attenuation >= 21.0f) ) + { + beta = 0.5842f * powf( (attenuation - 21.0f), 0.4f); + beta += 0.07886f * (attenuation - 21.0f); + } + + if (numTaps%2) + halfLength = (numTaps+1) / 2; + else + halfLength = numTaps / 2; + + for (int n=0; n < halfLength; n++) + { + coefficients[n] *= besselIzero(beta * + sqrtf(1.0f - powf( (1.0f-((2.0f*n)/((float)(numTaps-1)))), 2.0f ))) + / besselIzero(beta); + coefficients[numTaps-1-n] = coefficients[n]; + } +} + +//----------------------------------------------------------------------------- +float besselIzero(float in) +{ + float sum, numerator, denominator, term, halfIn; + + sum = 1.0f; + halfIn = in * 0.5f; + denominator = 1.0f; + numerator = 1.0f; + for (int m=1; m <= 32; m++) + { + numerator *= halfIn; + denominator *= (float)m; + term = numerator / denominator; + sum += term * term; + } + return sum; +} + +//----------------------------------------------------------------------------- +float besselIzero2(float in) +{ + float sum = 1.0f; + float ds = 1.0f; + float d = 0.0f; + + do + { + d += 2.0f; + ds *= ( in * in ) / ( d * d ); + sum += ds; + } + while ( ds > (1E-7f * sum) ); + + return sum; +} diff --git a/dfx-library/FIRfilter.h b/dfx-library/FIRfilter.h new file mode 100755 index 0000000..d0f763b --- /dev/null +++ b/dfx-library/FIRfilter.h @@ -0,0 +1,37 @@ +#ifndef __FIRfilter +#define __FIRfilter + +#include + + +#define PI 3.1415926535897932384626433832795f +#define SHELF_START_FIR 0.333f + + +//----------------------------------------------------------------------------- +void calculateFIRidealLowpassCoefficients(float cutoff, float samplerate, + int numTaps, float *coefficients); +void applyKaiserWindow(int numTaps, float *coefficients, float attenuation); +float besselIzero(float in); +float besselIzero2(float in); + +//----------------------------------------------------------------------------- +inline float processFIRfilter(float *in, int numTaps, float *coefficients, + long inPos, long arraySize) +{ + float out = 0.0f; + if ( (inPos+numTaps) > arraySize ) + { + for (long i=0; i < numTaps; i++) + out += in[(inPos+i)%arraySize] * coefficients[i]; + } + else + { + for (long i=0; i < numTaps; i++) + out += in[inPos+i] * coefficients[i]; + } + return out; +} + + +#endif \ No newline at end of file diff --git a/dfx-library/IIRfilter.cpp b/dfx-library/IIRfilter.cpp new file mode 100755 index 0000000..d78bf2f --- /dev/null +++ b/dfx-library/IIRfilter.cpp @@ -0,0 +1,61 @@ +#ifndef __IIRfilter +#include "IIRfilter.h" +#endif + +#include + + +//------------------------------------------------------------------------ +IIRfilter::IIRfilter() +{ + reset(); +} + +//------------------------------------------------------------------------ +IIRfilter::~IIRfilter() { } + +//------------------------------------------------------------------------ +void IIRfilter::calculateLowpassCoefficients(float cutoff, float samplerate) +{ + float twoPiFreqDivSR, cosTwoPiFreqDivSR, Q, slopeFactor, coeffScalar; + + Q = 0.5f; + twoPiFreqDivSR = 2.0f * PI * cutoff / samplerate; // ¹ ... 0 + cosTwoPiFreqDivSR = cosf(twoPiFreqDivSR); // 1 ... -1 + slopeFactor = sinf(twoPiFreqDivSR) / (Q * 2.0f); // 0 ... 1 ... 0 + coeffScalar = 1.0f / (1.0f + slopeFactor); // 1 ... 0.5 ... 1 + + // calculate filter coefficients + pInCoeff = (1.0f - cosTwoPiFreqDivSR) * coeffScalar; // 0 ... 2 + inCoeff = ppInCoeff = pInCoeff * 0.5f; // 0 ... 1 + pOutCoeff = (-2.0f * cosTwoPiFreqDivSR) * coeffScalar; // -2 ... 2 + ppOutCoeff = (1.0f - slopeFactor) * coeffScalar; // 1 ... 0 ... 1 +} + +//------------------------------------------------------------------------ +void IIRfilter::calculateHighpassCoefficients(float cutoff, float samplerate) +{ + float twoPiFreqDivSR, cosTwoPiFreqDivSR, Q, slopeFactor, coeffScalar; + + Q = 0.5f; + twoPiFreqDivSR = 2.0f * PI * cutoff / samplerate; // ¹ ... 0 + cosTwoPiFreqDivSR = cosf(twoPiFreqDivSR); // 1 ... -1 + slopeFactor = sinf(twoPiFreqDivSR) / (Q * 2.0f); // 0 ... 1 ... 0 + coeffScalar = 1.0f / (1.0f + slopeFactor); // 1 ... 0.5 ... 1 + + // calculate filter coefficients + pInCoeff = (-1.0f - cosTwoPiFreqDivSR) * coeffScalar; // 2 ... 0 + inCoeff = ppInCoeff = pInCoeff * (-0.5f); // -1 ... 0 + pOutCoeff = (-2.0f * cosTwoPiFreqDivSR) * coeffScalar; // -2 ... 2 + ppOutCoeff = (1.0f - slopeFactor) * coeffScalar; // 1 ... 0 ... 1 +} + +//------------------------------------------------------------------------ +void IIRfilter::copyCoefficients(IIRfilter *source) +{ + pOutCoeff = source->pOutCoeff; + ppOutCoeff = source->ppOutCoeff; + pInCoeff = source->pInCoeff; + ppInCoeff = source->ppInCoeff; + inCoeff = source->inCoeff; +} diff --git a/dfx-library/IIRfilter.h b/dfx-library/IIRfilter.h new file mode 100755 index 0000000..8729d36 --- /dev/null +++ b/dfx-library/IIRfilter.h @@ -0,0 +1,156 @@ +#ifndef __IIRfilter +#define __IIRfilter + + +#define PI 3.1415926535897932384626433832795f +#define SHELF_START_IIR 0.333f + +class IIRfilter +{ +public: + IIRfilter(); + ~IIRfilter(); + + void calculateLowpassCoefficients(float cutoff, float samplerate); + void calculateHighpassCoefficients(float cutoff, float samplerate); + void copyCoefficients(IIRfilter *source); + + void reset() + { + prevIn = prevprevIn = prevOut = prevprevOut = prevprevprevOut = currentOut = 0.0f; + } + + float prevIn, prevprevIn, prevOut, prevprevOut, prevprevprevOut, currentOut; + float pOutCoeff, ppOutCoeff, pInCoeff, ppInCoeff, inCoeff; + + +#ifdef USING_HERMITE + void process(float currentIn) +#else + float process(float currentIn) +#endif + { + #ifdef USING_HERMITE + // store 4 samples of history if we're preprocessing for Hermite interpolation + prevprevprevOut = prevprevOut; + #endif + prevprevOut = prevOut; + prevOut = currentOut; + +// currentOut = (currentIn*inCoeff) + (prevIn*pInCoeff) + (prevprevIn*ppInCoeff) +// - (prevOut*pOutCoeff) - (prevprevOut*ppOutCoeff); + currentOut = ((currentIn+prevprevIn)*inCoeff) + (prevIn*pInCoeff) + - (prevOut*pOutCoeff) - (prevprevOut*ppOutCoeff); + + prevprevIn = prevIn; + prevIn = currentIn; + + #ifndef USING_HERMITE + return currentOut; + #endif + } + +#ifdef USING_HERMITE +// start of pre-Hermite-specific functions +// there are 4 versions, 3 of which unroll for loops of 2, 3, & 4 iterations + + void processH1(float currentIn) + { + prevprevprevOut = prevprevOut; + prevprevOut = prevOut; + prevOut = currentOut; + // + currentOut = ( (currentIn+prevprevIn) * inCoeff ) + (prevIn * pInCoeff) + - (prevOut * pOutCoeff) - (prevprevOut * ppOutCoeff); + // + prevprevIn = prevIn; + prevIn = currentIn; + } + + void processH2(float *in, long inPos, long arraySize) + { + float in0 = in[inPos]; + float in1 = in[(inPos+1) % arraySize]; + + prevprevprevOut = prevprevOut; + prevprevOut = prevOut; + prevOut = currentOut; + currentOut = ( (in0+prevprevIn) * inCoeff ) + (prevIn * pInCoeff) + - (prevOut * pOutCoeff) - (prevprevOut * ppOutCoeff); + // + prevprevprevOut = prevprevOut; + prevprevOut = prevOut; + prevOut = currentOut; + currentOut = ( (in1+prevIn) * inCoeff ) + (in0 * pInCoeff) + - (prevOut * pOutCoeff) - (prevprevOut * ppOutCoeff); + // + prevprevIn = in0; + prevIn = in1; + } + + void processH3(float *in, long inPos, long arraySize) + { + float in0 = in[inPos]; + float in1 = in[(inPos+1) % arraySize]; + float in2 = in[(inPos+2) % arraySize]; + + prevprevprevOut = ( (in0+prevprevIn) * inCoeff ) + (prevIn * pInCoeff) + - (currentOut * pOutCoeff) - (prevOut * ppOutCoeff); + prevprevOut = ((in1+prevIn) * inCoeff) + (in0 * pInCoeff) + - (prevprevprevOut * pOutCoeff) - (currentOut * ppOutCoeff); + prevOut = ((in2+in0) * inCoeff) + (in1 * pInCoeff) + - (prevprevOut * pOutCoeff) - (prevprevprevOut * ppOutCoeff); + // + currentOut = prevOut; + prevOut = prevprevOut; + prevprevOut = prevprevprevOut; + prevprevprevOut = currentOut; + // + prevprevIn = in1; + prevIn = in2; + } + + void processH4(float *in, long inPos, long arraySize) + { + float in0 = in[inPos]; + float in1 = in[(inPos+1) % arraySize]; + float in2 = in[(inPos+2) % arraySize]; + float in3 = in[(inPos+3) % arraySize]; + + prevprevprevOut = ( (in0+prevprevIn) * inCoeff ) + (prevIn * pInCoeff) + - (currentOut * pOutCoeff) - (prevOut * ppOutCoeff); + prevprevOut = ((in1+prevIn) * inCoeff) + (in0 * pInCoeff) + - (prevprevprevOut * pOutCoeff) - (currentOut * ppOutCoeff); + prevOut = ((in2+in0) * inCoeff) + (in1 * pInCoeff) + - (prevprevOut * pOutCoeff) - (prevprevprevOut * ppOutCoeff); + currentOut = ((in3+in1) * inCoeff) + (in2 * pInCoeff) + - (prevOut * pOutCoeff) - (prevprevOut * ppOutCoeff); + // + prevprevIn = in2; + prevIn = in3; + } + +#endif +// end of USING_HERMITE batch of functions + +}; // end of IIRfilter class definition + + + +// 4-point Hermite spline interpolation for use with IIR filter output histories +inline float interpolateHermitePostFilter(IIRfilter *filter, double address) +{ + long pos = (long)address; + float posFract = (float) (address - (double)pos); + + float a = ( (3.0f*(filter->prevprevOut-filter->prevOut)) - + filter->prevprevprevOut + filter->currentOut ) * 0.5f; + float b = (2.0f*filter->prevOut) + filter->prevprevprevOut - + (2.5f*filter->prevprevOut) - (filter->currentOut*0.5f); + float c = (filter->prevOut - filter->prevprevprevOut) * 0.5f; + + return (( ((a*posFract)+b) * posFract + c ) * posFract) + filter->prevprevOut; +} + + +#endif \ No newline at end of file diff --git a/dfx-library/MultiKick.cpp b/dfx-library/MultiKick.cpp new file mode 100644 index 0000000..f2b3a97 --- /dev/null +++ b/dfx-library/MultiKick.cpp @@ -0,0 +1,114 @@ +/*------------ by Tom Murphy 7 ][ October 2001 ------------*/ + +#ifndef __MultiKick +#include "MultiKick.hpp" +#endif + +MultiKick::MultiKick (const CRect &size, + CControlListener *listener, + long tag, + int ns, + long heightOfOneImage, + CBitmap *background, + CPoint &offset) : + CControl (size, listener, tag, background), + numstates(ns), + offset (offset), + heightOfOneImage (heightOfOneImage), + buttondown(0), obdown(0), actualstate(0), oactualstate(0) { +setDirty(true); } + +MultiKick::~MultiKick () {} + +float MultiKick::getValue() { + if (numstates == 1) + return 0.0f; + else if (actualstate >= numstates) + return 1.0f; + else + return ((float)actualstate)/((float)(numstates-1)); +} + +void MultiKick::setValue(float f) { + actualstate = (int) (f * (numstates-1)); +} + +bool MultiKick::isDirty() { + return (actualstate == oactualstate || + buttondown == obdown); +} + +void MultiKick::setDirty(const bool val) { + if (val) oactualstate = -1; + else { + oactualstate = actualstate; + obdown = buttondown; + } +} + +void MultiKick::draw (CDrawContext *pContext) { + CPoint where (offset.h, offset.v); + + where.v += heightOfOneImage * ((actualstate<<1) + buttondown); + + if (pBackground) { + if (bTransparencyEnabled) + pBackground->drawTransparent (pContext, size, where); + else + pBackground->draw (pContext, size, where); + } + + setDirty (false); +} + +//------------------------------------------------------------------------ +void MultiKick::mouse (CDrawContext *pContext, CPoint &where) { + if (!bMouseEnabled) { buttondown = 0; return; } + + long button = pContext->getMouseButtons (); + if (!(button & kLButton)) { + buttondown = 0; + return; + } + + /* save old value in case the mouse is dragged off while the + button is still held down. */ + + int entrystate = actualstate; + + if (pContext->getMouseButtons ()) { + + // begin of edit parameter + getParent ()->beginEdit (tag); + do { + if (where.h >= size.left && where.v >= size.top && + where.h <= size.right && where.v <= size.bottom) { + actualstate = entrystate + 1; + actualstate %= numstates; + buttondown = 1 /* 1 */; + } else { + actualstate = entrystate; + buttondown = 0; + } + + if (isDirty ()) { + listener->valueChanged (pContext, this); + } + + pContext->getMouseLocation (where); + + doIdleStuff (); + draw(pContext); + } while (pContext->getMouseButtons ()); + + setDirty(true); + // end of edit parameter + getParent ()->endEdit (tag); + } else { + actualstate ++; + actualstate %= numstates; + } + draw(pContext); + buttondown = 0; + listener->valueChanged (pContext, this); +} diff --git a/dfx-library/MultiKick.hpp b/dfx-library/MultiKick.hpp new file mode 100644 index 0000000..3e3c8b2 --- /dev/null +++ b/dfx-library/MultiKick.hpp @@ -0,0 +1,42 @@ +/*------------ by Tom Murphy 7 ][ October 2001 ------------*/ + +#ifndef __MultiKick +#define __MultiKick + +#ifndef __vstgui__ +#include "vstgui.h" +#endif + + +/* idea for multikick */ + +class MultiKick : public CControl { +public: + MultiKick (const CRect &size, + CControlListener *listener, + long tag, + int numstates_, + long heightOfOneImage, // pixel + CBitmap *background, + CPoint &offset); + virtual ~MultiKick (); + + virtual void draw (CDrawContext*); + virtual void mouse (CDrawContext *pContext, CPoint &where); + + virtual void setValue(float); + virtual float getValue(); + virtual bool isDirty(); + virtual void setDirty(const bool val = true); + +protected: + int numstates; + CPoint offset; + long heightOfOneImage; + int buttondown; /* is a button down? */ + int obdown; + int actualstate; + int oactualstate; + +}; +#endif \ No newline at end of file diff --git a/dfx-library/TempoRateTable.cpp b/dfx-library/TempoRateTable.cpp new file mode 100755 index 0000000..bd39c5f --- /dev/null +++ b/dfx-library/TempoRateTable.cpp @@ -0,0 +1,72 @@ +#ifndef __TempoRateTable +#include "TempoRateTable.h" +#endif + +#include + + +//----------------------------------------------------------------------------- +TempoRateTable::TempoRateTable() +{ + int i; + + + scalars = 0; + scalars = new float[NUM_TEMPO_RATES]; + displays = 0; + displays = new char*[NUM_TEMPO_RATES]; + for (i = 0; i < NUM_TEMPO_RATES; i++) + displays[i] = new char[16]; + + i = 0; +#ifdef USE_SLOW_TEMPO_RATES + scalars[i] = 1.f/5.f; strcpy(displays[i++], "1/12"); + scalars[i] = 1.f/6.f; strcpy(displays[i++], "1/8"); + scalars[i] = 1.f/5.f; strcpy(displays[i++], "1/7"); +#endif +#ifndef USE_BUFFER_OVERRIDE_TEMPO_RATES + scalars[i] = 1.f/6.f; strcpy(displays[i++], "1/6"); + scalars[i] = 1.f/5.f; strcpy(displays[i++], "1/5"); +#endif + scalars[i] = 1.f/4.f; strcpy(displays[i++], "1/4"); + scalars[i] = 1.f/3.f; strcpy(displays[i++], "1/3"); + scalars[i] = 1.f/2.f; strcpy(displays[i++], "1/2"); + scalars[i] = 2.f/3.f; strcpy(displays[i++], "2/3"); + scalars[i] = 3.f/4.f; strcpy(displays[i++], "3/4"); + scalars[i] = 1.0f; strcpy(displays[i++], "1"); + scalars[i] = 2.0f; strcpy(displays[i++], "2"); + scalars[i] = 3.0f; strcpy(displays[i++], "3"); + scalars[i] = 4.0f; strcpy(displays[i++], "4"); + scalars[i] = 5.0f; strcpy(displays[i++], "5"); + scalars[i] = 6.0f; strcpy(displays[i++], "6"); + scalars[i] = 7.0f; strcpy(displays[i++], "7"); + scalars[i] = 8.0f; strcpy(displays[i++], "8"); + scalars[i] = 12.0f; strcpy(displays[i++], "12"); + scalars[i] = 16.0f; strcpy(displays[i++], "16"); + scalars[i] = 24.0f; strcpy(displays[i++], "24"); + scalars[i] = 32.0f; strcpy(displays[i++], "32"); + scalars[i] = 48.0f; strcpy(displays[i++], "48"); + scalars[i] = 64.0f; strcpy(displays[i++], "64"); + scalars[i] = 96.0f; strcpy(displays[i++], "96"); +#ifndef USE_SLOW_TEMPO_RATES + scalars[i] = 333.0f; strcpy(displays[i++], "333"); +#ifndef USE_BUFFER_OVERRIDE_TEMPO_RATES + scalars[i] = 3000.0f; strcpy(displays[i++], "infinity"); +#endif +#endif +} + +//----------------------------------------------------------------------------- +TempoRateTable::~TempoRateTable() +{ + if (scalars) + delete[] scalars; + for (int i=0; i < NUM_TEMPO_RATES; i++) + { + if (displays[i]) + delete[] displays[i]; + } + if (displays) + delete[] displays; + displays = 0; +} diff --git a/dfx-library/TempoRateTable.h b/dfx-library/TempoRateTable.h new file mode 100755 index 0000000..00f8cc7 --- /dev/null +++ b/dfx-library/TempoRateTable.h @@ -0,0 +1,47 @@ +#ifndef __TempoRateTable +#define __TempoRateTable + + +//-------------------------------------------------------------------------- +// the number of tempo beat division options +#ifdef USE_SLOW_TEMPO_RATES + #define NUM_TEMPO_RATES 25 +#else + #ifdef USE_BUFFER_OVERRIDE_TEMPO_RATES + #define NUM_TEMPO_RATES 21 + #else + #define NUM_TEMPO_RATES 24 + #endif +#endif + + + +//-------------------------------------------------------------------------- +// this holds the beat scalar values & textual displays for the tempo rates +class TempoRateTable +{ +public: + TempoRateTable(); + ~TempoRateTable(); + + float getScalar(float paramValue) + { return scalars[float2index(paramValue)]; } + char * getDisplay(float paramValue) + { return displays[float2index(paramValue)]; } + +protected: + int float2index(float f) + { + if (f < 0.0f) + f = 0.0f; + else if (f > 1.0f) + f = 1.0f; + return (int) (f * ((float)NUM_TEMPO_RATES-0.9f)); + } + + float *scalars; + char **displays; +}; + + +#endif \ No newline at end of file diff --git a/dfx-library/dfxmisc.cpp b/dfx-library/dfxmisc.cpp new file mode 100755 index 0000000..9d2d814 --- /dev/null +++ b/dfx-library/dfxmisc.cpp @@ -0,0 +1,77 @@ +#ifndef __dfxmisc +#include "dfxmisc.h" +#endif + + +/* +//----------------------------------------------------------------------------------------- +// the calculates the number of samples until the next musical measure starts + +long samplesToNextBar(VstTimeInfo *timeInfo) +{ + // default these values to something reasonable in case they are not available from the host + double currentBarStartPos = 0.0, currentPPQpos = 0.0, meterNumerator = 4.0; + double currentTempoBPS, numPPQ; + long numSamples; + + + // exit immediately if timeInfo got returned NULL - there's nothing we can do in that case + if (timeInfo == NULL) + return 0; + if (kVstTempoValid & timeInfo->flags) + currentTempoBPS = timeInfo->tempo / 60.0; + // there's no point in going on with this if the host isn't supplying tempo + else + return 0; + + // get the song beat position of the beginning of the previous measure + if (kVstBarsValid & timeInfo->flags) + currentBarStartPos = timeInfo->barStartPos; + + // get the song beat position of our precise current location + if (kVstPpqPosValid & timeInfo->flags) + currentPPQpos = timeInfo->ppqPos; + + // get the numerator of the time signature - this is the number of beats per measure + if (kVstTimeSigValid & timeInfo->flags) + meterNumerator = (double) timeInfo->timeSigNumerator; + // it will screw up the while loop below bigtime if timeSigNumerator isn't a positive number + if (meterNumerator <= 0.0) + meterNumerator = 4.0; + + // calculate the distance in beats to the upcoming measure beginning point + if (currentBarStartPos == currentPPQpos) + numPPQ = 0.0; + else + numPPQ = currentBarStartPos + meterNumerator - currentPPQpos; + + // do this stuff because some hosts (Cubase) give kind of wacky barStartPos sometimes + while (numPPQ < 0.0) + numPPQ += meterNumerator; + while (numPPQ > meterNumerator) + numPPQ -= meterNumerator; + + // convert the value for the distance to the next measure from beats to samples + numSamples = (long) ( numPPQ * timeInfo->sampleRate / currentTempoBPS ); + + // return the number of samples until the next measure + if (numSamples < 0) // just protecting again against wacky values + return 0; + else + return numSamples; +} +*/ + +//----------------------------------------------------------------------------------------- +// computes the principle branch of the Lambert W function +// { LambertW(x) = W(x), where W(x) * exp(W(x)) = x } + +double LambertW(double input) +{ + double x = fabs(input); + + if (x <= 500.0) + return 0.665 * ( 1.0 + (0.0195 * log(x+1.0)) ) * log(x+1.0) + 0.04; + else + return log(x-4.0) - ( (1.0 - 1.0/log(x)) * log(log(x)) ); +} diff --git a/dfx-library/dfxmisc.h b/dfx-library/dfxmisc.h new file mode 100755 index 0000000..1f70aa2 --- /dev/null +++ b/dfx-library/dfxmisc.h @@ -0,0 +1,194 @@ +#ifndef __dfxmisc +#define __dfxmisc + +#include +#include + +#ifdef WIN32 +/* turn off warnings about default but no cases in switch, etc. */ + #pragma warning( disable : 4065 57 4200 4244 ) + #include +#endif + + +//----------------------------------------------------------------------------- +// constants & macros + +#define DESTROY_FX_RULEZ + +#define onOffTest(fvalue) ((fvalue) > 0.5f) + +#define paramRangeScaled(value,min,max) ( ((value) * ((max)-(min))) + (min) ) +#define paramRangeUnscaled(value,min,max) ( ((value)-(min)) / ((max)-(min)) ) +#define paramRangeSquaredScaled(value,min,max) ( ((value)*(value) * ((max)-(min))) + (min) ) +#define paramRangeSquaredUnscaled(value,min,max) ( sqrtf(((value)-(min)) / ((max)-(min))) ) +#define paramRangeCubedScaled(value,min,max) ( ((value)*(value)*(value) * ((max)-(min))) + (min) ) +#define paramRangeCubedUnscaled(value,min,max) ( powf(((value)-(min)) / ((max)-(min)), 1.0f/3.0f) ) +#define paramRangePowScaled(value,min,max,power) ( (powf((value),(power)) * ((max)-(min))) + (min) ) +#define paramRangePowUnscaled(value,min,max,power) ( powf(((value)-(min)) / ((max)-(min)), 1.0f/(power)) ) +#define paramRangeExpScaled(value,min,max) ( expf(logf((max)-(min)+1.0f)*(value)) + (min) - 1.0f ) +#define paramRangeExpUnscaled(value,min,max) ( logf(1.0f-(min)+(value)) / logf(1.0f-(min)+(max)) ) +#define paramSteppedScaled(value,numSteps) ( (long)((value) * ((float)(numSteps)-0.01f)) ) +#define paramSteppedUnscaled(step,numSteps) ( (float)(step) / ((float)((numSteps)-1)) ) +#define paramRangeIntScaled(value,min,max) ( (long)((value) * ((float)((max)-(min)+1)-0.01f)) + (min) ) +#define paramRangeIntUnscaled(step,min,max) ( (float)((step)-(min)) / (float)((max)-(min)) ) +// scale logarithmicly from 20 Hz to 20 kHz +#define paramFrequencyScaled(value) (20.0f * powf(2.0f, (value) * 9.965784284662088765571752446703612804412841796875f)) +#define paramFrequencyUnscaled(value) ( (logf((value)/20.0f)/logf(2.0f)) / 9.965784284662088765571752446703612804412841796875f ) + +#define dBconvert(fvalue) ( 20.0f * log10f((fvalue)) ) + +#ifndef PI +#define PI 3.1415926535897932384626433832795f +#endif +#ifndef PId +#define PId 3.1415926535897932384626433832795 +#endif + +// reduces wasteful casting & division +const float ONE_DIV_RAND_MAX = 1.0f / (float)RAND_MAX; +#define randFloat() ( (float)rand() * ONE_DIV_RAND_MAX ) + +#ifndef clip +#define clip(fvalue) (if (fvalue < -1.0f) fvalue = -1.0f; else if (fvalue > 1.0f) fvalue = 1.0f) +#endif + +#ifndef undenormalize +#define undenormalize(fvalue) if (fabs(fvalue) < 1.0e-15) fvalue = 0.0 +//#define undenormalize(fvalue) (((*(unsigned int*)&(fvalue))&0x7f800000)==0)?0.0f:(fvalue) +#endif + +//#define kBeatSyncTimeInfoFlags (kVstTempoValid | kVstTransportChanged | kVstBarsValid | kVstPpqPosValid | kVstTimeSigValid) +#define kBeatSyncTimeInfoFlags 1 + +/* return the parameter with larger magnitude */ +inline float magmax(float a, float b) { + if (fabs(a) > fabs(b)) return a; + else return b; +} + + +//----------------------------------------------------------------------------- +// function prototypes + +//pi +//long samplesToNextBar(VstTimeInfo *timeInfo); + +// pi +//void processProgramChangeEvents(VstEvents *events, AudioEffectX *effect); + +double LambertW(double input); + + +//----------------------------------------------------------------------------- +// inline functions + +//----------------------------------------------------------------------------- +inline float interpolateHermite(float *data, double address, long arraysize) +{ + long pos = (long)address; + float posFract = (float) (address - (double)pos); + + long posMinus1 = (pos == 0) ? arraysize-1 : pos-1; + long posPlus1 = (pos+1) % arraysize; + long posPlus2 = (pos+2) % arraysize; + + float a = ( (3.0f*(data[pos]-data[posPlus1])) - data[posMinus1] + data[posPlus2] ) * 0.5f; + float b = (2.0f*data[posPlus1]) + data[posMinus1] - (2.5f*data[pos]) - (data[posPlus2]*0.5f); + float c = (data[posPlus1] - data[posMinus1]) * 0.5f; + + return (( ((a*posFract)+b) * posFract + c ) * posFract) + data[pos]; +} + +inline float interpolateLinear(float *data, double address, long arraysize) +{ + long pos = (long)address; + float posFract = (float) (address - (double)pos); + return (data[pos] * (1.0f-posFract)) + (data[(pos+1)%arraysize] * posFract); +} + +inline float interpolateRandom(float randMin, float randMax) +{ + float randy = (float)rand() * ONE_DIV_RAND_MAX; + return ((randMax-randMin) * randy) + randMin; +} + +inline float interpolateLinear2values(float point1, float point2, double address) +{ + float posFract = (float) (address - (double)((long)address)); + return (point1 * (1.0f-posFract)) + (point2 * posFract); +} + +//----------------------------------------------------------------------------- +// I found this somewhere on the internet +/* +inline float anotherSqrt(float x) +{ + float result = 1.0f; + float store = 0.0f; + while (store != result) + { + store = result; + result = 0.5f * (result + (x / result)); + } +} +*/ + + +//----------------------------------------------------------------------------- +// mutex stuff + +#if WIN32 + +struct dfxmutex { + CRITICAL_SECTION c; + dfxmutex() { InitializeCriticalSection(&c); } + ~dfxmutex() { DeleteCriticalSection(&c); } + void grab() { EnterCriticalSection(&c); } + void release() { LeaveCriticalSection(&c); } +}; + +/* +#elif MAC + +// Multiprocessing Services +#include +struct dfxmutex { + OSStatus initErr, deleteErr, enterErr, exitErr; + MPCriticalRegionID c; + Duration timeout; // in ms (available constants: kDurationImmediate, kDurationForever, kDurationMillisecond, kDurationMicrosecond) + dfxmutex() { initErr = MPCreateCriticalRegion(&c); } + ~dfxmutex() { deleteErr = MPDeleteCriticalRegion(c); } + void grab () { enterErr = MPEnterCriticalRegion(c, kDurationForever); } + void release () { exitErr = MPExitCriticalRegion(c); } +}; + +// POSIX +// can this even work for CFM? perhaps only mach-o +#include +//#include +struct dfxmutex { + int initErr, deleteErr, enterErr, exitErr; + pthread_mutex_t c; + dfxmutex() { initErr = pthread_mutex_init(&c, NULL); } + ~dfxmutex() { deleteErr = pthread_mutex_destroy(&c); } + void grab () { enterErr = pthread_mutex_lock(&c); } + void release () { exitErr = pthread_mutex_unlock(&c); + //pthread_testcancel(); + } +}; +*/ + +#else + +struct dfxmutex { + dfxmutex() {} + ~dfxmutex() {} + void grab () {} + void release () {} +}; + +#endif + + +#endif diff --git a/dfx-library/lfo.cpp b/dfx-library/lfo.cpp new file mode 100755 index 0000000..58a58c3 --- /dev/null +++ b/dfx-library/lfo.cpp @@ -0,0 +1,178 @@ +#ifndef __lfo +#include "lfo.h" +#endif + +#include +#include +#include +#include +#include + + +//------------------------------------------------------------------------ +LFO::LFO() +{ + sineTable = new float[NUM_LFO_POINTS]; + triangleTable = new float[NUM_LFO_POINTS]; + squareTable = new float[NUM_LFO_POINTS]; + sawTable = new float[NUM_LFO_POINTS]; + reverseSawTable = new float[NUM_LFO_POINTS]; + thornTable = new float[NUM_LFO_POINTS]; + + fillLFOtables(); + table = sineTable; // just to have it pointing to something at least + + srand((unsigned int)time(NULL)); // sets a seed value for rand() from the system clock + + reset(); +} + +//------------------------------------------------------------------------ +LFO::~LFO() +{ + if (sineTable) + delete[] sineTable; + if (triangleTable) + delete[] triangleTable; + if (squareTable) + delete[] squareTable; + if (sawTable) + delete[] sawTable; + if (reverseSawTable) + delete[] reverseSawTable; + if (thornTable) + delete[] thornTable; +} + +//------------------------------------------------------------------------ +void LFO::reset() +{ + position = 0.0f; + stepSize = 1.0f; // just to avoid anything really screwy + oldRandomNumber = (float)rand() / (float)RAND_MAX; + randomNumber = (float)rand() / (float)RAND_MAX; + smoothSamples = 0; + granularityCounter = 0; +} + +//----------------------------------------------------------------------------------------- +// this function creates tables for mapping out the sine, triangle, & saw LFO shapes + +void LFO::fillLFOtables() +{ + long i, n; + + + // fill the sine waveform table (oscillates from 0 to 1 & back to 0) + for (i = 0; (i < NUM_LFO_POINTS); i++) + sineTable[i] = (sinf( ( ((float)i/(float)NUM_LFO_POINTS)-0.25f ) * 2.0f * PI ) + 1.0f) * 0.5f; + + // fill the triangle waveform table + // ramp from 0 to 1 for the first half + for (i = 0; (i < NUM_LFO_POINTS/2); i++) + triangleTable[i] = (float)i / (float)(NUM_LFO_POINTS/2); + // & ramp from 1 to 0 for the second half + for (n = 0; (i < NUM_LFO_POINTS); n++) + { + triangleTable[i] = 1.0f - ((float)n / (float)(NUM_LFO_POINTS/2)); + i++; + } + + // fill the square waveform table + // stay at 1 for the first half + for (i = 0; (i < NUM_LFO_POINTS/2); i++) + squareTable[i] = 1.0f; + // & 0 for the second half + for (n = 0; (i < NUM_LFO_POINTS); n++) + { + squareTable[i] = 0.0f; + i++; + } + + // fill the sawtooth waveform table (ramps from 0 to 1) + for (i = 0; (i < NUM_LFO_POINTS); i++) + sawTable[i] = (float)i / (float)(NUM_LFO_POINTS-1); + + // fill the reverse sawtooth waveform table (ramps from 1 to 0) + for (i = 0; (i < NUM_LFO_POINTS); i++) + reverseSawTable[i] = (float)(NUM_LFO_POINTS-i-1) / (float)(NUM_LFO_POINTS-1); + + // fill the thorn waveform table + // exponentially slope up from 0 to 1 for the first half + for (i = 0; (i < NUM_LFO_POINTS/2); i++) + thornTable[i] = powf( ((float)i / (float)(NUM_LFO_POINTS/2)), 2.0f ); + // & exponentially slope down from 1 to 0 for the second half + for (n = 0; (i < NUM_LFO_POINTS); n++) + { + thornTable[i] = powf( (1.0f - ((float)n / (float)(NUM_LFO_POINTS/2))), 2.0f ); + i++; + } +} + + +//-------------------------------------------------------------------------------------- +void LFO::getShapeName(char *nameString) +{ + switch (LFOshapeScaled(fShape)) + { + case kSineLFO : strcpy(nameString, "sine"); break; + case kTriangleLFO : strcpy(nameString, "triangle"); break; + case kSquareLFO : strcpy(nameString, "square"); break; + case kSawLFO : strcpy(nameString, "sawtooth"); break; + case kReverseSawLFO : strcpy(nameString, "reverse sawtooth"); break; + case kThornLFO : strcpy(nameString, "thorn"); break; + case kRandomLFO : strcpy(nameString, "random"); break; + case kRandomInterpolatingLFO : strcpy(nameString, "random interpolating"); break; + default : break; + } +} + + +//-------------------------------------------------------------------------------------- +// this function points the LFO table pointers to the correct waveform tables + +void LFO::pickTheLFOwaveform() +{ + switch (LFOshapeScaled(fShape)) + { + case kSineLFO : + table = sineTable; + break; + case kTriangleLFO : + table = triangleTable; + break; + case kSquareLFO : + table = squareTable; + break; + case kSawLFO : + table = sawTable; + break; + case kReverseSawLFO : + table = reverseSawTable; + break; + case kThornLFO : + table = thornTable; + break; + default : + table = sineTable; + break; + } +} + +//-------------------------------------------------------------------------------------- +// calculates the position within an LFO's cycle needed to sync to the song's beat + +void LFO::syncToTheBeat(long samplesToBar) +{ + float countdown, cyclesize; + + // calculate how many samples long the LFO cycle is + cyclesize = NUM_LFO_POINTS_FLOAT / stepSize; + // calculate many more samples it will take for this cycle to coincide with the beat + countdown = fmodf( (float)samplesToBar, cyclesize); + // & convert that into the correct LFO position according to its table step size + position = (cyclesize - countdown) * stepSize; + // wrap around the new position if it is beyond the end of the LFO table + if (position >= NUM_LFO_POINTS_FLOAT) + position = fmodf(position, NUM_LFO_POINTS_FLOAT); +} diff --git a/dfx-library/lfo.h b/dfx-library/lfo.h new file mode 100755 index 0000000..0c743c7 --- /dev/null +++ b/dfx-library/lfo.h @@ -0,0 +1,150 @@ +/*------------------- by Marc Poirier ][ January 2002 ------------------*/ + +#ifndef __lfo +#define __lfo + +#include +#include + +#include "dfxmisc.h" +#include "TempoRateTable.h" + + +//------------------------------------------------------------------------------------- +// these are the 8 LFO waveforms: +enum +{ + kSineLFO, + kTriangleLFO, + kSquareLFO, + kSawLFO, + kReverseSawLFO, + kThornLFO, + kRandomLFO, + kRandomInterpolatingLFO, + + numLFOshapes +}; + +//------------------------------------------------------------------------------------- +// constants & macros + +#define LFOshapeScaled(A) (paramSteppedScaled((A), numLFOshapes)) +#define LFOshapeUnscaled(A) (paramSteppedUnscaled((A), numLFOshapes)) + +#define NUM_LFO_POINTS 512 +const float NUM_LFO_POINTS_FLOAT = (float)NUM_LFO_POINTS; // to reduce casting later on +const float LFO_TABLE_STEP = 1.0f / (float)NUM_LFO_POINTS; // to reduce division & encourage multiplication +const long SQUARE_HALF_POINT = NUM_LFO_POINTS / 2; // the point in the table when the square waveform drops to zero + +#define LFO_SMOOTH_DUR 48 +const float LFO_SMOOTH_STEP = 1.0f / (float)LFO_SMOOTH_DUR; + +// this scales the return of processLFO() from 0.0 - 1.0 output to 0.0 - 2.0 (oscillating around 1.0) +#define processLFOzero2two(A) ( ((A)->processLFO() * 2.0f) - (A)->fDepth + 1.0f ); + + +//----------------------------------------------------------------------------- +class LFO +{ +public: + LFO(); + ~LFO(); + + void reset(); + void fillLFOtables(); + + void pickTheLFOwaveform(); + void getShapeName(char *nameString); + + void syncToTheBeat(long samplesToBar); + + // the LFO waveform tables + float *sineTable, *triangleTable, *squareTable, *sawTable, *reverseSawTable, *thornTable; + + // the following are intended to be used as 0.0 - 1.0 VST parameter values: + float fOnOff; // parameter value for turning the LFO on or off + float fTempoSync; // parameter value for toggling tempo sync + float fRate; // parameter value for LFO rate (in Hz) + float fTempoRate; // parameter value for LFO rate (in cycles per beat) + float fDepth; // parameter value LFO depth + float fShape; // parameter value for LFO shape + + bool onOff; // in case it's easier to have a bool version of fOnOff + float position; // this tracks the position in the LFO table + float stepSize; // size of the steps through the LFO table + float *table; // pointer to the LFO table + float randomNumber; // this stores random values for the random LFO waveforms + float oldRandomNumber; // this stores previous random values for the random interpolating LFO waveform + float cycleRate; // the rate in Hz of the LFO (only used for first layer LFOs) + long smoothSamples; // a counter for the position during a smoothing fade + long granularityCounter; // a counter for implementing LFO processing on a block basis + long granularity; // the number of samples to wait before processing + + + //-------------------------------------------------------------------------------------- + // This function wraps around the LFO table position when it passes the cycle end. + // It also sets up the smoothing counter if a discontiguous LFO waveform is being used. + void updatePosition(long numSteps = 1) + { + // increment the LFO position tracker + position += (stepSize * (float)numSteps); + + if (position >= NUM_LFO_POINTS_FLOAT) + { + // wrap around the position tracker if it has made it past the end of the LFO table + position = fmodf(position, NUM_LFO_POINTS_FLOAT); + // get new random LFO values, too + oldRandomNumber = randomNumber; + randomNumber = (float)rand() / (float)RAND_MAX; + // set up the sample smoothing if a discontiguous waveform's cycle just ended + switch (LFOshapeScaled(fShape)) + { + case kSquareLFO : + case kSawLFO : + case kReverseSawLFO : + case kRandomLFO : + smoothSamples = LFO_SMOOTH_DUR; + default: + break; + } + } + + // special check for the square waveform - it also needs smoothing at the half point + else if (LFOshapeScaled(fShape) == kSquareLFO) + { + // check to see if it has just passed the halfway point + if ( ((long)position >= SQUARE_HALF_POINT) && + ((long)(position - stepSize) < SQUARE_HALF_POINT) ) + smoothSamples = LFO_SMOOTH_DUR; + } + } + + //-------------------------------------------------------------------------------------- + // this function gets the current 0.0 - 1.0 output value of the LFO & increments its position + float processLFO() + { + float randiScalar, outValue; + int shape = LFOshapeScaled(fShape); + + if (shape == kRandomInterpolatingLFO) + { + // calculate how far into this LFO cycle we are so far, scaled from 0.0 to 1.0 + randiScalar = position * LFO_TABLE_STEP; + // interpolate between the previous random number & the new one + outValue = (randomNumber * randiScalar) + (oldRandomNumber * (1.0f-randiScalar)); + } + // + else if (shape == kRandomLFO) + outValue = randomNumber; + // + else + outValue = table[(long)position]; + + return (outValue * fDepth); + } + +}; + + +#endif \ No newline at end of file -- cgit v1.2.1