<?xml version="1.0" ?>
<!DOCTYPE ladspa SYSTEM "ladspa-swh.dtd">
<?xml-stylesheet href="ladspa.css" type="text/css" ?>
<ladspa>
	<global>
		<meta name="maker" value="Steve Harris &lt;steve@plugin.org.uk&gt;"/>
		<meta name="copyright" value="GPL"/>
		<code><![CDATA[
#include "ladspa-util.h"

#define BASE_BUFFER 8 // Tape length (inches)
		]]></code>
	</global>

	<plugin label="tapeDelay" id="1211" class="DelayPlugin,SimulatorPlugin">
		<name>Tape Delay Simulation</name>
                <p>Correctly models the tape motion and some of the smear effect, there is no simulation fo the head saturation yet, as I don't have a good model of it. When I get one I will add it.</p>
                <p>The way the tape accelerates and decelerates gives a nicer delay effect for many purposes.</p>

		<callback event="instantiate"><![CDATA[
			unsigned int mbs = BASE_BUFFER * s_rate;
			sample_rate = s_rate;
			for (buffer_size = 4096; buffer_size < mbs;
			     buffer_size *= 2);
			buffer = malloc(buffer_size * sizeof(LADSPA_Data));
			buffer_mask = buffer_size - 1;
			phase = 0;
			last_phase = 0;
			last_in = 0.0f;
			last2_in = 0.0f;
			last3_in = 0.0f;
			z0 = 0.0f;
			z1 = 0.0f;
			z2 = 0.0f;
		]]></callback>

		<callback event="activate">
			int i;

			for (i = 0; i &lt; buffer_size; i++) {
				buffer[i] = 0;
			}
			phase = 0;
			last_phase = 0;
			last_in = 0.0f;
			last2_in = 0.0f;
			last3_in = 0.0f;
			sample_rate = sample_rate;
			z0 = 0.0f;
			z1 = 0.0f;
			z2 = 0.0f;
		</callback>

		<callback event="cleanup"><![CDATA[
			free(plugin_data->buffer);
		]]></callback>

		<callback event="run"><![CDATA[
unsigned int pos;
float increment = f_clamp(speed, 0.0f, 40.0f);
float lin_int, lin_inc;
unsigned int track;
unsigned int fph;
LADSPA_Data out;

const float da = DB_CO(da_db);
const float t1a = DB_CO(t1a_db);
const float t2a = DB_CO(t2a_db);
const float t3a = DB_CO(t3a_db);
const float t4a = DB_CO(t4a_db);
const unsigned int t1d_s = f_round(t1d * sample_rate);
const unsigned int t2d_s = f_round(t2d * sample_rate);
const unsigned int t3d_s = f_round(t3d * sample_rate);
const unsigned int t4d_s = f_round(t4d * sample_rate);

for (pos = 0; pos < sample_count; pos++) {
	fph = f_trunc(phase);
	last_phase = fph;
	lin_int = phase - (float)fph;

	out = buffer[(unsigned int)(fph - t1d_s) & buffer_mask] * t1a;
	out += buffer[(unsigned int)(fph - t2d_s) & buffer_mask] * t2a;
	out += buffer[(unsigned int)(fph - t3d_s) & buffer_mask] * t3a;
	out += buffer[(unsigned int)(fph - t4d_s) & buffer_mask] * t4a;

	phase += increment;
	lin_inc = 1.0f / (floor(phase) - last_phase + 1);
	lin_inc = lin_inc > 1.0f ? 1.0f : lin_inc;
	lin_int = 0.0f;
	for (track = last_phase; track < phase; track++) {
		lin_int += lin_inc;
		buffer[track & buffer_mask] =
		 cube_interp(lin_int, last3_in, last2_in, last_in, input[pos]);
	}
	last3_in = last2_in;
	last2_in = last_in;
	last_in = input[pos];
	out += input[pos] * da;
	buffer_write(output[pos], out);
	if (phase >= buffer_size) {
		phase -= buffer_size;
	}
}

// Store current phase in instance
plugin_data->phase = phase;
plugin_data->last_phase = last_phase;
plugin_data->last_in = last_in;
plugin_data->last2_in = last2_in;
plugin_data->last3_in = last3_in;
plugin_data->z0 = z0;
plugin_data->z1 = z1;
plugin_data->z2 = z2;
		]]></callback>

		<port label="speed" dir="input" type="control" hint="default_1">
			<name>Tape speed (inches/sec, 1=normal)</name>
			<range min="0" max="10"/>
		</port>

		<port label="da_db" dir="input" type="control" hint="default_minimum">
			<name>Dry level (dB)</name>
			<range min="-90" max="0"/>
		</port>

		<port label="t1d" dir="input" type="control" hint="default_0">
			<name>Tap 1 distance (inches)</name>
			<range min="0" max="4"/>
		</port>

		<port label="t1a_db" dir="input" type="control" hint="default_0">
			<name>Tap 1 level (dB)</name>
			<range min="-90" max="0"/>
		</port>

		<port label="t2d" dir="input" type="control" hint="default_low">
			<name>Tap 2 distance (inches)</name>
			<range min="0" max="4"/>
		</port>

		<port label="t2a_db" dir="input" type="control" hint="default_minimum">
			<name>Tap 2 level (dB)</name>
			<range min="-90" max="0"/>
		</port>

		<port label="t3d" dir="input" type="control" hint="default_middle">
			<name>Tap 3 distance (inches)</name>
			<range min="0" max="4"/>
		</port>

		<port label="t3a_db" dir="input" type="control" hint="default_minimum">
			<name>Tap 3 level (dB)</name>
			<range min="-90" max="0"/>
		</port>

		<port label="t4d" dir="input" type="control" hint="default_high">
			<name>Tap 4 distance (inches)</name>
			<range min="0" max="4"/>
		</port>

		<port label="t4a_db" dir="input" type="control" hint="default_minimum">
			<name>Tap 4 level (dB)</name>
			<range min="-90" max="0"/>
		</port>

		<port label="input" dir="input" type="audio">
			<name>Input</name>
		</port>

		<port label="output" dir="output" type="audio">
			<name>Output</name>
		</port>

		<instance-data label="buffer" type="LADSPA_Data *"/>
		<instance-data label="buffer_size" type="unsigned int"/>
		<instance-data label="buffer_mask" type="unsigned int"/>
		<instance-data label="phase" type="float"/>
		<instance-data label="last_phase" type="unsigned int"/>
		<instance-data label="last_in" type="LADSPA_Data"/>
		<instance-data label="last2_in" type="LADSPA_Data"/>
		<instance-data label="last3_in" type="LADSPA_Data"/>
		<instance-data label="sample_rate" type="int"/>
                <instance-data label="z0" type="LADSPA_Data"/>
                <instance-data label="z1" type="LADSPA_Data"/>
                <instance-data label="z2" type="LADSPA_Data"/>
	</plugin>
</ladspa>

