code:
/*
	Cabinet.cc

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

	http://quitte.de/dsp/

	CabinetI - 16th order IIR filters modeled after various impulse responses
	from Steve Harris' 'imp' plugin. Limited to 44.1 kHz sample rate.

	CabinetII - 32nd order IIR filters modeled after the same impulse responses
	using a different algorithm. Versions for 44.1 / 48 / 88.2 / 96 kHz sample
	rates, switched at runtime.
*/
/*
	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.
*/

#include "basics.h"

#include "Cabinet.h"
#include "Descriptor.h"

Model16
CabinetI::models [] =
{
	{
		1, /* identity */
		{1},
		{0},
		1,
	}, {
		16, /* unmatched, off-axis */
		{0.44334744339382504, 0.49764265352620912, 0.19936863766114088, 0.0038388115609433826, -0.072080744430548876, -0.092589757815768933, -0.023760971045285254, 0.058929802988203807, 0.11073296313735595, 0.14389046518738619, 0.052981055774577353, -0.11817321919764193, -0.22957467728465422, -0.26301284181138151, -0.25586853638823448, -0.10768194462289554},
		{0.0, 0.71138736215182674, 0.19571088506350195, -0.086897678126924227, -0.18344238266155902, -0.13338660100611671, -0.017424587504494098, 0.062014975470330351, 0.077979014877680469, 0.039134631327482176, -0.046646061538403727, -0.040653480351542266, 0.068462230153713749, 0.14313162261479676, 0.058844200671679531, -0.17878548463526983},
		1 / 4.4,
	}, {
		16, /* unmatched */
		{0.58952373363852417, 0.43625942509584309, 0.235412203403113, 0.048252951521505258, -0.1002076253350956, -0.14467958356216026, -0.074304873528329402, 0.060945557247412331, 0.15959845551788171, 0.20970924189636411, 0.15361368007229703, 0.025339061869183478, -0.11824836967489599, -0.19384403813690479, -0.19295873693806628, -0.058904754435169508},
		{0.0, 0.6596380198994729, 0.20825670531468143, -0.10508784276271754, -0.24698905246649294, -0.21519418569376192, -0.10057489587096909, -0.006175810942624007, -0.0019249936836196989, -0.045827268144865707, -0.10184708094147235, -0.09177820187618313, -0.017740067693127175, 0.058828573780348989, 0.010559807576350673, -0.19412688465216324},
		1 / 5.7,
	}, {
		16, /* superchamp */
		{0.5335550129666069, 0.61768496153556829, 0.2080126894040209, -0.0067283013134491337, -0.10433152421155355, -0.16159936513841233, -0.10593018443866807, -0.091854930675998661, 0.0023550324496513643, 0.14327516190088724, 0.14688292534697539, 0.089539872443625601, -0.053854769352683005, -0.15693904535289377, -0.083502230074838577, 0.0090113128614708465},
		{0.0, 0.67745858591653696, 0.044802106922746734, -0.1932642251200547, -0.18922360327572652, -0.052980570047914469, 0.020446992577988904, -0.028951451474818618, -0.085212072485126716, -0.12241212382510525, -0.089259371449674357, 0.010469056928395087, 0.049019357277555603, 0.037212453438250505, -0.046374612934843573, -0.045133341919937828},
		1 / 4.0,
	}, {
		16, /* fender-vibrolux-68 */
		{0.68447985102464837, 0.61538710771230021, -0.28804707230137599, -0.23656583372846893, 0.083100874242250655, -0.027792816938813913, 0.055558334440593965, 0.044458161718059774, -0.25467542393376252, -0.33660492613760157, -0.024663941486403884, 0.1172751972420942, -0.021832135450802759, 0.21440383631745469, 0.20828506390107443, -0.10289957687018361},
		{0.0, 0.50968169360260451, -0.48159141882733714, -0.10856607456906017, -0.026802006374108955, -0.24967309940249552, -0.21422424792787859, 0.019271890369619571, 0.08065394481240884, -0.061665636719946543, 0.031613782215493547, 0.069574436103950893, -0.07180222507768147, -0.14447996563879059, 0.012044815820150268, -0.0073237976200291044},
		1 / 2.0,
	}, {
		16, /* marshall */
		{0.38455665328113242, 0.50304089890302783, 0.33653970418909934, 0.085604896315814846, -0.070239383452479598, -0.10479060878654689, -0.060150883776583335, 0.030121882977878822, 0.12441775056532201, 0.18287316824579156, 0.17035705141865287, 0.10315414401519916, 0.036357097566567576, 0.024474446155666255, 0.042359967009557103, 0.059946316626725109},
		{0.0, 0.68167571829534335, 0.16877527811114035, -0.17427551663276897, -0.25780056810728452, -0.16065744581310681, -0.032007062964857856, 0.033882840656718101, -0.0038880045892747792, -0.084876415098991506, -0.13865107122780057, -0.10073571899064113, -0.013199668806255366, 0.038170305284592504, -0.026492576852036546, -0.12667775510054707},
		1 / 4.2,
	}
};

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

void
CabinetI::init()
{
	h = 0;
	model = 0;
}

void
CabinetI::switch_model (int m)
{
	if (m < 0) m = 0;
	else if (m > 5) m = 5;

	model = m;

	n = models[m].n;
	a = models[m].a;
	b = models[m].b;

	gain = models[m].gain * DSP::db2lin (getport(2));

	memset (x, 0, sizeof (x));
	memset (y, 0, sizeof (y));
}

void
CabinetI::activate()
{
	switch_model ((int) getport(1));
	gain = models[model].gain * DSP::db2lin (getport(2));
}

template <sample_func_t F>
void
CabinetI::one_cycle (int frames)
{
	sample_t * s = ports[0];

	int m = (int) getport (1);
	if (m != model) switch_model (m);

	sample_t g = models[model].gain * DSP::db2lin (getport(2));
	double gf = pow (g / gain, 1 / (double) frames);

	sample_t * d = ports[3];

	for (int i = 0; i < frames; ++i)
	{
		register cabinet_float out = s[i] + normal;

		x[h] = out;

		out *= a[0];

		for (int j = 1, z = h - 1; j < n; --z, ++j)
		{
			z &= 15;
			out += a[j] * x[z];
			out += b[j] * y[z];
		}

		y[h] = out;

		h = (h + 1) & 15;

		F (d, i, gain * out, adding_gain);
		gain *= gf;
	}
}

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

PortInfo
CabinetI::port_info [] =
{
	{
		"in",
		INPUT | AUDIO,
		{BOUNDED, -1, 1}
	}, {
		"model",
		INPUT | CONTROL,
		{BOUNDED | INTEGER | DEFAULT_1, 0, 5}
	}, {
		"gain (dB)",
		INPUT | CONTROL,
		{BOUNDED | DEFAULT_0, -24, 24}
	}, {
		"out",
		OUTPUT | AUDIO,
		{0}
	}
};

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

template <> void
Descriptor<CabinetI>::setup()
{
	UniqueID = 1766;
	Label = "CabinetI";
	Properties = HARD_RT;

	Name = CAPS "CabinetI - Loudspeaker cabinet emulation";
	Maker = "Tim Goetze <tim@quitte.de>";
	Copyright = "GPL, 2002-7";

	/* fill port info and vtable */
	autogen();
}

/* CabinetII ////////////////////////////////////////////////////////////// */

#include "Cabinet-Models32.h"

void
CabinetII::init()
{
	if (fs < 46000)
		models = models44100;
	else if (fs < 72000)
		models = models48000;
	else if (fs < 92000)
		models = models88200;
	else
		models = models96000;

	h = 0;
	model = 0;
}

void
CabinetII::switch_model (int m)
{
	model = m;

	n = models[m].n;
	a = models[m].a;
	b = models[m].b;

	gain = models[m].gain * DSP::db2lin (getport(2));

	memset (x, 0, sizeof (x));
	memset (y, 0, sizeof (y));
}

void
CabinetII::activate()
{
	switch_model ((int) getport(1));
}

template <sample_func_t F>
void
CabinetII::one_cycle (int frames)
{
	sample_t * s = ports[0];

	int m = (int) getport (1);
	if (m != model) switch_model (m);

	sample_t g = models[model].gain * DSP::db2lin (getport(2));
	double gf = pow (g / gain, 1 / (double) frames);
	sample_t * d = ports[3];

	for (int i = 0; i < frames; ++i)
	{
		register cabinet_float out = s[i] + normal;

		x[h] = out;

		out *= a[0];

		for (int j = 1, z = h - 1; j < n; --z, ++j)
		{
			z &= 31;
			out += a[j] * x[z];
			out += b[j] * y[z];
		}

		y[h] = out;

		h = (h + 1) & 31;

		F (d, i, gain * out, adding_gain);
		gain *= gf;
	}
}

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

PortInfo
CabinetII::port_info [] =
{
	{
		"in",
		INPUT | AUDIO,
		{BOUNDED, -1, 1}
	}, {
		"model",
		INPUT | CONTROL,
		{BOUNDED | INTEGER | DEFAULT_1, 0, 7}
	}, {
		"gain (dB)",
		INPUT | CONTROL,
		{BOUNDED | DEFAULT_0, -24, 24}
	}, {
		"out",
		OUTPUT | AUDIO,
		{0}
	}
};

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

template <> void
Descriptor<CabinetII>::setup()
{
	UniqueID = 2581;
	Label = "CabinetII";
	Properties = HARD_RT;

	Name = CAPS "CabinetII - Refined loudspeaker cabinet emulation";
	Maker = "Tim Goetze <tim@quitte.de>";
	Copyright = "GPL, 2002-7";

	/* fill port info and vtable */
	autogen();
}


code:
/*
	Cabinet.h

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

	http://quitte.de/dsp/

	CabinetI - 16th order IIR filters modeled after various impulse responses
	from Steve Harris' 'imp' plugin. Limited to 44.1 kHz sample rate.

	CabinetII - 32nd order IIR filters modeled after the same impulse responses
	using a different algorithm. Versions for 44.1 / 48 / 88.2 / 96 kHz sample
	rates, switched at runtime.
*/
/*
	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 _CABINET_H_
#define _CABINET_H_

#include "dsp/util.h"

/* cabinet_float sets the data type used for the IIR history and thus the
 * computing precision. doubles tend to make the sound more vivid and lively.
 * You can squeeze out a few extra cycles by making this 'float' if needed.
 * Be warned though that CabinetII has not been tested with 32-bit floats and
 * might become unstable due to the lower computing precision. */
typedef double cabinet_float;

typedef struct {
	int n;
	cabinet_float a[16], b[16];
	float gain;
} Model16;

typedef struct {
	int n;
	cabinet_float a[32], b[32];
	float gain;
} Model32;

class CabinetI
: public Plugin
{
	public:
		sample_t gain;
		static Model16 models [];

		int model;
		void switch_model (int m);

		int n, h;
		cabinet_float * a, * b;
		cabinet_float x[16], y[16];

		template <sample_func_t F>
			void one_cycle (int frames);

	public:
		static PortInfo port_info [];

		void init();

		void activate();

		void run (int n)
			{
				one_cycle<store_func> (n);
			}

		void run_adding (int n)
			{
				one_cycle<adding_func> (n);
			}
};

/* Second version with 32nd order filters precalculated for
 * 44.1 / 48 / 88.2 / 96 kHz sample rates */

class CabinetII
: public Plugin
{
	public:
		sample_t gain;

		static Model32 models44100 [];
		static Model32 models48000 [];
		static Model32 models88200 [];
		static Model32 models96000 [];

		Model32 * models;
		int model;
		void switch_model (int m);

		int n, h;
		cabinet_float * a, * b;
		cabinet_float x[32], y[32];

		template <sample_func_t F>
			void one_cycle (int frames);

	public:
		static PortInfo port_info [];

		sample_t adding_gain;

		void init();
		void activate();

		void run (int n)
			{
				one_cycle<store_func> (n);
			}

		void run_adding (int n)
			{
				one_cycle<adding_func> (n);
			}
};

#endif /* _CABINET_H_ */

repo_name: CYBERDEViL/LMMS

license: mit


code:
/*
	Chorus.cc

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

	http://quitte.de/dsp/

	mono and mono-to-stereo chorus units.

*/
/*
	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.
*/

#include "basics.h"

#include "Chorus.h"
#include "Descriptor.h"

