/*		Polyphonic 3xOsc Synthesizer

MIDI support: channel, velocity, all notes off, pan, volume, pitch, portamento...
2xOsc that can be sythesised in various ways,
per Osc: volume, pan, cycle delay, semitone (so you can make organs like sounds) and more.
glide, ADSR, plucked and more waveforms

Max oscillators, Max polyphony to save CPU power.
Cutoff effect
3xBand EQ

1. pan per note
send CC number 20 with any value above 1
to return to standard MIDI pan, send this CC with value 1 or below

2. slide note
on each slide note send CC 21
the value of this CC determine the pitch change speed.

it works per note, like velocity, for easy use.
only the first note after this CC is slide.
*/

desc: Read info...

slider1:0<0,18,1{Square,Saw,Sine,ASine,Cosine,ACosine,Triangle,Rectangle,Doubled,whatsup1,whatsup2,whatsup3,whatsup4,whatsup5,organ,Plucked,Randomize,Noise,Sample}>Waveform
slider2:/synthesizer:none:Sample
slider3:0<0,1,1{No,Yes}>Invert
slider4:0<0,1,0.001>Cycle Delay (samples per cycle)
slider5:3.14<0.01,179.99,0.01>Sine,Cosine - Angle (degrees)
slider6:0.5<0,1,0.01>Plucked Frequency
slider7:0.99<0,1,0.01>Plucked Amplitude
slider8:0<-60,60,1>Semitone
slider9:0.75<0,2,0.01>Vol (Amplitude)
slider10:0<-100,100,1>Pan

slider11:1<0,9,1{None,Add,Sub,Am1,Am2,Am3,Fm1,Fm2,Fm1Alt,Fm2Alt}>Synthesis
slider12:0<0,100,0.01>Modulation Amount

slider13:1<1,2,1>Oscillator selector
slider14:2<1,2,1>Max Oscillators
slider15:6<1,16,1>Max Polyphony

slider16:0.001<0,5,0.001>Attack (seconds)
slider17:1<0,10,0.001>Decay (seconds)
slider18:0.5<0,2,0.01>Sustain (volume)
slider19:0.25<0,5,0.001>Release (seconds)

// modify by the MIDI portamento, in the block section.
slider20:0<0,5,0.001>Glide Time (seconds, 0=off)

slider21:8000<10,20000,1>Frequency Start (Hz)
slider22:800<10,20000,10>Frequency End (Hz)
slider23:0<0,2,0.001>Frequency Time (seconds)
slider24:0<0,1,0.01>Frequency Amount (dry/wet)

slider25:0<-24,24,1>Low (dB)
slider26:200<0,22000,1>Frequency (Hz)
slider27:0<-24,24,1>Mid (dB)
slider28:2000<0,22000,1>Frequency (Hz)
slider29:0<-24,24,1>High (dB)

slider30:0.25<0,1,0.01>Master Volume

slider31:16<0,16,1{1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,All}>MIDI Channel

in_pin:none
out_pin:L out
out_pin:R out

//===============end of section===============

@init

//ext_noinit = 1;  // don't init on transport state

//----------caution: this section defines consts, pointers, try not alter them

//----------

//----------consts

//----------execute this part only on plugin load.
(ENV_ATTACK == 0) ? (

//ENV_RELEASE = 0;
ENV_ATTACK = 1;
ENV_DECAY = 2;
ENV_SUSTAIN = 3;

//OSC_SQUARE = 0;
OSC_SAW = 1;
OSC_SINE = 2;
OSC_ASINE = 3;
OSC_COSINE = 4;
OSC_ACOSINE = 5;
OSC_TRIANGLE = 6;
OSC_RECTANGLE = 7;
OSC_DOUBLED = 8;
OSC_WHATSUP1 = 9;
OSC_WHATSUP2 = 10;
OSC_WHATSUP3 = 11;
OSC_WHATSUP4 = 12;
OSC_WHATSUP5 = 13;
OSC_ORGAN = 14;
OSC_PLUCKED = 15;
OSC_RANDOMIZE = 16;
OSC_NOISE = 17;
OSC_SAMPLE = 18;
//OSC_AUDIO = 19;

//SYNTH_ADD = 1;
SYNTH_SUB = 2;
SYNTH_AM1 = 3;
SYNTH_AM2 = 4;
SYNTH_AM3 = 5;
SYNTH_FM1 = 6;
SYNTH_FM2 = 7;
SYNTH_FM1_ALT = 8;
SYNTH_FM2_ALT = 9;

MAX_VOICES = 16;

//----------

//----------pointers

//NoteList = 0;

//----------

VoiceList = 129;

//vNote = 0;
vVelocity = 1;
vPanPerNote = 2;

vEnvStage = 3;  // -1 = off note, 0 = released note (can be replaced by new note if there is no off note on the list), 1..3 = playing note (ADS)
vEnvVol = 4;
vEnvLen = 5;  // Samples in stage = srate * seconds (decreased per sample)
vEnvAdd = 6;  // Added to vol per sample = 1/len

vGlideNote = 7;  // for glide operation per Note
vGlideNoteAdd = 8;  // for glide operation per Note

vSlideNote = 9;

vOsc1_Pos = 10;  // 0..1, sample pos per cycle (counter) also OscBaseAddr
vOsc1_PosAdd = 11;  // frequency/srate
vPluck1_Size = 12;  // whole of srate/frequency
vPluck1_Frac = 13;  // frac of srate/frequency
vPluck1_Ptr = 14;  // plucked sample pos per cycle (counter)
vPluck1_Noise = 15;
vPluck1_Z0 = 16;
vPluck1_Z1 = 17;
vSmp1_Pos = 18;
vSmp1_Add = 19;

OSC_SIZE = 10;

vOsc2_Pos = 20;  // 0..1, sample pos per cycle (counter) also OscBaseAddr
vOsc2_PosAdd = 21;  // frequency/srate
vPluck2_Size = 22;  // whole of srate/frequency
vPluck2_Frac = 23;  // frac of srate/frequency
vPluck2_Ptr = 24;  // plucked sample pos per cycle (counter)
vPluck2_Noise = 25;
vPluck2_Z0 = 26;
vPluck2_Z1 = 27;
vSmp2_Pos = 28;
vSmp2_Add = 29;

PLUCK_SIZE = 5500;
vPluck1_Buf = 30;
vPluck2_Buf = vPluck1_Buf + PLUCK_SIZE;

VOICE_SIZE = vPluck2_Buf + PLUCK_SIZE;

//----------

SMP_SIZE = 8192;
Smp1_Buf = VoiceList + (VOICE_SIZE * MAX_VOICES);
Smp2_Buf = Smp1_Buf + SMP_SIZE;

/*
AUDIO_SIZE = SMP_SIZE / 2;
AUDIO_SIZE1 = AUDIO_SIZE - 1;
Audio1_Buf0 = Smp1_Buf;
Audio1_Buf1 = Audio1_Buf0 + AUDIO_SIZE;
Audio2_Buf0 = Smp2_Buf;
Audio2_Buf1 = Audio2_Buf0 + AUDIO_SIZE;
*/

freembuf(Smp2_Buf + SMP_SIZE + 1);

//----------

Smp1_Len = -1;
Smp2_Len = -1;

cDenorm = 10^-30;
cAmpDB = 8.65617025;

//----------

s1_Wave = slider1;
s1_Sample = slider2;
s1_Invert = slider3;
s1_Delay = -1 - slider4;
s1_Angle = slider5;
s1_Damp = slider6;
s1_Amp = slider7;
s1_Semitone = slider8;
s1_Vol = slider9 / 0.5;
s1_Pan = slider10 / 100;  // scale to -1 .. 1
s1_Synth = slider11;
s1_ModAmount = slider12;

s2_Wave = s1_Wave;
s2_Sample = s1_Sample;
s2_Invert = s1_Invert;
s2_Delay = s1_Delay;
s2_Angle = s1_Angle;
s2_Damp = s1_Damp;
s2_Amp = s1_Amp;
s2_Semitone = s1_Semitone;
s2_Vol = s1_Vol;
s2_Pan = s1_Pan;

s1_lastSample = -1;
s2_lastSample = -1;

sOscNum = slider13;
sMaxOscs = 10;

//----------

MIDIvolume = 127;
MIDIpan = 1;
MIDIpitch = 0;

);  //(ENV_ATTACK == 0)

