; this is beast is very crude Korg MS-20 clone
; by Severak
; not Behringer
<Cabbage>
form caption("MS20") size(1024, 500), colour(0, 51, 153), pluginid("ms20")
image bounds(0, 0, 1024, 343) file("ms20.png")
combobox bounds(6, 58, 64, 23) channel("vco1wave") text("triangle", "saw", "pulse", "noise")
combobox bounds(74, 58, 66, 23) channel("vco2wave") text("saw", "square")
rslider bounds(16, 116, 38, 37) range(0.1, 0.9, 0.1, 1, 0.001) channel("vco1pw")
rslider bounds(86, 116, 39, 35) range(-1, 1, 0, 1, 0.001) channel("vco2pitch")
rslider bounds(10, 176, 50, 51) range(-2, 2, 0, 1, 1.001) channel("vco1offset")
rslider bounds(82, 174, 48, 50) range(-2, 2, 0, 1, 1.001) channel("vco2offset")
rslider bounds(152, 50, 40, 39) range(0, 1, 1, 1, 0.001) channel("vco1mix")
rslider bounds(152, 122, 40, 39) range(0, 1, 0, 1, 0.001) channel("vco2mix")
rslider bounds(214, 46, 45, 47) range(0, 1, 0, 0.5, 0.001) channel("hpffreq")
rslider bounds(274, 46, 47, 50) range(0, 1, 1, 1, 0.001) channel("lpffreq")
rslider bounds(216, 120, 39, 40) range(0, 1, 0, 1, 0.001) channel("hpfres")
rslider bounds(276, 120, 43, 39) range(0, 1, 0, 1, 0.001) channel("lpfres")
combobox bounds(330, 218, 61, 22) channel("lfotype") text("triangle", "square")
rslider bounds(342, 260, 38, 37) range(0, 20, 1, 0.2, 0.001) channel("lfofreq")
rslider bounds(874, 34, 49, 55) range(0, 1, 0.1, 1, 0.001) channel("vol")
rslider bounds(406, 210, 40, 36) range(0.01, 1, 0.01, 1, 0.01) channel("env1att")
rslider bounds(404, 260, 38, 36) range(0.01, 1, 0.01, 1, 0.01) channel("env1rel")
rslider bounds(470, 110, 36, 39) range(0.01, 1, 0.01, 1, 0.01) channel("env2att")
rslider bounds(470, 158, 33, 33) range(0.01, 1, 0.01, 1, 0.01) channel("env2dec")
rslider bounds(472, 210, 31, 31) range(0.001, 1, 1, 1, 0.01) channel("env2sus")
rslider bounds(472, 260, 32, 35) range(0.01, 1, 0.01, 1, 0.01) channel("env2rel")
keyboard bounds(32, 354, 400, 100)
label bounds(436, 350, 574, 43) text("Korg MS20 clone by Severak")
label bounds(708, 402, 310, 29) text("(not by Behringer)")
label bounds(344, 468, 676, 22) text("this is actually batshit crazy project and I am already regretting it")
rslider bounds(216, 208, 37, 41) range(0, 1, 0, 1, 0.001) channel("hpfmodlfo")
rslider bounds(216, 262, 36, 33) range(0, 1, 0, 1, 0.001) channel("hpfmodenv")
rslider bounds(276, 208, 42, 37) range(0, 1, 0, 1, 0.001) channel("lpfmodlfo")
rslider bounds(278, 262, 40, 33) range(0, 1, 0, 1, 0.001) channel("lpfmodenv")
</Cabbage>
<CsoundSynthesizer>
<CsOptions>
-n -d -+rtmidi=NULL -M0 -m0d --midi-key-cps=4 --midi-velocity-amp=5
</CsOptions>
<CsInstruments>
; Initialize the global variables. 
ksmps = 32
nchnls = 2
0dbfs = 1

gkLFO init 0
gkLastNote init 0


;instrument will be triggered by keyboard widget
instr 1
    gkLastNote init p4
    
    if gkLastNote != 0 && gkLastNote != p4 then
        ; this is monophonic synth
        turnoff
    endif
    
    inotnum notnum
    
    ; ENV 1
    
    ienv1att chnget "env1att"
    ienv1rel chnget "env1rel"
    kenv1 madsr ienv1att, 0.0001, 1, ienv1rel
    
    
    ; VCO 1 
    kvco1offset chnget "vco1offset"
    kcps1 = cpsmidinn(inotnum) * octave(kvco1offset)
    
    kvco1pw chnget "vco1pw"
    
    ivco1waves[] fillarray -1, 12, 0, 2, -1  ; last one is noise
    ivco1wave chnget "vco1wave"
    
    aVco1 vco2 kenv1, kcps1, ivco1waves[ivco1wave], kvco1pw
    
    ; VCO 2
    kvco2offset chnget "vco2offset"
    kvco2pitch chnget "vco2pitch"
    kcps2 = cpsmidinn(inotnum) * octave(kvco2offset) * cent(kvco2pitch*100)
    
    ivco2waves[] fillarray -1, 0, 10
    ivco2wave chnget "vco2wave"
    
    aVco2 vco2 kenv1, kcps2, ivco2waves[ivco2wave]
    
    ; MIX
    kvco1mix chnget "vco1mix"
    kvco2mix chnget "vco2mix"
    
    aMix = aVco1 * kvco1mix + aVco2 * kvco2mix
    
    ; ENV2
    ienv2att chnget "env2att"
    ienv2dec chnget "env2dec"
    ienv2sus chnget "env2sus"
    ienv2rel chnget "env2rel"
    kenv2 madsr ienv2att, ienv2dec, ienv2sus, ienv2rel
    
    
    ; HPF
    khpffreq chnget "hpffreq"
    khpfres chnget "hpfres"
    
    khpfmodenv chnget "hpfmodenv"
    khpfmodlfo chnget "hpfmodlfo"
    
    khpfmodenvF =  (khpfmodenv * kenv2) - (khpfmodenv - 1)
    khpfmodlfoF = (khpfmodlfo * gkLFO) - (khpfmodlfo - 1)
                
    aMix K35_hpf aMix, khpffreq * 22000 * khpfmodenvF * khpfmodlfoF, khpfres * 10
    
    ; LPF
    klpffreq chnget "lpffreq"
    klpfres chnget "lpfres"
    
    klpfmodenv chnget "lpfmodenv"
    klpfmodlfo chnget "lpfmodlfo"
    
    klpfmodenvF =  (klpfmodenv * kenv2) - (klpfmodenv - 1)
    klpfmodlfoF = (klpfmodlfo * gkLFO) - (klpfmodlfo - 1)
                
    aMix K35_lpf aMix, klpffreq * 22000 * klpfmodenvF * klpfmodlfoF, klpfres * 10
    
    ; VCA
    
    ; it seems that VCA is driven by something from outside
    aMix = aMix * kenv2
    
    ; OUT
    kvol chnget "vol"
    
    ; to prevent disasters
    aMix clip aMix, 1, 1
    outs aMix * kvol, aMix * kvol
endin

instr 2
    klfofreq chnget "lfofreq"
    ilfotype chnget "lfotype"
    ilfotypes[] fillarray -1, 1, 2
    
    
    klfo lfo 0.5, klfofreq, ilfotypes[ilfotype]
    gkLFO = klfo + 0.5
endin

</CsInstruments>
<CsScore>
;causes Csound to run for about 7000 years...
f0 z
i2 0 3600 ; LFO 1 hour
</CsScore>
</CsoundSynthesizer>