template <sample_func_t F>
void
ChorusI::one_cycle (int frames)
{
	sample_t * s = ports[0];

	double one_over_n = 1 / (double) frames;
	double ms = .001 * fs;

	double t = time;
	time = getport(1) * ms;
	double dt = (time - t) * one_over_n;

	double w = width;
	width = getport(2) * ms;
	/* clamp, or we need future samples from the delay line */
	if (width >= t - 3) width = t - 3;
	double dw = (width - w) * one_over_n;

	if (rate != *ports[3])
		lfo.set_f (max (rate = getport(3), .000001), fs, lfo.get_phase());

	double blend = getport(4);
	double ff = getport(5);
	double fb = getport(6);

	sample_t * d = ports[7];

	DSP::FPTruncateMode truncate;

	for (int i = 0; i < frames; ++i)
	{
		sample_t x = s[i];

		/* truncate the feedback tap to integer, better quality for less
		 * cycles (just a bit of zipper when changing 't', but it does sound
		 * interesting) */
		int ti;
		fistp (t, ti);
		x -= fb * delay[ti];

		delay.put (x + normal);

#		if 0
		/* allpass delay sounds a little cleaner for a chorus
		 * but sucks big time when flanging. */
		x = blend * x + ff * tap.get (delay, t + w * lfo.get());
#		elif 0
		/* linear interpolation */
		x = blend * x + ff * delay.get_at (t + w * lfo.get());
#		else
		/* cubic interpolation */
		x = blend * x + ff * delay.get_cubic (t + w * lfo.get());
#		endif

		F (d, i, x, adding_gain);

		t += dt;
		w += dw;
	}
}

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

PortInfo
ChorusI::port_info [] =
{
	{
		"in",
		INPUT | AUDIO,
		{BOUNDED, -1, 1}
	}, {
		"t (ms)",
		INPUT | CONTROL,
		{BOUNDED | LOG | DEFAULT_LOW, 2.5, 40}
	}, {
		"width (ms)",
		INPUT | CONTROL,
		{BOUNDED | DEFAULT_1, .5, 10}
	}, {
		"rate (Hz)",
		INPUT | CONTROL,
		{BOUNDED | DEFAULT_LOW, 0, 5}
	}, {
		"blend",
		INPUT | CONTROL,
		{BOUNDED | DEFAULT_1, 0, 1}
	}, {
		"feedforward",
		INPUT | CONTROL,
		{BOUNDED | DEFAULT_LOW, 0, 1}
	}, {
		"feedback",
		INPUT | CONTROL,
		{BOUNDED | DEFAULT_0, 0, 1}
	}, {
		"out",
		OUTPUT | AUDIO,
		{0}
	}
};

template <> void
Descriptor<ChorusI>::setup()
{
	UniqueID = 1767;
	Label = "ChorusI";
	Properties = HARD_RT;

	Name = CAPS "ChorusI - Mono chorus/flanger";
	Maker = "Tim Goetze <tim@quitte.de>";
	Copyright = "GPL, 2004-7";

	/* fill port info and vtable */
	autogen();
}

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

template <sample_func_t F>
void
StereoChorusI::one_cycle (int frames)
{
	sample_t * s = ports[0];

	double one_over_n = 1 / (double) frames;
	double ms = .001 * fs;

	double t = time;
	time = getport(1) * ms;
	double dt = (time - t) * one_over_n;

	double w = width;
	width = getport(2) * ms;
	/* clamp, or we need future samples from the delay line */
	if (width >= t - 1) width = t - 1;
	double dw = (width - w) * one_over_n;

	if (rate != *ports[3] && phase != *ports[4])
	{
		rate = getport(3);
		phase = getport(4);
		double phi = left.lfo.get_phase();
		left.lfo.set_f (max (rate, .000001), fs, phi);
		right.lfo.set_f (max (rate, .000001), fs, phi + phase * M_PI);
	}

	double blend = getport(5);
	double ff = getport(6);
	double fb = getport(7);

	sample_t * dl = ports[8];
	sample_t * dr = ports[9];

	/* to go sure (on i386) that the fistp instruction does the right thing
	 * when looking up fractional sample indices */
	DSP::FPTruncateMode truncate;

	for (int i = 0; i < frames; ++i)
	{
		sample_t x = s[i];

		/* truncate the feedback tap to integer, better quality for less
		 * cycles (just a bit of zipper when changing 't', but it does sound
		 * interesting) */
		int ti;
		fistp (t, ti);
		x -= fb * delay[ti];

		delay.put (x + normal);

		sample_t l = blend * x + ff * delay.get_cubic (t + w * left.lfo.get());
		sample_t r = blend * x + ff * delay.get_cubic (t + w * right.lfo.get());

		F (dl, i, l, adding_gain);
		F (dr, i, r, adding_gain);

		t += dt;
		w += dw;
	}
}

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

PortInfo
StereoChorusI::port_info [] =
{
	{
		"in",
		INPUT | AUDIO,
		{BOUNDED, -1, 1}
	}, {
		"t (ms)",
		INPUT | CONTROL,
		{BOUNDED | DEFAULT_MIN, 2.5, 40}
	}, {
		"width (ms)",
		INPUT | CONTROL,
		{BOUNDED | DEFAULT_1, .5, 10}
	}, {
		"rate (Hz)",
		INPUT | CONTROL,
		{BOUNDED | DEFAULT_LOW, 0, 5}
	}, {
		"phase",
		INPUT | CONTROL,
		{BOUNDED | DEFAULT_MAX, 0, 1}
	}, {
		"blend",
		INPUT | CONTROL,
		{BOUNDED | DEFAULT_1, 0, 1}
	}, {
		"feedforward",
		INPUT | CONTROL,
		{BOUNDED | DEFAULT_LOW, 0, 1}
	}, {
		"feedback",
		INPUT | CONTROL,
		{BOUNDED | DEFAULT_0, 0, 1}
	}, {
		"out:l",
		OUTPUT | AUDIO,
		{0}
	}, {
		"out:r",
		OUTPUT | AUDIO,
		{0}
	}
};

template <> void
Descriptor<StereoChorusI>::setup()
{
	UniqueID = 1768;
	Label = "StereoChorusI";
	Properties = HARD_RT;

	Name = CAPS "StereoChorusI - Stereo chorus/flanger";
	Maker = "Tim Goetze <tim@quitte.de>";
	Copyright = "GPL, 2004-7";

	/* fill port info and vtable */
	autogen();
}

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

template <sample_func_t F>
void
ChorusII::one_cycle (int frames)
{
	sample_t * s = ports[0];

	double one_over_n = 1 / (double) frames;
	double ms = .001 * fs;

	double t = time;
	time = getport(1) * ms;
	double dt = (time - t) * one_over_n;

	double w = width;
	width = getport(2) * ms;
	/* clamp, or we need future samples from the delay line */
	if (width >= t - 3) width = t - 3;
	double dw = (width - w) * one_over_n;

	if (rate != *ports[3])
		set_rate (*ports[3]);

	double blend = getport(4);
	double ff = getport(5);
	double fb = getport(6);

	sample_t * d = ports[7];

	DSP::FPTruncateMode truncate;

	for (int i = 0; i < frames; ++i)
	{
		sample_t x = s[i];

		x -= fb * delay.get_cubic (t);

		delay.put (filter.process (x + normal));

		double a = 0;
		for (int j = 0; j < Taps; ++j)
			a += taps[j].get (delay, t, w);

		x = blend * x + ff * a;

		F (d, i, x, adding_gain);

		t += dt;
		w += dw;
	}
}

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

PortInfo
ChorusII::port_info [] =
{
	{
		"in",
		INPUT | AUDIO,
		{BOUNDED, -1, 1}
	}, {
		"t (ms)",
		INPUT | CONTROL,
		{BOUNDED | LOG | DEFAULT_LOW, 2.5, 40}
	}, {
		"width (ms)",
		INPUT | CONTROL,
		{BOUNDED | DEFAULT_1, .5, 10}
	}, {
		"rate",
		INPUT | CONTROL,
		{BOUNDED | DEFAULT_LOW, 0, 1}
	}, {
		"blend",
		INPUT | CONTROL,
		{BOUNDED | DEFAULT_1, 0, 1}
	}, {
		"feedforward",
		INPUT | CONTROL,
		{BOUNDED | DEFAULT_LOW, 0, 1}
	}, {
		"feedback",
		INPUT | CONTROL,
		{BOUNDED | DEFAULT_0, 0, 1}
	}, {
		"out",
		OUTPUT | AUDIO,
		{0}
	}
};

template <> void
Descriptor<ChorusII>::setup()
{
	UniqueID = 2583;
	Label = "ChorusII";
	Properties = HARD_RT;

	Name = CAPS "ChorusII - Mono chorus/flanger modulated by a fractal";
	Maker = "Tim Goetze <tim@quitte.de>";
	Copyright = "GPL, 2004-7";

	/* fill port info and vtable */
	autogen();
}

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

template <sample_func_t F>
void
StereoChorusII::one_cycle (int frames)
{
	sample_t * s = ports[0];

	double one_over_n = 1 / (double) frames;
	double ms = .001 * fs;

	double t = time;
	time = getport(1) * ms;
	double dt = (time - t) * one_over_n;

	double w = width;
	width = getport(2) * ms;
	/* clamp, or we need future samples from the delay line */
	if (width >= t - 1) width = t - 1;
	double dw = (width - w) * one_over_n;

	set_rate (*ports[3]);

	double blend = getport(4);
	double ff = getport(5);
	double fb = getport(6);

	sample_t * dl = ports[7];
	sample_t * dr = ports[8];

	/* to go sure (on i386) that the fistp instruction does the right thing
	 * when looking up fractional sample indices */
	DSP::FPTruncateMode truncate;

	for (int i = 0; i < frames; ++i)
	{
		sample_t x = s[i];

		/* truncate the feedback tap to integer, better quality for less
		 * cycles (just a bit of zipper when changing 't', but it does sound
		 * interesting) */
		int ti;
		fistp (t, ti);
		x -= fb * delay[ti];

		delay.put (x + normal);

		double m;
		m = left.lfo_lp.process (left.fractal.get());
		sample_t l = blend * x + ff * delay.get_cubic (t + w * m);
		m = right.lfo_lp.process (right.fractal.get());
		sample_t r = blend * x + ff * delay.get_cubic (t + w * m);

		F (dl, i, l, adding_gain);
		F (dr, i, r, adding_gain);

		t += dt;
		w += dw;
	}
}

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

PortInfo
StereoChorusII::port_info [] =
{
	{
		"in",
		INPUT | AUDIO,
		{BOUNDED, -1, 1}
	}, {
		"t (ms)",
		INPUT | CONTROL,
		{BOUNDED | DEFAULT_LOW, 2.5, 40}
	}, {
		"width (ms)",
		INPUT | CONTROL,
		{BOUNDED | DEFAULT_LOW, .5, 10}
	}, {
		"rate",
		INPUT | CONTROL,
		{BOUNDED | DEFAULT_LOW, 0, 1}
	}, {
		"blend",
		INPUT | CONTROL,
		{BOUNDED | DEFAULT_1, 0, 1}
	}, {
		"feedforward",
		INPUT | CONTROL,
		{BOUNDED | DEFAULT_MID, 0, 1}
	}, {
		"feedback",
		INPUT | CONTROL,
		{BOUNDED | DEFAULT_0, 0, 1}
	}, {
		"out:l",
		OUTPUT | AUDIO,
		{0}
	}, {
		"out:r",
		OUTPUT | AUDIO,
		{0}
	}
};

template <> void
Descriptor<StereoChorusII>::setup()
{
	UniqueID = 2584;
	Label = "StereoChorusII";
	Properties = HARD_RT;

	Name = CAPS "StereoChorusII - Stereo chorus/flanger modulated by a fractal";
	Maker = "Tim Goetze <tim@quitte.de>";
	Copyright = "GPL, 2004-7";

	/* fill port info and vtable */
	autogen();
}


code:
/*
	Chorus.h

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

	http://quitte.de/dsp/

	mono and stereo chorus/flanger units, traditional designs and some
	differentiated a bit further.

*/
/*
	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 _CHORUS_H_
#define _CHORUS_H_

#include "dsp/Sine.h"
#include "dsp/Roessler.h"
#include "dsp/Lorenz.h"
#include "dsp/Delay.h"
#include "dsp/OnePole.h"
#include "dsp/BiQuad.h"
#include "dsp/RBJ.h"

class ChorusStub
: public Plugin
{
	public:
		sample_t time, width, rate;
};

class ChorusI
: public ChorusStub
{
	public:
		DSP::Sine lfo;
		DSP::Delay delay;
		DSP::DelayTapA tap;

		template <sample_func_t>
			void one_cycle (int frames);

	public:
		static PortInfo port_info [];

		void init()
			{
				rate = .15;
				delay.init ((int) (.040 * fs));
			}

		void activate()
			{
				time = 0;
				width = 0;

				rate = *ports[3];

				delay.reset();
				tap.reset();

				lfo.set_f (rate, fs, 0);
			}

		void run (int n)
			{
				one_cycle<store_func> (n);
			}

		void run_adding (int n)
			{
				one_cycle<adding_func> (n);
			}
};

class StereoChorusI
: public ChorusStub
{
	public:
		sample_t rate;
		sample_t phase;

		DSP::Delay delay;

		struct {
			DSP::Sine lfo;
			DSP::DelayTapA tap;
		} left, right;

		template <sample_func_t>
			void one_cycle (int frames);

	public:
		static PortInfo port_info [];

		void init()
			{
				rate = .15;
				phase = .5; /* pi */

				delay.init ((int) (.040 * fs));
			}

		void activate()
			{
				time = 0;
				width = 0;

				delay.reset();

				left.tap.reset();
				right.tap.reset();

				left.lfo.set_f (rate, fs, 0);
				right.lfo.set_f (rate, fs, phase * M_PI);
			}

		void run (int n)
			{
				one_cycle<store_func> (n);
			}

		void run_adding (int n)
			{
				one_cycle<adding_func> (n);
			}
};

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