//----------

//----------reset all notes on playback seek
memset(NoteList,-1,129);

sMaxVoices = 0;

LastVoices = Smp1_Buf;
loop
(
MAX_VOICES,
LastVoices -= VOICE_SIZE;
LastVoices[] = 128;
LastVoices[vEnvStage] = -1;  // empty voice
LastVoices[vOsc1_Pos] = -1;
LastVoices[vOsc2_Pos] = -1;
);

PitchNote = 0;
PitchNoteAdd = 0;
lastNote = -1;

SlideNoteFlag = 0;
SlideNoteAdd = 0;

IsPanPerNote = 0;
IsSlideNote = 0;

//===============end of section===============

// this section is executed on project load/save
@serialize

file_var(0,s1_Wave);
file_var(0,s1_Sample);
file_var(0,s1_Invert);
file_var(0,s1_Delay);
file_var(0,s1_Angle);
file_var(0,s1_Damp);
file_var(0,s1_Amp);
file_var(0,s1_Semitone);
file_var(0,s1_Vol);
file_var(0,s1_Pan);
file_var(0,s1_Synth);
file_var(0,s1_ModAmount);

file_var(0,s2_Wave);
file_var(0,s2_Sample);
file_var(0,s2_Invert);
file_var(0,s2_Delay);
file_var(0,s2_Angle);
file_var(0,s2_Damp);
file_var(0,s2_Amp);
file_var(0,s2_Semitone);
file_var(0,s2_Vol);
file_var(0,s2_Pan);

//===============end of section===============

// this section is executed each time the user moves a slider (and after initialization)
@slider

slider1 &= $x7F;
slider2 &= $x7FFF;
(slider4 < 0) ? slider4 = 0;
slider14 |= 0;
(slider14 < 1) ? slider14 = 1 : (slider14 > 2) ? slider14 = 2;
slider13 |= 0;
(slider13 > slider14) ? slider13 = slider14;
slider15 = ((slider15 - 1) & $x0F) + 1;

(sMaxVoices != slider15) ?
(
sMaxVoices = slider15;
Tmp0 = LastVoices;
LastVoices = VoiceList + (VOICE_SIZE * sMaxVoices);
while
(
(Tmp0 > LastVoices) ?
(
Tmp0 -= VOICE_SIZE;
NoteList[ Tmp0[] ] = -1;
Tmp0[vEnvStage] = -1;  // empty voice
);
);
);

