// Simple Mono Synth

slider1:-48<-48,-12,0.1>Sine Volume (dB)
slider2:-12<-48,-12,0.1>Triangle Volume (dB)
slider3:-48<-48,-12,0.1>Saw Volume (dB)
slider4:-48<-48,-12,0.1>Square Volume (dB)
slider5:-48<-48,-12,0.1>extra Sine Volume (dB)
slider6:-48<-48,-12,0.1>Noise Volume (dB)
slider7:2<2,200,1>Attack (ms)
slider8:20<20,2000,1>Release (ms)
slider9:0<-4,4,1>Sine/Triangle Transpose (oct)
slider10:0<-4,4,1>extra Sine Transpose (oct)
slider11:-6<-30,0,0.1>Output Volume (dB)
slider12:0.5<0,1,0.01>Square mod
slider13:0<0,1,1{add,subtract}>Mode
slider14:150<20,250,5>Scope Size (ms)

import midi_queue.jsfx-inc

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

@init
ext_noinit = 1;
tone = 0;
vol = 0;

itm=otm=0;
m1=m0=0;

midiq.midiq_init(0, 256);

histbuf = 1000000;
histpos = 0;

@slider
outVol1 = slider1 <= -48.0 ? 0.0 : 10^(slider1/20);
outVol2 = slider2 <= -48.0 ? 0.0 : 10^(slider2/20);
outVol3 = slider3 <= -48.0 ? 0.0 : 10^(slider3/20);
outVol4 = slider4 <= -48.0 ? 0.0 : 10^(slider4/20);
outVol5 = slider5 <= -48.0 ? 0.0 : 10^(slider5/20);
outVol6 = slider6 <= -48.0 ? 0.0 : 10^((slider6-12)/20);
attack = 2/max(slider7*srate/1000, 0);
release = 2/max(slider8*srate/1000, 0);
transpose = slider9*12;
transpose2 = slider10*12;
outVol7 = 10^(slider11/20);
mod = slider12*0.99;

size = slider14;
histsize = size/1000*srate|0;

@block
midiq.midiq_collect();

@sample
while(midiq.midiq_remove()) (
status = midiq.msg1 & 0xF0;
velocity = midiq.msg3;
// Note On
status == 0x90 && velocity ? (
note = midiq.msg2;
freq = 440 * 2^((note-69)/12);
waveSpeed = (2*$pi*freq)/srate;
freq2 = 440 * 2^((note-69+transpose)/12);
waveSpeed2 = (2*$pi*freq2)/srate;
freq3 = 440 * 2^((note-69+transpose2)/12);
waveSpeed3 = (2*$pi*freq3)/srate;
seekVol = 1;
) :
// Note Off
status == 0x80 || (status == 0x90 && !velocity) ? (
midiq.msg2 == note ? seekVol = 0;
);
);

tone1 = sin(wavePos2); //sine
tone2 = 2*wavePos/$pi-1; (tone2>1) ? tone2 = 2-tone2; //triangle
tone3 = 2*(wavePos/(2*$pi)-((wavePos/(2*$pi) + 0.5)|0)); //saw
tone4 = (sin(wavePos)>mod) ? 1 : (sin(wavePos)<mod) ? -1 : mod; //square
tone5 = sin(wavePos3)+0.5*sin(wavePos3/2); //synth
tone6 = (rand(2)-1); //noise

slider13 == 1 ? (
tone = tone1*sqrt(vol)*outVol1;
tone -= tone2*sqrt(vol)*outVol2;
tone -= tone3*sqrt(vol)*outVol3;
tone -= tone4*sqrt(vol)*outVol4;
tone -= tone5*sqrt(vol)*outVol5;
tone -= tone6*sqrt(vol)*outVol6;
):(
tone = tone1*sqrt(vol)*outVol1;
tone += tone2*sqrt(vol)*outVol2;
tone += tone3*sqrt(vol)*outVol3;
tone += tone4*sqrt(vol)*outVol4;
tone += tone5*sqrt(vol)*outVol5;
tone += tone6*sqrt(vol)*outVol6;
);

out = tone;

otm=0.999*otm + out - itm; itm=out; out=otm;
m1=m0;
out=0.5*(m1+m0=out);

(wavePos += waveSpeed) >= 2*$pi ? wavePos -= 2*$pi;
(wavePos2 += waveSpeed2) >= 2*$pi ? wavePos2 -= 2*$pi;
(wavePos3 += waveSpeed3) >= 2*$pi ? wavePos3 -= 2*$pi;

vol > seekVol ? vol = max(vol-release,seekVol) : vol = min(vol+attack,seekVol);

histbuf[histpos]=out;
histbuf[histpos+histsize]=out;

histpos += 1;
histpos >= histsize ? histpos = 0;

spl0 += out*outVol7;
spl1 += out*outVol7;

@gfx 0 100
offs=histpos;
gscale=gfx_w/histsize;
gbuf=histbuf;
gscale2=gfx_h*0.5|0;

gfx_r=0;gfx_g=1;gfx_b=1; gfx_a=0.5;

ga=0;
loop(histsize,
gv=gbuf[offs];
offs+=1;
offs>=histsize?offs=0;
gx=ga*gscale|0;
gy=gfx_h*0.5 - gv*gscale2|0; 
ga ? gfx_lineto(gx,gy,0) : ( gfx_x=gx; gfx_y=gy; );
ga+=1;
);

gbuf+=histsize;
