aboutsummaryrefslogtreecommitdiff
path: root/dfx-library
diff options
context:
space:
mode:
Diffstat (limited to 'dfx-library')
-rwxr-xr-xdfx-library/FIRfilter.cpp97
-rwxr-xr-xdfx-library/FIRfilter.h37
-rwxr-xr-xdfx-library/IIRfilter.cpp61
-rwxr-xr-xdfx-library/IIRfilter.h156
-rw-r--r--dfx-library/MultiKick.cpp114
-rw-r--r--dfx-library/MultiKick.hpp42
-rwxr-xr-xdfx-library/TempoRateTable.cpp72
-rwxr-xr-xdfx-library/TempoRateTable.h47
-rwxr-xr-xdfx-library/dfxmisc.cpp77
-rwxr-xr-xdfx-library/dfxmisc.h194
-rwxr-xr-xdfx-library/lfo.cpp178
-rwxr-xr-xdfx-library/lfo.h150
12 files changed, 1225 insertions, 0 deletions
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 <math.h>
+
+
+#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 <math.h>
+
+
+//------------------------------------------------------------------------
+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 <string.h>
+
+
+//-----------------------------------------------------------------------------
+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 <math.h>
+#include <stdlib.h>
+
+#ifdef WIN32
+/* turn off warnings about default but no cases in switch, etc. */
+ #pragma warning( disable : 4065 57 4200 4244 )
+ #include <windows.h>
+#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 <Multiprocessing.h>
+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 <pthread.h>
+//#include <Carbon/Carbon.h>
+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 <stdio.h>
+#include <math.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+
+//------------------------------------------------------------------------
+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 <math.h>
+#include <stdlib.h>
+
+#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