(sOscNum == slider13) ?
(
(sOscNum < 2) ?
(
s1_Wave = slider1;
s1_Sample = slider2;
s1_Invert = slider3;
s1_Delay = -1 - slider4;
s1_Angle = slider5;
s1_Damp = slider6;
s1_Amp = slider7;
(s1_Semitone != slider8) ?
(
s1_Semitone = slider8;
sMaxOscs = 0;
);
s1_Vol = slider9 / 0.5;
s1_Pan = slider10 / 100;  // scale to -1 .. 1
(slider11 >= 1) ? s1_Synth = slider11;
//Tmp0 = s1_Synth;
s1_ModAmount = slider12;
) :
(
s2_Wave = slider1;
s2_Sample = slider2;
s2_Invert = slider3;
s2_Delay = -1 - slider4;
s2_Angle = slider5;
s2_Damp = slider6;
s2_Amp = slider7;
(s2_Semitone != slider8) ?
(
s2_Semitone = slider8;
sMaxOscs = 0;
);
s2_Vol = slider9 / 0.5;
s2_Pan = slider10 / 100;  // scale to -1 .. 1
);

(s1_Wave == OSC_SAMPLE) ?
(
(s1_Sample != s1_lastSample) ?
(
slider2 = s1_Sample;
Tmp0=file_open(slider2);
(Tmp0 > 0) ?
(
file_riff(Tmp0, Tmp1, sMaxOscs);
(Tmp1 == 1) ?
(
Tmp1=file_avail(Tmp0);
(Tmp1 >= 1) ?
(
Smp1_Len = file_mem(Tmp0, Smp1_Buf, min(Tmp1, SMP_SIZE));
s1_lastSample = s1_Sample;
);
);
file_close(Tmp0);
sMaxOscs = 0;
);
s1_Sample = s1_lastSample;
);
s1_SampleFlag = Smp1_Len;
) :

/*
(s1_Wave == OSC_AUDIO) ?
(
(s1_SampleFlag > -2) ?
(
s1_SampleFlag = -2;
Smp1_Len = AUDIO_SIZE;
Audio1_Ptr = 0;
memset(Smp1_Buf,0,SMP_SIZE);
s1_lastSample = -1;
);
) :
*/

s1_SampleFlag = -1;

(s2_Wave == OSC_SAMPLE) ?
(
(s2_Sample != s2_lastSample) ?
(
slider2 = s2_Sample;
Tmp0=file_open(slider2);
(Tmp0 > 0) ?
(
file_riff(Tmp0, Tmp1, sMaxOscs);
(Tmp1 == 1) ?
(
Tmp1=file_avail(Tmp0);
(Tmp1 >= 1) ?
(
Smp2_Len = file_mem(Tmp0, Smp2_Buf, min(Tmp1, SMP_SIZE));
s2_lastSample = s2_Sample;
);
);
file_close(Tmp0);
sMaxOscs = 0;
);
s2_Sample = s2_lastSample;
);
s2_SampleFlag = Smp2_Len;
) :

/*
(s2_Wave == OSC_AUDIO) ?
(
(s2_SampleFlag > -2) ?
(
s2_SampleFlag = -2;
Smp2_Len = AUDIO_SIZE;
Audio2_Ptr = 0;
memset(Smp2_Buf,0,SMP_SIZE);
s2_lastSample = -1;
);
) :
*/

s2_SampleFlag = -1;

slider2 = (sOscNum < 2) ? s1_Sample : s2_Sample;

) :
(
sOscNum = slider13;

(sOscNum < 2) ?
(
slider1 = s1_Wave;
slider2 = s1_Sample;
slider3 = s1_Invert;
slider4 = -1 - s1_Delay;
slider5 = s1_Angle;
slider6 = s1_Damp;
slider7 = s1_Amp;
slider8 = s1_Semitone;
slider9 = s1_Vol * 0.5;
slider10 = s1_Pan * 100;  // scale to -100 .. 100
//Tmp0 = s1_Synth;
slider12 = s1_ModAmount;
) :
(
slider1 = s2_Wave;
slider2 = s2_Sample;
slider3 = s2_Invert;
slider4 = -1 - s2_Delay;
slider5 = s2_Angle;
slider6 = s2_Damp;
slider7 = s2_Amp;
slider8 = s2_Semitone;
slider9 = s2_Vol * 0.5;
slider10 = s2_Pan * 100;  // scale to -100 .. 100
);
);

//slider11 = (sOscNum < slider14) ? Tmp0 : 0;
slider11 = (sOscNum < slider14) ? s1_Synth : 0;

(sMaxOscs != slider14) ?
(
while
(
(sMaxOscs < slider14) ?
(
Tmp0 = VoiceList + (sMaxOscs * OSC_SIZE);
while
(
//Tmp0[vOsc1_Pos] = -1;
Tmp0[vOsc1_PosAdd] = 0;
Tmp0[vPluck1_Noise] = -1;
Tmp0[vSmp1_Pos] = 0;
Tmp0 += VOICE_SIZE;
(Tmp0 < LastVoices);
);
sMaxOscs += 1;
);
);
sMaxOscs = slider14;

vLastOscPosAdd = vOsc1_PosAdd + (OSC_SIZE * (sMaxOscs - 1));
);

s1Wave = s1_Wave;
s2Wave = s2_Wave;

sAttack = slider16;
sDecay = slider17;
sSustain = slider18;
sRelease = slider19;

sGlide = slider20;

(slider21 < 10) ? 10 : (slider21 > 20000) ? 20000;
(slider22 < 10) ? 10 : (slider22 > 20000) ? 20000;
(slider24 < 0) ? 0 : (slider24 > 1) ? 1;
sFreq1 = slider21;
sFreqTime = (slider23 > 0) ? slider23 * srate : 1;
sFreqAmount = slider24;

sFreqAdd = (sFreq1 - slider22) / sFreqTime;

lVol = exp(slider25/cAmpDB); 
mVol = exp(slider27/cAmpDB); 
hVol = exp(slider29/cAmpDB); 

freqLP = min(min(slider26,srate),slider28);
xLP = exp(-2.0*$pi*freqLP/srate);
a0LP = 1.0-xLP;
b1LP = -xLP;

freqHP = max(min(slider28,srate),slider26);
xHP = exp(-2.0*$pi*freqHP/srate);
a0HP = 1.0-xHP;
b1HP = -xHP;

sMaster = slider30;
Volume0 = sMaster * (MIDIvolume / 127);
//Pan-Left,Center ? Decrease Right Channel  else  (Pan-Right) Decrease Left Channel
(MIDIpan <= 1) ?
(
PanVolume0 = Volume0;
PanVolume1 = Volume0 * MIDIpan;
) :
(
PanVolume1 = Volume0;
PanVolume0 = Volume0 * (1.984375 - MIDIpan);
);

sMIDIchannel = slider31 &= $x1F;

//===============end of section===============

// this section is executed before processing each sample block
@block

//SAMPLE_NUMBER = 0;  // testing variable to see how much samples per block

