code:
/*
	dsp/BiQuad.h

	Copyright 2003-7 Tim Goetze <tim@quitte.de>

	http://quitte.de/dsp/

	Bi-quad IIR filter.

*/
/*
	This program is free software; you can redistribute it and/or
	modify it under the terms of the GNU General Public License
	as published by the Free Software Foundation; either version 2
	of the License, or (at your option) any later version.

	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	You should have received a copy of the GNU General Public License
	along with this program; if not, write to the Free Software
	Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
	02111-1307, USA or point your web browser to http://www.gnu.org.
*/

#ifndef _DSP_BI_QUAD_H_
#define _DSP_BI_QUAD_H_

namespace DSP {

class BiQuad
{
	public:
		/* coefficients */
		sample_t a[3], b[3];

		/* history */
		int h;
		sample_t x[2], y[2];

		BiQuad()
			{
				unity();
				reset();
			}

		void unity()
			{
				a[0] = 1;
				a[1] = a[2] = b[0] = b[1] = b[2] = 0;
			}

		void copy (BiQuad & bq)
			{
				for (int i = 0; i < 3; ++i)
					a[i] = bq.a[i],
					b[i] = bq.b[i];
			}

		void reset()
			{
				h = 0;

				x[0] = x[1] =
				y[0] = y[1] = 0.;
			}

		/* denormal zapping */
		void flush_0()
			{
				for (int i = 0; i < 2; ++i)
					if (is_denormal (y[i]))
						y[i] = 0;
			}

		inline sample_t process (sample_t s)
			{
				register int z = h;

				register sample_t r = s * a[0];

				r += a[1] * x[z];
				r += b[1] * y[z];

				z ^= 1;
				r += a[2] * x[z];
				r += b[2] * y[z];

				y[z] = r;
				x[z] = s;

				h = z;

				return r;
			}

		/* Following are additional methods for using the biquad to filter an
		 * upsampled signal with 0 padding -- some terms reduce to 0 in this
		 * case */
		inline sample_t process_0_1()
			{
				register int z = h;

				register sample_t r = 0;

				r += a[1] * x[z];
				r += b[1] * y[z];

				z ^= 1;
				r += a[2] * x[z];
				r += b[2] * y[z];

				y[z] = r;
				x[z] = 0;

				h = z;

				return r;
			}

		inline sample_t process_0_2()
			{
				register int z = h;

				register sample_t r = 0;

				r += b[1] * y[z];

				z ^= 1;
				r += a[2] * x[z];
				r += b[2] * y[z];

				y[z] = r;
				x[z] = 0;

				h = z;

				return r;
			}

		inline sample_t process_0_3()
			{
				register int z = h;

				register sample_t r = 0;

				r += b[1] * y[z];

				z ^= 1;
				r += b[2] * y[z];

				y[z] = r;
				x[z] = 0;

				h = z;

				return r;
			}
};

} /* namespace DSP */

#endif /* _DSP_BI_QUAD_H_ */


code:
/*
	dsp/Delay.h

	Copyright 2003-4, 2010 Tim Goetze <tim@quitte.de>

	http://quitte.de/dsp/

	delay lines with fractional (linear or cubic interpolation) lookup
	and an allpass interpolating tap (which needs more work).

	delay line storage is aligned to powers of two for simplified wrapping
	checks (no conditional or modulo, binary and suffices instead).

*/
/*
	This program is free software; you can redistribute it and/or
	modify it under the terms of the GNU General Public License
	as published by the Free Software Foundation; either version 2
	of the License, or (at your option) any later version.

	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	You should have received a copy of the GNU General Public License
	along with this program; if not, write to the Free Software
	Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
	02111-1307, USA or point your web browser to http://www.gnu.org.
*/

#ifndef _DSP_DELAY_H_
#define _DSP_DELAY_H_

#include "util.h"
#include "FPTruncateMode.h"

namespace DSP {

class Delay
{
	public:
		int size;
		sample_t * data;
		int read, write;

		Delay()
			{
				read = write = 0;
				data = 0;
			}

		~Delay()
			{
				if (data) free (data);
			}

		void init (int n)
			{
				size = next_power_of_2 (n);
				data = (sample_t *) calloc (sizeof (sample_t), size);
				size -= 1;
				write = n;
			}

		void reset()
			{
				memset (data, 0, (size + 1) * sizeof (sample_t));
			}

		sample_t &
		operator [] (int i)
			{
				return data [(write - i) & size];
			}

		inline void
		put (sample_t x)
			{
				data [write] = x;
				write = (write + 1) & size;
			}

		inline sample_t
		get()
			{
				sample_t x = data [read];
				read = (read + 1) & size;
				return x;
			}

		inline sample_t
		putget (sample_t x)
			{
				put (x);
				return get();
			}

		/* fractional lookup, linear interpolation */
		inline sample_t
		get_at (float f)
			{
				int n;
				fistp (f, n); /* read: i = (int) f; relies on FPTruncateMode */
				f -= n;

				return (1 - f) * (*this) [n] + f * (*this) [n + 1];
			}

		/* fractional lookup, cubic interpolation */
		inline sample_t
		get_cubic (float f)
			{
				int n;
				fistp (f, n); /* see FPTruncateMode */
				f -= n;

				sample_t x_1 = (*this) [n - 1];
				sample_t x0 = (*this) [n];
				sample_t x1 = (*this) [n + 1];
				sample_t x2 = (*this) [n + 2];

				/* sample_t (32bit) quicker than double here */
				register sample_t a =
						(3 * (x0 - x1) - x_1 + x2) * .5;
				register sample_t b =
						2 * x1 + x_1 - (5 * x0 + x2) * .5;
				register sample_t c =
						(x1 - x_1) * .5;

				return x0 + (((a * f) + b) * f + c) * f;
			}
};

/* allpass variant */

class DelayTapA
{
	public:
		sample_t x1, y1;

		DelayTapA()
			{
				reset();
			}

		void reset()
			{
				x1 = y1 = 0;
			}

		sample_t get (Delay & d, float f)
			{
				int n;
				fistp (f, n); /* read: n = (int) f; relies on FPTruncateMode */
				f -= n;
				if (0 && f < .5)
					f += 1,
					n -= 1;

				sample_t x = d[n];
				f = (1 - f) / (1 + f);
				y1 = x1 + f * x - f * y1;
				x1 = x;
				return y1;
			}
};

}; /* namespace DSP */

#endif /* _DSP_DELAY_H_ */

repo_name: CYBERDEViL/LMMS

license: mit


code:
/*
	Eq.h

	Copyright 2004-7 Tim Goetze <tim@quitte.de>

	http://quitte.de/dsp/

	Equalizer circuit using recursive filtering.
	Based on a motorola paper implementing a similar circuit on a DSP56001.

*/
/*
	This program is free software; you can redistribute it and/or
	modify it under the terms of the GNU General Public License
	as published by the Free Software Foundation; either version 2
	of the License, or (at your option) any later version.

	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	You should have received a copy of the GNU General Public License
	along with this program; if not, write to the Free Software
	Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
	02111-1307, USA or point your web browser to http://www.gnu.org.
*/

#ifndef _DSP_EQ_H_
#define _DSP_EQ_H_

namespace DSP {

/* A single bandpass as used by the Eq, expressed as a biquad. Like all
 * band-pass filters I know of, the filter works with a FIR coefficient of 0
 * for x[-1], so a generic biquad isn't the optimum implementation.
 *
 * This routine isn't used anywhere, just here for testing purposes.
 */
template <class T>
void
_BP (double fc, double Q, T * ca, T * cb)
{
	double theta = 2 * fc * M_PI;

	double
		b = (Q - theta * .5) / (2 * Q + theta),
		a = (.5 - b) / 2,
		c = (.5 + b) * cos (theta);

	ca[0] = 2 * a;
	ca[1] = 0;
	ca[2] = -2 * a;

	cb[0] = 0;
	cb[1] = 2 * c;
	cb[2] = -2 * b;
}

template <int Bands, class eq_sample = float>
class Eq
{
	public:
		/* recursion coefficients, 3 per band */
		eq_sample __attribute__ ((aligned)) a[Bands], b[Bands], c[Bands];
		/* past outputs, 2 per band */
		eq_sample __attribute__ ((aligned)) y[2][Bands];
		/* current gain and recursion factor, each 1 per band = 2 */
		eq_sample __attribute__ ((aligned)) gain[Bands], gf[Bands];
		/* input history */
		eq_sample x[2];
		/* history index */
		int h;

		eq_sample normal;

		Eq()
			{
				h = 0;
				normal = NOISE_FLOOR;
			}

		void reset()
			{
				for (int z = 0; z < 2; ++z)
				{
					memset( y[z], 0, Bands*sizeof( eq_sample ) );
					x[z] = 0;
				}
			}

		void init (double fs, double Q)
			{
				double f = 31.25;
				int i = 0;

				for (i = 0; i < Bands && f < fs / 2; ++i, f *= 2)
					init_band (i, 2 * f * M_PI / fs, Q);
				/* just in case, zero the remaining coefficients */
				for (  ; i < Bands; ++i)
					zero_band (i);

				reset();
			}

		void init_band (int i, double theta, double Q)
			{
				b[i] = (Q - theta * .5) / (2 * Q + theta);
				a[i] = (.5 - b[i]) / 2;
				c[i] = (.5 + b[i]) * cos (theta);
				/* fprintf (stderr, "%02d %f %f %f\n", i, a[i], b[i], c[i]); */
				gain[i] = 1;
				gf[i] = 1;
			}

		void zero_band (int i)
			{
				a[i] = b[i] = c[i] = 0;
			}

		/* per-band recursion:
		 * 	y = 2 * (a * (x - x[-2]) + c * y[-1] - b * y[-2])
		 */
		eq_sample process (eq_sample s)
			{
				int z1 = h, z2 = h ^ 1;

				eq_sample * y1 = y[z1];
				eq_sample * y2 = y[z2];

				eq_sample x_x2 = s - x[z2];
				eq_sample r = 0;

				for (int i = 0; i < Bands; ++i)
				{
					y2[i] = normal + 2 * (a[i] * x_x2 + c[i] * y1[i] - b[i] * y2[i]);
					r += gain[i] * y2[i];
					gain[i] *= gf[i];
				}

				x[z2] = s;
				h = z2;

				return r;
			}

		/* zap denormals in history */
		void flush_0()
			{
				for (int i = 0; i < Bands; ++i)
					if (is_denormal (y[0][i]))
						y[0][i] = 0;
			}
};

} /* namespace DSP */

#endif /* _DSP_EQ_H_ */


code:
/*
	dsp/FIR.h

	Copyright 2003-10 Tim Goetze <tim@quitte.de>

	http://quitte.de/dsp/

	finite impulse response filters, with options for up- and down-sampling.

*/
/*
	This program is free software; you can redistribute it and/or
	modify it under the terms of the GNU General Public License
	as published by the Free Software Foundation; either version 2
	of the License, or (at your option) any later version.

	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	You should have received a copy of the GNU General Public License
	along with this program; if not, write to the Free Software
	Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
	02111-1307, USA or point your web browser to http://www.gnu.org.
*/

#ifndef _FIR_H_
#define _FIR_H_

#include "util.h"

namespace DSP {

/* brute-force FIR filter with downsampling method (decimating).
 *
 * CAVEAT: constructing it from another FIR makes the filter share the other's
 * kernel data set. IOW, the other FIR must be valid throughout the lifetime
 * of this instance.
 */
class FIR
{
	public:
		/* kernel length, history length - 1 */
		int n, m;

		/* coefficients, history */
		sample_t * c, * x;
		bool borrowed_kernel;

		/* history index */
		int h;

		FIR (int N)
			{
				c = 0;
				init (N);
			}

		FIR (FIR & fir)
			{
				c = fir.c;
				init (fir.n);
			}

		FIR (int n, sample_t * kernel)
			{
				c = 0;
				init (n);
				memcpy (c, kernel, n * sizeof (*c));
			}

		~FIR()
			{
				if (!borrowed_kernel)
					free (c);
				free (x);
			}

		void init (int N)
			{
				n = N;

				/* keeping history size a power of 2 makes it possible to wrap the
				 * history pointer by & instead of %, saving a few cpu cycles. */
				m = next_power_of_2 (n);

				if (c)
					borrowed_kernel = true;
				else
					borrowed_kernel = false,
					c = (sample_t *) malloc (n * sizeof (sample_t));

				x = (sample_t *) malloc (m * sizeof (sample_t));

				m -= 1;

				reset();
			}

		void reset()
			{
				h = 0;
				memset (x, 0, n * sizeof (sample_t));
			}

		/* TODO: write an SSE-enabled version */
		inline sample_t process (sample_t s)
			{
				x[h] = s;

				s *= c[0];

				for (int Z = 1, z = h - 1; Z < n; --z, ++Z)
					s += c[Z] * x[z & m];

				h = (h + 1) & m;

				return s;
			}

		/* Z is the time, in samples, since the last non-zero sample.
		 * OVER is the oversampling factor. just here for documentation, use
		 * a FIRUpsampler instead.
		 */
		template <int Z, int OVER>
		inline sample_t upsample (sample_t s)
			{
				x[h] = s;

				s = 0;

				/* for the interpolation, iterate over the history in z ^ -OVER
				 * steps -- all the samples between are 0.
				 */
				for (int j = Z, z = h - Z; j < n; --z, j += OVER)
					s += c[j] * x[z & m];

				h = (h + 1) & m;

				return s;
			}