#define FRACTAL_RATE 0.02

/* fractally modulated Chorus units */

class FracTap
{
	public:
		DSP::Lorenz f1;
		DSP::Roessler f2;
		DSP::OnePoleLP lp;

		void init (double fs)
			{
				lp.set_f (30. / fs);
				f1.init (.001, frandom());
				f2.init (.001, frandom());
			}

		void set_rate (sample_t r)
			{
				f1.set_rate (r * FRACTAL_RATE);
				f2.set_rate (3.3 * r * FRACTAL_RATE);
			}

		/* t = time, w = width, should inline nicely */
		sample_t get (DSP::Delay & d, double t, double w)
			{
				double m = lp.process (f1.get() + .3 * f2.get());
				return d.get_cubic (t + w * m);
			}
};

class ChorusII
: public ChorusStub
{
	public:
		enum {
			Taps = 1
		};

		FracTap taps[Taps];
		DSP::BiQuad filter;
		DSP::Delay delay;

		template <sample_func_t>
			void one_cycle (int frames);

		void set_rate (sample_t r)
			{
				rate = r;
				for (int i = 0; i < Taps; ++i)
				{
					taps[i].set_rate (rate * (i * FRACTAL_RATE) / Taps);
					// fprintf (stderr, "[%d] %.3f\n", i, (rate * (i * FRACTAL_RATE) / Taps));
				}
			}

	public:
		static PortInfo port_info [];

		void init()
			{
				delay.init ((int) (.040 * fs));
				for (int i = 0; i < Taps; ++i)
					taps[i].init (fs);
				DSP::RBJ::HiShelve (1000. / fs, 1., 6, filter.a, filter.b);
			}

		void activate()
			{
				time = 0;
				width = 0;

				set_rate (*ports[3]);

				delay.reset();
				filter.reset();
			}

		void run (int n)
			{
				one_cycle<store_func> (n);
			}

		void run_adding (int n)
			{
				one_cycle<adding_func> (n);
			}
};

class StereoChorusII
: public ChorusStub
{
	public:
		sample_t rate;
		sample_t phase;

		DSP::Delay delay;

		struct {
			DSP::Roessler fractal;
			DSP::OnePoleLP lfo_lp;
			DSP::DelayTapA tap;
		} left, right;

		template <sample_func_t>
		void one_cycle (int frames);

		void set_rate (sample_t r)
			{
				rate = r;
				left.fractal.set_rate (rate * FRACTAL_RATE);
				right.fractal.set_rate (rate * FRACTAL_RATE);
				left.lfo_lp.set_f (3. / fs);
				right.lfo_lp.set_f (3. / fs);
			}

	public:
		static PortInfo port_info [];
		sample_t adding_gain;

		void init()
			{
				phase = .5; /* pi */

				delay.init ((int) (.040 * fs));

				left.fractal.init (.001, frandom());
				right.fractal.init (.001, frandom());
			}

		void activate()
			{
				time = 0;
				width = 0;

				delay.reset();

				left.tap.reset();
				right.tap.reset();

				set_rate (*ports[3]);
			}

		void run (int n)
			{
				one_cycle<store_func> (n);
			}

		void run_adding (int n)
			{
				one_cycle<adding_func> (n);
			}
};

#endif /* _CHORUS_H_ */


code:
/*
	Click.cc

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

	http://quitte.de/dsp/

	Plugins playing a sound snippet in regular intervals.

*/
/*
	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.
*/

#include "basics.h"

#include "waves/click.h"
#include "waves/money.h"

#include "Click.h"
#include "Descriptor.h"

void
ClickStub::init (float * _wave, int _N)
{
	wave = _wave;
	N = _N;
	bpm = -1;
}

template <sample_func_t F>
void
ClickStub::one_cycle (int frames)
{
	bpm = getport(0);
	sample_t gain = getport(1) * *ports[1];
	lp.set (1 - *ports[2]);

	sample_t * d = ports[3];

	while (frames)
	{
		if (period == 0)
		{
			period = (int) (fs * 60 / bpm);
			played = 0;
		}

		int n = min (frames, period);

		if (played < N)
		{
			n = min (n, N - played);

			for (int i = 0; i < n; ++i)
			{
				sample_t x = gain * wave [played + i] + normal;
				F (d, i, lp.process (x), adding_gain);
				normal = -normal;
			}

			played += n;
		}
		else
		{
			for (int i = 0; i < n; ++i)
			{
				F (d, i, lp.process (normal), adding_gain);
				normal = -normal;
			}
		}

		period -= n;
		frames -= n;
		d += n;
	}
}

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

PortInfo
ClickStub::port_info [] =
{
	{
		"bpm",
		INPUT | CONTROL,
		{BOUNDED | DEFAULT_LOW, 4, 244}
	}, {
		"volume",
		INPUT | CONTROL,
		{BOUNDED | DEFAULT_MID, 0, 1}
	}, {
		"damping",
		INPUT | CONTROL,
		{BOUNDED | DEFAULT_HIGH, 0, 1}
	}, {
		"out",
		OUTPUT | AUDIO,
		{0}
	}
};

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

#define LENGTH(W) ((int) (sizeof (W) / sizeof (float)))

void
Click::init()
{
	this->ClickStub::init (click, LENGTH (click));
}

template <> void
Descriptor<Click>::setup()
{
	UniqueID = 1769;
	Label = "Click";
	Properties = HARD_RT;

	Name = CAPS "Click - Metronome";
	Maker = "Tim Goetze <tim@quitte.de>";
	Copyright = "GPL, 2004-7";

	/* fill port info and vtable */
	autogen();
}

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

PortInfo
CEO::port_info [] =
{
	{
		"mpm",
		INPUT | CONTROL,
		{BOUNDED | DEFAULT_HIGH, 4, 244}
	}, {
		"volume",
		INPUT | CONTROL,
		{BOUNDED | DEFAULT_MID, 0, 1}
	}, {
		"damping",
		INPUT | CONTROL,
		{BOUNDED | DEFAULT_MIN, 0, 1}
	}, {
		"out",
		OUTPUT | AUDIO,
		{0}
	}
};

void
CEO::init()
{
	this->ClickStub::init (money, LENGTH (money));
}

template <> void
Descriptor<CEO>::setup()
{
	UniqueID = 1770;
	Label = "CEO";
	Properties = HARD_RT;

	Name = CAPS "CEO - Chief Executive Oscillator";
	Maker = "Tim Goetze <tim@quitte.de>";
	Copyright = "GPL, 2004-7";

	/* fill port info and vtable */
	autogen();
}

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

float dirac [] = { 1, };

PortInfo
Dirac::port_info [] =
{
	{
		"ppm",
		INPUT | CONTROL,
		{BOUNDED | DEFAULT_MIN, 30, 60}
	}, {
		"volume",
		INPUT | CONTROL,
		{BOUNDED | DEFAULT_0, 0, 1}
	}, {
		"damping",
		INPUT | CONTROL,
		{BOUNDED | DEFAULT_0, 0, 1}
	}, {
		"out",
		OUTPUT | AUDIO,
		{0}
	}
};

void
Dirac::init()
{
	this->ClickStub::init (dirac, LENGTH (dirac));
}

template <> void
Descriptor<Dirac>::setup()
{
	UniqueID = 2585;
	Label = "Dirac";
	Properties = HARD_RT;

	Name = CAPS "Dirac - One-sample impulse generator";
	Maker = "Tim Goetze <tim@quitte.de>";
	Copyright = "GPL, 2004-7";

	/* fill port info and vtable */
	autogen();
}


code:
/*
	Click.h

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

	http://quitte.de/dsp/

	units perpetually repeating a recorded sample.

*/
/*
	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 _CLICK_H_
#define _CLICK_H_

#include "dsp/OnePole.h"
#include "dsp/util.h"

class ClickStub
: public Plugin
{
	public:
		sample_t bpm;

		float * wave;
		int N; /* number of samples in wave */

		DSP::OnePoleLP lp;

		int period; /* frames remaining in period */
		int played; /* frames played from sample */

		template <sample_func_t F>
			void one_cycle (int frames);

	public:
		static PortInfo port_info [];

		void init (float * _wave, int _N);

		void activate()
			{
				played = 0;
				period = 0;
			}

		void run (int n)
			{
				one_cycle<store_func> (n);
			}

		void run_adding (int n)
			{
				one_cycle<adding_func> (n);
			}
};

class Click
: public ClickStub
{
	public:
		void init();
};

class CEO
: public ClickStub
{
	public:
		void init();

		static PortInfo port_info [];
};

class Dirac
: public ClickStub
{
	public:
		void init();

		static PortInfo port_info [];
};

#endif /* _CLICK_H_ */


code:
/*
	Clip.cc

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

	http://quitte.de/dsp/

	simple oversampled hard clipper

*/
/*
	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.
*/

#include "basics.h"

#include "Clip.h"
#include "Descriptor.h"

void
Clip::init()
{
	gain = 1;

	threshold[0] = -.9;
	threshold[1] = +.9;

	/* going a bit lower than nominal with fc */
	double f = .5 * M_PI / OVERSAMPLE;

	/* construct the upsampler filter kernel */
	DSP::sinc (f, up.c, FIR_SIZE);
	DSP::kaiser<DSP::apply_window> (up.c, FIR_SIZE, 6.4);

	/* copy upsampler filter kernel for downsampler, make sum */
	double s = 0;
	for (int i = 0; i < up.n; ++i)
		down.c[i] = up.c[i],
		s += up.c[i];

	/* scale downsampler kernel for unity gain */
	s = 1 / s;
	for (int i = 0; i < down.n; ++i)
		down.c[i] *= s;

	/* scale upsampler kernel for unity gain */
	s *= OVERSAMPLE;
	for (int i = 0; i < up.n; ++i)
		up.c[i] *= s;
}

inline sample_t
Clip::clip (sample_t a)
{
	if (a < threshold[0])
		return threshold[0];
	if (a > threshold[1])
		return threshold[1];
	return a;
}

template <sample_func_t F>
void
Clip::one_cycle (int frames)
{
	sample_t * s = ports[0];

	double g = getport (1);
	double gf;
	if (g == gain_db)
		gf = 1;
	else
	{
		gain_db = g;
		sample_t g = DSP::db2lin (gain_db);
		gf = pow (g / gain, 1 / (double) frames);
	}

	sample_t * d = ports[2];
	*ports[3] = OVERSAMPLE;

	for (int i = 0; i < frames; ++i)
	{
		register sample_t a = gain * s[i];

		a = down.process (clip (up.upsample (a)));

		for (int o = 1; o < OVERSAMPLE; ++o)
			down.store (clip (up.pad (o)));

		F (d, i, a, adding_gain);

		gain *= gf;
	}
}

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

PortInfo
Clip::port_info [] =
{
	{
		"in",
		INPUT | AUDIO,
		{BOUNDED, -1, 1}
	}, {
		"gain (dB)",
		INPUT | CONTROL,
		{BOUNDED | DEFAULT_1, -72, 72}
	}, {
		"out",
		OUTPUT | AUDIO,
		{0}
	}, {
		"latency",
		OUTPUT | CONTROL,
		{0}
	}
};

template <> void
Descriptor<Clip>::setup()
{
	UniqueID = 1771;
	Label = "Clip";
	Properties = HARD_RT;

	Name = CAPS "Clip - Hard clipper, 8x oversampled";
	Maker = "Tim Goetze <tim@quitte.de>";
	Copyright = "GPL, 2003-7";

	/* fill port info and vtable */
	autogen();
}


