slider1:0.4<0,8,0.1>Rate (Hz)
slider2:25<0,100,1>Width (%)
slider3:60<0,100,1>Feedback (%)
slider4:5<0,100,1>Delay (ms)
slider5:0<0,9,1{Mono,Mono Minus,Mono Both,Stereo,Stereo Minus,Stereo Both,Mono Wet Only,Mono Wet Only Minus,Stereo Wet Only,Stereo Wet Only Minus}>Mix Mode
slider6:-3<-30,12,0.1>Wet (dB)
slider7:-30<-30,12,0.1>Dry (dB)
slider8:0<0,1,1{tanh,hard}>--Limit

in_pin:L in
in_pin:R in
out_pin:L out
out_pin:R out

@init
_feedbackPhase = 1;
_sweepSamples = 0; // sweep width in # of samples
_fp = 0; // fill/write pointer
_sweep = 0; // current value of sweep in steps behind fill pointer

outval1 = outval2 = 0; // most recent output value (for feedback)
	
_mixLeftWet =
_mixLeftDry =
_mixRightWet =
_mixRightDry = 0.5;

_mixMono = 1;

BSZ = 8192; // ~0.2*srate
//buffer1 = 128;
//memset(buffer1, 0, BSZ);
//buffer2 = 128;
//memset(buffer2, 0, BSZ);

function tanh(x) 
( 
x = exp(2*x);
(x - 1) / (x + 1);
);

@slider
_paramSweepRate = slider1/10;
_paramWidth = slider2/100;
//_paramFeedback = max(min(slider3/100,1),0.01);
_paramFeedback = slider3/100;
_paramDelay = slider4/100;

// rate
// map into param onto 0.05Hz - 10hz with log curve
_sweepRate = pow(10,_paramSweepRate);
_sweepRate -= 1;
_sweepRate *= 1.05556;
_sweepRate += 0.05;

// width
// map so that we can spec between 0ms and 10ms
( _paramWidth == 0) ? (
// eat some noise on the bottom end
_sweepSamples = 0;
) : (
// otherwise calc # of samples for the total width
_sweepSamples = _paramWidth * 0.01 * srate|0;
);

// sweep
// calc # of samples per second we'll need to move to achieve spec'd sweep rate
_step = (_sweepSamples * 2 * _sweepRate) / srate;

// calc max and start sweep at 0
_sweep = 0;
_maxSweepSamples = _sweepSamples;

wet = slider6 <= -30 ? 0 : 10^(slider6/20);
dry = slider7 <= -30 ? 0 : 10^(slider7/20);

@sample
slider5 == 0 ? (
_mixMono = 1;
_mixLeftWet = _mixRightWet = _mixLeftDry = _mixRightDry = 1;
_feedbackPhase = 1;
);

slider5 == 1 ? (
_mixMono = 1;
_mixLeftWet = _mixRightWet = -1;
_mixLeftDry = _mixRightDry = 1;
_feedbackPhase = -1;
);

slider5 == 2 ? (
_mixMono = 1;
_mixLeftWet = _mixLeftDry = _mixRightDry = 1;
_mixRightWet = -1;
_feedbackPhase = 1;
);

slider5 == 3 ? (
_mixMono = 0;
_mixLeftWet = _mixLeftDry = _mixRightDry = 1;
_mixRightWet = -1;
_feedbackPhase = 1;
);

slider5 == 4 ? (
_mixMono = 0;
_mixLeftWet = _mixLeftDry = _mixRightDry = 1;
_mixRightWet = -1;
_feedbackPhase = -1;
);

slider5 == 5 ? (
_mixMono = 0;
_mixLeftWet = _mixRightWet = -1;
_mixLeftDry = _mixRightDry = 1;
_feedbackPhase = -1;
);

slider5 == 6 ? (
_mixMono = 1;
_mixLeftWet = _mixRightWet = 1;
_mixLeftDry = _mixRightDry = 0;
_feedbackPhase = 1;
);

slider5 == 7 ? (
_mixMono = 1;
_mixLeftWet = _mixRightWet = 1;
_mixLeftDry = _mixRightDry = 0;
_feedbackPhase = -1;
);

slider5 == 8 ? (
_mixMono = 0;
_mixLeftWet = 1;
_mixRightWet = -1;
_mixLeftDry = _mixRightDry = 0;
_feedbackPhase = 1;
);

slider5 == 9 ? (
_mixMono = 0;
_mixLeftWet = 1;
_mixRightWet = -1;
_mixLeftDry = _mixRightDry = 0;
_feedbackPhase = -1;
);

in0 = spl0;
in1 = spl1;

( _mixMono ) ? (
inval1 = inval2 = (in0 + in1)*0.5;
):(
inval1 = in0;
inval2 = in1;
);
		
inmix1 = inval1 + tanh(_paramFeedback * _feedbackPhase * outval1);
inmix2 = inval2 + tanh(_paramFeedback * _feedbackPhase * outval2);

buf1[buffer1+_fp] = inmix1;
buf2[buffer2+_fp] = inmix2;
_fp = (_fp + 1) & (BSZ-1);

// delay 0.0-1.0 maps to 0.02ms to 10ms (always have at least 1 sample of delay)
delaySamples = (_paramDelay * srate * 0.01) + 1;
delaySamples += _sweep;

ep = _fp - delaySamples;
( ep < 0) ? (
ep += BSZ;
);

ep1 = ep|0;
w2 = ep-ep1;

ep1 &= (BSZ-1);
ep2 = ep1 + 1;
ep2 &= (BSZ-1);
w1 = 1 - w2;
outval1 = buf1[buffer1+ep1] * w1 + buf1[buffer1+ep2] * w2;
outval2 = buf2[buffer2+ep1] * w1 + buf2[buffer2+ep2] * w2;

// develop output mix
slider8 ? (
out0 = min(max(_mixLeftDry * inval1 + _mixLeftWet  * outval1,-0.99), 0.99);
out1 = min(max(_mixRightDry * inval2 + _mixRightWet  * outval2,-0.99), 0.99);
):(
out0 = tanh(_mixLeftDry * inval1 + _mixLeftWet  * outval1);
out1 = tanh(_mixRightDry * inval2 + _mixRightWet  * outval2);
);

// see if we're doing sweep
( _step != 0) ? (
// increment the sweep
_sweep += _step;
( _sweep <= 0) ? (
// make sure we don't go negative
_sweep = 0;
// and reverse direction
_step = -_step;
) : ( _sweep >= _maxSweepSamples) ? (
_step = -_step;
);
);

spl0 = in0*dry + out0*wet;
spl1 = in1*dry + out1*wet;