		/* used in downsampling */
		inline void store (sample_t s)
			{
				x[h] = s;
				h = (h + 1) & m;
			}
};

/* close relative of FIR, but distinct enough to not justify inheritance.
 *
 * the difference to the FIR is the shorter history length. don't need
 * to clutter the d-cache with interleaved 0s.
 *
 * however, an initial test shows this to be a fraction *slower* than a
 * complete FIR for N = 32, OVER = 4.
 */
class FIRUpsampler
{
	public:
		/* kernel length, history length - 1 */
		int n, m;

		/* oversampling ratio */
		int over;

		/* coefficients, history */
		sample_t * c, * x;

		/* history index */
		int h;

		FIRUpsampler (int _n, int _over)
			{
				c = x = 0;
				init (_n, _over);
			}

		FIRUpsampler (FIR & fir, int _over)
			{
				c = x = 0;
				init (fir.n, _over);
				memcpy (c, fir.c, n * sizeof (sample_t));
			}

		~FIRUpsampler()
			{
				if (c) free (c);
				if (x) free (x);
			}

		void init (int _n, int _over)
			{
				/* oversampling ratio must be multiple of FIR kernel length */
				// assert (_n % _over == 0);

				n = _n;
				over = _over;

				/* like FIR, keep the history buffer a power of 2; additionally,
				 * compress and don't store the 0 samples inbetween.
				 */
				m = next_power_of_2 ((n + over - 1) / over);

				c = (sample_t *) malloc (n * sizeof (sample_t));
				x = (sample_t *) malloc (m * sizeof (sample_t));

				m -= 1;

				reset();
			}

		void reset()
			{
				h = 0;
				memset (x, 0, (m + 1) * sizeof (sample_t));
			}

		/* upsample the given sample */
		inline sample_t upsample (sample_t s)
			{
				x[h] = s;

				s = 0;

				for (int Z = 0, z = h; Z < n; --z, Z += over)
					s += c[Z] * x[z & m];

				h = (h + 1) & m;

				return s;
			}

		/* upsample a zero sample (interleaving), Z being the time, in samples,
		 * since the last non-0 sample. */
		inline sample_t pad (int Z)
			{
				sample_t s = 0;

				for (int z = h - 1; Z < n; --z, Z += over)
					s += c[Z] * x[z & m];

				return s;
			}

};

}; /* namespace DSP */

#endif /* _FIR_H_ */


code:
/* Copyright 2001-4 tim goetze <tim@quitte.de> -- see 'COPYING'. */

/* Sets the FP rounding mode to 'truncate' in the constructor
 * and loads the previous FP conrol word in the destructor.
 *
 * By directly using the machine instruction to convert float to int
 * we avoid the performance hit that loading the control word twice for
 * every (int) cast causes on i386.
 *
 * On other architectures this is a no-op.
 */

#ifndef _DSP_FP_TRUNCATE_MODE_H_
#define _DSP_FP_TRUNCATE_MODE_H_

#ifdef __i386__
	#define fstcw(i) \
		__asm__ __volatile__ ("fstcw %0" : "=m" (i))

	#define fldcw(i) \
		__asm__ __volatile__ ("fldcw %0" : : "m" (i))

	/* gcc chokes on __volatile__ sometimes. */
	#define fistp(f,i) \
		__asm__ ("fistpl %0" : "=m" (i) : "t" (f) : "st")
#else /* ! __i386__ */
	#include <cstdint>

	inline void fistp(float f, int32_t& i) { i = static_cast<int32_t>(f); }
#endif

namespace DSP {

class FPTruncateMode
{
	public:
#ifdef __i386__
		int cw0; /* fp control word */

		FPTruncateMode()
			{
				fstcw (cw0);
				const int cw1 = cw0 | 0xC00;
				fldcw (cw1);
			}

		~FPTruncateMode()
			{
				fldcw (cw0);
			}
#else
	// Avoid warnings about unused variables
	FPTruncateMode() { (void)0; }
	~FPTruncateMode() { (void)0; }
#endif
};

} /* namespace DSP */

#endif /* _DSP_FP_TRUNCATE_MODE_H_ */


code:
/*
	LatFilt.h

	Copyright 2006 David Yeh <dtyeh@ccrma.stanford.edu>

	Lattice digital filter.
	Assumes order of b = order of a.
	Assumes a0 = 1.

*/
/*
	This program is free software; you can redistribute it and/or
	modify it under the terms of the GNU General Public License
	as published by the Free Software Foundation; either version 2
	of the License, or (at your option) any later version.

	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	You should have received a copy of the GNU General Public License
	along with this program; if not, write to the Free Software
	Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
	02111-1307, USA or point your web browser to http://www.gnu.org.
*/

#ifndef _DSP_LatFilt_H_
#define _DSP_LatFilt_H_

namespace DSP {

// ORDER is the highest power of s in the transfer function
template <int ORDER>
class LatFilt
{
	public:
		double vcoef[ORDER+1];
		double kcoef[ORDER];
		double state[ORDER];
		double y;

		// fade factors
		double vf[ORDER+1];
		double kf[ORDER];

		void reset()
			{
				for (int i = 0; i < ORDER; i++) {
						state[i] = 0;   // zero state
						vf[i] = 1;      // reset fade factor
						kf[i] = 1;
				}
				vf[ORDER] = 1;
				y = 0;
			}

		void init (double fs)
			{
				reset();
				clearcoefs();
			}

		void clearcoefs() {
				for (int i=0; i< ORDER; i++) {
						vcoef[i] = 0;
						kcoef[i] = 0;
				}
				vcoef[ORDER] = 0;
		}

		sample_t process (sample_t s) {
				double tmp;

				int i = ORDER-1;
				tmp = -kcoef[i]*state[i] + s;
				y = vcoef[i+1]*(state[i] + kcoef[i]*tmp);

				for (i = ORDER-2; i >= 0; i--) {
						tmp = -kcoef[i]*state[i] + tmp;
						state[i+1] = kcoef[i]*tmp + state[i];
						y = y + vcoef[i+1]*state[i+1];
				}
				state[0] = tmp;
				y = y + vcoef[0]*tmp;

				return (sample_t) y;
		}

		inline void set_vi(double coef, int i) {
				vcoef[i] = coef;
		}

		inline void set_ki(double coef, int i) {
				kcoef[i] = coef;
		}
};

} /* namespace DSP */

#endif /* _DSP_LatFilt_H_ */


code:
/*
	dsp/Lorenz.h

	Copyright 2001-4 Tim Goetze <tim@quitte.de>

	http://quitte.de/dsp/

	Lorenz fractal.

*/
/*
	This program is free software; you can redistribute it and/or
	modify it under the terms of the GNU General Public License
	as published by the Free Software Foundation; either version 2
	of the License, or (at your option) any later version.

	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	You should have received a copy of the GNU General Public License
	along with this program; if not, write to the Free Software
	Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
	02111-1307, USA or point your web browser to http://www.gnu.org.
*/

#ifndef _DSP_LORENZ_H_
#define _DSP_LORENZ_H_

namespace DSP {

class Lorenz
{
	public:
		double x[2], y[2], z[2];
		double h, a, b, c;
		int I;

	public:
		Lorenz()
			{
				h = 0.001;
				a = 10.0;
				b = 28.0;
				c = 8.0 / 3.0;
			}

		/* rate is normalized (0 .. 1) */
		void set_rate (double r)
			{
				h = max (.0000001, r * .015);
			}

		void init (double _h = .001, double seed = .0)
			{
				I = 0;

				x[0] = .1 + seed - frandom() * .1;
				y[0] = 0;
				z[0] = 0;

				/* progress quickly to get a 'stable' system */
				h = .001;

				int n = 10000 + min ((int) (10000 * seed), 10000);
				for (int i = 0; i < n; ++i)
					step();

				h = _h;
			}

		sample_t get()
			{
				step();
				return .5 * get_y() + get_z();
			}

		void step()
			{
				int J = I ^ 1;

				x[J] = x[I] + h * a * (y[I] - x[I]);
				y[J] = y[I] + h * (x[I] * (b - z[I]) - y[I]);
				z[J] = z[I] + h * (x[I] * y[I] - c * z[I]);

				I = J;
			}

		double get_x()
			{
				return .024 * (x[I] - .172);
			}

		double get_y()
			{
				return .018 * (y[I] - .172);
			}

		double get_z()
			{
				return .019 * (z[I] - 25.43);
			}
};

} /* namespace DSP */

#endif /* _DSP_LORENZ_H_ */


code:
/*
	dsp/OnePole.h

	Copyright 2003-7 Tim Goetze <tim@quitte.de>

	http://quitte.de/dsp/

	one pole (or one zero, or one zero, one pole) hi- and lo-pass filters.

*/
/*
	This program is free software; you can redistribute it and/or
	modify it under the terms of the GNU General Public License
	as published by the Free Software Foundation; either version 2
	of the License, or (at your option) any later version.

	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	You should have received a copy of the GNU General Public License
	along with this program; if not, write to the Free Software
	Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
	02111-1307, USA or point your web browser to http://www.gnu.org.
*/

#ifndef _ONE_POLE_H_
#define _ONE_POLE_H_

namespace DSP {

class OnePoleLP
{
	public:
		sample_t a0, b1, y1;

		OnePoleLP (double d = 1.)
			{
				set (d);
				y1 = 0.;
			}

		inline void reset()
			{
				y1 = 0.;
			}

		inline void set_f (double fc)
			{
				set (exp (-2 * M_PI * fc));
			}

		inline void set (double d)
			{
				a0 = (sample_t) d;
				b1 = (sample_t) 1. - d;
			}

		inline sample_t process (sample_t x)
			{
				return y1 = a0 * x + b1 * y1;
			}

		inline void decay (double d)
			{
				a0 *= d;
				b1 = 1. - a0;
			}

		/* clear denormal numbers in history */
		void flush_0()
			{
				if (is_denormal (y1))
					y1 = 0;
			}
};

class OnePoleHP
{
	public:
		sample_t a0, a1, b1, x1, y1;

		OnePoleHP (double d = 1.)
			{
				set (d);
				x1 = y1 = 0.;
			}

		void set_f (double f)
			{
				set (exp (-2 * M_PI * f));
			}

		inline void set (double d)
			{
				a0 = (sample_t) ((1. + d) / 2.);
				a1 = (sample_t) ((1. + d) / -2.);
				b1 = d;
			}

		inline sample_t process (sample_t x)
			{
				y1 = a0 * x + a1 * x1 + b1 * y1;
				x1 = x;
				return y1;
			}

		void reset()
			{
				x1 = y1 = 0;
			}

		/* clear denormal numbers in history */
		void flush_0()
			{
				if (is_denormal (y1))
					y1 = 0;
			}
};

} /* namespace DSP */

#endif /* _ONE_POLE_H_ */


code:
/*
  dsp/RBJ.h

	Copyright
		1998 Robert Bristow-Johnson
		2004-10 Tim Goetze <tim@quitte.de>

	biquad prototypes according to the eq cookbook. easy-to-use, nice,
	predictable filters. thanks rbj!
*/
/*
	This program is free software; you can redistribute it and/or
	modify it under the terms of the GNU General Public License
	as published by the Free Software Foundation; either version 2
	of the License, or (at your option) any later version.

	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	You should have received a copy of the GNU General Public License
	along with this program; if not, write to the Free Software
	Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
	02111-1307, USA or point your web browser to http://www.gnu.org.
*/

#ifndef _DSP_RBJ_H_
#define _DSP_RBJ_H_

#include "BiQuad.h"

namespace DSP {
namespace RBJ {

/* base class, prepares common parameters */
class RBJ
{
	public:
		double Q, alpha, sin, cos;
		double a[3], b[3];

	public:
		RBJ (double f, double _Q)
			{
				Q = _Q;

				double w = 2 * M_PI * f;

				sin = ::sin (w);
				cos = ::cos (w);

				alpha = sin / (2 * Q);
			}