code:
/*
	Clip.h

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

	http://quitte.de/dsp/

	oversampled hard ('diode', 'transistor', sometimes 'op-amp') clipper.

*/
/*
	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 _CLIP_H_
#define _CLIP_H_

#include "dsp/util.h"
#include "dsp/FIR.h"
#include "dsp/sinc.h"
#include "dsp/windows.h"

class Clip
: public Plugin
{
	public:
		sample_t gain, gain_db;

		sample_t threshold[2];

		enum {
			OVERSAMPLE = 8,
			FIR_SIZE = 64,
		};

		/* antialias filters */
		DSP::FIRUpsampler up;
		DSP::FIR down;

		template <sample_func_t F>
			void one_cycle (int frames);

		inline sample_t clip (sample_t x);

	public:
		static PortInfo port_info[];

		Clip()
			: up (FIR_SIZE, OVERSAMPLE),
				down (FIR_SIZE)
			{ }

		void init();

		void activate()
			{
				up.reset();
				down.reset();
				gain_db = *ports[1];
				gain = DSP::db2lin (gain_db);
			}

		void run (int n)
			{
				one_cycle<store_func> (n);
			}

		void run_adding (int n)
			{
				one_cycle<adding_func> (n);
			}
};

#endif /* _CLIP_H_ */


code:
/*
	Compress.cc

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

	http://quitte.de/dsp/

	mono compressor suitable for solo instruments. adaptation of Steve
	Harris' 'sc1' unit, with minor tweaks: table lookup for attack and
	release time to frames mapping replaced with exp. port order changed.
*/
/*
	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.
*/

#include "basics.h"

#include "Compress.h"
#include "Descriptor.h"

template <sample_func_t F>
void
Compress::one_cycle (int frames)
{
	sample_t * s = ports[0];

	sample_t range = DSP::db2lin (getport(1));
	sample_t ratio = (*ports[2] - 1) / getport(2);

	/* sc1 has lookup tables here, and they're only 40 % used (400 ms/1 s).
	 * thus, sc1's attack/release controls are a bit coarse due to truncation
	 * error. calling exp() once per cycle doesn't seem too expensive.
	 *
	 * besides, i have a suspicion that the attack and release parameters
	 * don't work like they should. if they, as the code suggests, control
	 * an exponential envelope fade, pow (.5, n_frames) or something like
	 * that seems more appropriate. so ...
	 *
	 * TODO: check whether these parameters work like they should, try pow()
	 */
	double ga = exp (-1 / (fs * getport(3)));
	double gr = exp (-1 / (fs * getport(4)));

	sample_t threshold = getport(5);
	sample_t knee = getport(6);

	sample_t * d = ports[7];

	sample_t knee0 = DSP::db2lin (threshold - knee);
	sample_t knee1 = DSP::db2lin (threshold + knee);

	sample_t ef_a = ga * .25;
	sample_t ef_ai = 1 - ef_a;

	for (int i = 0; i < frames; ++i)
	{
		sum += s[i] * s[i];

		if (amp > env)
			env = env * ga + amp * (1 - ga);
		else
			env = env * gr + amp * (1 - gr);

		if ((count++ & 3) == 3)
		{
			amp = rms.process (sum * .25);
			sum = 0;

			if (env < knee0)
				gain_t = 1;
			else if (env < knee1)
			{
				float x = -(threshold - knee - DSP::lin2db (env)) / knee;
				gain_t = DSP::db2lin (-knee * ratio * x * x * 0.25f);
			}
			else
				gain_t = DSP::db2lin ((threshold - DSP::lin2db (env)) * ratio);
		}

	  gain = gain * ef_a + gain_t * ef_ai;

		F (d, i, s[i] * gain * range, adding_gain);
	}
}

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

PortInfo
Compress::port_info [] =
{
	{
		"in",
		INPUT | AUDIO,
		{BOUNDED, -1, 1}
	}, {
		"gain (dB)",
		INPUT | CONTROL,
		{BOUNDED | DEFAULT_LOW, 0, 24}
	}, {
		"ratio (1:n)",
		INPUT | CONTROL,
		{BOUNDED | DEFAULT_MIN, 1, 10}
	}, {
		"attack (s)",
		INPUT | CONTROL,
		{BOUNDED | DEFAULT_MIN, .001, 1}
	}, {
		"release (s)",
		INPUT | CONTROL,
		{BOUNDED | DEFAULT_MID, .001, 1}
	}, {
		"threshold (dB)",
		INPUT | CONTROL,
		{BOUNDED | DEFAULT_0, -30, 400}
	}, {
		"knee radius (dB)",
		INPUT | CONTROL,
		{BOUNDED | DEFAULT_LOW, 1, 10}
	}, {
		"out",
		OUTPUT | AUDIO,
		{0}
	}
};

template <> void
Descriptor<Compress>::setup()
{
	UniqueID = 1772;
	Label = "Compress";
	Properties = HARD_RT;

	Name = CAPS "Compress - Mono compressor";
	Maker = "Tim Goetze <tim@quitte.de>, Steve Harris <steve@plugin.org.uk>";
	Copyright = "GPL, 2004-7";

	/* fill port info and vtable */
	autogen();
}


code:
/*
	Compress.h

	Copyright 2004-5 Tim Goetze <tim@quitte.de>, Steve Harris

	http://quitte.de/dsp/

	mono compressor.

*/
/*
	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 _COMPRESS_H_
#define _COMPRESS_H_

#include "dsp/RMS.h"
#include "dsp/util.h"

class Compress
: public Plugin
{
	public:
		double fs;
		sample_t f;

		DSP::RMS rms;
		sample_t sum, amp, env, gain, gain_t;

		int count;

		template <sample_func_t F>
			void one_cycle (int frames);

	public:
		static PortInfo port_info [];

		void init() {}
		void activate()
			{
				rms.reset();

				sum = 0;
				count = 0;

				amp = 0;
				env = 0;

				gain = 0;
				gain_t = 0;
			}

		void run (int n)
			{
				one_cycle<store_func> (n);
			}

		void run_adding (int n)
			{
				one_cycle<adding_func> (n);
			}
};

#endif /* _COMPRESS_H_ */


code:
/*
	Descriptor.h

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

	http://quitte.de/dsp/

	Creating a LADSPA_Descriptor for a CAPS plugin via a C++ template,
	saving a virtual function call compared to the usual method used
	for C++ plugins in a C context.

	Descriptor<P> expects P to declare some common methods, like init(),
	activate() etc, plus a static port_info[] and LADSPA_Data * ports[]
	and adding_gain.  (P should derive from Plugin, too.)

*/
/*
	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 _DESCRIPTOR_H_
#define _DESCRIPTOR_H_

#ifdef __SSE__
#include <xmmintrin.h>
#endif
#ifdef __SSE3__
#include <pmmintrin.h>
#endif

/* common stub for Descriptor makes it possible to delete() without special-
 * casing for every plugin class.
 */
class DescriptorStub
: public LADSPA_Descriptor
{
	public:
		DescriptorStub()
			{
				PortCount = 0;
			}

		~DescriptorStub()
			{
				if (PortCount)
				{
					delete [] PortNames;
					delete [] PortDescriptors;
					delete [] PortRangeHints;
				}
			}
};

inline void
processor_specific_denormal_measures()
{
	#ifdef __SSE3__
	/* this one works reliably on a 6600 Core2 */
	_MM_SET_DENORMALS_ZERO_MODE (_MM_DENORMALS_ZERO_ON);
	#endif

	#ifdef __SSE__
	/* this one doesn't ... */
	_MM_SET_FLUSH_ZERO_MODE (_MM_FLUSH_ZERO_ON);
	#endif
}

template <class T>
class Descriptor
: public DescriptorStub
{
	public:
		LADSPA_PortRangeHint * ranges;

	public:
		Descriptor() { setup(); }
		void setup();

		void autogen()
			{
				PortCount = (sizeof (T::port_info) / sizeof (PortInfo));

				/* unroll PortInfo members */
				const char ** names = new const char * [PortCount];
				LADSPA_PortDescriptor * desc = new LADSPA_PortDescriptor [PortCount];
				ranges = new LADSPA_PortRangeHint [PortCount];

				/* could also assign directly but const_cast is ugly. */
				for (int i = 0; i < (int) PortCount; ++i)
				{
					names[i] = T::port_info[i].name;
					desc[i] = T::port_info[i].descriptor;
					ranges[i] = T::port_info[i].range;
				}

				PortNames = names;
				PortDescriptors = desc;
				PortRangeHints = ranges;

				/* LADSPA_Descriptor vtable entries */
				instantiate = _instantiate;
				connect_port = _connect_port;
				activate = _activate;
				run = _run;
				run_adding = _run_adding;
				set_run_adding_gain = _set_run_adding_gain;
				deactivate = 0;
				cleanup = _cleanup;
			}

		static LADSPA_Handle _instantiate (
				const struct _LADSPA_Descriptor * d, ulong fs)
			{
				T * plugin = new T();
				int n = (int) d->PortCount;

				LADSPA_PortRangeHint * ranges = ((Descriptor *) d)->ranges;
				plugin->ranges = ranges;

				plugin->ports = new sample_t * [n];

				/* connect to lower bound as a safety measure */
				for (int i = 0; i < n; ++i)
					plugin->ports[i] = &(ranges[i].LowerBound);

				plugin->fs = fs;
				plugin->normal = NOISE_FLOOR;
				plugin->init();

				return plugin;
			}

		static void _connect_port (LADSPA_Handle h, ulong i, LADSPA_Data * p)
			{
				((T *) h)->ports[i] = p;
			}

		static void _activate (LADSPA_Handle h)
			{
				T * plugin = (T *) h;

				plugin->first_run = 1;

				/* since none of the plugins do any RT-critical work in
				 * activate(), it's safe to defer the actual call to the
				 * plugin's activate() method for the first run() after
				 * the host called in here.
				 *
				 * It's the simplest way to prevent a parameter smoothing sweep
				 * in the first audio block after activation.
				plugin->activate();
				 */
			}

		static void _run (LADSPA_Handle h, ulong n)
			{
				T * plugin = (T *) h;

				/* We don't reset the processor flags later, it's true. */
				processor_specific_denormal_measures();

				/* If this is the first audio block after activation,
				 * initialize the plugin from the current set of parameters. */
				if (plugin->first_run)
				{
					plugin->activate();
					plugin->first_run = 0;
				}

				plugin->run (n);
				plugin->normal = -plugin->normal;
			}

		static void _run_adding (LADSPA_Handle h, ulong n)
			{
				T * plugin = (T *) h;

				/* We don't reset the processor flags later, it's true. */
				processor_specific_denormal_measures();

				/* If this is the first audio block after activation,
				 * initialize the plugin from the current set of parameters. */
				if (plugin->first_run)
				{
					plugin->activate();
					plugin->first_run = 0;
				}

				plugin->run_adding (n);
				plugin->normal = -plugin->normal;
			}

		static void _set_run_adding_gain (LADSPA_Handle h, LADSPA_Data g)
			{
				T * plugin = (T *) h;

				plugin->adding_gain = g;
			}

		static void _cleanup (LADSPA_Handle h)
			{
				T * plugin = (T *) h;

				delete [] plugin->ports;
				delete plugin;
			}
};

#endif /* _DESCRIPTOR_H_ */


code:
/*
	Eq.cc

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

	http://quitte.de/dsp/

	10-band octave-spread equalizer.

*/
/*
	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.
*/

#include "basics.h"
#include <stdio.h>

#include "Eq.h"
#include "Descriptor.h"

/* slight adjustments to gain to keep response optimally flat at
 * 0 dB gain in all bands */
inline static double
adjust_gain (int i, double g)
{
	static float adjust[] = {
		0.69238604707174034, 0.67282771124180096,
		0.67215187672467813, 0.65768648447259315,
		0.65988083755898952, 0.66359580101701909,
		0.66485139160960427, 0.65890297086039662,
		0.6493229390740376, 0.82305724539749325
	};

	return g * adjust[i];
}

#define Q 1.414

void
Eq::init()
{
	eq.init (fs, Q);
}

void
Eq::activate()
{
	for (int i = 0; i < 10; ++i)
	{
		gain[i] = getport (1 + i);
		eq.gain[i] = adjust_gain (i, DSP::db2lin (gain[i]));
		eq.gf[i] = 1;
	}
}

template <sample_func_t F>
void
Eq::one_cycle (int frames)
{
	sample_t * s = ports[0];

	/* evaluate band gain changes and compute recursion factor to prevent
	 * zipper noise */
	double one_over_n = frames > 0 ? 1. / frames : 1;

	for (int i = 0; i < 10; ++i)
	{
		sample_t g = getport (1 + i);
		if (g == gain[i])
		{
			/* no gain factoring */
			eq.gf[i] = 1;
			continue;
		}
		gain[i] = g;

		double want = adjust_gain (i, DSP::db2lin (g));
		eq.gf[i] = pow (want / eq.gain[i], one_over_n);
	}

	sample_t * d = ports[11];

	for (int i = 0; i < frames; ++i)
	{
		sample_t x = s[i];
		x = eq.process (x);
		F (d, i, x, adding_gain);
	}

	eq.normal = -normal;
	eq.flush_0();
}

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