while
(
(midirecv(msgpos,msg1,msg23)) ?
(
// channel filter
((sMIDIchannel >= 16) || ((msg1 & $x0F) == sMIDIchannel)) ?
(
msg = msg1 & $x00F0;
Note = msg23 & $x7F;
Velocity = (msg23 / 256) & $x7F;

//---------- note on
((msg == $x0090) && Velocity) ?  // some midi hardware send note off as note on with velocity 0
(
(IsSlideNote) ?
(
(SlideNoteFlag == 0) ? SlideNote = 0;
destSlideNote = Note - lastNote - SlideNote;
SlideNoteAdd = destSlideNote / (srate * IsSlideNote);
SlideNoteFlag = 1;
IsSlideNote = 0;
) :
(
Voice = NoteList[Note];
(Voice <= 0) ?
(
Tmp0 = VoiceList;
while
(
(Tmp0[vEnvStage] <= 0) ? Voice = Tmp0;
(Tmp0[vEnvStage] >= 0) ?
(
Tmp0 += VOICE_SIZE;
(Tmp0 < LastVoices);
);
);
//there0000:
);
(Voice > 0) ?
(
(Voice[vEnvStage] == 0) ? NoteList[Voice[]] = -1;  // shoulde be here instead of there0000, because of the condition (voice > 0)
NoteList[Note] = Voice;
Voice[] = Note;
Voice[vVelocity] = Velocity / 127;
Voice[vPanPerNote] = MIDIpan;

Voice[vEnvStage] = ENV_ATTACK;
Voice[vEnvVol] = 0;
Voice[vEnvLen] = (sAttack) ? sAttack * srate : 1;
Voice[vEnvAdd] = 1 / Voice[vEnvLen];  // n..1

Freq1 = sFreq1;
FreqTime = sFreqTime;
FreqAdd = sFreqAdd;
Fd1_0 = 0;
Fd1_1 = 0;
Fd2_0 = 0;
Fd2_1 = 0;

Voice[vLastOscPosAdd] = 0;  // last Osc Pos = flag to update all oscillators PosAdd for frequency change

((sGlide == 0) || (lastNote < 0)) ? lastGlideNote = Note;
Voice[vGlideNote] = lastGlideNote;
Voice[vGlideNoteAdd] = (Note-lastGlideNote) / ((sGlide * srate) + 0.0001);  // 0.0001 prevent divide by zero
lastNote = Note;

Voice[vSlideNote] = 0;
SlideNoteFlag = 0;

Voice[vOsc1_Pos] = s1_Delay;
Voice[vPluck1_Noise] = -1;
Voice[vSmp1_Pos] = 0;

Voice[vOsc2_Pos] = s2_Delay;
Voice[vPluck2_Noise] = -1;
Voice[vSmp2_Pos] = 0;
);
);  //: (IsSlideNote)
) :

//---------note off
((msg == $x0080) || (msg == $x0090)) ?
(
Voice = NoteList[Note];
(Voice > 0) ?
(
Voice[vEnvStage] = 0;  // ENV_RELEASE
Voice[vEnvLen] = (sRelease) ? sRelease * srate : 1;
Voice[vEnvAdd] = (0 - Voice[vEnvVol]) / Voice[vEnvLen];  // n..0
);
) :

//--------CC
(msg == $x00B0) ?
(
((Note == 7) || (Note == 10)) ?
(
(Note == 7) ? MIDIvolume = Velocity : MIDIpan = Velocity / 64;
Volume0 = sMaster * (MIDIvolume / 127);
//---------Pan-Left,Center ? Decrease Right Channel  else  (Pan-Right) Decrease Left Channel
(MIDIpan <= 1) ?
(
PanVolume0 = Volume0;
PanVolume1 = Volume0 * MIDIpan;
) :
(
PanVolume1 = Volume0;
PanVolume0 = Volume0 * (1.984375 - MIDIpan);
);
) :
(Note == $x0014) ? IsPanPerNote = Velocity :
(Note == $x0015) ?
(
(Velocity <= 1) ?
(
IsSlideNote = 0;
SlideNoteAdd = 0;
) :
(
(IsSlideNote == 0) ?
(
Voice = VoiceList;
while
(
Voice[vSlideNote] = 1;
Voice += VOICE_SIZE;
(Voice < LastVoices);
);
);
IsSlideNote = Velocity / 48;
);
) :
(Note == $x0025) ? slider20 = Velocity * (5/127) :  // portamento (glide)  scale from MIDI 0..127 to 0..5 (seconds)
//---------all Notes off
(Note == $x007B) ?
(
//----------shutdown all Voices
Voice = VoiceList;
while
(
NoteList[ Voice[] ] = -1;
Voice[vEnvStage] = -1;  // empty voice
Voice += VOICE_SIZE;
(Voice < LastVoices);
);
);
) :  //(msg == $x00B0)

//----------pitch
(msg == $x00E0) ?
(
(Velocity & 1) ? Note = Note | 128;
MIDIpitch = (Note | ((Velocity & $x7E) * 128)) - 8192;  // decode MIDI value to Real value
destPitchNote = MIDIpitch / 682.6667;  // scale pitch value to Note value, 8192 = 12 Semitones = 12 Notes
PitchNoteAdd = ((destPitchNote - PitchNote) * 4) / srate;
) :

//----------poly aftertouch
(msg == $x00A0) ?
(
Voice = NoteList[Note];
(Voice > 0) ? Voice[vVelocity] = Velocity / 127;
);

);  //----------channel filter

midisend(msgpos,msg1,msg23);  // don't eat midi, send it to host
);
);

//===============end of section===============

// cycles_per_second =  frequency
// samples_per_cycle = srate / cycles_per_second = srate / frequency
// increment_per_sample = 1 / samples_per_cycle = 1 / (srate / frequency) = (1 * frequency) / srate

// this section is executed srate times a second
@sample

//-----------MIDI pitch
(PitchNoteAdd) ?
(
(PitchNote == destPitchNote) ? PitchNoteAdd = 0 :
(
PitchNote += PitchNoteAdd;
(PitchNoteAdd > 0) ?
(
(PitchNote > destPitchNote) ? PitchNote = destPitchNote;
) :
(
(PitchNote < destPitchNote) ? PitchNote = destPitchNote;
);
);
);

//----------Slide Note
(SlideNoteAdd) ?
(
(SlideNote == destSlideNote) ? SlideNoteAdd = 0 :
(
SlideNote += SlideNoteAdd;
(SlideNoteAdd > 0) ?
(
(SlideNote > destSlideNote) ? SlideNote = destSlideNote;
) :
(
(SlideNote < destSlideNote) ? SlideNote = destSlideNote;
);
);
);

//-------------------------

//----------loop Voices