		/* templated so we can set double and float coefficients from the same
		 * piece of code */
		template <class T>
		void make_direct_I (T * ca, T * cb)
			{
				double a0i = 1 / a[0];

				ca[0] = b[0] * a0i;
				ca[1] = b[1] * a0i;
				ca[2] = b[2] * a0i;

				/* our bi-quad implementation /adds/ b[i] * y[i] so we need to
				 * toggle the sign for the b[] coefficients.
				 */
				cb[0] = 0;
				cb[1] = -a[1] * a0i;
				cb[2] = -a[2] * a0i;
			}
};

/* now the individual prototypes.
 * set-up is not optimal, i.e. does a lot of operations twice for readability.
 */
class LP
: public RBJ
{
	public:
		LP (double f, double Q, BiQuad & bq) : RBJ (f, Q)
			{ ab (bq.a, bq.b); }

		template <class T>
		LP (double f, double Q, T * ca, T * cb) : RBJ (f, Q)
			{ ab (ca, cb); }

		template <class T>
		void ab (T * ca, T * cb)
			{
				b[0] = (1 - cos) * .5;
				b[1] = (1 - cos);
				b[2] = (1 - cos) * .5;

				a[0] = 1 + alpha;
				a[1] = -2 * cos;
				a[2] = 1 - alpha;

				make_direct_I (ca, cb);
			}
};

class BP
: public RBJ
{
	public:
		BP (double f, double Q, BiQuad & bq) : RBJ (f, Q)
			{ ab (bq.a, bq.b); }

		template <class T>
		BP (double f, double Q, T * ca, T * cb) : RBJ (f, Q)
			{ ab (ca, cb); }

		template <class T>
		void ab (T * ca, T * cb)
			{
				b[0] = Q * alpha;
				b[1] = 0;
				b[2] = -Q * alpha;

				a[0] = 1 + alpha;
				a[1] = -2 * cos;
				a[2] = 1 - alpha;

				make_direct_I (ca, cb);
			}
};

class HP
: public RBJ
{
	public:
		HP (double f, double Q, BiQuad & bq) : RBJ (f, Q)
			{ ab (bq.a, bq.b); }

		template <class T>
		HP (double f, double Q, T * ca, T * cb) : RBJ (f, Q)
			{ ab (ca, cb); }

		template <class T>
		void ab (T * ca, T * cb)
			{
				b[0] =  (1 + cos) * .5;
				b[1] = -(1 + cos);
				b[2] =  (1 + cos) * .5;

				a[0] = 1 + alpha;
				a[1] = -2 * cos;
				a[2] = 1 - alpha;

				make_direct_I (ca, cb);
			}
};

class Notch
: public RBJ
{
	public:
		Notch (double f, double Q, BiQuad & bq) : RBJ (f, Q)
			{ ab (bq.a, bq.b); }

		template <class T>
		Notch (double f, double Q, T * ca, T * cb) : RBJ (f, Q)
			{ ab (ca, cb); }

		template <class T>
		void ab (T * ca, T * cb)
			{
				b[0] = 1;
				b[1] = -2 * cos;
				b[2] = 1;

				a[0] = 1 + alpha;
				a[1] = -2 * cos;
				a[2] = 1 - alpha;

				make_direct_I (ca, cb);
			}
};

/* shelving and peaking dept. ////////////////////////////////////////////// */

class PeakShelve
: public RBJ
{
	public:
		double A, beta;

	public:
		PeakShelve (double f, double Q, double dB)
			: RBJ (f, Q)
			{
				A = pow (10, dB * .025);
				double S = Q; /* slope */
				beta = sqrt ((A * A + 1) / S - (A - 1) * (A - 1));
			}
};

class LoShelve
: public PeakShelve
{
	public:
		LoShelve (double f, double Q, double dB, BiQuad & bq)
			: PeakShelve (f, Q, dB)
			{ ab (bq.a, bq.b); }

		template <class T>
		LoShelve (double f, double Q, double dB, T * ca, T * cb)
			: PeakShelve (f, Q, dB)
			{ ab (ca, cb); }

		template <class T>
		void ab (T * ca, T * cb)
			{
				double Ap1 = A + 1, Am1 = A - 1;
				double beta_sin = beta * sin;

				b[0] =     A * (Ap1 - Am1 * cos + beta_sin);
				b[1] = 2 * A * (Am1 - Ap1 * cos);
				b[2] =     A * (Ap1 - Am1 * cos - beta_sin);

				a[0] =          Ap1 + Am1 * cos + beta_sin;
				a[1] = -2 *    (Am1 + Ap1 * cos);
				a[2] =          Ap1 + Am1 * cos - beta_sin;

				make_direct_I (ca, cb);
			}
};

class PeakingEQ
: public PeakShelve
{
	public:
		PeakingEQ (double f, double Q, double dB, BiQuad & bq)
			: PeakShelve (f, Q, dB)
			{ ab (bq.a, bq.b); }

		template <class T>
		PeakingEQ (double f, double Q, double dB, T * ca, T * cb)
			: PeakShelve (f, Q, dB)
			{ ab (ca, cb); }

		template <class T>
		void ab (T * ca, T * cb)
			{
				b[0] = 1 + alpha * A;
				b[1] = -2 * cos;
				b[2] = 1 - alpha * A;

				a[0] = 1 + alpha / A;
				a[1] = -2 * cos;
				a[2] = 1 - alpha / A;

				make_direct_I (ca, cb);
			}
};

class HiShelve
: public PeakShelve
{
	public:
		HiShelve (double f, double Q, double dB, BiQuad & bq)
			: PeakShelve (f, Q, dB)
			{ ab (bq.a, bq.b); }

		template <class T>
		HiShelve (double f, double Q, double dB, T * ca, T * cb)
			: PeakShelve (f, Q, dB)
			{ ab (ca, cb); }

		template <class T>
		void ab (T * ca, T * cb)
			{
				double Ap1 = A + 1, Am1 = A - 1;
				double beta_sin = beta * sin;

				b[0] =      A * (Ap1 + Am1 * cos + beta_sin);
				b[1] = -2 * A * (Am1 + Ap1 * cos);
				b[2] =      A * (Ap1 + Am1 * cos - beta_sin);

				a[0] =           Ap1 - Am1 * cos + beta_sin;
				a[1] =  2 *     (Am1 - Ap1 * cos);
				a[2] =           Ap1 - Am1 * cos - beta_sin;

				make_direct_I (ca, cb);
			}
};

} /* ~namespace RBJ */
} /* ~namespace DSP */

#endif /* _DSP_RBJ_H_ */


code:
/*
	dsp/RMS.h

	Copyright 2004 Tim Goetze <tim@quitte.de>

	http://quitte.de/dsp/

	root-mean-square accumulator.

*/
/*
	This program is free software; you can redistribute it and/or
	modify it under the terms of the GNU General Public License
	as published by the Free Software Foundation; either version 2
	of the License, or (at your option) any later version.

	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	You should have received a copy of the GNU General Public License
	along with this program; if not, write to the Free Software
	Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
	02111-1307, USA or point your web browser to http://www.gnu.org.
*/

#ifndef _DSP_RMS_H_
#define _DSP_RMS_H_

namespace DSP {

class RMS
{
	protected:
		sample_t buffer[64];
		int write;

	public:
		double sum;

		RMS()
			{
				write = 0;
				reset();
			}

		void reset()
			{
				sum = 0.;
				memset (buffer, 0, sizeof (buffer));
			}

		/* caution: pass in the *squared* sample value */
		void store (sample_t x)
			{
				sum -= buffer[write];
				sum += (buffer[write] = x);
				write = (write + 1) & 63;
			}

		sample_t process (sample_t x)
			{
				store (x);
				return rms();
			}

		sample_t rms()
			{
				/* fabs it before sqrt, just in case ... */
				return sqrt (fabs (sum) / 64);
			}
};

} /* namespace DSP */

#endif /* _DSP_RMS_H_ */


code:
/*
	dsp/Roessler.h

	Copyright 2003-4 Tim Goetze <tim@quitte.de>

	http://quitte.de/dsp/

	Roessler fractal.

*/
/*
	This program is free software; you can redistribute it and/or
	modify it under the terms of the GNU General Public License
	as published by the Free Software Foundation; either version 2
	of the License, or (at your option) any later version.

	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	You should have received a copy of the GNU General Public License
	along with this program; if not, write to the Free Software
	Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
	02111-1307, USA or point your web browser to http://www.gnu.org.
*/

#ifndef _DSP_ROESSLER_H_
#define _DSP_ROESSLER_H_

namespace DSP {

class Roessler
{
	public:
		double x[2], y[2], z[2];
		double h, a, b, c;
		int I;

	public:
		Roessler()
			{
				h = 0.001;
				a = .2;
				b = .2;
				c = 5.7;
			}

		/* rate is normalized (0 .. 1) */
		void set_rate (double r)
			{
				h = max (.000001, r * .096);
			}

		void init (double _h = .001, double seed = .0)
			{
				h = _h;

				I = 0;

				x[0] = .0001 + .0001 * seed;
				y[0] = .0001;
				z[0] = .0001;

				for (int i = 0; i < 5000; ++i)
					get();
			}

		sample_t get()
			{
				int J = I ^ 1;

				x[J] = x[I] + h * (- y[I] - z[I]);
				y[J] = y[I] + h * (x[I] + a * y[I]);
				z[J] = z[I] + h * (b + z[I] * (x[I] - c));

				I = J;

				return x[I] * .01725 + z[I] * .015;
			}

		double get_x()
			{
				return x[I];
			}

		double get_y()
			{
				return y[I];
			}

		double get_z()
			{
				return z[I];
			}
};

} /* namespace DSP */

#endif /* _DSP_ROESSLER_H_ */


code:
/*
	dsp/SVF.h

	Copyright 2002-4 Tim Goetze <tim@quitte.de>

	http://quitte.de/dsp/

	ladder filter in Chamberlin topology. supports largely independent
	f and Q adjustments and sweeps.

*/
/*
	This program is free software; you can redistribute it and/or
	modify it under the terms of the GNU General Public License
	as published by the Free Software Foundation; either version 2
	of the License, or (at your option) any later version.

	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	You should have received a copy of the GNU General Public License
	along with this program; if not, write to the Free Software
	Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
	02111-1307, USA or point your web browser to http://www.gnu.org.
*/
/*
  inspired by this music-dsp entry:

	State Variable Filter (Double Sampled, Stable)
	Type : 2 Pole Low, High, Band, Notch and Peaking
	References :Posted by Andrew Simper

	Notes :
	Thanks to Laurent de Soras for the stability limit
	and Steffan Diedrichsen for the correct notch output.

	Code :
	input  = input buffer;
	output = output buffer;
	fs     = sampling frequency;
	fc     = cutoff frequency normally something like:
					 440.0*pow(2.0, (midi_note - 69.0)/12.0);
	res    = resonance 0 to 1;
	drive  = internal distortion 0 to 0.1
	freq   = MIN(0.25, 2.0*sin(PI*fc/(fs*2)));  // the fs*2 is because it's double sampled
	damp   = MIN(2.0*(1.0 - pow(res, 0.25)), MIN(2.0, 2.0/freq - freq*0.5));
	notch  = notch output
	low    = low pass output
	high   = high pass output
	band   = band pass output
	peak   = peaking output = low - high
	--
	double sampled svf loop:
	for (i=0; i<numSamples; i++)
	{
		in    = input[i];
		notch = in - damp*band;
		low   = low + freq*band;
		high  = notch - low;
		band  = freq*high + band - drive*band*band*band;
		out   = 0.5*(notch or low or high or band or peak);
		notch = in - damp*band;
		low   = low + freq*band;
		high  = notch - low;
		band  = freq*high + band - drive*band*band*band;
		out  += 0.5*(same out as above);
		output[i] = out;
	}
*/

#ifndef _DSP_SVF_H_
#define _DSP_SVF_H_

namespace DSP {

template <int OVERSAMPLE>
class SVF
{
	protected:
		/* loop parameters */
		sample_t f, q, qnorm;

		/* outputs (peak and notch left out) */
		sample_t lo, band, hi;
		sample_t * out;

	public:
		/* the type of filtering to do. */
		enum {
			Low = 0,
			Band = 1,
			High = 2
		};

		SVF()
			{
				set_out (Low);
				set_f_Q (.1, .1);
			}

		void reset()
			{
				hi = band = lo = 0;
			}

		void set_f_Q (double fc, double Q)
			{
				/* this is a very tight limit */
				f = min (.25, 2 * sin (M_PI * fc / OVERSAMPLE));

				q = 2 * cos (pow (Q, .1) * M_PI * .5);
				q = min (q, min (2., 2 / f - f * .5));
				qnorm = sqrt (fabs (q) / 2. + .001);
			}

		void set_out (int o)
			{
				if (o == Low)
					out = &lo;
				else if (o == Band)
					out = &band;
				else
					out = &hi;
			}

		void one_cycle (sample_t * s, int frames)
			{
				for (int i = 0; i < frames; ++i)
					s[i] = process (s[i]);
			}

		sample_t process (sample_t x)
			{
				x = qnorm * x;

				for (int pass = 0; pass < OVERSAMPLE; ++pass)
				{
					hi = x - lo - q * band;
					band += f * hi;
					lo += f * band;

					/* zero-padding, not 0th order holding. */
					x = 0;
				}

				/* peak and notch outputs don't belong in the loop, put them
				 * here (best in a template) if needed. */

				return *out;
			}
};

template <int STACKED, int OVERSAMPLE>
class StackedSVF
{
	public:
		SVF<OVERSAMPLE> svf [STACKED];

		void reset()
			{
				for (int i = 0; i < STACKED; ++i)
					svf[i].reset();
			}

		void set_out (int out)
			{
				for (int i = 0; i < STACKED; ++i)
					svf[i].set_out (out);
			}

		void set_f_Q (double f, double Q)
			{
				for (int i = 0; i < STACKED; ++i)
					svf[i].set_f_Q (f, Q);
			}

		sample_t process (sample_t x)
			{
				for (int i = 0; i < STACKED; ++i)
					x = svf[i].process (x);

				return x;
			}
};

} /* namespace DSP */

#endif /* _DSP_SVF_H_ */