PortInfo
Eq::port_info [] =
{
	{
		"in",
		INPUT | AUDIO,
		{0, -1, 1}
	}, {
		"31 Hz",
		INPUT | CONTROL,
		{BOUNDED | DEFAULT_0, -48, 24}
	}, {
		"63 Hz",
		INPUT | CONTROL,
		{BOUNDED | DEFAULT_0, -48, 24}
	}, {
		"125 Hz",
		INPUT | CONTROL,
		{BOUNDED | DEFAULT_0, -48, 24}
	}, {
		"250 Hz",
		INPUT | CONTROL,
		{BOUNDED | DEFAULT_0, -48, 24}
	}, {
		"500 Hz",
		INPUT | CONTROL,
		{BOUNDED | DEFAULT_0, -48, 24}
	}, {
		"1 kHz",
		INPUT | CONTROL,
		{BOUNDED | DEFAULT_0, -48, 24}
	}, {
		"2 kHz",
		INPUT | CONTROL,
		{BOUNDED | DEFAULT_0, -48, 24}
	}, {
		"4 kHz",
		INPUT | CONTROL,
		{BOUNDED | DEFAULT_0, -48, 24}
	}, {
		"8 kHz",
		INPUT | CONTROL,
		{BOUNDED | DEFAULT_0, -48, 24}
	}, {
		"16 kHz",
		INPUT | CONTROL,
		{BOUNDED | DEFAULT_0, -48, 24}
	}, {
		"out",
		OUTPUT | AUDIO,
		{0}
	}
};

template <> void
Descriptor<Eq>::setup()
{
	UniqueID = 1773;
	Label = "Eq";
	Properties = HARD_RT;

	Name = CAPS "Eq - 10-band equalizer";
	Maker = "Tim Goetze <tim@quitte.de>";
	Copyright = "GPL, 2004-7";

	/* fill port info and vtable */
	autogen();
}

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

void
Eq2x2::init()
{
	for (int c = 0; c < 2; ++c)
		eq[c].init (fs, Q);
}

void
Eq2x2::activate()
{
	/* Fetch current parameter settings so we won't sweep band gains in the
	 * first block to process.
	 */
	for (int i = 0; i < 10; ++i)
	{
		gain[i] = getport (2 + i);
		double a = adjust_gain (i, DSP::db2lin (gain[i]));
		for (int c = 0; c < 2; ++c)
			eq[c].gf[i] = 1,
			eq[c].gain[i] = a;
	}
}

template <sample_func_t F>
void
Eq2x2::one_cycle (int frames)
{
	/* evaluate band gain changes and compute recursion factor to prevent
	 * zipper noise */
	double one_over_n = frames > 0 ? 1. / frames : 1;

	for (int i = 0; i < 10; ++i)
	{
		double a;

		if (*ports [2 + i] == gain[i])
			/* still same value, no gain fade */
			a = 1;
		else
		{
			gain[i] = getport (2 + i);

			/* prepare factor for logarithmic gain fade */
			a = adjust_gain (i, DSP::db2lin (gain[i]));
			a = pow (a / eq[0].gain[i], one_over_n);
		}

		for (int c = 0; c < 2; ++c)
			eq[c].gf[i] = a;
	}

	for (int c = 0; c < 2; ++c)
	{
		sample_t
			* s = ports[c],
			* d = ports[12 + c];

		for (int i = 0; i < frames; ++i)
		{
			sample_t x = s[i];
			x = eq[c].process (x);
			F (d, i, x, adding_gain);
		}
	}

	/* flip 'renormal' values */
	for (int c = 0; c < 2; ++c)
	{
		eq[c].normal = normal;
		eq[c].flush_0();
	}
}

PortInfo
Eq2x2::port_info [] =
{
	{
		"in:l",
		INPUT | AUDIO,
		{0, -1, 1}
	}, {
		"in:r",
		INPUT | AUDIO,
		{0, -1, 1}
	}, {
		"31 Hz",
		INPUT | CONTROL,
		{BOUNDED | DEFAULT_0, -48, 24}
	}, {
		"63 Hz",
		INPUT | CONTROL,
		{BOUNDED | DEFAULT_0, -48, 24}
	}, {
		"125 Hz",
		INPUT | CONTROL,
		{BOUNDED | DEFAULT_0, -48, 24}
	}, {
		"250 Hz",
		INPUT | CONTROL,
		{BOUNDED | DEFAULT_0, -48, 24}
	}, {
		"500 Hz",
		INPUT | CONTROL,
		{BOUNDED | DEFAULT_0, -48, 24}
	}, {
		"1 kHz",
		INPUT | CONTROL,
		{BOUNDED | DEFAULT_0, -48, 24}
	}, {
		"2 kHz",
		INPUT | CONTROL,
		{BOUNDED | DEFAULT_0, -48, 24}
	}, {
		"4 kHz",
		INPUT | CONTROL,
		{BOUNDED | DEFAULT_0, -48, 24}
	}, {
		"8 kHz",
		INPUT | CONTROL,
		{BOUNDED | DEFAULT_0, -48, 24}
	}, {
		"16 kHz",
		INPUT | CONTROL,
		{BOUNDED | DEFAULT_0, -48, 24}
	}, {
		"out:l",
		OUTPUT | AUDIO,
		{0}
	}, {
		"out:r",
		OUTPUT | AUDIO,
		{0}
	}
};

template <> void
Descriptor<Eq2x2>::setup()
{
	UniqueID = 2594;
	Label = "Eq2x2";
	Properties = HARD_RT;

	Name = CAPS "Eq2x2 - stereo 10-band equalizer";
	Maker = "Tim Goetze <tim@quitte.de>";
	Copyright = "GPL, 2004-7";

	/* fill port info and vtable */
	autogen();
}

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

/*
	todo: parametric -- 20-400, 60-1k, 150-2.5k, 500-8k, 1k-20k
	bandwidth 0-2 octaves
 */


code:
/*
	Eq.h

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

	http://quitte.de/dsp/

	equalizer circuit using recursive filtering.

*/
/*
	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 _EQ_H_
#define _EQ_H_

#include "dsp/util.h"
#include "dsp/Eq.h"
#include "dsp/BiQuad.h"
#include "dsp/RBJ.h"

class Eq
: public Plugin
{
	public:
		sample_t gain[10];
		DSP::Eq<10> eq;

		int block;
			enum { BlockSize = 64 };

		template <sample_func_t F>
			void one_cycle (int frames);

	public:
		static PortInfo port_info [];

		void init();
		void activate();

		void run (int n)
			{
				one_cycle<store_func> (n);
			}

		void run_adding (int n)
			{
				one_cycle<adding_func> (n);
			}
};

class Eq2x2
: public Plugin
{
	public:
		sample_t gain[10];
		DSP::Eq<10> eq[2];

		template <sample_func_t F>
			void one_cycle (int frames);

	public:
		static PortInfo port_info [];

		void init();
		void activate();

		void run (int n)
			{
				one_cycle<store_func> (n);
			}

		void run_adding (int n)
			{
				one_cycle<adding_func> (n);
			}
};

#endif /* _EQ_H_ */


code:
/*
	HRTF.cc

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

	http://quitte.de/dsp/

	high-order IIR filtering modeled after HRTF impulse responses

*/
/*
	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.
*/

#include "basics.h"

#include "HRTF.h"
#include "Descriptor.h"

#include "elev0.h"

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

void
HRTF::init()
{
	h = 0;
}

void
HRTF::set_pan (int p)
{
	n = 31;

	pan = p;

	if (p >= 0)
	{
		left.a = elev0[p].left.a;
		left.b = elev0[p].left.b;
		right.a = elev0[p].right.a;
		right.b = elev0[p].right.b;
	}
	else
	{
		p = -p;
		left.a = elev0[p].right.a;
		left.b = elev0[p].right.b;
		right.a = elev0[p].left.a;
		right.b = elev0[p].left.b;
	}

	memset (left.y, 0, sizeof (left.y));
	memset (right.y, 0, sizeof (right.y));
}

template <sample_func_t F>
void
HRTF::one_cycle (int frames)
{
	sample_t * s = ports[0];

	int p = (int) getport(1);
	if (p != pan) set_pan (p);

	sample_t * dl = ports[2];
	sample_t * dr = ports[3];

	double l, r;

	for (int i = 0; i < frames; ++i)
	{
		x[h] = l = r = s[i] + normal;

		l *= left.a[0];
		r *= right.a[0];

		for (int j = 1, z = h - 1; j < n; --z, ++j)
		{
			z &= 31;
			l += left.a[j] * x[z];
			l += left.b[j] * left.y[z];
			r += right.a[j] * x[z];
			r += right.b[j] * right.y[z];
		}

		left.y[h] = l;
		right.y[h] = r;

		h = (h + 1) & 31;

		F (dl, i, l, adding_gain);
		F (dr, i, r, adding_gain);
	}
}

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

PortInfo
HRTF::port_info [] =
{
	{
		"in",
		INPUT | AUDIO,
		{BOUNDED, -1, 1}
	}, {
		"pan",
		INPUT | CONTROL,
		{BOUNDED | INTEGER | DEFAULT_0, -36, 36}
	}, {
		"out:l",
		OUTPUT | AUDIO,
		{0}
	}, {
		"out:r",
		OUTPUT | AUDIO,
		{0}
	}
};

template <> void
Descriptor<HRTF>::setup()
{
	UniqueID = 1787;
	Label = "HRTF";
	Properties = HARD_RT;

	Name = CAPS "HRTF - Head-related transfer function at elevation 0";
	Maker = "Tim Goetze <tim@quitte.de>";
	Copyright = "GPL, 2004-7";

	/* fill port info and vtable */
	autogen();
}


code:
/*
	HRTF.h

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

	http://quitte.de/dsp/

	IIR filtering based on HRTF data sets

*/
/*
	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 _HRTF_H_
#define _HRTF_H_

#include "dsp/util.h"

class HRTF
: public Plugin
{
	public:
		int pan;
		int n, h;

		double x[32];

		struct {
			double * a, * b;
			double y[32];
		} left, right;

		void set_pan (int p);

		template <sample_func_t F>
		void one_cycle (int frames);

	public:
		static PortInfo port_info [];

		void init();
		void activate()
			{
				set_pan ((int) *ports[1]);
			}

		void run (int n)
			{
				one_cycle<store_func> (n);
			}

		void run_adding (int n)
			{
				one_cycle<adding_func> (n);
			}
};

#endif /* _HRTF_H_ */


code:
/*
	Lorenz.cc

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

	http://quitte.de/dsp/

	the sound of a Lorenz attractor.

*/
/*
	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.
*/

#include <stdlib.h>

#include "basics.h"

#include "Lorenz.h"
#include "Descriptor.h"

void
Lorenz::init()
{
	lorenz.init (h = .001, 0.1 * frandom());
	gain = 0;
}

template <sample_func_t F>
void
Lorenz::one_cycle (int frames)
{
	lorenz.set_rate (*ports[0]);

	double g = (gain == *ports[4]) ?
		1 : pow (getport(4) / gain, 1. / (double) frames);

	sample_t * d = ports[5];

	sample_t x, sx = getport(1), sy = getport(2), sz = getport(3);

	for (int i = 0; i < frames; ++i)
	{
		lorenz.step();

		x = sx * lorenz.get_x() + sy * lorenz.get_y() + sz * lorenz.get_z();

		F (d, i, gain * x, adding_gain);
		gain *= g;
	}

	gain = getport(4);
}

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

PortInfo
Lorenz::port_info [] =
{
	{
		"h",
		INPUT | CONTROL,
		{BOUNDED | DEFAULT_LOW, 0, 1}
	}, {
		"x",
		INPUT | CONTROL,
		{BOUNDED | DEFAULT_1, 0, 1}
	}, {
		"y",
		INPUT | CONTROL,
		{BOUNDED | DEFAULT_0, 0, 1}
	}, {
		"z",
		INPUT | CONTROL,
		{BOUNDED | DEFAULT_0, 0, 1}
	}, {
		"volume",
		INPUT | CONTROL,
		{BOUNDED | DEFAULT_MID, MIN_GAIN, 1}
	}, {
		"out",
		OUTPUT | AUDIO,
		{0}
	}
};

