; ANALOG NOMAD
;
; more powerful analog-like synth
;
; (s) Severák 2019-20
; licensed with MIT license


; TODO
; - presets system like ToneZ
; - velocity sesnsitivity checkbox
; - chorus?
; - manuál

<Cabbage>
form caption("NOMAD") size(500, 330), colour(0, 51, 153), pluginid("anod")
keyboard bounds(8, 220, 381, 95)
combobox bounds(8, 10, 61, 25)  channel("offset") text("-24", "-12", "+0", "+12", "+24") value(3)
hslider bounds(4, 42, 136, 22) range(0.01, 1, 0.01, 1, 0.001) channel("attack") text("attack")
hslider bounds(3, 74, 138, 23) range(0.01, 1, 0.5, 1, 0.001) channel("decay") text("decay")
checkbox bounds(22, 102, 117, 30) channel("hold") text("hold")
checkbox bounds(22, 136, 117, 30) channel("mono") text("mono")


hslider bounds(152, 40, 132, 24) range(0, 0.3, 0, 1, 0.001) channel("pulse") text("pulse")
hslider bounds(152, 68, 133, 26) range(0, 0.3, 0.3, 1, 0.001) channel("saw") text("saw")
hslider bounds(152, 102, 135, 29) range(0, 0.3, 0, 1, 0.001) channel("sub") text("sub")
hslider bounds(152, 138, 135, 29) range(0, 0.3, 0, 1, 0.001) channel("noise") text("noise")

hslider bounds(292, 40, 150, 25) range(0.01, 0.99, 0.5, 1, 0.001) channel("pulse_kpw") text("width")
hslider bounds(292, 68, 150, 27) range(0.01, 0.99, 0.5, 1, 0.001) channel("saw_kpw") text("angle")
hslider bounds(292, 102, 150, 28) range(-100, 100, 0, 1, 1) channel("det") text("det")

hslider bounds(6, 176, 485, 34) range(0, 22000, 22000, 0.5, 0.001) channel("traveller")
checkbox bounds(292, 138, 75, 30) channel("quack") text("quack")
hslider bounds(374, 138, 70, 30) range(0, 0.5, 0, 1, 0.1) channel("bite")

rslider bounds(404, 236, 60, 60) range(0, 3, 1, 1, 0.001) channel("vol")

label bounds(74, 8, 208, 27) text("Analog NOMAD")

combobox bounds(292, 10, 122, 24) populate("*.snaps")
filebutton bounds(424, 10, 65, 24) mode("snapshot") text("SNAP")

</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

giOffset[] fillarray 0,-24,-12,0,12,24
gkLastNote init 0

;instrument will be triggered by keyboard widget
instr 1
    gkLastNote init p4
    imono chnget "mono"
    
    if imono==1 && gkLastNote != 0 && gkLastNote != p4 then
        ; this is monophonic synth
        turnoff
    endif


    ; note freq and offset
    inotnum notnum
    ioffsetVal chnget "offset"
    ioffset = giOffset[ioffsetVal]
    
    kbnd pchbend 0, 100
    
    ifinal = inotnum + ioffset
    icent chnget "det"
    
    kcps = cpsmidinn(inotnum + ioffset) + kbnd
    kcpsSaw = (cpsmidinn(inotnum + ioffset - 12) + kbnd) * cent(icent)
    kcpsSub = cpsmidinn(inotnum + ioffset - 12) + kbnd 

    kVol chnget "vol"
    kfilter chnget "traveller"
    ibite chnget "bite"

    isustain chnget "hold"
    iattack chnget "attack"
    idecay chnget "decay"
    
    iquack chnget "quack"
    
    ibite chnget "bite"
    
    if isustain == 1 then
        kEnv madsr iattack, 0.0001, 1, idecay
    else
        kEnv linsegr 0, iattack, 1, idecay, 0, iattack+idecay, 0
    endif
    
    
    kSaw chnget "saw"
    kPulse chnget "pulse"
    kSub chnget "sub"
    kNoise chnget "noise"
    
    kPulseKpw chnget "pulse_kpw"
    kSawKpw chnget "saw_kpw"
    
    aSaw vco2 kSaw, kcps, 4, kSawKpw
    aPulse vco2 kPulse, kcps, 2, kPulseKpw
    aSub vco2 kSub, kcpsSub, 10, kPulseKpw
    aNoise noise kNoise, 0.5
    
    if kcpsSaw != kcps then
        aSaw2 vco2 kSaw, kcpsSaw, 4, kSawKpw 
        aSaw = (aSaw/2) + (aSaw2/2)
    endif
    
    aOsc = (aSaw + aPulse + aSub + aNoise) * kEnv
    
    if iquack==1 then
        aOutFilter moogladder2 aOsc, kfilter * kEnv, ibite
    else
        aOutFilter moogladder2 aOsc, kfilter, ibite
    endif
    
    aOut clip aOutFilter * kVol, 0, 1
    
    outs aOut, aOut
endin

</CsInstruments>
<CsScore>
;causes Csound to run for about 7000 years...
f0 z
</CsScore>
</CsoundSynthesizer>
