-- # superfm
-- > 6-op FM synth (DX7-like). Works a bit different from the original DX7. Instead of algorithms, you set the amount of modulation every operator receives from other operators and itself (feedback), virtually providing an endless number of possible combinations (algorithms).
--    voice is the preset number: 0 is user-defined; 1-5 are randomly generated presets
--  lfofreq is the overall pitch modulation frequency
--  lfodepth is the overall pitch modulation amplitude

-- Each operator responds to
--
--   amp (operator volume - becomes carrier)
--   ratio (frequency ratio)
--   detune (in Hz)
--   eglevel (1-4) (4 envelope generator levels)
--   egrate (1-4) (4 envelope generator rates)
--
-- The syntax for operator arguments is <argumentName + opIndex>[modulatorIndex | egIndex]. For example:
--
--     amp1 1 (op1 as carrier with full volume)
--     ratio2 2.3 (op2 frequency ratio)
--     mod11 0.5 (op1 feedback)
--     mod12 0.78 (op1 modulation amount by op2)
--     detune1 0.2 (op1 detune)
--     eglevel12 0.1 (op1 EG level2)
--     egrate11 0.01 (op1 EG rate1) – WARNING: higher values go FASTER!


-- region paul1 functions
do
-- sets the amount of operator 'op' in the superfm output mix
-- (1 <= op <= 6)
-- fmamp :: Int -> Pattern Double -> ControlPattern
let fmamp op = pF ("amp" ++ show op)
-- sets the ratio for operator 'op'.
-- the frequency is note * ratio + detune Hz
-- (1 <= op <= 6)
-- fmratio :: Int -> Pattern Double -> ControlPattern
let fmratio op = pF ("ratio" ++ show op)
-- set the detune for operator 'op'
-- fmdetune :: Int -> Pattern Double -> ControlPattern
let fmdetune op = pF ("detune" ++ show op)
-- set the modulation of oerator opa by operator opb
-- if opa == opb, then the modulation amount is multiplied by the
-- 'feedback' parameter
-- fmmod :: Int -> Int -> Pattern Double -> ControlPattern
let fmmod opa opb = pF ("mod" ++ show opa ++ show opb)
-- feedback
-- fmfeedback :: Pattern Double -> ControlPattern
let fmfeedback = pF "feedback"
-- Envelope definition: each operator has an envelop with 4 steps
-- fmeglevel :: Int -> Int -> Pattern Double -> ControlPattern
let fmeglevel op step = pF ("eglevel" ++ show op ++ show step)
-- Envelope definition: sets the rate at which the envelope moves
-- between steps.  Low numbers are slow, high numbers are fast.
-- fmegrate :: Int -> Int -> Pattern Double -> ControlPattern
let fmegrate op step = pF ("egrate" ++ show op ++ show step)
let fmparam function (x:xs) = foldr (#) (function 1 x) (zipWith function [2..] xs)
let fmamps = fmparam fmamp
let fmratios = fmparam fmratio
let fmdetunes = fmparam fmdetune
let envrate op = fmparam (fmegrate op)
let envlevel op = fmparam (fmeglevel op)
d1
    $ stut 2 0.7 0.125
    $ slow 3 $ s "superfm"
    |+| note (arp "pinkyup" "[0,4,7,12] [0,5,7,9]" )
    # fmfeedback 1
    -- # fmamps    [1, 1, 1, 0, 0, 0]
    # fmratios  [1, (range 0 4 (slow 4 sine)), 0.26, 0.5, 0.5, 0.5]
    -- # fmdetunes [0, 1, 0, 0, 0, 0]
    # fmmod 1 1 "<0 1.25>"
    # fmmod 1 2 (range 0 4 (slow 4 sine))
    # fmmod 1 3 (range 0 4 (slow 3 saw))
    # fmmod 3 2 (range 0 3 (slow 2 sine))
    # envlevel 1 [1, 0.5, 0, 0, 0, 0]
    # envrate  1 [10, 0.1, 0.1, 1, 0, 0]
    # envlevel 2 [1, 0, 0, 0, 0, 0]
    # envrate  2 [1, 0.3, 0.7, 1, 0, 0]
    # envlevel 3 [1, 0.2, 0, 1, 0, 0]
    # envrate  3 [10, 0.5, 0.4, 1, 0, 0]
    # lpf 1000
    # room 0.3



d1 $ stut 2 0.7 0.125 $ slow 3 $ s "superfm"
  |+| note (arp "pinkyup" "[0,4,7,12] [0,5,7,9]" )
  # fmfeedback 1    -- global multiplier for 'fmod x x' feedback parameters.
  # fmamp 1 0      -- amplitudes default to '1', so probably need to set all 6 of them...
  # fmamp 2 0
  # fmamp 3 1
  # fmamp 4 0
  # fmamp 5 0
  # fmamp 6 0
  # fmratio 1 1 -- oscillator frequency is note * ratio + detune Hz.
  # fmratio 2 0.5 -- (range 0.25 20 (slow 3 $ sine))
  # fmdetune 2 1
  # fmratio 3 0.26
  # fmmod 1 1 "0"
  # fmmod 1 2  (range 0 4 (slow 4 $ sine))   -- fmod a b Pattern  = modulate op a with op b..
  # fmmod 1 3  (range 0 4 (slow 3 $ sine))
  # fmmod 3 2  (range 0 3 (slow 2 $ sine))
  # fmeglevel 1 1 "1" -- envelope generator has 4 rates and 4 steps for each operator...
  # fmeglevel 1 2 "0.5"
  # fmeglevel 1 3 "0"
  # fmeglevel 1 4 "0"
  # fmegrate 1 1 "10"
  # fmegrate 1 2 "0.1"
  # fmegrate 1 3 "0.1"
  # fmegrate 1 4 "1"
  # fmeglevel 2 1 "1" -- envelope generator has 4 rates and 4 steps for each operator...
  # fmeglevel 2 2 "0"
  # fmeglevel 2 3 "0"
  # fmeglevel 2 4 "0"
  # fmegrate 2 1 "1"
  # fmegrate 2 2 "0.3"
  # fmegrate 2 3 "0.7"
  # fmegrate 2 4 "1"
  # fmeglevel 3 1 "1" -- envelope generator has 4 rates and 4 steps for each operator...
  # fmeglevel 3 2 "0.2"
  # fmeglevel 3 3 "0"
  # fmeglevel 3 4 "1"
  # fmegrate 3 1 "10"
  # fmegrate 3 2 "0.5"
  # fmegrate 3 3 "0.4"
  # fmegrate 3 4 "1"
  # room 0.3
  -- # gain 0.7
-- endregion


-- region manual definitions à la Yaxu
do-- modulators
let mod11 = pF "mod11"
let mod12 = pF "mod12"
let mod13 = pF "mod13"
let mod14 = pF "mod14"
let mod15 = pF "mod15"
let mod16 = pF "mod16"
let mod21 = pF "mod21"
let mod22 = pF "mod22"
let mod23 = pF "mod23"
let mod24 = pF "mod24"
let mod25 = pF "mod25"
let mod26 = pF "mod26"
let mod31 = pF "mod31"
let mod32 = pF "mod32"
let mod33 = pF "mod33"
let mod34 = pF "mod34"
let mod35 = pF "mod35"
let mod36 = pF "mod36"
let mod41 = pF "mod41"
let mod42 = pF "mod42"
let mod43 = pF "mod43"
let mod44 = pF "mod44"
let mod45 = pF "mod45"
let mod46 = pF "mod46"
let mod51 = pF "mod51"
let mod52 = pF "mod52"
let mod53 = pF "mod53"
let mod54 = pF "mod54"
let mod55 = pF "mod55"
let mod56 = pF "mod56"
let mod61 = pF "mod61"
let mod62 = pF "mod62"
let mod63 = pF "mod63"
let mod64 = pF "mod64"
let mod65 = pF "mod65"
let mod66 = pF "mod66"
-- operator envelope generator levels
let eglevel11 = pF "eglevel11"
let eglevel12 = pF "eglevel12"
let eglevel13 = pF "eglevel13"
let eglevel14 = pF "eglevel14"
let eglevel21 = pF "eglevel21"
let eglevel22 = pF "eglevel22"
let eglevel23 = pF "eglevel23"
let eglevel24 = pF "eglevel24"
let eglevel31 = pF "eglevel31"
let eglevel32 = pF "eglevel32"
let eglevel33 = pF "eglevel33"
let eglevel34 = pF "eglevel34"
let eglevel41 = pF "eglevel41"
let eglevel42 = pF "eglevel42"
let eglevel43 = pF "eglevel43"
let eglevel44 = pF "eglevel44"
let eglevel51 = pF "eglevel51"
let eglevel52 = pF "eglevel52"
let eglevel53 = pF "eglevel53"
let eglevel54 = pF "eglevel54"
let eglevel61 = pF "eglevel61"
let eglevel62 = pF "eglevel62"
let eglevel63 = pF "eglevel63"
let eglevel64 = pF "eglevel64"
-- operator envelope generator rates
let egrate11 = pF "egrate11"
let egrate12 = pF "egrate12"
let egrate13 = pF "egrate13"
let egrate14 = pF "egrate14"
let egrate21 = pF "egrate21"
let egrate22 = pF "egrate22"
let egrate23 = pF "egrate23"
let egrate24 = pF "egrate24"
let egrate31 = pF "egrate31"
let egrate32 = pF "egrate32"
let egrate33 = pF "egrate33"
let egrate34 = pF "egrate34"
let egrate41 = pF "egrate41"
let egrate42 = pF "egrate42"
let egrate43 = pF "egrate43"
let egrate44 = pF "egrate44"
let egrate51 = pF "egrate51"
let egrate52 = pF "egrate52"
let egrate53 = pF "egrate53"
let egrate54 = pF "egrate54"
let egrate61 = pF "egrate61"
let egrate62 = pF "egrate62"
let egrate63 = pF "egrate63"
let egrate64 = pF "egrate64"
-- operator output levels
let amp1 = pF "amp1"
let amp2 = pF "amp2"
let amp3 = pF "amp3"
let amp4 = pF "amp4"
let amp5 = pF "amp5"
let amp6 = pF "amp6"
-- operator frequency ratios
let ratio1 = pF "ratio1"
let ratio2 = pF "ratio2"
let ratio3 = pF "ratio3"
let ratio4 = pF "ratio4"
let ratio5 = pF "ratio5"
let ratio6 = pF "ratio6"
-- operator frequency detuners
let detune1 = pF "detune1"
let detune2 = pF "detune2"
let detune3 = pF "detune3"
let detune4 = pF "detune4"
let detune5 = pF "detune5"
let detune6 = pF "detune6"
-- other
let feedback = pF "feedback"
let lfofreq = pF "lfofreq"
let lfodepth = pF "lfodepth"
d1
  -- $ ply "3 4"
  -- $ ply 2
  -- $ superimpose (# octave 3)
  $ slow 2
  $ up (arpeggiate "<a4'min7 e5'min7>")
  # "superfm"
  # gain 0.65
  # amp1 1 # detune1 20
  # amp2 1 # detune2 1
  -- # room 0.5 # sz 0.5
  -- region Double Saw
  # amp1 1
  # amp2 0
  # amp3 1
  # amp4 0
  # amp5 0
  # amp6 0
  # ratio2 1.01
  # mod12 0.75
  # mod34 0.7
  # mod45 0.6
  -- endregion
  -- region Double pulse
  # amp1 1
  # amp2 0
  # amp3 1
  # amp4 0
  # amp5 0
  # amp6 0
  # ratio2 2.01
  # ratio4 2
  # ratio5 2
  # mod12 0.75
  # mod34 0.7
  # mod45 0.6
  -- endregion
  -- region FM Bass
  # amp1 1
  # amp2 1
  # amp3 0
  # amp4 0
  # amp5 0
  # amp6 1
  # ratio2 2
  # ratio3 3
  # ratio4 4
  # ratio5 0.5
  # ratio6 0.25
  # feedback 1
  # mod11 1
  # mod16 1
  # mod23 1
  # mod34 1
  # mod45 1
  # mod66 1
  # egrate61 1
  # egrate62 10
  # egrate63 1
  # eglevel62 0.13
  # eglevel63 1.5
  # room 0.5
  -- endregion

--  endregion DRONEDIM