template <> void
Descriptor<Lorenz>::setup()
{
	UniqueID = 1774;
	Label = "Lorenz";
	Properties = HARD_RT;

	Name = CAPS "Lorenz - The sound of a Lorenz attractor";
	Maker = "Tim Goetze <tim@quitte.de>";
	Copyright = "GPL, 2004-7";

	/* fill port info and vtable */
	autogen();
}


code:
/*
	Lorenz.h

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

	http://quitte.de/dsp/

	turns the state of a Lorenz fractal into sound.

*/
/*
	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 _LORENZ_H_
#define _LORENZ_H_

#include "dsp/Lorenz.h"

class Lorenz
: public Plugin
{
	public:
		sample_t h, gain;

		DSP::Lorenz lorenz;

		template <sample_func_t F>
			void one_cycle (int frames);

	public:
		static PortInfo port_info [];

		void init();
		void activate()
			{ gain = getport(4); }

		void run (int n)
			{
				one_cycle<store_func> (n);
			}

		void run_adding (int n)
			{
				one_cycle<adding_func> (n);
			}
};

#endif /* _LORENZ_H_ */


code:
/*
	Pan.cc

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

	http://quitte.de/dsp/

	panorama with width control,
	stereo image width reduction

*/
/*
	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.
*/

#include "basics.h"

#include "Pan.h"
#include "Descriptor.h"

void
Pan::init()
{
	delay.init ((int) (.040 * fs));
}

void
Pan::activate()
{
	delay.reset();
	tap.reset (400 / fs);
	set_pan (getport (1));
}

inline void
Pan::set_pan (sample_t p)
{
	pan = p;

	double phi = (pan + 1) * M_PI * .25;

	gain_l = cos (phi);
	gain_r = sin (phi);
}

template <sample_func_t F>
void
Pan::one_cycle (int frames)
{
	sample_t * s = ports[0];

	if (pan != *ports[1])
		set_pan (getport(1));

	sample_t g = getport(2);
	sample_t
		width_l = g * gain_r,
		width_r = g * gain_l;

	tap.t = (int) (getport(3) * fs * .001);

	bool mono = getport(4);

	sample_t * dl = ports[5];
	sample_t * dr = ports[6];

	sample_t x, xt;

	if (mono) for (int i = 0; i < frames; ++i)
	{
		x = s[i];

		xt = tap.get (delay);

		delay.put (x + normal);

		x = (gain_l * x + gain_r * x + width_l * xt + width_r * xt) * .5;

		F (dl, i, x, adding_gain);
		F (dr, i, x, adding_gain);

		normal = -normal;
	}
	else /* stereo */ for (int i = 0; i < frames; ++i)
	{
		x = s[i];

		xt = tap.get (delay);

		delay.put (x + normal);

		F (dl, i, gain_l * x + width_l * xt, adding_gain);
		F (dr, i, gain_r * x + width_r * xt, adding_gain);

		normal = -normal;
	}
}

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

PortInfo
Pan::port_info [] =
{
	{
		"in",
		INPUT | AUDIO,
		{0}
	}, {
		"pan",
		INPUT | CONTROL,
		{BOUNDED | DEFAULT_0, -1, 1}
	}, {
		"width",
		INPUT | CONTROL,
		{BOUNDED | DEFAULT_0, 0, 1}
	}, {
		"t",
		INPUT | CONTROL,
		{BOUNDED | DEFAULT_LOW, 0.1, 40}
	}, {
		"mono",
		INPUT | CONTROL,
		{BOUNDED | DEFAULT_0 | INTEGER | TOGGLE, 0, 1}
	}, {
		"out:l",
		OUTPUT | AUDIO,
		{0}
	}, {
		"out:r",
		OUTPUT | AUDIO,
		{0}
	}
};

template <> void
Descriptor<Pan>::setup()
{
	UniqueID = 1788;
	Label = "Pan";
	Properties = HARD_RT;

	Name = CAPS "Pan - Pan and width";
	Maker = "Tim Goetze <tim@quitte.de>";
	Copyright = "GPL, 2004-7";

	/* fill port info and vtable */
	autogen();
}

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

void
Narrower::init()
{
}

void
Narrower::activate()
{
}

template <sample_func_t F>
void
Narrower::one_cycle (int frames)
{
	sample_t * sl = ports[0];
	sample_t * sr = ports[1];

	if (strength != *ports[2])
		strength = *ports[2];

	sample_t * dl = ports[3];
	sample_t * dr = ports[4];

	double xl, xr, m;
	double dry = 1 - strength, wet = strength;

	for (int i = 0; i < frames; ++i)
	{
		xl = sl[i];
		xr = sr[i];

		m = wet * (xl + xr) * .5;

		xl *= dry;
		xr *= dry;

		xl += m;
		xr += m;

		F (dl, i, xl, adding_gain);
		F (dr, i, xr, adding_gain);
	}
}

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

PortInfo
Narrower::port_info [] =
{
	{
		"in:l",
		INPUT | AUDIO,
		{0}
	}, {
		"in:r",
		INPUT | AUDIO,
		{0}
	}, {
		"strength",
		INPUT | CONTROL,
		{BOUNDED | DEFAULT_LOW, 0, 1}
	}, {
		"out:l",
		OUTPUT | AUDIO,
		{0}
	}, {
		"out:r",
		OUTPUT | AUDIO,
		{0}
	}
};

template <> void
Descriptor<Narrower>::setup()
{
	UniqueID = 2595;
	Label = "Narrower";
	Properties = HARD_RT;

	Name = CAPS "Narrower - Stereo image width reduction";
	Maker = "Tim Goetze <tim@quitte.de>";
	Copyright = "GPL, 2011";

	/* fill port info and vtable */
	autogen();
}


code:
/*
	Pan.h

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

	http://quitte.de/dsp/

	panorama with width control,
	stereo image width reduction

*/
/*
	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 _PAN_H_
#define _PAN_H_

#include "dsp/Delay.h"
#include "dsp/OnePole.h"

class PanTap
{
	public:
		int t;
		DSP::OnePoleLP damper;

		sample_t get (DSP::Delay & delay)
			{
				return damper.process (delay[t]);
			}

		void reset (double c)
			{
				damper.set_f (c);
				damper.reset();
			}
};

class Pan
: public Plugin
{
	public:
		sample_t pan;

		sample_t gain_l, gain_r;

		DSP::Delay delay;
		PanTap tap;

		template <sample_func_t F>
			void one_cycle (int frames);

		inline void set_pan (sample_t);

	public:
		static PortInfo port_info [];

		void init();
		void activate();

		void run (int n)
			{
				one_cycle<store_func> (n);
			}

		void run_adding (int n)
			{
				one_cycle<adding_func> (n);
			}
};

/* stereo width reduction */
class Narrower
: public Plugin
{
	public:
		sample_t strength;

		template <sample_func_t F>
			void one_cycle (int frames);

	public:
		static PortInfo port_info [];

		void init();
		void activate();

		void run (int n)
			{
				one_cycle<store_func> (n);
			}

		void run_adding (int n)
			{
				one_cycle<adding_func> (n);
			}

};

#endif /* _PAN_H_ */


code:
/*
	Phaser.cc

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

	http://quitte.de/dsp/

	One simple mono phaser, 6 all-pass lines, the usual controls.

	Another unit in the same vein with the filter modulation controlled by
	a 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.
*/

#include "basics.h"

#include "Phaser.h"
#include "Descriptor.h"

template <sample_func_t F>
void
PhaserI::one_cycle (int frames)
{
	sample_t * s = ports[0];

	if (rate != *ports[1])
	{
		rate = getport(1);
		lfo.set_f (max (.001, rate * (double) blocksize), fs, lfo.get_phase());
	}

	double depth = getport(2);
	double spread = 1 + getport(3);
	double fb = getport(4);

	sample_t * dst = ports[5];

	while (frames)
	{
		if (remain == 0) remain = 32;

		int n = min (remain, frames);

		double d = delay.bottom + delay.range * (1. - fabs (lfo.get()));

		for (int j = 5; j >= 0; --j)
		{
			ap[j].set (d);
			d *= spread;
		}

		for (int i = 0; i < n; ++i)
		{
			sample_t x = s[i];
			sample_t y = x + y0 * fb + normal;

			for (int j = 5; j >= 0; --j)
				y = ap[j].process (y);

			y0 = y;

			F (dst, i, x + y * depth, adding_gain);
		}

		s += n;
		dst += n;
		frames -= n;
		remain -= n;
	}
}

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

PortInfo
PhaserI::port_info [] =
{
	{
		"in",
		INPUT | AUDIO,
		{BOUNDED, -1, 1}
	}, {
		"rate (Hz)",
		INPUT | CONTROL,
		{BOUNDED | DEFAULT_1, 0, 10}
	}, {
		"depth",
		INPUT | CONTROL,
		{BOUNDED | DEFAULT_HIGH, 0, 1}
	}, {
		"spread",
		INPUT | CONTROL,
		{BOUNDED | DEFAULT_LOW, 0, M_PI}
	}, {
		"feedback",
		INPUT | CONTROL,
		{BOUNDED | DEFAULT_HIGH, 0, .999}
	}, {
		"out",
		OUTPUT | AUDIO,
		{0}
	}
};

template <> void
Descriptor<PhaserI>::setup()
{
	UniqueID = 1775;
	Label = "PhaserI";
	Properties = HARD_RT;

	Name = CAPS "PhaserI - Mono phaser";
	Maker = "Tim Goetze <tim@quitte.de>";
	Copyright = "GPL, 2002-7";

	/* fill port info and vtable */
	autogen();
}

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

template <sample_func_t F>
void
PhaserII::one_cycle (int frames)
{
	sample_t * s = ports[0];

	lorenz.set_rate (getport(1) * .08);

	double depth = getport(2);
	double spread = 1 + getport(3);
	double fb = getport(4);

	sample_t * dst = ports[5];

	while (frames)
	{
		if (remain == 0) remain = 32;

		int n = min (remain, frames);

		double d = delay.bottom + delay.range * (.3 * lorenz.get());

		for (int j = 5; j >= 0; --j)
		{
			ap[j].set (d);
			d *= spread;
		}

		for (int i = 0; i < n; ++i)
		{
			sample_t x = s[i];
			sample_t y = x + y0 * fb + normal;

			for (int j = 5; j >= 0; --j)
				y = ap[j].process (y);

			y0 = y;

			F (dst, i, x + y * depth, adding_gain);
		}

		s += n;
		dst += n;
		frames -= n;
		remain -= n;
	}
}

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

PortInfo
PhaserII::port_info [] =
{
	{
		"in",
		INPUT | AUDIO,
		{BOUNDED, -1, 1}
	}, {
		"rate",
		INPUT | CONTROL,
		{BOUNDED | DEFAULT_LOW, 0, 1}
	}, {
		"depth",
		INPUT | CONTROL,
		{BOUNDED | DEFAULT_HIGH, 0, 1}
	}, {
		"spread",
		INPUT | CONTROL,
		{BOUNDED | DEFAULT_LOW, 0, M_PI * .5}
	}, {
		"feedback",
		INPUT | CONTROL,
		{BOUNDED | DEFAULT_HIGH, 0, .999}
	}, {
		"out",
		OUTPUT | AUDIO,
		{0}
	}
};

template <> void
Descriptor<PhaserII>::setup()
{
	UniqueID = 2586;
	Label = "PhaserII";
	Properties = HARD_RT;

	Name = CAPS "PhaserII - Mono phaser modulated by a Lorenz fractal";
	Maker = "Tim Goetze <tim@quitte.de>";
	Copyright = "GPL, 2002-7";

	/* fill port info and vtable */
	autogen();
}


code:
/*
	Phaser.h

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

	http://quitte.de/dsp/

	Standard and fractal-modulated phaser units.

*/
/*
	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 _PHASER_H_
#define _PHASER_H_

#include "dsp/Sine.h"
#include "dsp/Lorenz.h"
#include "dsp/Delay.h"

/* all-pass as used by the phaser. */
class PhaserAP
{
	public:
		sample_t a, m;

		PhaserAP()
		{
			a = m = 0.;
		}

		void set (double delay)
		{
			a = (1 - delay) / (1 + delay);
		}

		sample_t process (sample_t x)
		{
			register sample_t y = -a * x + m;
			m = a * y + x;

			return y;
		}
};

class PhaserI
: public Plugin
{
	public:
		PhaserAP ap[6];
		DSP::Sine lfo;

		sample_t rate;
		sample_t y0;

		struct {
			double bottom, range;
		} delay;

		template <sample_func_t>
			void one_cycle (int frames);

		int blocksize, remain;

	public:
		static PortInfo port_info [];

		void init()
			{
				blocksize = 32;
			}

		void activate()
			{
				y0 = 0.;
				remain = 0;

				delay.bottom = 400. / fs;
				delay.range = 2200. / fs;

				rate = -1; /* force lfo reset in one_cycle() */
			}

		void run (int n)
			{
				one_cycle<store_func> (n);
			}

		void run_adding (int n)
			{
				one_cycle<adding_func> (n);
			}
};