VoiceOut0 = 0;
VoiceOut1 = 0;
Voice = VoiceList;
while
(
(Voice[vEnvStage] >= 0) ?
(
Note = Voice[];

//----------env
(Voice[vEnvStage] == ENV_SUSTAIN) ?
(
Voice[vEnvVol] = sSustain;
) :
(
Voice[vEnvVol] += Voice[vEnvAdd];
Voice[vEnvLen] -= 1;
(Voice[vEnvStage] == ENV_ATTACK) ?
(
(Voice[vEnvLen] <= 0) ?
(
Voice[vEnvStage] = ENV_DECAY;
Voice[vEnvLen] = (sDecay) ? sDecay * srate : 1;
Voice[vEnvAdd] = ((sSustain - Voice[vEnvVol]) / Voice[vEnvLen]) / 1.5;  // n..0
);
) :
(Voice[vEnvStage] == ENV_DECAY) ?
(
((Voice[vEnvLen] <= 0) || (Voice[vEnvVol] == sSustain)) ?
(
Voice[vEnvStage] = ENV_SUSTAIN;
Voice[vEnvAdd] = 0;
);
) :
//----------ENV_RELEASE
(Voice[vEnvLen] <= 0) ?
(
NoteList[Note] = -1;
Voice[vEnvStage] = -1;  // empty voice
);
);

//----------

GlideNote = Voice + vGlideNote;
LastOscPosAdd = Voice + vLastOscPosAdd;

(Voice[vGlideNoteAdd]) ?
(
LastOscPosAdd[] = 0;  // flag to update frequency

GlideNote[] += Voice[vGlideNoteAdd];
(Voice[vGlideNoteAdd] > 0) ?
(
(GlideNote[] > Note) ? (GlideNote[] = Note; Voice[vGlideNoteAdd] = 0);
) :
(
(GlideNote[] < Note) ? (GlideNote[] = Note; Voice[vGlideNoteAdd] = 0);
);

(lastNote == Note) ? lastGlideNote = GlideNote[];
);

//----------

//----------osc1

((LastOscPosAdd[] == 0) || PitchNoteAdd || SlideNoteAdd) ?  // flags to update all oscillators's CyclePosAdd for frequency changes operations
(
tmpPitchNote = GlideNote[] + PitchNote;
(Voice[vSlideNote] > 0) ? tmpPitchNote += SlideNote;
Tmp0 = tmpPitchNote + s1_Semitone;
(Tmp0 < 0) ? Tmp0 = 0 : (Tmp0 > 127) ? Tmp0 = 127;
Voice[vOsc1_PosAdd] = 2 / (Tmp0 = srate / (440 * pow(2.0,(Tmp0-69.0)/12.0)));  // srate / frequency = samples per cycle
Voice[vSmp1_Add] = Smp1_Len / Tmp0;
Voice[vPluck1_Size] = floor(Tmp0);
Voice[vPluck1_Frac] = Tmp0 - Voice[vPluck1_Size];
);

OscPos = Voice + vOsc1_Pos;
(OscPos[] >= -1) ?  // cycle delay
(
(OscPos[] >= 1) ?
(
OscPos[] -= 2;  // -1 .. 1 one cycle has completed

s1_Wave == OSC_RANDOMIZE ?
(
st1 += 1;
st1 >= 4 ? (st1 = 0; s1Wave = floor(rand(OSC_RANDOMIZE)));
);
);

/*
(s1Wave == OSC_AUDIO) ?
(
Audio1_Buf0[Audio1_Ptr] = spl0;
Audio1_Buf1[Audio1_Ptr] = spl1;
Audio1_Ptr = (Audio1_Ptr + 1) & AUDIO_SIZE1;

Tmp0 = Voice + vSmp1_Pos;
(Tmp0[] >= Smp1_Len) ? Tmp0[] -= Smp1_Len;
OscSumOut0 = Audio1_Buf0[floor(Tmp0[])];
OscSumOut1 = Audio1_Buf1[floor(Tmp0[])];
Tmp0[] += Voice[vSmp1_Add];
) :
*/

s1Wave == OSC_PLUCKED ?
(
PluckPtr = Voice + vPluck1_Ptr;
((PluckPtr[] >= Voice[vPluck1_Size]) || (PluckPtr[] >= PLUCK_SIZE)) ? PluckPtr[] = 0;
(Voice[vPluck1_Noise] < 0) ?
(
Voice[vPluck1_Noise] = Voice[vPluck1_Size];
Voice[vPluck1_Z0] = 0;
Voice[vPluck1_Z1] = 0;
PluckPtr[] = 0;
);
PluckBuf0 = Voice + vPluck1_Buf + PluckPtr[];
(Voice[vPluck1_Noise] > 0) ?
(
Voice[vPluck1_Noise] -= 1;
Tmp0 = rand(1)-0.5;
Tmp1 = rand(1)-0.5;
) :
(
Tmp1 = Tmp0 = PluckBuf0[];
);
OscSumOut0 = (Tmp0*(1-Voice[vPluck1_Frac])) + (Voice[vPluck1_Z0]*Voice[vPluck1_Frac]);
OscSumOut1 = (Tmp1*(1-Voice[vPluck1_Frac])) + (Voice[vPluck1_Z1]*Voice[vPluck1_Frac]);
PluckBuf0[] = (Tmp0 * (1 - s1_Damp)) + (Voice[vPluck1_Z0] * s1_Damp * s1_Amp);
Voice[vPluck1_Z0] = Tmp0;
Voice[vPluck1_Z1] = Tmp1;
PluckPtr[] += 1;
) :
(
(s1_SampleFlag > 0) ?
(
Tmp0 = Voice + vSmp1_Pos;
(Tmp0[] >= Smp1_Len) ? Tmp0[] -= Smp1_Len;
OscSumOut0 = Smp1_Buf[floor(Tmp0[])];
Tmp0[] += Voice[vSmp1_Add];
) :
s1Wave == OSC_ORGAN ?  // organ
(
OscPos[] < -0.6 ? OscSumOut0 = -1 - OscPos[] :
OscPos[] < -0.4 ? OscSumOut0 = OscPos[] + 0.2 :
OscPos[] < -0.2 ? OscSumOut0 = -0.6 - OscPos[] :
OscPos[] < 0.2 ? OscSumOut0 = OscPos[] * 2 :
OscPos[] < 0.4 ? OscSumOut0 = 0.6 - OscPos[] :
OscPos[] < 0.6 ? OscSumOut0 = OscPos[] - 0.2 :
OscSumOut0 = 1 - OscPos[];
) :
s1Wave == OSC_WHATSUP5 ?  // dark organ
(
OscPos[] < -0.6 ? OscSumOut0 = -1 - OscPos[] :
OscPos[] < -0.2 ? OscSumOut0 = -0.4 :
OscPos[] < 0.2 ? OscSumOut0 = OscPos[] * 2 :
OscPos[] < 0.6 ? OscSumOut0 = 0.4 :
OscSumOut0 = 1 - OscPos[];
) :
s1Wave == OSC_WHATSUP4 ?
(
OscPos[] < -0.8 ? OscSumOut0 = -1.2 - OscPos[] :
OscPos[] < -0.2 ? OscSumOut0 = -0.4 :
OscPos[] < 0.2 ? OscSumOut0 = OscPos[] * 2 :
OscPos[] < 0.8 ? OscSumOut0 = 0.4 :
OscSumOut0 = 1 - OscPos[];
) :
s1Wave == OSC_WHATSUP3 ?  // accordion
(
OscPos[] < -0.5 ? OscSumOut0 = -0.5 :
OscPos[] < 0.5 ? OscSumOut0 = 0 - OscPos[] :
OscPos[] < 0.6 ? OscSumOut0 = OscPos[] - 0.1 :
OscPos[] < 0.7 ? OscSumOut0 = 0.9 - OscPos[] :
OscPos[] < 0.8 ? OscSumOut0 = OscPos[] - 0.3 :
OscPos[] < 0.9 ? OscSumOut0 = 1.4 - OscPos[] :
OscSumOut0 = OscPos[] - 0.5;
) :
s1Wave == OSC_WHATSUP2 ?
(
OscSumOut0 = sin(OscPos[] * 12.5);
) :
s1Wave == OSC_WHATSUP1 ?  // excellent rectangle
(
OscPos[] < -0.7 ? OscSumOut0 = -0.5 :
OscPos[] < 0.7 ? OscSumOut0 = 0 - OscPos[] :
OscSumOut0 = 0.5;
) :
s1Wave == OSC_DOUBLED ?  // doubled (pwm like)
(
OscPos[] < -0.5 ? OscSumOut0 = -0.5 :
OscPos[] < 0.5 ? OscSumOut0 = 0 - OscPos[] :
OscSumOut0 = 0.5 - OscPos[];
) :
s1Wave == OSC_RECTANGLE ?
(
OscSumOut0 = OscPos[] < -0.5 ? -0.5 : 0.5;
) :
s1Wave == OSC_TRIANGLE ?
(
OscSumOut0 = OscPos[] < 0 ? OscPos[] + 0.5 : 0.5 - OscPos[];
) :
s1Wave == OSC_ACOSINE ?
(
OscSumOut0 = acos(OscPos[] * s1_Angle);  // nice 17.5
) :
s1Wave == OSC_COSINE ?
(
OscSumOut0 = cos(OscPos[] * s1_Angle);  // nice 20,25,35
) :
s1Wave == OSC_ASINE ?
(
OscSumOut0 = asin(OscPos[] * s1_Angle);  // nice 20,25,35
) :
s1Wave == OSC_SINE ?
(
OscSumOut0 = sin(OscPos[] * s1_Angle);  // nice 20,25,35
) :
s1Wave == OSC_SAW ?
(
OscSumOut0 = OscPos[] / 2;
) :
s1Wave == OSC_SQUARE ?
(
OscSumOut0 = OscPos[] < 0 ? -0.5 : 0.5;
) :
//s1Wave == OSC_NOISE ?
(
OscSumOut0 = rand(1)-0.5;  // -0.5 .. 0.5
//OscSumOut1 = rand(1)-0.5;  // -0.5 .. 0.5
);

OscSumOut1 = OscSumOut0;
);

(s1_Invert >= 1) ? (OscSumOut0 = 0 - OscSumOut0; OscSumOut1 = 0 - OscSumOut1);

//----------vol per osc
OscSumOut0 *= s1_Vol;
OscSumOut1 *= s1_Vol;

//----------pan per osc
//----------Pan-Left,Center ? Decrease Right Osc	else  (Pan-Right) Decrease Left Osc
(s1_Pan <= 0) ? OscSumOut1 *= 1 + s1_Pan : OscSumOut0 *= 1 - s1_Pan;
) :
(
OscSumOut0 = 0;
OscSumOut1 = 0;
);  //----------cycle delay

OscPos[] += Voice[vOsc1_PosAdd];

//---------

(sMaxOscs >= 2) ?
(

//----------osc2

((LastOscPosAdd[] == 0) || PitchNoteAdd || SlideNoteAdd) ?  // flags to update all oscillators's CyclePosAdd for frequency changes operations
(
Tmp0 = tmpPitchNote + s2_Semitone;
(Tmp0 < 0) ? Tmp0 = 0 : (Tmp0 > 127) ? Tmp0 = 127;
LastOscPosAdd[] = 2 / (Tmp0 = srate / (440 * pow(2.0,(Tmp0-69.0)/12.0)));  // srate / frequency = samples per cycle
Voice[vSmp2_Add] = Smp2_Len / Tmp0;
Voice[vPluck2_Size] = floor(Tmp0);
Voice[vPluck2_Frac] = Tmp0 - Voice[vPluck2_Size];
);

OscPos = Voice + vOsc2_Pos;
(OscPos[] >= -1) ?  // cycle delay
(
(OscPos[] >= 1) ?
(
OscPos[] -= 2;  // -1 .. 1 one cycle has completed

s2_Wave == OSC_RANDOMIZE ?
(
st2 += 1;
st2 >= 4 ? (st2 = 0; s2Wave = floor(rand(OSC_RANDOMIZE)));
);
);

/*
s2Wave == OSC_AUDIO ?
(
Audio2_Buf0[Audio2_Ptr] = spl0;
Audio2_Buf1[Audio2_Ptr] = spl1;
Audio2_Ptr = (Audio2_Ptr + 1) & AUDIO_SIZE1;

Tmp0 = Voice + vSmp2_Pos;
(Tmp0[] >= Smp2_Len) ? Tmp0[] -= Smp2_Len;
Osc2Out0 = Audio2_Buf0[floor(Tmp0[])];
Osc2Out1 = Audio2_Buf1[floor(Tmp0[])];
Tmp0[] += Voice[vSmp2_Add];
) :
*/

s2Wave == OSC_PLUCKED ?
(
PluckPtr = Voice + vPluck2_Ptr;
((PluckPtr[] >= Voice[vPluck2_Size]) || (PluckPtr[] >= PLUCK_SIZE)) ? PluckPtr[] = 0;
(Voice[vPluck2_Noise] < 0) ?
(
Voice[vPluck2_Noise] = Voice[vPluck2_Size];
Voice[vPluck2_Z0] = 0;
Voice[vPluck2_Z1] = 0;
PluckPtr[] = 0;
);
PluckBuf0 = Voice + vPluck2_Buf + PluckPtr[];
(Voice[vPluck2_Noise] > 0) ?
(
Voice[vPluck2_Noise] -= 1;
Tmp0 = rand(1)-0.5;
Tmp1 = rand(1)-0.5;
) :
(
Tmp1 = Tmp0 = PluckBuf0[];
);
Osc2Out0 = (Tmp0*(1-Voice[vPluck2_Frac])) + (Voice[vPluck2_Z0]*Voice[vPluck2_Frac]);
Osc2Out1 = (Tmp1*(1-Voice[vPluck2_Frac])) + (Voice[vPluck2_Z1]*Voice[vPluck2_Frac]);
PluckBuf0[] = (Tmp0 * (1 - s2_Damp)) + (Voice[vPluck2_Z0] * s2_Damp * s2_Amp);
Voice[vPluck2_Z0] = Tmp0;
Voice[vPluck2_Z1] = Tmp1;
PluckPtr[] += 1;
) :
(
(s2_SampleFlag > 0) ?
(
Tmp0 = Voice + vSmp2_Pos;
(Tmp0[] >= Smp2_Len) ? Tmp0[] -= Smp2_Len;
Osc2Out0 = Smp2_Buf[floor(Tmp0[])];
Tmp0[] += Voice[vSmp2_Add];
) :
s2Wave == OSC_ORGAN ?  // organ
(
OscPos[] < -0.6 ? Osc2Out0 = -1 - OscPos[] :
OscPos[] < -0.4 ? Osc2Out0 = OscPos[] + 0.2 :
OscPos[] < -0.2 ? Osc2Out0 = -0.6 - OscPos[] :
OscPos[] < 0.2 ? Osc2Out0 = OscPos[] * 2 :
OscPos[] < 0.4 ? Osc2Out0 = 0.6 - OscPos[] :
OscPos[] < 0.6 ? Osc2Out0 = OscPos[] - 0.2 :
Osc2Out0 = 1 - OscPos[];
) :
s2Wave == OSC_WHATSUP5 ?  // dark organ
(
OscPos[] < -0.6 ? Osc2Out0 = -1 - OscPos[] :
OscPos[] < -0.2 ? Osc2Out0 = -0.4 :
OscPos[] < 0.2 ? Osc2Out0 = OscPos[] * 2 :
OscPos[] < 0.6 ? Osc2Out0 = 0.4 :
Osc2Out0 = 1 - OscPos[];
) :
s2Wave == OSC_WHATSUP4 ?
(
OscPos[] < -0.8 ? Osc2Out0 = -1.2 - OscPos[] :
OscPos[] < -0.2 ? Osc2Out0 = -0.4 :
OscPos[] < 0.2 ? Osc2Out0 = OscPos[] * 2 :
OscPos[] < 0.8 ? Osc2Out0 = 0.4 :
Osc2Out0 = 1 - OscPos[];
) :
s2Wave == OSC_WHATSUP3 ?  // accordion
(
OscPos[] < -0.5 ? Osc2Out0 = -0.5 :
OscPos[] < 0.5 ? Osc2Out0 = 0 - OscPos[] :
OscPos[] < 0.6 ? Osc2Out0 = OscPos[] - 0.1 :
OscPos[] < 0.7 ? Osc2Out0 = 0.9 - OscPos[] :
OscPos[] < 0.8 ? Osc2Out0 = OscPos[] - 0.3 :
OscPos[] < 0.9 ? Osc2Out0 = 1.4 - OscPos[] :
Osc2Out0 = OscPos[] - 0.5;
) :
s2Wave == OSC_WHATSUP2 ?
(
Osc2Out0 = sin(OscPos[] * 12.5);
) :
s2Wave == OSC_WHATSUP1 ?  // excellent rectangle
(
OscPos[] < -0.7 ? Osc2Out0 = -0.5 :
OscPos[] < 0.7 ? Osc2Out0 = 0 - OscPos[] :
Osc2Out0 = 0.5;
) :
s2Wave == OSC_DOUBLED ?  // doubled (pwm like)
(
OscPos[] < -0.5 ? Osc2Out0 = -0.5 :
OscPos[] < 0.5 ? Osc2Out0 = 0 - OscPos[] :
Osc2Out0 = 0.5 - OscPos[];
) :
s2Wave == OSC_RECTANGLE ?
(
Osc2Out0 = OscPos[] < -0.5 ? -0.5 : 0.5;
) :
s2Wave == OSC_TRIANGLE ?
(
Osc2Out0 = OscPos[] < 0 ? OscPos[] + 0.5 : 0.5 - OscPos[];
) :
s2Wave == OSC_ACOSINE ?
(
Osc2Out0 = acos(OscPos[] * s2_Angle);  // nice 17.5
) :
s2Wave == OSC_COSINE ?
(
Osc2Out0 = cos(OscPos[] * s2_Angle);  // nice 20,25,35
) :
s2Wave == OSC_ASINE ?
(
Osc2Out0 = asin(OscPos[] * s2_Angle);  // nice 20,25,35
) :
s2Wave == OSC_SINE ?
(
Osc2Out0 = sin(OscPos[] * s2_Angle);  // nice 20,25,35
) :
s2Wave == OSC_SAW ?
(
Osc2Out0 = OscPos[] / 2;
) :
s2Wave == OSC_SQUARE ?
(
Osc2Out0 = OscPos[] < 0 ? -0.5 : 0.5;
) :
//s2Wave == OSC_NOISE ?
(
Osc2Out0 = rand(1)-0.5;  // -0.5 .. 0.5
//Osc2Out1 = rand(1)-0.5;  // -0.5 .. 0.5
);

Osc2Out1 = Osc2Out0;
);

(s2_Invert >= 1) ? (Osc2Out0 = 0 - Osc2Out0; Osc2Out1 = 0 - Osc2Out1);

//----------vol per osc
Osc2Out0 *= s2_Vol;
Osc2Out1 *= s2_Vol;

//----------pan per osc
//----------Pan-Left,Center ? Decrease Right Osc	else  (Pan-Right) Decrease Left Osc
(s2_Pan <= 0) ? Osc2Out1 *= 1 + s2_Pan : Osc2Out0 *= 1 - s2_Pan;
) :
(
Osc2Out0 = 0;
Osc2Out1 = 0;
);  //----------cycle delay

OscPos[] += LastOscPosAdd[];

(s1_Synth >= SYNTH_FM2_ALT) ?
(
OscSumOut0 = sin(OscSumOut0 + (sin(Osc2Out0) * s1_ModAmount));
OscSumOut1 = sin(OscSumOut1 + (sin(Osc2Out1) * s1_ModAmount));
) :
(s1_Synth >= SYNTH_FM1_ALT) ?
(
OscSumOut0 = sin(OscSumOut0 + (Osc2Out0 * s1_ModAmount));
OscSumOut1 = sin(OscSumOut1 + (Osc2Out1 * s1_ModAmount));
) :
(s1_Synth >= SYNTH_FM2) ?
(
OscSumOut0 = sin(Osc2Out0 + (sin(OscSumOut0) * s1_ModAmount));
OscSumOut1 = sin(Osc2Out1 + (sin(OscSumOut1) * s1_ModAmount));
) :
(s1_Synth >= SYNTH_FM1) ?
(
OscSumOut0 = sin(Osc2Out0 + (OscSumOut0 * s1_ModAmount));
OscSumOut1 = sin(Osc2Out1 + (OscSumOut1 * s1_ModAmount));
) :
(s1_Synth >= SYNTH_AM3) ?
(
OscSumOut0 = Osc2Out0 * acos(OscSumOut0 * s1_ModAmount);
OscSumOut1 = Osc2Out1 * acos(OscSumOut1 * s1_ModAmount);
) :
(s1_Synth >= SYNTH_AM2) ?
(
OscSumOut0 *= cos(Osc2Out0 * s1_ModAmount);
OscSumOut1 *= cos(Osc2Out1 * s1_ModAmount);
) :
(s1_Synth >= SYNTH_AM1) ?
(
OscSumOut0 *= Osc2Out0 * cos(s1_ModAmount);
OscSumOut1 *= Osc2Out1 * cos(s1_ModAmount);
) :
(s1_Synth >= SYNTH_SUB) ?
(
OscSumOut0 -= Osc2Out0;
OscSumOut1 -= Osc2Out1;
) :
//(s1_Synth >= SYNTH_ADD) ?
(
OscSumOut0 += Osc2Out0;
OscSumOut1 += Osc2Out1;
);

/*
(sMaxOscs >= 3) ?
(

//---------osc3

(s2_Synth >= SYNTH_SUB) ?
(
(s1_Synth != SYNTH_SUB) ?
(
Osc2Out0 -= Osc1Out0;
Osc2Out1 -= Osc1Out1;
) :
(
Osc2Out0 = 0 - Osc1Out0;
Osc2Out1 = 0 - Osc1Out1;
);
) :
//(s2_Synth >= SYNTH_ADD) ?
(
(s1_Synth != SYNTH_ADD) ?  // no need to add twice the same osc
(
Osc2Out0 += Osc1Out0;
Osc2Out1 += Osc1Out1;
) :
(
Osc2Out0 = Osc1Out0;
Osc2Out1 = Osc1Out1;
);
);

OscSumOut0 += Osc2Out0;
OscSumOut1 += Osc2Out1;

);  //----------end osc3
*/

);  //----------end osc2

//-----------

(IsPanPerNote > 1) ?
(
Tmp0 = Voice[vPanPerNote];
(Tmp0 <= 1) ? OscSumOut1 *= Tmp0 : OscSumOut0 *= 1.984375 - Tmp0;
);
//----------MIDI velocity
Tmp0 = Voice[vEnvVol] * Voice[vVelocity];
VoiceOut0 += OscSumOut0 * Tmp0;
VoiceOut1 += OscSumOut1 * Tmp0;
);

Voice += VOICE_SIZE;
(Voice < LastVoices);
);  //----------loop Voices

