/*
Pitch Tracker

This plug-in tracks the frequency of the input signal with an oscillator, ring modulator or filter.
The pitch tracking only works with monophonic inputs,
but can create interesting effects on unpitched sounds such as drums.

Mode	SINE		- Sine wave oscillator
	TRIANGLE	- Triangle wave oscillator
	SQUARE		- Square wave oscillator
	SAW		- Sawtooth wave oscillator
	NOISE		- White noise
	RING		- Ring modulator
	EQ		- Peaking EQ
Dynamics		Apply dynamics of input signal to generated output
Mix		Wet/ dry mix
Glide		Maximum pitch change rate
Transpose	Pitch offset to create harmonics, octave doubling, etc.
Maximum		Maximum allowed pitch - to supress pitch tracking errors
Trigger		Threshold level for pitch tracker - raise to stop tracking in gaps
Output		Level trim

This plug can be used with white or pink noise inputs to generate random pitch sequences.
Interesting evolving soundscapes can be made with a drum loop input and Tracker, RezFilter and Delay in series.
Sounds nice with a Roland TR-505/TR-707 drum kit.
*/

slider1:0<0,6,1{Sine,Triangle,Square,Saw,Noise,Ring,Filter}>mode
slider2:1<0,1,0.01>dynamics
slider3:1<0,1,0.01>mix
slider4:0.5<0,1,0.01>glide
slider5:0.5<0,1,0.01>transpose
slider6:0.5<0,1,0.01>maximum
slider7:0.5<0,1,0.01>trigger
slider8:0.5<0,1,0.01>output

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

@init
ext_noinit = 1;

twopi = 6.2831853;
bold = 0;
dn = 0;
buf1 = buf2 = buf3 = buf4 = 0;

dphi = 100/srate; //initial pitch
min = srate/30; //lower limit
res1 = cos(0.01); //p
res2 = sin(0.01); //q

att = pow(10,-60/srate);
//rel = pow(10,-10/srate);
rel = pow(10,-60/srate); // ???

function filterFreq(hz) (
r = 0.999;
j = r * r - 1;
k = (2 - 2 * r * r * cos(0.647 * hz / srate ));
hz = ((sqrt(k*k - 4*j*j) - k) / (2*j));
);

fo = filterFreq(50);
fi = (1 - fo)*(1 - fo);

itm1=itm2=otm1=otm2=0;

@slider
fParam1 = slider1; //Mode
fParam2 = slider2; //Dynamics
fParam3 = slider3; //Mix
fParam4 = slider4; //Tracking
fParam5 = slider5; //Transpose
fParam6 = slider6; //Maximum Hz
fParam7 = slider7; //Trigger dB
fParam8 = slider8; //Output dB

mode = fParam1|0;

ddphi = fParam4 * fParam4;
thr = pow(10, 3*fParam7 - 3.8);
max = (srate / pow(10, 1.6 + 2.2 * fParam6))|0;
trans = pow(1.0594631,(72*fParam5 - 36|0));
wet = pow(10, 2*fParam8 - 1);

(mode<6) ? (
dyn = wet * 0.6 * fParam3 * fParam2;
dry = wet * sqrt(1 - fParam3);
wet = wet * 0.3 * fParam3 * (1 - fParam2);
):(
dry = wet * (1 - fParam3);
wet *= (0.02*fParam3 - 0.004);
dyn = 0;
);

@sample
b1=buf1;
b2=buf2;
b3=buf3;
b4=buf4;

n=num;

p=phi;
dp=dphi;
s=sig;
bo=bold;

e=env;
sw=saw;
dsw=dsaw;
r1=res1;
r2=res2;

otm1=0.999*otm1 + spl0 - itm1; itm1=spl0; spl0=otm1;
otm2=0.999*otm2 + spl1 - itm2; itm2=spl1; spl1=otm2;

a = spl0;
b = spl1;

x = a + b;

tmp = (x>0) ? x : -x; //dynamics envelope
//e = (tmp>e) ? 0.5*(tmp + e) : e * rel; // ???
//e = (tmp>e) ? 4*tmp + att*(e-4*tmp) : e * rel; // ???
e = (tmp>e) ? 4*tmp + att*(e-4*tmp) : 4*tmp + rel*(e-4*tmp); // ???