/* same as above, but filter sweep is controlled by a Lorenz fractal */

class PhaserII
: public Plugin
{
	public:
		double fs;

		PhaserAP ap[6];
		DSP::Lorenz lorenz;

		sample_t rate;
		sample_t y0;

		struct {
			double bottom, range;
		} delay;

		template <sample_func_t>
			void one_cycle (int frames);

		int blocksize, remain;

	public:
		static PortInfo port_info [];

		void init()
			{
				blocksize = 32;
				lorenz.init();
			}

		void activate()
			{
				y0 = 0.;
				remain = 0;

				delay.bottom = 400. / fs;
				delay.range = 2200. / fs;

				rate = -1; /* force lfo reset in one_cycle() */
			}

		void run (int n)
			{
				one_cycle<store_func> (n);
			}

		void run_adding (int n)
			{
				one_cycle<adding_func> (n);
			}
};

#endif /* _PHASER_H_ */


code:
/*
	Preamp.cc

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

	http://quitte.de/dsp/

	Loosely 12AX7-based tube preamp model with 8x oversampling.
*/
/*
	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.
*/

#include "basics.h"
#include <stdio.h>

#include "Amp.h"
#include "Descriptor.h"

void
PreampIII::init()
{
	this->AmpStub::init();

	DSP::RBJ::LoShelve (200 / fs, .2, -6, filter.a, filter.b);
}

template <sample_func_t F, int OVERSAMPLE>
void
PreampIII::one_cycle (int frames)
{
	sample_t * s = ports[0];
	sample_t gain = getport(1);
	sample_t temp = getport(2) * tube.scale;
	sample_t * d = ports[3];
	*ports[4] = OVERSAMPLE;

	double g = current.g;

	current.g = max (gain < 1 ? gain : exp2 (gain - 1), .000001);
	/* correction for attenuated first transfer */
	current.g *= tube.scale / fabs (tube.transfer (temp));

	if (g == 0) g = current.g;

	/* recursive fade to prevent zipper noise from the 'gain' knob */
	double one_over_n = frames > 0 ? 1. / frames : 1;
	double gf = pow (current.g / g, one_over_n);

	for (int i = 0; i < frames; ++i)
	{
		register sample_t a = s[i] + normal;

		a = g * tube.transfer (a * temp);
		a = filter.process (a);
		a = down.process (tube.transfer_clip (up.upsample (a)));

		for (int o = 1; o < OVERSAMPLE; ++o)
			down.store (tube.transfer_clip (up.pad (o)));

		F (d, i, dc_blocker.process (a), adding_gain);

		g *= gf;
	}

	current.g = g;
}

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

PortInfo
PreampIII::port_info [] =
{
	{
		"in",
		INPUT | AUDIO,
		{BOUNDED, -1, 1}
	}, {
		"gain",
		INPUT | CONTROL,
		{BOUNDED | DEFAULT_1, 0, 10}
	}, {
		"temperature",
		INPUT | CONTROL,
		{BOUNDED | DEFAULT_LOW, 0.005, 1}
	}, {
		"out",
		OUTPUT | AUDIO,
		{0}
	}, {
		"latency",
		OUTPUT | CONTROL,
		{0}
	}
};

template <> void
Descriptor<PreampIII>::setup()
{
	UniqueID = 1776;
	Label = "PreampIII";
	Properties = HARD_RT;

	Name = CAPS "PreampIII - Tube preamp emulation";
	Maker = "Tim Goetze <tim@quitte.de>";
	Copyright = "GPL, 2002-7";

	/* fill port info and vtable */
	autogen();
}

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

void
PreampIV::init()
{
	this->AmpStub::init();
	tone.init (fs);
}

void
PreampIV::activate()
{
	this->PreampIII::activate();

	tone.activate (ports + 3);
}

template <sample_func_t F, int OVERSAMPLE>
void
PreampIV::one_cycle (int frames)
{
	double one_over_n = frames > 0 ? 1. / frames : 1;

	sample_t * s = ports[0];
	sample_t gain = getport(1);
	sample_t temp = getport(2) * tube.scale;

	tone.start_cycle (ports + 3, one_over_n);

	sample_t * d = ports[7];
	*ports[8] = OVERSAMPLE;

	double g = current.g;

	current.g = max (gain < 1 ? gain : exp2 (gain - 1), .000001);
	current.g *= tube.scale / fabs (tube.transfer (temp));

	if (g == 0) g = current.g;

	/* recursive fade to prevent zipper noise from the 'gain' knob */
	double gf = pow (current.g / g, one_over_n);

	for (int i = 0; i < frames; ++i)
	{
		register sample_t a = tone.process (s[i] + normal);

		a = g * tube.transfer (a * temp);

		a = down.process (tube.transfer_clip (up.upsample (a)));

		for (int o = 1; o < OVERSAMPLE; ++o)
			down.store (tube.transfer_clip (up.pad (o)));

		F (d, i, dc_blocker.process (a), adding_gain);

		g *= gf;
	}

	current.g = g;
}

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

PortInfo
PreampIV::port_info [] =
{
	{
		"in",
		INPUT | AUDIO,
		{BOUNDED, -1, 1}
	}, {
		"gain",
		INPUT | CONTROL,
		{BOUNDED | DEFAULT_1, 0, 10}
	}, {
		"temperature",
		INPUT | CONTROL,
		{BOUNDED | DEFAULT_MID, 0.005, 1}
	}, {
		"bass",
		INPUT | CONTROL,
		{BOUNDED | DEFAULT_0, -20, 20}
	}, {
		"mid",
		INPUT | CONTROL,
		{BOUNDED | DEFAULT_0, -20, 20}
	}, {
		"treble",
		INPUT | CONTROL,
		{BOUNDED | DEFAULT_0, -20, 20}
	}, {
		"hi",
		INPUT | CONTROL,
		{BOUNDED | DEFAULT_0, -20, 20}
	}, {
		"out",
		OUTPUT | AUDIO,
		{0}
	}, {
		"latency",
		OUTPUT | CONTROL,
		{0}
	}
};

template <> void
Descriptor<PreampIV>::setup()
{
	UniqueID = 1777;
	Label = "PreampIV";
	Properties = HARD_RT;

	Name = CAPS "PreampIV - Tube preamp emulation + tone controls";
	Maker = "Tim Goetze <tim@quitte.de>";
	Copyright = "GPL, 2002-7";

	/* fill port info and vtable */
	autogen();
}


code:
This is CAPS, the C Audio Plugin Suite
======================================

For all questions, please be referred to the HTML documentation of
this software package in the file 'caps.html', also available from

http://quitte.de/dsp/caps.html

path: plugins/LadspaEffect/caps/README


code:
Ardour Users: Notice and WARNING
================================

ALL the plugins in caps have been renamed as of caps-0.3.0. While this is
clearly within the bounds of the LADSPA specification, ardour will fail to
load caps plugins from earlier releases referenced in your existing session
files should you install caps-0.3.0 over a previous release.

As a quick workaround, you can install caps with

# make alt-install

which will install the plugins as 'caps-ng.so', leaving your existing
installation of caps intact so you can manually update your sessions within
ardour to use the latest versions of the caps plugins.

The downside is you're now stuck with two implementations of identical
plugins, and some hosts will (quite sensibly) complain about this. So after
you're done updating your ardour sessions, installing caps under its rightful
name of 'caps.so' is a good idea.

As an alternative, you can also run a search-and-replace on your ardour
session files. I'll be happy to help you there should you require
assistance, just drop me a mail.

RDF metadata
============

Pete Leigh has graciously provided a RDF file that refines the user interface
of the Cabinet and SweepVF plugins within ardour (adding labels to the SweepVF
filter modes and the Cabinet speaker models to be precise). I have dabbled
with these files so if they fail to work for you, it's all my fault.

You should be able install the file on your system with

# make rdf-install

but be warned that I have set this up blindly. Tell me if it works for you.


code:
Distribution Notice for the caps audio plugin suite
===================================================

If you intend to package caps for redistribution PLEASE include the html
and pdf documentation files, and make clear to your users that they exist
and where to find them.

caps 0.3 Notice and WARNING
===========================

The 0.3 release has relabelled the SweepVF, Cabinet, Chorus, StereoChorus
and Phaser plugins (appending an 'I' to their label to be precise).
Unfortunately, this might break some hosts' session files. Sorry about that.

Ardour users are well-advised to read the file 'README.ardour' in this
directory before installing caps 0.3.0.


code:
/*
	Reverb.cc

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

	http://quitte.de/dsp/

	three reverb units: JVRev, Plate and Plate2x2.

	the former is a rewrite of STK's JVRev, a traditional design.

	original comment:

		This is based on some of the famous
		Stanford CCRMA reverbs (NRev, KipRev)
		all based on the Chowning/Moorer/
		Schroeder reverberators, which use
		networks of simple allpass and comb
		delay filters.

	the algorithm is mostly unchanged in this implementation; the delay
	line lengths have been fiddled with to make the stereo field more
	evenly weighted, and denormal protection has been added.

	the latter two are based on the circuit discussed in Jon Dattorro's
	september 1997 JAES paper on effect design (part 1: reverb & 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.
*/

#include "basics.h"

#include "Reverb.h"
#include "Descriptor.h"

int
JVRev::default_length[9] = {
#if 1 /* slightly modified, tg */
	1777, 1847, 1993, 2137, 389, 127, 43, 211, 209
#else
	4799, 4999, 5399, 5801, 1051, 337, 113, 573, 487
#endif
};

void
JVRev::init()
{
	memcpy (length, default_length, sizeof (length));

	if (fs != 44100)
	{
		double s = fs / 44100.;

		for (int i = 0; i < 9; ++i)
		{
			int v = (int) (s * length[i]);
			v |= 1;
			while (!DSP::isprime (v))
				v += 2;
			length[i] = v;
		}
	}

	for (int i = 0; i < 4; ++i)
		comb[i].init (length[i]);

	for (int i = 0; i < 3; ++i)
		allpass[i].init (length[i+4]);

	left.init (length[7]);
	right.init (length[8]);

	/* such a simple number, but i couldn't find a better one. */
	apc = .7;
}

void
JVRev::set_t60 (sample_t t)
{
	t60 = t;

	t = max (.00001, t);

	for (int i = 0; i < 4; ++i)
		comb[i].c = pow (10, (-3 * length[i] / (t * fs)));
}

void
JVRev::activate()
{
	for (int i = 0; i < 3; ++i)
		allpass[i].reset();

	for (int i = 0; i < 4; ++i)
		comb[i].reset();

	left.reset();
	right.reset();

	set_t60 (getport(1));
}

template <sample_func_t F>
void
JVRev::one_cycle (int frames)
{
	sample_t * s = ports[0];

	if (t60 != *ports[1])
		set_t60 (getport(1));

	double wet = getport(2), dry = 1 - wet;

	sample_t * dl = ports[3];
	sample_t * dr = ports[4];

	for (int i = 0; i < frames; ++i)
	{
		sample_t x = s[i], a = x + normal;

		x *= dry;

		/* diffusors */
		a = allpass[0].process (a, -apc);
		a = allpass[1].process (a, -apc);
		a = allpass[2].process (a, -apc);

		/* tank */
		sample_t t = 0;
		a -= normal;

		for (int j = 0; j < 4; ++j)
			t += comb[j].process (a);

		F (dl, i, x + wet * left.putget (t), adding_gain);
		F (dr, i, x + wet * right.putget (t), adding_gain);
	}
}

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

PortInfo
JVRev::port_info [] =
{
	{
		"in",
		INPUT | AUDIO,
		{BOUNDED, -1, 1}
	}, {
		"t60 (s)",
		INPUT | CONTROL,
		{BOUNDED | DEFAULT_MID, 0, 4.6}
	}, {
		"blend",
		INPUT | CONTROL,
		{BOUNDED | DEFAULT_LOW, 0, .28}
	}, {
		"out:l",
		OUTPUT | AUDIO,
		{0}
	}, {
		"out:r",
		OUTPUT | AUDIO,
		{0}
	}
};

template <> void
Descriptor<JVRev>::setup()
{
	UniqueID = 1778;
	Label = "JVRev";
	Properties = HARD_RT;

	Name = CAPS "JVRev - Stanford-style reverb from STK";
	Maker = "Tim Goetze <tim@quitte.de>";
	Copyright = "GPL, 2004-7";

	/* fill port info and vtable */
	autogen();
}

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