code:
/*
	dsp/Sine.h

	Copyright 2003-4 Tim Goetze <tim@quitte.de>

	http://quitte.de/dsp/

	direct form I recursive sin() generator.

*/
/*
	This program is free software; you can redistribute it and/or
	modify it under the terms of the GNU General Public License
	as published by the Free Software Foundation; either version 2
	of the License, or (at your option) any later version.

	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	You should have received a copy of the GNU General Public License
	along with this program; if not, write to the Free Software
	Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
	02111-1307, USA or point your web browser to http://www.gnu.org.
*/

#ifndef _DSP_SINE_H_
#define _DSP_SINE_H_

namespace DSP {

class Sine
{
	protected:
		int z;
		double y[2];
		double b;

	public:
		Sine()
			{
				b = 0;
				y[0] = y[1] = 0;
				z = 0;
			}

		Sine (double f, double fs, double phase)
			{
				set_f (f, fs, phase);
			}

		Sine (double omega, double phase = 0.)
			{
				set_f (omega, phase);
			}

		inline void set_f (double f, double fs, double phase)
			{
				set_f (f * M_PI / fs, phase);
			}

		inline void set_f (double w, double phase)
			{
				b = 2 * cos (w);
				y[0] = sin (phase - w);
				y[1] = sin (phase - w * 2);
				z = 0;
			}

		/* advance and return 1 sample */
		inline double get()
			{
				register double s = b * y[z];
				z ^= 1;
				s -= y[z];
				return y[z] = s;
			}

		double get_phase()
			{
				double x0 = y[z], x1 = b * y[z] - y[z^1];
				double phi = asin (x0);

				/* slope is falling, we're into the 2nd half. */
				if (x1 < x0)
					return M_PI - phi;

				return phi;
			}
};

} /* namespace DSP */

#endif /* _DSP_SINE_H_ */


code:
/*
	TDFII.h

	Copyright 2006-7
		David Yeh <dtyeh@ccrma.stanford.edu> (implementation)
		Tim Goetze <tim@quitte.de> (cosmetics)

	transposed Direct Form II digital filter.
	Assumes order of b = order of a.
	Assumes a0 = 1.

*/
/*
	This program is free software; you can redistribute it and/or
	modify it under the terms of the GNU General Public License
	as published by the Free Software Foundation; either version 2
	of the License, or (at your option) any later version.

	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	You should have received a copy of the GNU General Public License
	along with this program; if not, write to the Free Software
	Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
	02111-1307, USA or point your web browser to http://www.gnu.org.
*/

#ifndef _DSP_TDFII_H_
#define _DSP_TDFII_H_

namespace DSP {

// ORDER is the highest power of s in the transfer function
template <int Order>
class TDFII
{
	public:
		double a[Order + 1];
		double b[Order + 1];
		double h[Order + 1];

		void reset()
			{
				for (int i = 0; i <= Order; ++i)
					h[i] = 0;   // zero state
			}

		void init (double fs)
			{
				reset();
				clear();
			}

		void clear()
			{
				for (int i=0; i<= Order; i++)
						a[i] = b[i] = 1;
			}

		/* per-band recursion:
		 * 	y = 2 * (a * (x - x[-2]) + c * y[-1] - b * y[-2])
		 */
		sample_t process (sample_t s)
			{
				double y = h[0] + b[0] * s;

				for (int i = 1; i < Order; ++i)
						h[i - 1] = h[i] + b[i] * s - a[i] * y;

				h[Order - 1] = b[Order] * s - a[Order] * y;

				return (sample_t) y;
			}
};

} /* namespace DSP */

#endif /* _DSP_TDFII_H_ */


code:
/*
	ToneStack.h

	Copyright 2006-9
		David Yeh <dtyeh@ccrma.stanford.edu> (implementation)
		Tim Goetze <tim@quitte.de> (cosmetics)

	Tone Stack emulation.

*/
/*
	This program is free software; you can redistribute it and/or
	modify it under the terms of the GNU General Public License
	as published by the Free Software Foundation; either version 2
	of the License, or (at your option) any later version.

	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	You should have received a copy of the GNU General Public License
	along with this program; if not, write to the Free Software
	Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
	02111-1307, USA or point your web browser to http://www.gnu.org.
*/

#ifndef _DSP_TONESTACK_H_
#define _DSP_TONESTACK_H_

#include "util.h"
#include "windows.h"
#include "TDFII.h"
#include "LatFilt.h"
#include "tonestack/tables.h"

namespace DSP {

typedef struct {
	double R1, R2, R3, R4;
	double C1, C2, C3;
} TSParameters;

#define TS_N_PRESETS (sizeof (DSP::ToneStack::presets) / \
				sizeof (DSP::TSParameters))

class ToneStack
{
  private:
		enum { Order = 3 };

		double c;   // BT coef

		double b1t, b1m, b1l, b1d,
				b2t, b2m2, b2m, b2l, b2lm, b2d,
				b3lm, b3m2, b3m, b3t, b3tm, b3tl,
				a0, a1d, a1m, a1l, a2m, a2lm, a2m2, a2l, a2d,
				a3lm, a3m2, a3m, a3l, a3d;      // intermediate calculations

		struct {
				double b1;
				double b2;
				double b3;
				double a1;
				double a2;
				double a3;
		} acoef; // analog coefficients

		// digital coefficients
		double dcoef_a[Order + 1];
		double dcoef_b[Order + 1];

		TDFII<Order> filter;

	public:
		int model;

		static TSParameters presets[]; /* in ../ToneStack.cc */
		static int n_presets;

		ToneStack()
			{
				model = -1;
				setparams (presets[0]);
			}

		void init (double _fs)
			{
				c = 2 * _fs;
			}

		void activate (sample_t ** ports)
			{
				filter.reset();
			}

		/* pass in pointer to ports and relative index of first eq band control */
		void start_cycle (sample_t ** ports, int bassindex = 1)
		{
			int m = clamp<int> ((int) *ports[0], 0, n_presets - 1);
			if (m != model)
			{
				model = m;
				setparams (presets[model]);
				filter.reset();
			}
			updatecoefs (ports + bassindex);
		}

		void setparams (TSParameters & p)
			{
				double R1 = p.R1, R2 = p.R2, R3 = p.R3, R4 = p.R4;
				double C1 = p.C1, C2 = p.C2, C3 = p.C3;

				b1t  = C1*R1;
				b1m  = C3*R3;
				b1l  = C1*R2 + C2*R2;
				b1d  = C1*R3 + C2*R3;
				b2t  = C1*C2*R1*R4 + C1*C3*R1*R4;
				b2m2 = -(C1*C3*R3*R3 + C2*C3*R3*R3);
				b2m  = C1*C3*R1*R3 + C1*C3*R3*R3 + C2*C3*R3*R3;
				b2l  = C1*C2*R1*R2 + C1*C2*R2*R4 + C1*C3*R2*R4;
				b2lm = C1*C3*R2*R3 + C2*C3*R2*R3;
				b2d  = C1*C2*R1*R3 + C1*C2*R3*R4 + C1*C3*R3*R4;
				b3lm = C1*C2*C3*R1*R2*R3 + C1*C2*C3*R2*R3*R4;
				b3m2 = -(C1*C2*C3*R1*R3*R3 + C1*C2*C3*R3*R3*R4);
				b3m  = C1*C2*C3*R1*R3*R3 + C1*C2*C3*R3*R3*R4;
				b3t  = C1*C2*C3*R1*R3*R4;
				b3tm = -b3t;
				b3tl = C1*C2*C3*R1*R2*R4;
				a0   = 1;
				a1d  = C1*R1 + C1*R3 + C2*R3 + C2*R4 + C3*R4;
				a1m  = C3*R3;
				a1l  = C1*R2 + C2*R2;
				a2m  = C1*C3*R1*R3 - C2*C3*R3*R4 + C1*C3*R3*R3 + C2*C3*R3*R3;
				a2lm = C1*C3*R2*R3 + C2*C3*R2*R3;
				a2m2 = -(C1*C3*R3*R3 + C2*C3*R3*R3);
				a2l  = C1*C2*R2*R4 + C1*C2*R1*R2 + C1*C3*R2*R4 + C2*C3*R2*R4;
				a2d  = C1*C2*R1*R4 + C1*C3*R1*R4 + C1*C2*R3*R4
						+ C1*C2*R1*R3 + C1*C3*R3*R4 + C2*C3*R3*R4;
				a3lm = C1*C2*C3*R1*R2*R3 + C1*C2*C3*R2*R3*R4;
				a3m2 = -(C1*C2*C3*R1*R3*R3 + C1*C2*C3*R3*R3*R4);
				a3m  = C1*C2*C3*R3*R3*R4 + C1*C2*C3*R1*R3*R3 - C1*C2*C3*R1*R3*R4;
				a3l  = C1*C2*C3*R1*R2*R4;
				a3d  = C1*C2*C3*R1*R3*R4;

				filter.reset();
			}

		inline void updatecoefs (sample_t ** ports)
			{
				/* range checks on input */
				double b = clamp<double> (*ports[0], 0, 1);
				double m = clamp<double> (*ports[1], 0, 1);
				double t = clamp<double> (*ports[2], 0, 1);

				m = (m - 1) * 3.5;
				m = pow (10, m);

				acoef.a1 = a1d + m*a1m + b*a1l;
				acoef.a2 = m*a2m + b*m*a2lm + m*m*a2m2 + b*a2l + a2d;
				acoef.a3 = b*m*a3lm + m*m*a3m2 + m*a3m + b*a3l + a3d;
				dcoef_a[0] = -1 - acoef.a1*c - acoef.a2*c*c - acoef.a3*c*c*c; // sets scale
				dcoef_a[1] = -3 - acoef.a1*c + acoef.a2*c*c + 3*acoef.a3*c*c*c;
				dcoef_a[2] = -3 + acoef.a1*c + acoef.a2*c*c - 3*acoef.a3*c*c*c;
				dcoef_a[3] = -1 + acoef.a1*c - acoef.a2*c*c + acoef.a3*c*c*c;

				acoef.b1 = t*b1t + m*b1m + b*b1l + b1d;
				acoef.b2 = t*b2t + m*m*b2m2 + m*b2m + b*b2l + b*m*b2lm + b2d;
				acoef.b3 = b*m*b3lm + m*m*b3m2 + m*b3m + t*b3t + t*m*b3tm + t*b*b3tl;
				dcoef_b[0] = - acoef.b1*c - acoef.b2*c*c - acoef.b3*c*c*c;
				dcoef_b[1] = - acoef.b1*c + acoef.b2*c*c + 3*acoef.b3*c*c*c;
				dcoef_b[2] = acoef.b1*c + acoef.b2*c*c - 3*acoef.b3*c*c*c;
				dcoef_b[3] = acoef.b1*c - acoef.b2*c*c + acoef.b3*c*c*c;

				for (int i=1; i<=3; ++i)
					filter.a[i] = dcoef_a[i] / dcoef_a[0];

				for (int i=0; i<=3; ++i)
					filter.b[i] = dcoef_b[i] / dcoef_a[0];
			}

		// actualy do the DFII filtering, one sample at a time
		inline sample_t process (sample_t x)
			{
				return filter.process (x);
			}
};

/* /////////////////////////////////////////////////////////////////////// */

/*
	hardcode this, known size memory blocks
	extern double* KS;    // 25 x 25 x 3
	extern double* VS;    // 25 x 25 x 25 x 4
	extern double KS[NSTEPS][NSTEPS][TSORDER]; //[bass][mid][coefs]
	extern double VS[NSTEPS][NSTEPS][NSTEPS][TSORDER+1]; //[bass][mid][treb][coefs]
 */

class ToneStackLT
{
  private:
		enum { Order = 3, Steps = 25 };

		// digital coefficients
		double *kcoef;
		double *vcoef;
		LatFilt<Order> filter;

	public:
		ToneStackLT()
			{
				setparams (250000, 1000000, 25000, 56000, 0.25e-9, 20e-9, 20e-9);
			}

		void init (double _fs)
			{ }

		void activate (sample_t ** ports)
			{
				filter.reset();
			}

		void setparams
			(double R1, double R2, double R3, double R4,
							double C1, double C2, double C3) {
		}

		void updatecoefs (sample_t ** ports)
			{
				double b = min (Steps - 1, max (*ports[0] * (Steps - 1), 0));
				double m = min (Steps - 1, max (*ports[1] * (Steps - 1), 0));
				double t = min (Steps - 1, max (*ports[2] * (Steps - 1), 0));

				int bi = (int) b;
				int mi = (int) m;
				int ti = (int) t;

				kcoef = DSP::ToneStackKS +  (mi * Steps + bi) * Order;
				vcoef = DSP::ToneStackVS + ((mi * Steps + bi) * Steps + ti) * (Order + 1);

				for (int i = 0; i < Order; ++i)
						filter.set_ki (kcoef[i], i);

				for (int i = 0; i < Order + 1; ++i)
						filter.set_vi (vcoef[i], i);
			}

		// actualy do the DFII filtering, one sample at a time
		inline sample_t process (sample_t x)
			{
				return filter.process (x);
			}
};

} /* namespace DSP */

#endif /* _DSP_TONESTACK_H_ */


code:
/*
	dsp/TwelveAX7.h

	Copyright 2003-6 Tim Goetze <tim@quitte.de>

	http://quitte.de/dsp/

	collection of approximations of the 12AX7 voltage transfer function
*/
/*
	This program is free software; you can redistribute it and/or
	modify it under the terms of the GNU General Public License
	as published by the Free Software Foundation; either version 2
	of the License, or (at your option) any later version.

	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	You should have received a copy of the GNU General Public License
	along with this program; if not, write to the Free Software
	Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
	02111-1307, USA or point your web browser to http://www.gnu.org.
*/

