// chorus_00 + feedback slider

slider1:_paramSweepRate=1<0,8,0.1>Rate (Hz)
slider2:_paramWidth=5<0,100,1>Width (%)
slider3:_paramFeedback=70<0,100,1>Feedback (%)
slider4:_paramDelay=12<0,100,1>Delay (ms)
slider5:_paramMix=0<0,7,1{Mono,Stereo,Mono Minus,Stereo Minus,Mono Wet Only,Stereo Wet Only,Mono Wet Only Minus,Stereo Wet Only Minus}>Mix Mode
slider6:0<0,100,1>Dry Mix (%)
slider7:0<-30,12,0.1>Output (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;

outval = 0; // most recent output value (for feedback)

_mixLeftWet =
_mixLeftDry =
_mixRightWet =
_mixRightDry = 0.5;

BSZ = 8192; // ~0.2*srate
buf = BSZ;
memset(buf,0,BSZ);

i=0;
while(i<BSZ) (
i+=1;
buf[i]=0;
);

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

function _sweepRate(x)
(
// rate
// map into param onto desired sweep range with log curve
_sweepRate = pow(10,_paramSweepRate*0.1);
_sweepRate -= 1;
_sweepRate *= 1.1;
_sweepRate += 0.1;
);

@slider
width = _paramWidth * 0.0005;
delay = pow(10, _paramDelay * 0.02)/1000; // map logarithmically and convert to seconds
sweep = _sweepRate();

(width != old_width || delay != old_delay || sweep != old_sweep) ? (
// width
// map so that we can spec between 0ms and 50ms
_sweepSamples = ceil(width * srate);

// delay
_delaySamples = ceil(delay * srate);

// sweep
_step = (_sweepSamples * 2 * sweep) / srate;

// calc min and max sweep now
_minSweepSamples = _delaySamples;
_maxSweepSamples = _delaySamples + _sweepSamples;

// set intial sweep pointer to midrange
_sweep = (_minSweepSamples + _maxSweepSamples) / 2;

old_width = width;
old_delay = delay;
old_sweep = sweep;
);

mix = slider6 * 0.01;
output = 10^(slider7/20);

@sample
_paramMix == 0 ? ( //mono
_mixLeftWet = _mixRightWet = 1;
_mixLeftDry = _mixRightDry = 1;
_feedbackPhase = 1;
);
_paramMix == 1 ? ( //stereo
_mixLeftWet = 1;
_mixLeftDry = 1;
_mixRightWet = -1;
_mixRightDry = 1;
_feedbackPhase = 1;
);
_paramMix == 2 ? ( //mono minus
_mixLeftWet = _mixRightWet = 1;
_mixLeftDry = _mixRightDry = 1;
_feedbackPhase = -1;
);
_paramMix == 3 ? ( //stereo minus
_mixLeftWet = 1;
_mixLeftDry = 1;
_mixRightWet = -1;
_mixRightDry = 1;
_feedbackPhase = -1;
);
_paramMix == 4 ? ( //mono wet only
_mixLeftWet = _mixRightWet = 1;
_mixLeftDry = _mixRightDry = 0;
_feedbackPhase = 1;
);
_paramMix == 5 ? ( //stereo wet only
_mixLeftWet = 1;
_mixLeftDry = 0;
_mixRightWet = -1;
_mixRightDry = 0;
_feedbackPhase = 1;
);
_paramMix == 6 ? ( //mono wet only minus
_mixLeftWet = _mixRightWet = 1;
_mixLeftDry = _mixRightDry = 0;
_feedbackPhase = -1;
);
_paramMix == 7 ? ( //stereo wet only minus
_mixLeftWet = 1;
_mixLeftDry = 0;
_mixRightWet = -1;
_mixRightDry = 0;
_feedbackPhase = -1;
);

inval = (spl0 + spl1)*0.5;

inmix = inval + tanh(_paramFeedback * 0.01 * _feedbackPhase * outval);

buf[_fp] = inmix;
_fp = (_fp + 1) & (BSZ-1);

outval = 0;

// build the two emptying pointers and do linear interpolation
Samples = (_paramDelay * srate * 0.0001) + 1;
Samples += _sweep;

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

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

ep1 &= (BSZ-1);
ep2 = ep1 + 1;
ep2 &= (BSZ-1);
w1 = 1 - w2;
outval = buf[ep1] * w1 + buf[ep2] * w2;

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

// increment the sweep
_sweep += _step;
(_sweep >= _maxSweepSamples || _sweep <= _minSweepSamples) ? (
_step = -_step;
);

_paramMix > 3 ? (
spl0 = (spl0*mix + out0*(1-mix))*output;
spl1 = (spl1*mix + out1*(1-mix))*output;
):(
spl0 = out0*output*0.707;
spl1 = out1*output*0.707;
);