b1 = fo*b1 + fi*x; 
b2 = fo*b2 + b1; //low-pass filter

(b2>thr) ? //if >thresh
(
(s<1) ? //and was <thresh
(
(n<min) ? //not long ago
(
tmp2 = b2 / (b2 - bo); //update period
tmp = trans*twopi/(n + dn - tmp2);
dp = dp + ddphi * (tmp - dp);
dn = tmp2;
dsw = 0.3183098 * dp;

(mode==6) ?
(
r1 = cos(4*dp); //resonator
r2 = sin(4*dp);
);
);
n = 0; //restart period measurement
);
s = 1;
):(
(n>max) ? s = 0; //now <thresh
);
n += 1;
bo = b2;

//p = mod(p+dp,twopi);
test0 = p+dp;
test1 = (test0 / twopi) |0;
test2 = test1 * twopi;
p = test0 - test2;

mode==0 ? ( //sine
x=sin(p);
);
mode==1 ? ( //triangle
x = (2*p/$pi-1);
(x>1) ? x = 2-x;
);
mode==2 ? ( //square
x=(sin(p)>0) ? 0.5 : -0.5;
);
mode==3 ? ( //saw
//sw = mod(sw+dsw,2);
test10 = sw+dsw;
test11 = (test10 / 2) |0;
test12 = test11 * 2;
sw = test10 - test12;
x = sw - 1;
);
mode==4 ? ( //noise
x = (rand(2)-1)*0.25;
);
mode==5 ? ( //ring
x *= sin(p);
);
mode==6 ? ( //filt
x += (b3 * r1) - (b4 * r2); 
b4 = 0.996 * ((b3 * r2) + (b4 * r1));
b3 = 0.996 * x;
);

x *= (wet + dyn * e);

spl0 = dry*a + x;
spl1 = dry*b + x;

(abs(b1)<0.000000001) ? ( buf1=0; buf2=0; buf3=0; buf4=0; ):( buf1=b1; buf2=b2; buf3=b3; buf4=b4; );

phi=p;
dphi=dp;
sig=s;
bold=bo;

num=(n>100000) ? 100000 : n;

env=e;
saw=sw;
dsaw=dsw;
res1=r1;
res2=r2;

@gfx 0 160
gfx_r=0; gfx_g=0.9; gfx_b=0; gfx_a=1;
gfx_setfont(1,"Arial", 16);

gfx_x =20; gfx_y =10;  gfx_printf("%.0f",(100 * fParam2) );
gfx_x =80; gfx_y =10;  gfx_drawchar($'%');
gfx_x =130; gfx_y =10;  gfx_printf("Dynamics");

gfx_x =20; gfx_y =30;  gfx_printf("%.0f",(100 * fParam3) );
gfx_x =80; gfx_y =30;  gfx_drawchar($'%');
gfx_x =130; gfx_y =30;  gfx_printf("Mix");

gfx_x =20; gfx_y =50;  gfx_printf("%.0f",(100 * fParam4) );
gfx_x =80; gfx_y =50;  gfx_drawchar($'%');
gfx_x =130; gfx_y =50;  gfx_printf("Glide");

gfx_x =20; gfx_y =70;  gfx_printf("%.0f",(72*fParam5 - 36) );
gfx_x =80; gfx_y =70;  gfx_printf("semi");
gfx_x =130; gfx_y =70;  gfx_printf("Transpose");

gfx_x =20; gfx_y =90;  gfx_printf("%.0f",(srate/max) );
gfx_x =80; gfx_y =90;  gfx_printf("Hz");
gfx_x =130; gfx_y =90;  gfx_printf("Maximum");

gfx_x =20; gfx_y =110;  gfx_printf("%.1f",(60*fParam7 - 60) );
gfx_x =80; gfx_y =110;  gfx_printf("dB");
gfx_x =130; gfx_y =110;  gfx_printf("Trigger");

gfx_x =20; gfx_y =130;  gfx_printf("%.1f",(40*fParam8 - 20) );
gfx_x =80; gfx_y =130;  gfx_printf("dB");
gfx_x =130; gfx_y =130;  gfx_printf("Output");