#ifndef _DSP_TWELVE_AX_7_H_
#define _DSP_TWELVE_AX_7_H_

namespace DSP {

#include "r12ax7.h"

typedef sample_t tube_sample;

/* this is the original tube model from caps < 0.1.9 or preamp.so, put
 * back into use in 0.1.11; the replacement (below) is too strong in
 * odd-order harmonics at the expense of even-order. it has to sound
 * good: it took a good deal of fiddling to get the coefficients right.
 */
class TwelveAX7
{
	public:
		tube_sample b, c, d;

		struct {
			tube_sample threshold, value;
		} clip[2];

		/* amplitude at which clipping starts */
		tube_sample scale;

	public:
		TwelveAX7()
			{
				/* transfer polynomial parameters */
				b = -0.79618574210627535;
				c = -0.21108555430962023;
				d = +0.38944033523200522;

				set_clips();

				scale = min (fabs (clip[0].threshold), fabs (clip[1].threshold));
			}

		inline tube_sample transfer (tube_sample a)
			{
				return a * (b + a * (c + a * d));
			}

		inline tube_sample transfer_clip (tube_sample a)
			{
				if (a <= clip[0].threshold)
					return clip[0].value;
				if (a >= clip[1].threshold)
					return clip[1].value;
				return transfer (a);
			}

		inline double get_root (double sign)
			{
				/* only once, no need to optimize */
				return
					(-2*c + sign * sqrt ((2*c) * (2*c) - 4 * (3 * d * b))) / (6 * d);
			}

		inline void set_clips()
			{
				/* find 0 crossings in the derived, this is where we'll clip */
				double x0 = get_root (-1);
				double x1 = get_root (+1);

				clip[0].value = transfer (x0);
				clip[1].value = transfer (x1);

				clip[0].threshold = x0;
				clip[1].threshold = x1;
			}
};

/* reworked model. higher order (than 3) polynomials make little sense;
 * sonically the difference is minim, and the cycle count increases
 * dramatically.
 */
class TwelveAX7_2
{
	public:
		tube_sample b, c, d;

		struct {
			tube_sample threshold, value;
		} clip[2];

		tube_sample scale;

	public:
		TwelveAX7_2()
			{
				/* transfer polynomial parameters, made with gnuplot::fit() */
				b = -1.08150605597883;
				c = -0.262760944760536;
				d = 0.445770802765903;

				static double x[2] = {-.52, +.98};

				for (int i = 0; i < 2; ++i)
					clip[i].threshold = x[i],
					clip[i].value = transfer (x[i]);

				scale = min (fabs (clip[0].threshold), fabs (clip[1].threshold));
			}

		inline tube_sample transfer (tube_sample a)
			{
				return a * (b + a * (c + a * d));
			}

		inline tube_sample transfer_clip (tube_sample a)
			{
				if (a <= clip[0].threshold)
					return clip[0].value;
				if (a >= clip[1].threshold)
					return clip[1].value;
				return transfer (a);
			}
};

/* third model relies on linear interpolation based on the transfer function
 * as calculated from a spice model.
 */
class TwelveAX7_3
{
	public:
		tube_sample b, c, d;

		struct {
			tube_sample threshold, value;
		} clip[2];

		tube_sample scale;

	public:
		TwelveAX7_3()
			{
				static double x[2] =
					{
						(double) r12AX7::Zero /
								((double) r12AX7::Samples - (double) r12AX7::Zero),
						1
					};

				for (int i = 0; i < 2; ++i)
					clip[i].threshold = x[i],
					clip[i].value = transfer (x[i]);

				scale = min (fabs (clip[0].threshold), fabs (clip[1].threshold));
			}

		inline tube_sample transfer (tube_sample a)
			{
				a = r12AX7::Zero + a * (r12AX7::Samples - r12AX7::Zero);
				if (a <= 0)
					return r12AX7::v2v[0];
				if (a >= r12AX7::Samples - 1)
					return r12AX7::v2v [r12AX7::Samples - 1];

				/* linear interpolation from sampled function */
				register int i = lrintf (a);
				a -= i;

				return (r12AX7::v2v [i] * (1.f - a) + r12AX7::v2v [i + 1] * a);
			}

		inline tube_sample transfer_clip (tube_sample a)
			{
				return transfer (a);
			}
};

/* experimental */
class NoTwelveAX7
{
	public:
		struct {
			tube_sample threshold, value;
		} clip[2];

		/* amplitude at which clipping starts */
		tube_sample scale;

	public:
		NoTwelveAX7()
			{
				static double x[2] = { -1, 1 };

				for (int i = 0; i < 2; ++i)
					clip[i].threshold = x[i],
					clip[i].value = transfer (x[i]);

				scale = min (fabs (clip[0].threshold), fabs (clip[1].threshold));
			}

		inline tube_sample transfer (tube_sample a)
			{
				return 0.5469181606780 * (pow (1 - a, 1.5) - 1);
			}

		inline tube_sample transfer_clip (tube_sample a)
			{
				if (a <= clip[0].threshold)
					return clip[0].value;
				if (a >= clip[1].threshold)
					return clip[1].value;
				return transfer (a);
			}
};

} /* namespace DSP */

#endif /* _DSP_TWELVE_AX_7_H_ */


code:
/*
  dsp/VCO.h

	Copyright 2004, 2010 Tim Goetze <tim@quitte.de>

	oscillators for triangle/sawtooth/square waves, and a combination
	for detuning and hard sync.

	NB: these oscillators are *not* bandlimited. oversample if needed.

 */
/*
	This program is free software; you can redistribute it and/or
	modify it under the terms of the GNU General Public License
	as published by the Free Software Foundation; either version 2
	of the License, or (at your option) any later version.

	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	You should have received a copy of the GNU General Public License
	along with this program; if not, write to the Free Software
	Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
	02111-1307, USA or point your web browser to http://www.gnu.org.
*/

#ifndef _DSP_VCO_H_
#define _DSP_VCO_H_

namespace DSP {

/* variable triangle to sawtooth generator. you can use two of these to
 * generate a square, but we prefer the integrated solution below.
 */
class TriSaw
{
	public:
		/* doubles for maximum stability */
		double phase, inc;

		double tri, tri1, tri2;

	public:
		TriSaw()
			{
				phase = 0;
				tri = .5;
			}

		inline void set_f (double f, double fs)
			{
				set_inc (f / fs);
			}

		inline void set_inc (double i)
			{
				inc = i;
			}

		/* 0: triangle, 1: saw */
		inline void set_saw (double t)
			{
				tri = .5 + .5 * t;
				tri1 = 2. / tri;
				tri2 = 2. / (1 - tri);
			}

		/* advance and return 1 sample.
		 * many conditionals, but quicker than a solution based on fmod()
		 */
		inline float get()
			{
				phase += inc;

				/* the good thing is that tri is always > .5, which implies
				 * that this first conditional is true more often than not. */
				if (phase <= tri)
					return -1 + phase * tri1;
				if (phase < 1)
					return 1 - (phase - tri) * tri2;

				phase -= 1;
				return -1 + phase * tri1;
			}
};

/* variable triangle to sawtooth to square generator */
class TriSawSquare
{
	public:
		/* doubles for maximum stability, using floats here increases
		 * cycle need on my athlon */
		double phase, inc;
		double * sync;

		float sync_phase;

		/* using doubles here increases cycle need significantly */
		float square_i;
		float tri, tri1, tri2;
		float st1, st2;

	public:
		TriSawSquare()
			{
				reset();
			}

		void reset()
			{
				phase = 0;
				sync = &phase;
				sync_phase = 0;
				set_saw_square (.5, .5);
			}

		inline void set_f (double f, double fs)
			{
				set_inc (f / fs);
			}

		inline void set_inc (double i)
			{
				inc = i;
			}

		inline void set_sync (TriSawSquare & tss, float p)
			{
				sync = &tss.phase;
				sync_phase = p;
			}

		/* t = 0: tri     - 1: saw,
		 * s = 0: tri/saw - 1: square
		 */
		inline void set_saw_square (float t, float s)
			{
				tri = .5 + .5 * t;
				square_i = 1 - s;

				float si2 = 2 * square_i;
				float one_m_t = 1 - tri;

				tri1 = si2 / tri;
				tri2 = si2 / one_m_t;

				st1 = s * one_m_t;
				st2 = s * tri;
			}

		/* advance and return 1 sample.
		 * many branching instructions but on this intel chip faster than
		 * a version using floor() to keep the phase within [0..1].
		 */
		inline float get()
			{
				phase += inc;

				if (phase <= tri)
					first_half:
					/* raw version:
					return (1 - square) * (-1 + phase * 2 / tri) - square * (1 - tri);
					 */
					return -square_i + phase * tri1 - st1;

				if (phase < 1)
					/* raw version:
					return (1 - square) * (1 - (phase - tri) * 2 / (1 - tri)) + square * tri;
					 */
					return square_i - (phase - tri) * tri2 + st2;

				phase -= 1;
				*sync = phase + sync_phase;
				goto first_half;
			}
};

class VCO2
{
	public:
		TriSawSquare vco[2];
		float blend, i_blend;

	public:
		VCO2()
			{
				set_blend (.5);
			}

		void reset()
			{
				set_blend (.5);
				vco[0].reset();
				vco[1].reset();
			}

		void set_f (double f, double fs, double detune)
			{
				vco[0].set_f (f, fs);
				vco[1].set_f (f * pow (2, detune / 12.), fs);
			}

		inline void set_blend (float b)
			{
				blend = b;
				i_blend = 1 - fabs (b);
			}

		inline void set_sync (float sync)
			{
				vco[0].set_sync (sync ? vco[1] : vco[0], sync);
			}

		inline float get()
			{
				return vco[0].get() * blend + vco[1].get() * i_blend;
			}
};

} /* namespace DSP */

#endif /* _DSP_VCO_H_ */


code:
/*
  dsp/White.h

	Copyright 2004 Tim Goetze <tim@quitte.de>

	simple white noise generator, based on Jon Dattorro's 3/2002 JAES
	paper. quite an elegant design; consumes next to no CPU	on a processor
	providing a decent binary shift operator. most of all, no random() calls.

*/
/*
	This program is free software; you can redistribute it and/or
	modify it under the terms of the GNU General Public License
	as published by the Free Software Foundation; either version 2
	of the License, or (at your option) any later version.

	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	You should have received a copy of the GNU General Public License
	along with this program; if not, write to the Free Software
	Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
	02111-1307, USA or point your web browser to http://www.gnu.org.
*/

#ifndef _DSP_WHITE_H_
#define _DSP_WHITE_H_

namespace DSP {

/* after initializing, call either get() or get_31() to get a sample, don't
 * mix them. (get_31 output goes out of range if called after get()).
 */
class White
{
	public:
		uint32 b;

		White()
			{
				b = 0x1fff7777;
			}

		void init (float f)
			{
				b = (uint32) (f * (float) 0x1fff7777);
			}

		sample_t abs()
			{
				return fabs (get());
			}

		/* 32-bit version */
		sample_t get()
			{
#				define BIT(y) ((b << (31 - y)) & 0x80000000)

				b = ((BIT (28) ^ BIT (27) ^ BIT (1) ^ BIT (0))) | (b >> 1);
				return (4.6566128730773926e-10 * (sample_t) b) - 1;

#				undef BIT
			}

		/* 31-bit version, at least 6 instructions less / sample. probably only
		 * pays off on a processor not providing a decent binary shift. */
		sample_t get_31()
			{
#				define BIT(y) ((b << (30 - y)) & 0x40000000)

				b = ((BIT (3) ^ BIT (0))) | (b >> 1);
				return (9.3132257461547852e-10 * (sample_t) b) - 1;

#				undef BIT
			}
};

} /* namespace DSP */

#endif /* _DSP_WHITE_H_ */


code:
/*
	dsp/sinc.h

	Copyright 2003-4 Tim Goetze <tim@quitte.de>

	http://quitte.de/dsp/

	computes the sinc function: sin (x * pi) / (x * pi).

*/
/*
	This program is free software; you can redistribute it and/or
	modify it under the terms of the GNU General Public License
	as published by the Free Software Foundation; either version 2
	of the License, or (at your option) any later version.

	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	You should have received a copy of the GNU General Public License
	along with this program; if not, write to the Free Software
	Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
	02111-1307, USA or point your web browser to http://www.gnu.org.
*/

#ifndef _SINC_H_
#define _SINC_H_

#include "Sine.h"

namespace DSP {

/* sample sinc() with step size omega into s[], centered around s + n / 2 */

inline void
sinc (double omega, sample_t * s, int n)
{
	/* initial phase */
	double phi = (n / 2) * -omega;

	Sine sine (omega, phi);

	for (int i = 0; i < n; ++i, phi += omega)
	{
		double sin_phi = sine.get();

		if (fabs (phi) < 0.000000001)
			s[i] = 1.;
		else
			s[i] = sin_phi / phi;
	}
}

}; /* namespace DSP */

#endif /* _SINC_H_ */


