desc:PM 5 Synth (phase modulation, ADSR, 5th note)

/*

Monophonic Pulse Modulation Synth


02-01-2014
 by Sault


Algorithm : A -> B, A -> C


I basically just took one of Tale's example synths and ran with it
from there. I added 7 of his PolyBLEP waveforms, phase modulation,
a 5th note you can blend in, soft-clip limiting, and a simple lowpass
to tame high frequencies.

It's simple, it's sweet, and it didn't take me too long to whip together.
Thank you for the excellent work, Tale!

note : I did go up to 1:9 ratio and up to 0.3 mod Index, both of which
are really at the outer end of usefulness. Quite often only a little bit
of mod Index at a lower ratio is all it takes.


*/


slider1:5<1,5000,1>Attack (ms)
slider2:600<1,15000,1>Decay (ms)
slider3:-6.0<-120.0,24.0,1.0>Sustain (dB)
slider4:200<0,5000,1>Release (ms)
slider5:0<0,6,1{sine,saw,square,pulse,hammond,rect sine,tri pulse}>Carrier Waveform
slider6:1<1,9,1>Ratio
slider7:0<0,0.3,0.001>Mod Index
slider8:0<0,6,1{sine,saw,square,pulse,hammond,rect sine,tri pulse}>Mod Waveform
slider9:-15<-30,0,1>Add 5th note (dB)
slider10:15000<100,20000,1>Lowpass (Hz)
slider11:-3<-60,15,0.1>Master Vol

import adsr.jsfx-inc
import mono_synth.jsfx-inc
import poly_blep.jsfx-inc
import rc_filter.jsfx-inc


@init

out = 0;

fifthVol = 2^(slider9/6);
outLP.rc_setf(slider10);
masterVol = 2^(slider11/6);

  amp_dB = 8.6562;
  threshold_dB = -3.0;
  limit_dB = -0.2;
  a = 1.017;
  b = -0.025;

@slider

adsr.adsr_seta(slider1 * 0.001);
adsr.adsr_setd(slider2 * 0.001);
adsr.adsr_sets(10^(slider3 / 20));
adsr.adsr_setr(slider4 * 0.001);
fifthVol = 2^(slider9/6);
outLP.rc_setf(slider10);
masterVol = 2^(slider11/6);

@sample

// Parse the MIDI messages in the queue
synth.synth_midi();

// Process the ADSR envelope
synth.note_change ? synth.note_on ? adsr.adsr_a(synth.velocity) : adsr.adsr_r();
adsr.adsr_process() ? (

  // Process Pitch Wheel and Note On/Off
  synth.synth_pitch() || synth.synth_note() ? 
	(
	  osc.poly_setf(synth.freq);
	  mod.poly_setf(synth.freq * slider6);
	  osc5.poly_setf(synth.freq * 1.498307);
	);

  // generate an OSC sample
  

slider8 == 0 ? mout = mod.poly_sin();
slider8 == 1 ? mout = mod.poly_saw();
slider8 == 2 ? mout = mod.poly_sqr();
slider8 == 3 ? mout = mod.poly_rect();
slider8 == 4 ? mout = mod.poly_ham();
slider8 == 5 ? mout = mod.poly_full();
slider8 == 6 ? mout = mod.poly_trip();

osc.poly_sync(osc.t + slider7 * mout);
osc5.poly_sync(osc5.t + slider7 * mout * 0.8);

slider5 == 0 ? out1 = osc.poly_sin();
slider5 == 1 ? out1 = osc.poly_saw();
slider5 == 2 ? out1 = osc.poly_sqr();
slider5 == 3 ? out1 = osc.poly_rect();
slider5 == 4 ? out1 = osc.poly_ham();
slider5 == 5 ? out1 = osc.poly_full();
slider5 == 6 ? out1 = osc.poly_trip();

slider5 == 0 ? out5 = osc5.poly_sin();
slider5 == 1 ? out5 = osc5.poly_saw();
slider5 == 2 ? out5 = osc5.poly_sqr();
slider5 == 3 ? out5 = osc5.poly_rect();
slider5 == 4 ? out5 = osc5.poly_ham();
slider5 == 5 ? out5 = osc5.poly_full();
slider5 == 6 ? out5 = osc5.poly_trip();

  out5 *= fifthVol;

  out1 = amp_dB * log(abs(out1)) + boost_dB;
  out5 = amp_dB * log(abs(out5)) + boost_dB;

  (out1 > threshold_dB) ? (
    over_dB = out1 - threshold_dB;
    over_dB = a * over_dB + b * over_dB * over_dB;
    out1 = min(threshold_dB + over_dB, limit_dB);
  );

  (out5 > threshold_dB) ? (
    over_dB = out5 - threshold_dB;
    over_dB = a * over_dB + b * over_dB * over_dB;
    out5 = min(threshold_dB + over_dB, limit_dB);
  );

  out1 = exp(out1 / amp_dB) * sign(out1);
  out5 = exp(out5 / amp_dB) * sign(out5);

  out = outLP.rc_lp(out1 + out5) * adsr.env * masterVol;

  out = amp_dB * log(abs(out)) + boost_dB;
  (out > threshold_dB) ? (
    over_dB = out - threshold_dB;
    over_dB = a * over_dB + b * over_dB * over_dB;
    out = min(threshold_dB + over_dB, limit_dB);
  );

  out = exp(out / amp_dB) * sign(out);

  spl0 += out;
  spl1 += out;

);