//-----------

//Cutoff effect
(sFreqAmount) ?
(
(FreqTime > 0) ?
(
FreqTime -= 1;
Freq1 -= FreqAdd;

Tmp0 = 1 / tan($pi * Freq1 / srate);
Tmp1 = 1 + Tmp0*(Tmp0 + 0.7);
Fa1 = 2 * (1 - Tmp0 * Tmp0) / Tmp1;
Fa0 = (1 + Tmp0 * (Tmp0 - 0.7)) / Tmp1;
Fk = Tmp0 * 0.7 / Tmp1;
);

Tmp0 = Fk * VoiceOut0 - (Fa1 * Fd1_0 + Fa0 * Fd2_0);
Tmp1 = Fk * VoiceOut1 - (Fa1 * Fd1_1 + Fa0 * Fd2_1);
VoiceOut0 = (VoiceOut0 * (1 - sFreqAmount)) + ((Tmp0 - Fd2_0) * sFreqAmount);
VoiceOut1 = (VoiceOut1 * (1 - sFreqAmount)) + ((Tmp1 - Fd2_1) * sFreqAmount);
Fd2_0 = Fd1_0;
Fd2_1 = Fd1_1;
Fd1_0 = Tmp0;
Fd1_1 = Tmp1;
);

//----------3xBand EQ
sl0 = tmp0LP = (a0LP*VoiceOut0) - (b1LP*tmp0LP) + cDenorm;
sl1 = tmp1LP = (a0LP*VoiceOut1) - (b1LP*tmp1LP) + cDenorm;

sh0 = VoiceOut0 - (tmp0HP = (a0HP*VoiceOut0) - (b1HP*tmp0HP) + cDenorm);
sh1 = VoiceOut1 - (tmp1HP = (a0HP*VoiceOut1) - (b1HP*tmp1HP) + cDenorm);

VoiceOut0 = (sl0*lVol) + ((VoiceOut0 - sl0 - sh0)*mVol) + (sh0*hVol);
VoiceOut1 = (sl1*lVol) + ((VoiceOut1 - sl1 - sh1)*mVol) + (sh1*hVol);

(IsPanPerNote <= 1) ? 
(
spl0 = VoiceOut0 * PanVolume0;
spl1 = VoiceOut1 * PanVolume1;
) :
(
spl0 = VoiceOut0 * Volume0;
spl1 = VoiceOut1 * Volume0;
);

//SAMPLE_NUMBER += 1;  // testing variable to see how much samples per block