code:
/*
  ks_tab.h

	Copyright 2006 David Yeh <dtyeh@ccrma.stanford.edu>

	http://quitte.de/dsp/

	Tone Stack emulation coefficient table for lattice filter.

*/
/*
	This program is free software; you can redistribute it and/or
	modify it under the terms of the GNU General Public License
	as published by the Free Software Foundation; either version 2
	of the License, or (at your option) any later version.

	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	You should have received a copy of the GNU General Public License
	along with this program; if not, write to the Free Software
	Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
	02111-1307, USA or point your web browser to http://www.gnu.org.
*/

#ifndef _TS_TABLES_H_
#define _TS_TABLES_H_

namespace DSP {

extern double ToneStackKS[];
extern double ToneStackVS[];

} /* namespace DSP */

#endif /* _TS_TABLES_H_ */


code:
/*
	dsp/util.h

	Copyright 2002-4 Tim Goetze <tim@quitte.de>

	http://quitte.de/dsp/

	Common math utility functions.

*/
/*
	This program is free software; you can redistribute it and/or
	modify it under the terms of the GNU General Public License
	as published by the Free Software Foundation; either version 2
	of the License, or (at your option) any later version.

	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	You should have received a copy of the GNU General Public License
	along with this program; if not, write to the Free Software
	Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
	02111-1307, USA or point your web browser to http://www.gnu.org.
*/

#ifndef _DSP_UTIL_H_
#define _DSP_UTIL_H_

namespace DSP {

inline int next_power_of_2 (int n)
{
	assert (n <= 0x40000000);

	int m = 1;

	while (m < n)
		m <<= 1;

	return m;
}

inline bool
isprime (int v)
{
	if (v <= 3)
		return true;

	if (!(v & 1))
		return false;

	for (int i = 3; i < (int) sqrt (v) + 1; i += 2)
		if ((v % i) == 0)
			return false;

	return true;
}

inline double
db2lin (double db)
{
	return pow (10., db * .05);
}

inline double
lin2db (double lin)
{
	return 20. * log10 (lin);
}

} /* namespace DSP */

#endif /* _DSP_UTIL_H_ */


code:
/*
	dsp/windows.h

	Copyright 2004-11 Tim Goetze <tim@quitte.de>

	http://quitte.de/dsp/

	select few common windowing algorithms.

*/
/*
	This program is free software; you can redistribute it and/or
	modify it under the terms of the GNU General Public License
	as published by the Free Software Foundation; either version 2
	of the License, or (at your option) any later version.

	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	You should have received a copy of the GNU General Public License
	along with this program; if not, write to the Free Software
	Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
	02111-1307, USA or point your web browser to http://www.gnu.org.
*/

#ifndef _DSP_WINDOWS_H_
#define _DSP_WINDOWS_H_

namespace DSP {

/* prototypes for window value application ... */
typedef void (*window_sample_func_t) (sample_t &, sample_t);

/* ... which go as template parameters for the window calculation below */
inline void
store_sample (sample_t & d, sample_t s)
{
	d = s;
}

inline void
apply_window (sample_t &d, sample_t s)
{
	d *= s;
}

template <window_sample_func_t F>
void
hanning (sample_t * s, int n)
{
	/* could speed up by using DSP::Sine but we rarely use this window */
	for (int i = 0; i < n; ++i)
	{
		register double f = (double) i / n - 1;
		F (s[i], .5 - .5 * cos (2 * M_PI * f));
	}
}

template <window_sample_func_t F>
void
blackman (sample_t * s, int n)
{
	register float w = n;

	for (int i = 0; i < n; ++i)
	{
		register float f = (float) i;

		register double b = .42f -
						.5f * cos (2.f * f * M_PI / w) +
						.08 * cos (4.f * f * M_PI / w);

		F (s[i], b);
	}
}

template <window_sample_func_t F>
void
blackman_harris (sample_t * s, int n)
{
	register double w1 = 2.f * M_PI / (n - 1);
	register double w2 = 2.f * w1;
	register double w3 = 3.f * w1;

	for (int i = 0; i < n; ++i)
	{
		register double f = (double) i;

		register double bh = .35875f -
				.48829f * cos (w1 * f) +
				.14128f * cos (w2 * f) -
				.01168f * cos (w3 * f);

		bh *= .761f;

		F (s[i], bh);
	}
}

/* helper for the kaiser window, courtesy of R. Dobson, courtesy of csound */
inline double
besseli (double x)
{
	double ax, ans;
	double y;

	if ((ax = fabs (x)) < 3.75)
	{
		y = x / 3.75;
		y *= y;
		ans = (1.0 + y * (3.5156229 +
			y * (3.0899424 +
				y * (1.2067492 +
					y * (0.2659732 +
						y * (0.360768e-1 +
							y * 0.45813e-2))))));
	}
	else
	{
		y = 3.75 / ax;
		ans = ((exp (ax) / sqrt (ax))
			* (0.39894228 +
				y * (0.1328592e-1 +
					y * (0.225319e-2 +
						y * (-0.157565e-2 +
							y * (0.916281e-2 +
								y * (-0.2057706e-1 +
									y * (0.2635537e-1 +
										y * (-0.1647633e-1 +
											y * 0.392377e-2)))))))));
	}

	return ans;
}

template <window_sample_func_t F>
void
kaiser (sample_t * s, int n, double beta)
{
	double bb = besseli (beta);
	int si = 0;

	for (double i = -n / 2 + .1; si < n; ++si, ++i)
	{
		double k = besseli ((beta * sqrt (1 - pow ((2 * i / (n - 1)), 2)))) / bb;

		/* can you spell hack */
		if (!isfinite (k) || isnan(k))
			k = 0;

		F (s[si], k);
	}
	/* asymmetrical hack: sort out first value!
	win[0] = win[len-1];
	*/
}

}; /* namespace DSP */

#endif /* _DSP_WINDOWS_H_ */


code:
/*
  interface.cc

	Copyright 2004-11 Tim Goetze <tim@quitte.de>

	http://quitte.de/dsp/

	LADSPA descriptor factory, host interface.

*/
/*
	This program is free software; you can redistribute it and/or
	modify it under the terms of the GNU General Public License
	as published by the Free Software Foundation; either version 2
	of the License, or (at your option) any later version.

	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	You should have received a copy of the GNU General Public License
	along with this program; if not, write to the Free Software
	Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
	02111-1307, USA or point your web browser to http://www.gnu.org.
*/
/*
	LADSPA ID ranges 1761 - 1800 and 2581 - 2660
	(2541 - 2580 donated to artemio@kdemail.net)
*/

#include <sys/time.h>

#include "basics.h"

#include "Cabinet.h"
#include "Chorus.h"
#include "Phaser.h"
#include "Sin.h"
#include "Lorenz.h"
#include "Roessler.h"
#include "Reverb.h"
#include "Compress.h"
#include "Click.h"
#include "Eq.h"
#include "Clip.h"
#include "White.h"
#include "SweepVF.h"
#include "VCO.h"
#include "Amp.h"
#include "HRTF.h"
#include "Pan.h"
#include "Scape.h"
#include "ToneStack.h"

#include "Descriptor.h"

#define N 39
static DescriptorStub * descriptors [N];

/*static inline void
seed()
{
	static struct timeval tv;
  gettimeofday (&tv, 0);

	srand (tv.tv_sec ^ tv.tv_usec);
}*/

extern "C" {

__attribute__ ((constructor))
void caps_so_init()
{
	DescriptorStub ** d = descriptors;

	*d++ = new Descriptor<Eq>();
	*d++ = new Descriptor<Eq2x2>();
	*d++ = new Descriptor<Compress>();
	*d++ = new Descriptor<Pan>();
	*d++ = new Descriptor<Narrower>();

	*d++ = new Descriptor<PreampIII>();
	*d++ = new Descriptor<PreampIV>();
	*d++ = new Descriptor<ToneStack>();
	*d++ = new Descriptor<ToneStackLT>();
	*d++ = new Descriptor<AmpIII>();
	*d++ = new Descriptor<AmpIV>();
	*d++ = new Descriptor<AmpV>();
	*d++ = new Descriptor<AmpVTS>();
	*d++ = new Descriptor<CabinetI>();
	*d++ = new Descriptor<CabinetII>();
	*d++ = new Descriptor<Clip>();

	*d++ = new Descriptor<ChorusI>();
	*d++ = new Descriptor<StereoChorusI>();
	*d++ = new Descriptor<ChorusII>();
	*d++ = new Descriptor<StereoChorusII>();
	*d++ = new Descriptor<PhaserI>();
	*d++ = new Descriptor<PhaserII>();
	*d++ = new Descriptor<SweepVFI>();
	*d++ = new Descriptor<SweepVFII>();
	*d++ = new Descriptor<AutoWah>();
	*d++ = new Descriptor<Scape>();

	*d++ = new Descriptor<VCOs>();
	*d++ = new Descriptor<VCOd>();
	*d++ = new Descriptor<CEO>();
	*d++ = new Descriptor<Sin>();
	*d++ = new Descriptor<White>();
	*d++ = new Descriptor<Lorenz>();
	*d++ = new Descriptor<Roessler>();

	*d++ = new Descriptor<JVRev>();
	*d++ = new Descriptor<Plate>();
	*d++ = new Descriptor<Plate2x2>();

	*d++ = new Descriptor<Click>();
	*d++ = new Descriptor<Dirac>();
	*d++ = new Descriptor<HRTF>();

	/* make sure N is correct */
	assert (d - descriptors == N);

	//seed();
}

__attribute__ ((destructor))
void caps_so_fini()
{
	for (ulong i = 0; i < N; ++i)
		delete descriptors[i];
}

/* /////////////////////////////////////////////////////////////////////// */

const LADSPA_Descriptor *
ladspa_descriptor (unsigned long i)
{
	if (i < N)
		return descriptors[i];
	return 0;
}

}; /* extern "C" */


