; Horowitz Organik - an 70s style string machine  
; 
; frequency multiplier scheme based on the code by Victor Lazzarini 
;
; (s) Severák 2020
; licensed with MIT license
<Cabbage> bounds(0, 0, 0, 0)
form caption("Horowitz Organik") size(400, 300), colour(0, 51, 153), pluginid("horg")
keyboard bounds(8, 152, 381, 101)
vslider bounds(16, 12, 28, 107) range(0.1, 1, 0.1, 1, 0.001) channel("attack")
vslider bounds(52, 12, 31, 108) range(0.1, 1, 0.1, 1, 0.001) channel("decay")
vslider bounds(104, 12, 30, 108) range(0, 0.3, 0, 1, 0.001) channel("cello")
vslider bounds(152, 10, 33, 109) range(0, 0.3, 0.3, 1, 0.001) channel("viola")
vslider bounds(198, 10, 34, 109) range(0, 1, 0, 1, 0.001) channel("violin")
vslider bounds(260, 10, 36, 109) range(2800, 22000, 22000, 1, 0.001) channel("tone")
label bounds(8, 124, 80, 16) text("crescendo")
label bounds(100, 124, 44, 16) text("cello")
label bounds(144, 124, 44, 16) text("viola")
label bounds(190, 124, 50, 16) text("violin")
label bounds(256, 124, 45, 16) text("tone")
label bounds(12, 260, 363, 32) text("Horowitz Organik")
vslider bounds(306, 10, 33, 108) range(0, 1, 0, 1, 0.001) channel("reverb")
vslider bounds(348, 10, 33, 108) range(0, 1, 0, 1, 0.001) channel("chorus")
label bounds(302, 124, 43, 16) text("rev")
label bounds(348, 124, 52, 16) text("chorus")
</Cabbage>
<CsoundSynthesizer>
<CsOptions>
-n -d -+rtmidi=NULL -M0 -m0d  --midi-key-pch=5 --midi-velocity-amp=4
</CsOptions> 
<CsInstruments>
; Initialize the global variables. 
ksmps = 32
nchnls = 2
0dbfs = 1

massign 1,2
massign 2,2
massign 3,2
massign 4,2

// phase signals
gaphs[] init 12
// lowest oct
ioct init 4
// partial arrays
iarr[] init sr/(2*cpspch(ioct+1))

// sawtooth table generation
while ioct < 12 do
// reset partial table
icnt = 0
while icnt < lenarray(iarr) do
iarr[icnt] = 0
icnt += 1
od
// fill partial table
icnt = 1
while icnt <= sr/(2*cpspch(ioct+1)) do
iarr[icnt-1] = 1/icnt
icnt += 1
od
// create bandlimited table
ifn ftgen ioct,0,16384,10,iarr
ioct += 1
od

// 12 phase signals
instr 1
inst = p4/100
gaphs[p4] = phasor:a(cpspch(inst))
if p4 < 11 then
inst += .01
schedule(1+inst,0,p3,p4+1)
endif
endin
schedule(1.,0,-1,0)

// note generator
gasig init 0
instr 2

idec chnget "decay"

kcello chnget "cello"
kviola chnget "viola"
kviolin chnget "violin"

indx = round(frac(p5)*100)
ioct = int(p5)
itab = ioct < 4 ? 4 : (ioct > 12 ? 12 : ioct)

if ioct>5 then
a1 = tablei:a(gaphs[indx]*2^(ioct-1),itab-1,1,0,1) * kcello
gasig += a1*linenr:a(.2,0,idec+0.1,.01)
endif

if ioct<12 then
a2 = tablei:a(gaphs[indx]*2^ioct,itab,1,0,1) * kviola
gasig += a2*linenr:a(.2,0,idec+0.1,.01)
endif

if ioct<11 then
a3 = tablei:a(gaphs[indx]*2^(ioct+1),itab+1,1,0,1) * kviolin
gasig += a3*linenr:a(.2,0,idec+0.1,.01)
endif

endin

// VCA
instr 3

kattack chnget "attack"
kdecay chnget "decay"

kact active 2
kgate = kact > 0 ? 1 : 0
if kgate > 0 then
kht = kattack
else
kht = kdecay
endif
kenv = portk(kgate,kht)
gasig *= kenv
endin
schedule(3,0,-1)

// chorus
instr 4

ktone chnget "tone"
kreverb chnget "reverb"
kchorus chnget "chorus"


asig zdf_2pole gasig, ktone, 0.5

aLreverb, aRreverb reverbsc asig, asig, 0.7, 10000

aL ntrpol asig, aLreverb, kreverb
aR ntrpol asig, aRreverb, kreverb


amod1 = randi:a(3,.75)+oscili(2,.35)+31
amod2 = randi:a(2,.65)+oscili(3,.55)+29
a1 = vdelay(aL*.5,amod1,35)
a2 = vdelay(aR*.5,amod2,35)

aLchorus = aL + a1
aRchorus = aR + a2 

aL ntrpol aL, aLchorus, kchorus
aR ntrpol aR, aRchorus, kchorus

out aL, aR

gasig = 0
endin
schedule(4,0,-1)
</CsInstruments>
<CsScore>
;causes Csound to run for about 7000 years...
f0 z
</CsScore>
</CsoundSynthesizer>