void
PlateStub::init()
{
	f_lfo = -1;

#	define L(i) ((int) (l[i] * fs))
	static float l[] = {
		0.004771345048889486, 0.0035953092974026408,
		0.01273478713752898, 0.0093074829474816042,
		0.022579886428547427, 0.030509727495715868,
		0.14962534861059779, 0.060481838647894894, 0.12499579987231611,
		0.14169550754342933, 0.089244313027116023, 0.10628003091293972
	};

	/* lh */
	input.lattice[0].init (L(0));
	input.lattice[1].init (L(1));

	/* rh */
	input.lattice[2].init (L(2));
	input.lattice[3].init (L(3));

	/* modulated, width about 12 samples @ 44.1 */
	tank.mlattice[0].init (L(4), (int) (0.00040322707570310132 * fs));
	tank.mlattice[1].init (L(5), (int) (0.00040322707570310132 * fs));

	/* lh */
	tank.delay[0].init (L(6));
	tank.lattice[0].init (L(7));
	tank.delay[1].init (L(8));

	/* rh */
	tank.delay[2].init (L(9));
	tank.lattice[1].init (L(10));
	tank.delay[3].init (L(11));
#	undef L

#	define T(i) ((int) (t[i] * fs))
	static float t[] = {
		0.0089378717113000241, 0.099929437854910791, 0.064278754074123853,
		0.067067638856221232, 0.066866032727394914, 0.006283391015086859,
		0.01186116057928161, 0.12187090487550822, 0.041262054366452743,
		0.089815530392123921, 0.070931756325392295, 0.011256342192802662
	};

	for (int i = 0; i < 12; ++i)
		tank.taps[i] = T(i);
#	undef T

	/* tuned for soft attack, ambience */
	indiff1 = .742;
	indiff2 = .712;

	dediff1 = .723;
	dediff2 = .729;
}

inline void
PlateStub::process (sample_t x, sample_t decay, sample_t * _xl, sample_t * _xr)
{
	x = input.bandwidth.process (x);

	/* lh */
	x = input.lattice[0].process (x, indiff1);
	x = input.lattice[1].process (x, indiff1);

	/* rh */
	x = input.lattice[2].process (x, indiff2);
	x = input.lattice[3].process (x, indiff2);

	/* summation point */
	register sample_t xl = x + decay * tank.delay[3].get();
	register sample_t xr = x + decay * tank.delay[1].get();

	/* lh */
	xl = tank.mlattice[0].process (xl, dediff1);
	xl = tank.delay[0].putget (xl);
	xl = tank.damping[0].process (xl);
	xl *= decay;
	xl = tank.lattice[0].process (xl, dediff2);
	tank.delay[1].put (xl);

	/* rh */
	xr = tank.mlattice[1].process (xr, dediff1);
	xr = tank.delay[2].putget (xr);
	xr = tank.damping[1].process (xr);
	xr *= decay;
	xr = tank.lattice[1].process (xr, dediff2);
	tank.delay[3].put (xr);

	/* gather output */
	xl  = .6 * tank.delay[2] [tank.taps[0]];
	xl += .6 * tank.delay[2] [tank.taps[1]];
	xl -= .6 * tank.lattice[1] [tank.taps[2]];
	xl += .6 * tank.delay[3] [tank.taps[3]];
	xl -= .6 * tank.delay[0] [tank.taps[4]];
	xl += .6 * tank.lattice[0] [tank.taps[5]];

	xr  = .6 * tank.delay[0] [tank.taps[6]];
	xr += .6 * tank.delay[0] [tank.taps[7]];
	xr -= .6 * tank.lattice[0] [tank.taps[8]];
	xr += .6 * tank.delay[1] [tank.taps[9]];
	xr -= .6 * tank.delay[2] [tank.taps[10]];
	xr += .6 * tank.lattice[1] [tank.taps[11]];

	*_xl = xl;
	*_xr = xr;
}

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

template <sample_func_t F>
void
Plate::one_cycle (int frames)
{
	sample_t * s = ports[0];

	input.bandwidth.set (exp (-M_PI * (1. - getport(1))));

	sample_t decay = getport(2);

	double damp = exp (-M_PI * getport(3));
	tank.damping[0].set (damp);
	tank.damping[1].set (damp);

	sample_t blend = getport(4), dry = 1 - blend;

	sample_t * dl = ports[5];
	sample_t * dr = ports[6];

	/* the modulated lattices interpolate, which needs truncated float */
	DSP::FPTruncateMode _truncate;

	for (int i = 0; i < frames; ++i)
	{
		normal = -normal;
		sample_t x = s[i] + normal;

		sample_t xl, xr;

		PlateStub::process (x, decay, &xl, &xr);

		x = dry * s[i];

		F (dl, i, x + blend * xl, adding_gain);
		F (dr, i, x + blend * xr, adding_gain);
	}
}

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

PortInfo
Plate::port_info [] =
{
	{
		"in",
		INPUT | AUDIO,
		{BOUNDED, -1, 1}
	}, {
		"bandwidth",
		INPUT | CONTROL,
		{BOUNDED | DEFAULT_MID, 0.005, .999} /* .9995 */
	}, {
		"tail",
		INPUT | CONTROL,
		{BOUNDED | DEFAULT_MID, 0, .749} /* .5 */
	}, {
		"damping",
		INPUT | CONTROL,
		{BOUNDED | DEFAULT_LOW, .0005, 1} /* .0005 */
	}, {
		"blend",
		INPUT | CONTROL,
		{BOUNDED | DEFAULT_LOW, 0, 1}
	}, {
		"out:l",
		OUTPUT | AUDIO,
		{0}
	}, {
		"out:r",
		OUTPUT | AUDIO,
		{0}
	}
};

template <> void
Descriptor<Plate>::setup()
{
	UniqueID = 1779;
	Label = "Plate";
	Properties = HARD_RT;

	Name = CAPS "Plate - Versatile plate reverb";
	Maker = "Tim Goetze <tim@quitte.de>";
	Copyright = "GPL, 2004-7";

	/* fill port info and vtable */
	autogen();
}

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

template <sample_func_t F>
void
Plate2x2::one_cycle (int frames)
{
	sample_t * sl = ports[0];
	sample_t * sr = ports[1];

	input.bandwidth.set (exp (-M_PI * (1. - getport(2))));

	sample_t decay = getport(3);

	double damp = exp (-M_PI * getport(4));
	tank.damping[0].set (damp);
	tank.damping[1].set (damp);

	sample_t blend = getport(5), dry = 1 - blend;

	sample_t * dl = ports[6];
	sample_t * dr = ports[7];

	/* the modulated lattices interpolate, which needs truncated float */
	DSP::FPTruncateMode _truncate;

	for (int i = 0; i < frames; ++i)
	{
		normal = -normal;
		sample_t x = (sl[i] + sr[i] + normal) * .5;

		sample_t xl, xr;
		PlateStub::process (x, decay, &xl, &xr);

		xl = blend * xl + dry * sl[i];
		xr = blend * xr + dry * sr[i];

		F (dl, i, xl, adding_gain);
		F (dr, i, xr, adding_gain);
	}
}

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

PortInfo
Plate2x2::port_info [] =
{
	{
		"in:l",
		INPUT | AUDIO,
		{BOUNDED, -1, 1}
	}, {
		"in:r",
		INPUT | AUDIO,
		{BOUNDED, -1, 1}
	}, {
		"bandwidth",
		INPUT | CONTROL,
		{BOUNDED | DEFAULT_MID, 0.005, .999} /* .9995 */
	}, {
		"tail",
		INPUT | CONTROL,
		{BOUNDED | DEFAULT_MID, 0, .749} /* .5 */
	}, {
		"damping",
		INPUT | CONTROL,
		{BOUNDED | DEFAULT_LOW, .0005, 1} /* .0005 */
	}, {
		"blend",
		INPUT | CONTROL,
		{BOUNDED | DEFAULT_LOW, 0, 1}
	}, {
		"out:l",
		OUTPUT | AUDIO,
		{0}
	}, {
		"out:r",
		OUTPUT | AUDIO,
		{0}
	}
};

template <> void
Descriptor<Plate2x2>::setup()
{
	UniqueID = 1795;
	Label = "Plate2x2";
	Properties = HARD_RT;

	Name = CAPS "Plate2x2 - Versatile plate reverb, stereo inputs";
	Maker = "Tim Goetze <tim@quitte.de>";
	Copyright = "GPL, 2004-7";

	/* fill port info and vtable */
	autogen();
}


code:
/*
	Reverb.h

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

	http://quitte.de/dsp/

	two reverb units: JVRev and Plate.

	the former is a rewrite of STK's JVRev, a traditional design.

	original comment:

		This is based on some of the famous
		Stanford CCRMA reverbs (NRev, KipRev)
		all based on the Chowning/Moorer/
		Schroeder reverberators, which use
		networks of simple allpass and comb
		delay filters.

	(STK is an effort of Gary Scavone).

	the algorithm is mostly unchanged in this implementation; the delay
	line lengths have been fiddled with to make the stereo field more
	evenly weighted, and denormal protection has been added.

	the Plate reverb is based on the circuit discussed in Jon Dattorro's
	september 1997 JAES paper on effect design (part 1: reverb & 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 _REVERB_H_
#define _REVERB_H_

#include <stdio.h>

#include "dsp/Delay.h"
#include "dsp/OnePole.h"
#include "dsp/Sine.h"
#include "dsp/util.h"

/* both reverbs use this */
class Lattice
: public DSP::Delay
{
	public:
		inline sample_t
		process (sample_t x, double d)
			{
				sample_t y = get();
				x -= d * y;
				put (x);
				return d * x + y;
			}
};

/* helper for JVRev */
class JVComb
: public DSP::Delay
{
	public:
		float c;

		inline sample_t
		process (sample_t x)
			{
				x += c * get();
				put (x);
				return x;
			}
};

class JVRev
: public Plugin
{
	public:
		static int default_length[9];
		sample_t t60;

		Lattice allpass [3];
		JVComb comb[4];

		DSP::Delay left, right;

		double apc;

		template <sample_func_t F>
		void one_cycle (int frames);

		int length [9];

		void set_t60 (sample_t t);

	public:
		static PortInfo port_info [];

		void init();
		void activate();

		void run (int n)
			{
				one_cycle<store_func> (n);
			}

		void run_adding (int n)
			{
				one_cycle<adding_func> (n);
			}
};

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

class ModLattice
{
	public:
		float n0, width;

		DSP::Delay delay;
		DSP::Sine lfo;
		DSP::DelayTapA tap;

		void init (int n, int w)
			{
				n0 = n;
				width = w;
				delay.init (n + w);
			}

		void reset()
			{
				delay.reset();
				tap.reset();
			}

		inline sample_t
		process (sample_t x, double d)
			{
				/* TODO: try all-pass interpolation */
				sample_t y = delay.get_at (n0 + width * lfo.get());
				x += d * y;
				delay.put (x);
				return y - d * x; /* note sign */
			}
};

class PlateStub
: public Plugin
{
	public:
		sample_t f_lfo;

		sample_t indiff1, indiff2, dediff1, dediff2;

		struct {
			DSP::OnePoleLP bandwidth;
			Lattice lattice[4];
		} input;

		struct {
			ModLattice mlattice[2];
			Lattice lattice[2];
			DSP::Delay delay[4];
			DSP::OnePoleLP damping[2];
			int taps[12];
		} tank;

	public:
		void init();
		void activate()
			{
				input.bandwidth.reset();

				for (int i = 0; i < 4; ++i)
				{
					input.lattice[i].reset();
					tank.delay[i].reset();
				}

				for (int i = 0; i < 2; ++i)
				{
					tank.mlattice[i].reset();
					tank.lattice[i].reset();
					tank.damping[i].reset();
				}

				tank.mlattice[0].lfo.set_f (1.2, fs, 0);
				tank.mlattice[1].lfo.set_f (1.2, fs, .5 * M_PI);
			}

		inline void process (sample_t x, sample_t decay,
					sample_t * xl, sample_t * xr);
};

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

class Plate
: public PlateStub
{
	public:
		template <sample_func_t F>
		void one_cycle (int frames);

	public:
		static PortInfo port_info [];

		void run (int n)
			{
				one_cycle<store_func> (n);
			}

		void run_adding (int n)
			{
				one_cycle<adding_func> (n);
			}
};

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

class Plate2x2
: public PlateStub
{
	public:
		template <sample_func_t F>
		void one_cycle (int frames);

	public:
		static PortInfo port_info [];

		void run (int n)
			{
				one_cycle<store_func> (n);
			}

		void run_adding (int n)
			{
				one_cycle<adding_func> (n);
			}
};

#endif /* _REVERB_H_ */