code:
INCLUDE_DIRECTORIES("${CMAKE_SOURCE_DIR}/include")
FILE(GLOB_RECURSE SOURCES cmt/src/*.cpp)
LIST(SORT SOURCES)
ADD_LIBRARY(cmt MODULE ${SOURCES})
INSTALL(TARGETS cmt LIBRARY DESTINATION "${PLUGIN_DIR}/ladspa")

SET_TARGET_PROPERTIES(cmt PROPERTIES PREFIX "")
SET_TARGET_PROPERTIES(cmt PROPERTIES COMPILE_FLAGS "-Wall -O3 -fno-strict-aliasing")

IF(LMMS_BUILD_WIN32 AND NOT CMAKE_BUILD_TYPE MATCHES "Deb")
	ADD_CUSTOM_COMMAND(TARGET cmt POST_BUILD COMMAND "${STRIP}" "$<TARGET_FILE:cmt>")
ELSE()
	SET_TARGET_PROPERTIES(cmt PROPERTIES COMPILE_FLAGS "${COMPILE_FLAGS} -fPIC")
ENDIF()

IF(NOT LMMS_BUILD_APPLE AND NOT LMMS_BUILD_OPENBSD)
	SET_TARGET_PROPERTIES(cmt PROPERTIES LINK_FLAGS "${LINK_FLAGS} -shared -Wl,-no-undefined")
ENDIF()


code:
# Create blank config.h
FILE(WRITE ladspa/config.h "")

# Precompiler PIC Macro
IF(LMMS_BUILD_WIN32)
	SET(PIC_FLAGS "")
ELSE()
	SET(PIC_FLAGS "-fPIC -DPIC")
ENDIF()

# Additional compile flags
SET(COMPILE_FLAGS "${COMPILE_FLAGS} -O3 -Wall")
SET(COMPILE_FLAGS "${COMPILE_FLAGS} -fomit-frame-pointer -funroll-loops -ffast-math -c -fno-strict-aliasing")
SET(COMPILE_FLAGS "${COMPILE_FLAGS} ${PIC_FLAGS}")

# Loop over every XML file
FILE(GLOB XML_SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/ladspa/*.xml")
LIST(SORT XML_SOURCES)
FOREACH(_item ${XML_SOURCES})
	# Get library name and (soon to be) C file
	GET_FILENAME_COMPONENT(_plugin "${_item}" NAME_WE)
	SET(_out_file "${CMAKE_CURRENT_SOURCE_DIR}/ladspa/${_plugin}.c")

	# Coerce XML source file to C
	ADD_CUSTOM_COMMAND(
		OUTPUT "${_out_file}"
		COMMAND ./makestub.pl "${_item}" > "${_out_file}"
		DEPENDS "${_item}"
		WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/ladspa"
		VERBATIM
	)

	# Add a library target for this C file, which depends on success of makestup.pl
	ADD_LIBRARY("${_plugin}" MODULE "${_out_file}")

	# Vocoder does not use fftw
	IF(NOT ("${_plugin}" STREQUAL "vocoder_1337"))
		TARGET_LINK_LIBRARIES("${_plugin}" ${FFTW3F_LIBRARIES})
	ENDIF()
	IF(NOT MSVC)
		TARGET_LINK_LIBRARIES("${_plugin}" m)
	ENDIF()

	SET_TARGET_PROPERTIES("${_plugin}" PROPERTIES PREFIX "")
	SET_TARGET_PROPERTIES("${_plugin}" PROPERTIES COMPILE_FLAGS "${COMPILE_FLAGS}")
	SET_TARGET_PROPERTIES("${_plugin}" PROPERTIES LINK_FLAGS "${LINK_FLAGS}")
	INSTALL(TARGETS "${_plugin}" LIBRARY DESTINATION "${PLUGIN_DIR}/ladspa")
ENDFOREACH()

ADD_DEFINITIONS(-DFFTW3)
INCLUDE_DIRECTORIES(
	"${CMAKE_SOURCE_DIR}/include"
	"${CMAKE_CURRENT_SOURCE_DIR}/ladspa"
	"${FFTW3F_INCLUDE_DIRS}"
	"${CMAKE_BINARY_DIR}"
)

ADD_LIBRARY(iir STATIC ladspa/util/iir.c)
SET_TARGET_PROPERTIES(iir PROPERTIES COMPILE_FLAGS "${PIC_FLAGS}")
TARGET_LINK_LIBRARIES(bandpass_a_iir_1893 iir)
TARGET_LINK_LIBRARIES(bandpass_iir_1892 iir)
TARGET_LINK_LIBRARIES(butterworth_1902 iir)
TARGET_LINK_LIBRARIES(highpass_iir_1890 iir)
TARGET_LINK_LIBRARIES(lowpass_iir_1891 iir)
TARGET_LINK_LIBRARIES(notch_iir_1894 iir)

FILE(GLOB GSM_SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/ladspa/gsm/*.c")
LIST(SORT GSM_SOURCES)
ADD_LIBRARY(gsm STATIC ${GSM_SOURCES})
SET_TARGET_PROPERTIES(gsm PROPERTIES COMPILE_FLAGS "${PIC_FLAGS}")
TARGET_LINK_LIBRARIES(gsm_1215 gsm)

ADD_LIBRARY(gverb STATIC ladspa/gverb/gverb.c ladspa/gverb/gverbdsp.c)
SET_TARGET_PROPERTIES(gverb PROPERTIES COMPILE_FLAGS "${PIC_FLAGS}")
TARGET_LINK_LIBRARIES(gverb_1216 gverb)

ADD_LIBRARY(blo STATIC ladspa/util/blo.c)
SET_TARGET_PROPERTIES(blo PROPERTIES COMPILE_FLAGS "${PIC_FLAGS}")
TARGET_LINK_LIBRARIES(analogue_osc_1416 blo)
TARGET_LINK_LIBRARIES(fm_osc_1415 blo)
TARGET_LINK_LIBRARIES(hermes_filter_1200 blo)

ADD_LIBRARY(rms STATIC ladspa/util/rms.c)
ADD_LIBRARY(db STATIC ladspa/util/db.c)
SET_TARGET_PROPERTIES(rms PROPERTIES COMPILE_FLAGS "${PIC_FLAGS}")
SET_TARGET_PROPERTIES(db PROPERTIES COMPILE_FLAGS "${PIC_FLAGS}")
TARGET_LINK_LIBRARIES(sc1_1425 rms db)
TARGET_LINK_LIBRARIES(sc2_1426 rms db)
TARGET_LINK_LIBRARIES(sc3_1427 rms db)
TARGET_LINK_LIBRARIES(sc4_1882 rms db)
TARGET_LINK_LIBRARIES(sc4m_1916 rms db)
TARGET_LINK_LIBRARIES(se4_1883 rms db)

ADD_LIBRARY(pitchscale STATIC ladspa/util/pitchscale.c)
SET_TARGET_PROPERTIES(pitchscale PROPERTIES COMPILE_FLAGS "${PIC_FLAGS}")
TARGET_LINK_LIBRARIES(pitchscale -lfftw3f)
TARGET_LINK_LIBRARIES(pitch_scale_1193 pitchscale)
TARGET_LINK_LIBRARIES(pitch_scale_1194 pitchscale)


code:
INCLUDE_DIRECTORIES("${CMAKE_SOURCE_DIR}/include")
FILE(GLOB PLUGIN_SOURCES tap-plugins/*.c)
LIST(SORT PLUGIN_SOURCES)
SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O3 -Wno-write-strings -fomit-frame-pointer -fno-strict-aliasing -funroll-loops -ffast-math")
FOREACH(_item ${PLUGIN_SOURCES})
	GET_FILENAME_COMPONENT(_plugin "${_item}" NAME_WE)
	ADD_LIBRARY("${_plugin}" MODULE "${_item}")
	# TAP pinknoise will re-init srand(); use existing seed instead
	IF("${_plugin}" MATCHES "tap_pinknoise")
		TARGET_COMPILE_DEFINITIONS("${_plugin}" PRIVATE TAP_DISABLE_SRAND=1)
	ENDIF()
	INSTALL(TARGETS "${_plugin}" LIBRARY DESTINATION "${PLUGIN_DIR}/ladspa")
	SET_TARGET_PROPERTIES("${_plugin}" PROPERTIES PREFIX "")
	# Don't strip if "Debug" or "RelWithDebInfo"
	IF(LMMS_BUILD_WIN32 AND NOT CMAKE_BUILD_TYPE MATCHES "Deb")
		ADD_CUSTOM_COMMAND(TARGET "${_plugin}" POST_BUILD COMMAND "${STRIP}" \"$<TARGET_FILE:${_plugin}>\")
	ENDIF()
	IF(NOT MSVC)
		TARGET_LINK_LIBRARIES("${_plugin}" m)
	ENDIF()
ENDFOREACH()


code:
IF(LMMS_HAVE_LV2)
	INCLUDE_DIRECTORIES(${LV2_INCLUDE_DIRS})
	INCLUDE_DIRECTORIES(${LILV_INCLUDE_DIRS})
	INCLUDE_DIRECTORIES(${SUIL_INCLUDE_DIRS})
	INCLUDE(BuildPlugin)
	BUILD_PLUGIN(lv2effect Lv2Effect.cpp Lv2FxControls.cpp Lv2FxControlDialog.cpp Lv2Effect.h Lv2FxControls.h Lv2FxControlDialog.h
		MOCFILES Lv2Effect.h Lv2FxControls.h Lv2FxControlDialog.h
		EMBEDDED_RESOURCES logo.png)
ENDIF(LMMS_HAVE_LV2)


code:
/*
 * Lv2Effect.cpp - implementation of LV2 effect
 *
 * Copyright (c) 2018-2020 Johannes Lorenz <jlsf2013$users.sourceforge.net, $=@>
 *
 * This file is part of LMMS - https://lmms.io
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public
 * License along with this program (see COPYING); if not, write to the
 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA 02110-1301 USA.
 *
 */

#include "Lv2Effect.h"

#include <QDebug>
#include <lv2.h>

#include "Lv2SubPluginFeatures.h"

#include "embed.h"
#include "plugin_export.h"

extern "C"
{

Plugin::Descriptor PLUGIN_EXPORT lv2effect_plugin_descriptor =
{
	STRINGIFY(PLUGIN_NAME),
	"LV2",
	QT_TRANSLATE_NOOP("PluginBrowser",
		"plugin for using arbitrary LV2-effects inside LMMS."),
	"Johannes Lorenz <jlsf2013$$$users.sourceforge.net, $$$=@>",
	0x0100,
	Plugin::Effect,
	new PluginPixmapLoader("logo"),
	nullptr,
	new Lv2SubPluginFeatures(Plugin::Effect)
};

}

Lv2Effect::Lv2Effect(Model* parent, const Descriptor::SubPluginFeatures::Key *key) :
	Effect(&lv2effect_plugin_descriptor, parent, key),
	m_controls(this, key->attributes["uri"]),
	m_tmpOutputSmps(Engine::mixer()->framesPerPeriod())
{
}

bool Lv2Effect::processAudioBuffer(sampleFrame *buf, const fpp_t frames)
{
	if (!isEnabled() || !isRunning()) { return false; }
	Q_ASSERT(frames <= static_cast<fpp_t>(m_tmpOutputSmps.size()));

	m_controls.copyBuffersFromLmms(buf, frames);
	m_controls.copyModelsFromLmms();

//	m_pluginMutex.lock();
	m_controls.run(frames);
//	m_pluginMutex.unlock();

	m_controls.copyModelsToLmms();
	m_controls.copyBuffersToLmms(m_tmpOutputSmps.data(), frames);

	double outSum = .0;
	bool corrupt = wetLevel() < 0; // #3261 - if w < 0, bash w := 0, d := 1
	const float d = corrupt ? 1 : dryLevel();
	const float w = corrupt ? 0 : wetLevel();
	for(fpp_t f = 0; f < frames; ++f)
	{
		buf[f][0] = d * buf[f][0] + w * m_tmpOutputSmps[f][0];
		buf[f][1] = d * buf[f][1] + w * m_tmpOutputSmps[f][1];
		double l = static_cast<double>(buf[f][0]);
		double r = static_cast<double>(buf[f][1]);
		outSum += l*l + r*r;
	}
	checkGate(outSum / frames);

	return isRunning();
}

extern "C"
{

// necessary for getting instance out of shared lib
PLUGIN_EXPORT Plugin *lmms_plugin_main(Model *_parent, void *_data)
{
	using KeyType = Plugin::Descriptor::SubPluginFeatures::Key;
	Lv2Effect* eff = new Lv2Effect(_parent, static_cast<const KeyType*>(_data));
	if (!eff->isValid()) { delete eff; eff = nullptr; }
	return eff;
}

}


code:
/*
 * Lv2Effect.h - implementation of LV2 effect
 *
 * Copyright (c) 2018-2020 Johannes Lorenz <jlsf2013$users.sourceforge.net, $=@>
 *
 * This file is part of LMMS - https://lmms.io
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public
 * License along with this program (see COPYING); if not, write to the
 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA 02110-1301 USA.
 *
 */

#ifndef LV2_EFFECT_H
#define LV2_EFFECT_H

#include "Effect.h"
#include "Lv2FxControls.h"

class Lv2Effect : public Effect
{
	Q_OBJECT

public:
	/*
		initialization
	*/
	Lv2Effect(Model* parent, const Descriptor::SubPluginFeatures::Key* _key);
	//! Must be checked after ctor or reload
	bool isValid() const { return m_controls.isValid(); }

	bool processAudioBuffer( sampleFrame* buf, const fpp_t frames ) override;
	EffectControls* controls() override { return &m_controls; }

	Lv2FxControls* lv2Controls() { return &m_controls; }
	const Lv2FxControls* lv2Controls() const { return &m_controls; }

private:
	Lv2FxControls m_controls;
	std::vector<sampleFrame> m_tmpOutputSmps;
};

#endif // LMMS_HAVE_LV2


code:
/*
 * Lv2FxControlDialog.cpp - Lv2FxControlDialog implementation
 *
 * Copyright (c) 2018-2020 Johannes Lorenz <jlsf2013$users.sourceforge.net, $=@>
 *
 * This file is part of LMMS - https://lmms.io
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public
 * License along with this program (see COPYING); if not, write to the
 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA 02110-1301 USA.
 *
 */

#include "Lv2FxControlDialog.h"

#include <QDebug>
#include <QPushButton>
#include <lv2.h>

#include "Lv2Effect.h"
#include "Lv2FxControls.h"

Lv2FxControlDialog::Lv2FxControlDialog(Lv2FxControls *controls) :
	EffectControlDialog(controls),
	Lv2ViewBase(this, controls)
{
	if (m_reloadPluginButton) {
		connect(m_reloadPluginButton, &QPushButton::clicked,
				this, [this](){ lv2Controls()->reloadPlugin(); });
	}
	if (m_toggleUIButton) {
		connect(m_toggleUIButton, &QPushButton::toggled,
			this, [this](){ toggleUI(); });
	}
	if (m_helpButton) {
		connect(m_helpButton, &QPushButton::toggled,
			this, [this](bool visible){ toggleHelp(visible); });
	}
	// for Effects, modelChanged only goes to the top EffectView
	// we need to call it manually
	modelChanged();
}

Lv2FxControls *Lv2FxControlDialog::lv2Controls()
{
	return static_cast<Lv2FxControls *>(m_effectControls);
}

void Lv2FxControlDialog::modelChanged()
{
	Lv2ViewBase::modelChanged(lv2Controls());
}


code:
/*
 * Lv2FxControlDialog.h - Lv2FxControlDialog implementation
 *
 * Copyright (c) 2018-2020 Johannes Lorenz <jlsf2013$users.sourceforge.net, $=@>
 *
 * This file is part of LMMS - https://lmms.io
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public
 * License along with this program (see COPYING); if not, write to the
 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA 02110-1301 USA.
 *
 */

#ifndef LV2_FX_CONTROL_DIALOG_H
#define LV2_FX_CONTROL_DIALOG_H

#include "EffectControlDialog.h"
#include "Lv2ViewBase.h"

class Lv2FxControls;

class Lv2FxControlDialog : public EffectControlDialog, public Lv2ViewBase
{
	Q_OBJECT

public:
	Lv2FxControlDialog(Lv2FxControls *controls);

private:
	Lv2FxControls *lv2Controls();
	void modelChanged() override;
};

#endif


code:
/*
 * Lv2FxControls.cpp - Lv2FxControls implementation
 *
 * Copyright (c) 2018-2020 Johannes Lorenz <jlsf2013$users.sourceforge.net, $=@>
 *
 * This file is part of LMMS - https://lmms.io
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public
 * License along with this program (see COPYING); if not, write to the
 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA 02110-1301 USA.
 *
 */

#include "Lv2FxControls.h"

#include <QDomElement>

#include "Engine.h"
#include "Lv2Effect.h"
#include "Lv2FxControlDialog.h"
#include "Lv2Proc.h"

Lv2FxControls::Lv2FxControls(class Lv2Effect *effect, const QString& uri) :
	EffectControls(effect),
	Lv2ControlBase(this, uri)
{
	if (isValid())
	{
		connect(Engine::mixer(), &Mixer::sampleRateChanged,
			this, [this](){Lv2ControlBase::reloadPlugin();});
	}
}

void Lv2FxControls::saveSettings(QDomDocument &doc, QDomElement &that)
{
	Lv2ControlBase::saveSettings(doc, that);
}

void Lv2FxControls::loadSettings(const QDomElement &that)
{
	Lv2ControlBase::loadSettings(that);
}

int Lv2FxControls::controlCount()
{
	return static_cast<int>(Lv2ControlBase::controlCount());
}

EffectControlDialog *Lv2FxControls::createView()
{
	return new Lv2FxControlDialog(this);
}

void Lv2FxControls::changeControl() // TODO: what is that?
{
	//	engine::getSong()->setModified();
}

DataFile::Types Lv2FxControls::settingsType()
{
	return DataFile::EffectSettings;
}

void Lv2FxControls::setNameFromFile(const QString &name)
{
	effect()->setDisplayName(name);
}


code:
/*
 * Lv2FxControls.h - Lv2FxControls implementation
 *
 * Copyright (c) 2018-2020 Johannes Lorenz <jlsf2013$users.sourceforge.net, $=@>
 *
 * This file is part of LMMS - https://lmms.io
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public
 * License along with this program (see COPYING); if not, write to the
 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA 02110-1301 USA.
 *
 */

#ifndef LV2_FX_CONTROLS_H
#define LV2_FX_CONTROLS_H

#include "EffectControls.h"
#include "Lv2ControlBase.h"

class Lv2Effect;

class Lv2FxControls : public EffectControls, public Lv2ControlBase
{
	Q_OBJECT
public:
	Lv2FxControls(Lv2Effect *effect, const QString &uri);

	void saveSettings(QDomDocument &_doc, QDomElement &_parent) override;
	void loadSettings(const QDomElement &that) override;
	inline QString nodeName() const override
	{
		return Lv2ControlBase::nodeName();
	}

	int controlCount() override;
	EffectControlDialog *createView() override;

private slots:
	void changeControl();

private:
	DataFile::Types settingsType() override;
	void setNameFromFile(const QString &name) override;

	friend class Lv2FxControlDialog;
	friend class Lv2Effect;
};

#endif


code:
IF(LMMS_HAVE_LV2)
	INCLUDE_DIRECTORIES(${LV2_INCLUDE_DIRS})
	INCLUDE_DIRECTORIES(${LILV_INCLUDE_DIRS})
	INCLUDE_DIRECTORIES(${SUIL_INCLUDE_DIRS})
	INCLUDE(BuildPlugin)
	BUILD_PLUGIN(lv2instrument Lv2Instrument.cpp Lv2Instrument.h MOCFILES Lv2Instrument.h EMBEDDED_RESOURCES logo.png)
ENDIF(LMMS_HAVE_LV2)


code:
/*
 * Lv2Instrument.cpp - implementation of LV2 instrument
 *
 * Copyright (c) 2018-2020 Johannes Lorenz <jlsf2013$users.sourceforge.net, $=@>
 *
 * This file is part of LMMS - https://lmms.io
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public
 * License along with this program (see COPYING); if not, write to the
 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA 02110-1301 USA.
 *
 */

#include "Lv2Instrument.h"

#include <QDebug>
#include <QDragEnterEvent>

#include "Engine.h"
#include "InstrumentPlayHandle.h"
#include "InstrumentTrack.h"
#include "Lv2SubPluginFeatures.h"
#include "Mixer.h"
#include "StringPairDrag.h"
#include "Clipboard.h"

#include "embed.h"
#include "plugin_export.h"

extern "C"
{

Plugin::Descriptor PLUGIN_EXPORT lv2instrument_plugin_descriptor =
{
	STRINGIFY(PLUGIN_NAME),
	"LV2",
	QT_TRANSLATE_NOOP("PluginBrowser",
		"plugin for using arbitrary LV2 instruments inside LMMS."),
	"Johannes Lorenz <jlsf2013$$$users.sourceforge.net, $$$=@>",
	0x0100,
	Plugin::Instrument,
	new PluginPixmapLoader("logo"),
	nullptr,
	new Lv2SubPluginFeatures(Plugin::Instrument)
};

}

/*
	Lv2Instrument
*/

Lv2Instrument::Lv2Instrument(InstrumentTrack *instrumentTrackArg,
	Descriptor::SubPluginFeatures::Key *key) :
	Instrument(instrumentTrackArg, &lv2instrument_plugin_descriptor, key),
	Lv2ControlBase(this, key->attributes["uri"])
{
	if (Lv2ControlBase::isValid())
	{
#ifdef LV2_INSTRUMENT_USE_MIDI
		for (int i = 0; i < NumKeys; ++i) { m_runningNotes[i] = 0; }
#endif
		connect(instrumentTrack()->pitchRangeModel(), SIGNAL(dataChanged()),
			this, SLOT(updatePitchRange()), Qt::DirectConnection);
		connect(Engine::mixer(), &Mixer::sampleRateChanged,
			this, [this](){Lv2ControlBase::reloadPlugin();});

		// now we need a play-handle which cares for calling play()
		InstrumentPlayHandle *iph =
			new InstrumentPlayHandle(this, instrumentTrackArg);
		Engine::mixer()->addPlayHandle(iph);
	}
}

Lv2Instrument::~Lv2Instrument()
{
	Engine::mixer()->removePlayHandlesOfTypes(instrumentTrack(),
		PlayHandle::TypeNotePlayHandle |
						  PlayHandle::TypeInstrumentPlayHandle);
}

bool Lv2Instrument::isValid() const { return Lv2ControlBase::isValid(); }

void Lv2Instrument::saveSettings(QDomDocument &doc, QDomElement &that)
{
	Lv2ControlBase::saveSettings(doc, that);
}

void Lv2Instrument::loadSettings(const QDomElement &that)
{
	Lv2ControlBase::loadSettings(that);
}

void Lv2Instrument::loadFile(const QString &file)
{
	Lv2ControlBase::loadFile(file);
}

#ifdef LV2_INSTRUMENT_USE_MIDI
bool Lv2Instrument::handleMidiEvent(
	const MidiEvent &event, const TimePos &time, f_cnt_t offset)
{
	// this function can be called from GUI threads while the plugin is running
	// handleMidiInputEvent will use a thread-safe ringbuffer
	handleMidiInputEvent(event, time, offset);
	return true;
}
#endif

// not yet working
#ifndef LV2_INSTRUMENT_USE_MIDI
void Lv2Instrument::playNote(NotePlayHandle *nph, sampleFrame *)
{
}
#endif

void Lv2Instrument::play(sampleFrame *buf)
{
	copyModelsFromLmms();

	fpp_t fpp = Engine::mixer()->framesPerPeriod();

	run(fpp);

	copyModelsToLmms();
	copyBuffersToLmms(buf, fpp);

	instrumentTrack()->processAudioBuffer(buf, fpp, nullptr);
}

PluginView *Lv2Instrument::instantiateView(QWidget *parent)
{
	return new Lv2InsView(this, parent);
}

void Lv2Instrument::updatePitchRange()
{
	qDebug() << "Lmms: Cannot update pitch range for lv2 plugin:"
				"not implemented yet";
}

QString Lv2Instrument::nodeName() const
{
	return Lv2ControlBase::nodeName();
}

DataFile::Types Lv2Instrument::settingsType()
{
	return DataFile::InstrumentTrackSettings;
}

void Lv2Instrument::setNameFromFile(const QString &name)
{
	instrumentTrack()->setName(name);
}

/*
	Lv2InsView
*/

Lv2InsView::Lv2InsView(Lv2Instrument *_instrument, QWidget *_parent) :
	InstrumentView(_instrument, _parent),
	Lv2ViewBase(this, _instrument)
{
	setAutoFillBackground(true);
	if (m_reloadPluginButton) {
		connect(m_reloadPluginButton, &QPushButton::clicked,
			this, [this](){ this->castModel<Lv2Instrument>()->reloadPlugin();} );
	}
	if (m_toggleUIButton) {
		connect(m_toggleUIButton, &QPushButton::toggled,
			this, [this](){ toggleUI(); });
	}
	if (m_helpButton) {
		connect(m_helpButton, &QPushButton::toggled,
			this, [this](bool visible){ toggleHelp(visible); });
	}
}

void Lv2InsView::dragEnterEvent(QDragEnterEvent *_dee)
{
	// For mimeType() and MimeType enum class
	using namespace Clipboard;

	void (QDragEnterEvent::*reaction)(void) = &QDragEnterEvent::ignore;

	if (_dee->mimeData()->hasFormat( mimeType( MimeType::StringPair )))
	{
		const QString txt =
			_dee->mimeData()->data( mimeType( MimeType::StringPair ) );
		if (txt.section(':', 0, 0) == "pluginpresetfile") {
			reaction = &QDragEnterEvent::acceptProposedAction;
		}
	}

	(_dee->*reaction)();
}

void Lv2InsView::dropEvent(QDropEvent *_de)
{
	const QString type = StringPairDrag::decodeKey(_de);
	const QString value = StringPairDrag::decodeValue(_de);
	if (type == "pluginpresetfile")
	{
		castModel<Lv2Instrument>()->loadFile(value);
		_de->accept();
		return;
	}
	_de->ignore();
}

void Lv2InsView::modelChanged()
{
	Lv2ViewBase::modelChanged(castModel<Lv2Instrument>());
}

extern "C"
{

// necessary for getting instance out of shared lib
PLUGIN_EXPORT Plugin *lmms_plugin_main(Model *_parent, void *_data)
{
	using KeyType = Plugin::Descriptor::SubPluginFeatures::Key;
	Lv2Instrument* ins = new Lv2Instrument(
							static_cast<InstrumentTrack*>(_parent),
							static_cast<KeyType*>(_data ));
	if (!ins->isValid()) { delete ins; ins = nullptr; }
	return ins;
}

}


code:
/*
 * Lv2Instrument.h - implementation of LV2 instrument
 *
 * Copyright (c) 2018-2020 Johannes Lorenz <jlsf2013$users.sourceforge.net, $=@>
 *
 * This file is part of LMMS - https://lmms.io
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public
 * License along with this program (see COPYING); if not, write to the
 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA 02110-1301 USA.
 *
 */

#ifndef LV2_INSTRUMENT_H
#define LV2_INSTRUMENT_H

#include <QString>

#include "Instrument.h"
#include "InstrumentView.h"
#include "Note.h"
#include "Lv2ControlBase.h"
#include "Lv2ViewBase.h"

// whether to use MIDI vs playHandle
// currently only MIDI works
#define LV2_INSTRUMENT_USE_MIDI

class QPushButton;

class Lv2Instrument : public Instrument, public Lv2ControlBase
{
	Q_OBJECT
public:
	/*
		initialization
	*/
	Lv2Instrument(InstrumentTrack *instrumentTrackArg,
		 Descriptor::SubPluginFeatures::Key* key);
	~Lv2Instrument() override;
	//! Must be checked after ctor or reload
	bool isValid() const;

	/*
		load/save
	*/
	void saveSettings(QDomDocument &doc, QDomElement &that) override;
	void loadSettings(const QDomElement &that) override;
	void loadFile(const QString &file) override;

	/*
		realtime funcs
	*/
	bool hasNoteInput() const override { return Lv2ControlBase::hasNoteInput(); }
#ifdef LV2_INSTRUMENT_USE_MIDI
	bool handleMidiEvent(const MidiEvent &event,
		const TimePos &time = TimePos(), f_cnt_t offset = 0) override;
#else
	void playNote(NotePlayHandle *nph, sampleFrame *) override;
#endif
	void play(sampleFrame *buf) override;

	/*
		misc
	*/
	Flags flags() const override
	{
#ifdef LV2_INSTRUMENT_USE_MIDI
		return IsSingleStreamed | IsMidiBased;
#else
		return IsSingleStreamed;
#endif
	}
	PluginView *instantiateView(QWidget *parent) override;

private slots:
	void updatePitchRange();

private:
	QString nodeName() const override;
	DataFile::Types settingsType() override;
	void setNameFromFile(const QString &name) override;

#ifdef LV2_INSTRUMENT_USE_MIDI
	int m_runningNotes[NumKeys];
#endif

	friend class Lv2InsView;
};

class Lv2InsView : public InstrumentView, public Lv2ViewBase
{
	Q_OBJECT
public:
	Lv2InsView(Lv2Instrument *_instrument, QWidget *_parent);

protected:
	void dragEnterEvent(QDragEnterEvent *_dee) override;
	void dropEvent(QDropEvent *_de) override;

private:
	void modelChanged() override;
};

#endif // LV2_INSTRUMENT_H


code:
INCLUDE(BuildPlugin)

BUILD_PLUGIN(midiexport MidiExport.cpp MidiExport.h MidiFile.hpp
		MOCFILES MidiExport.h)