:set -XOverloadedStrings
:set prompt ""

import Sound.Tidal.Context

import System.IO (hSetEncoding, stdout, utf8)

hSetEncoding stdout utf8

-- OSCTarget for pattern visualizing.
patternTarget = OSCTarget { oName = "Pattern handler", oAddress = "127.0.0.1", oPort = 5050, oPath = "/trigger/something", oShape = Nothing, oLatency = 0.02, oPreamble = [], oTimestamp = BundleStamp }

-- OSCTarget for play music via SuperCollider.
musicTarget = superdirtTarget { oLatency = 0.2, oAddress = "127.0.0.1", oPort = 57120 }

-- total latency = oLatency + cFrameTimespan
config = defaultConfig {cFrameTimespan = 1/20}

-- Send pattern as osc both to SC and to tidal-vis
-- tidal <- startMulti [musicTarget, patternTarget] config
-- OR
-- Send pattern as osc to SC only
tidal <- startTidal musicTarget config

:{
let p = streamReplace tidal
    hush = streamHush tidal
    list = streamList tidal
    mute = streamMute tidal
    unmute = streamUnmute tidal
    solo = streamSolo tidal
    unsolo = streamUnsolo tidal
    once = streamOnce tidal
    first = streamFirst tidal
    asap = once
    nudgeAll = streamNudgeAll tidal
    all = streamAll tidal
    resetCycles = streamResetCycles tidal
    setcps = asap . cps
    xfade i = transition tidal True (Sound.Tidal.Transition.xfadeIn 4) i
    xfadeIn i t = transition tidal True (Sound.Tidal.Transition.xfadeIn t) i
    histpan i t = transition tidal True (Sound.Tidal.Transition.histpan t) i
    wait i t = transition tidal True (Sound.Tidal.Transition.wait t) i
    waitT i f t = transition tidal True (Sound.Tidal.Transition.waitT f t) i
    jump i = transition tidal True (Sound.Tidal.Transition.jump) i
    jumpIn i t = transition tidal True (Sound.Tidal.Transition.jumpIn t) i
    jumpIn' i t = transition tidal True (Sound.Tidal.Transition.jumpIn' t) i
    jumpMod i t = transition tidal True (Sound.Tidal.Transition.jumpMod t) i
    mortal i lifespan release = transition tidal True (Sound.Tidal.Transition.mortal lifespan release) i
    interpolate i = transition tidal True (Sound.Tidal.Transition.interpolate) i
    interpolateIn i t = transition tidal True (Sound.Tidal.Transition.interpolateIn t) i
    clutch i = transition tidal True (Sound.Tidal.Transition.clutch) i
    clutchIn i t = transition tidal True (Sound.Tidal.Transition.clutchIn t) i
    anticipate i = transition tidal True (Sound.Tidal.Transition.anticipate) i
    anticipateIn i t = transition tidal True (Sound.Tidal.Transition.anticipateIn t) i
    forId i t = transition tidal False (Sound.Tidal.Transition.mortalOverlay t) i
    d1 = p 1 . (|< orbit 0)
    d2 = p 2 . (|< orbit 1)
    d3 = p 3 . (|< orbit 2)
    d4 = p 4 . (|< orbit 3)
    d5 = p 5 . (|< orbit 4)
    d6 = p 6 . (|< orbit 5)
    d7 = p 7 . (|< orbit 6)
    d8 = p 8 . (|< orbit 7)
    d9 = p 9 . (|< orbit 8)
    d10 = p 10 . (|< orbit 9)
    d11 = p 11 . (|< orbit 10)
    d12 = p 12 . (|< orbit 11)
    d13 = p 13
    d14 = p 14
    d15 = p 15
    d16 = p 16
:}

:{
let setI = streamSetI tidal
    setF = streamSetF tidal
    setS = streamSetS tidal
    setR = streamSetR tidal
    setB = streamSetB tidal
:}

:{
let modIndex = pF "modIndex"
    mix =       pF "mix"
    vibrato =   pF "vibrato"
    chorus = pF "chorus"
    lagamount = pF "lagamount"
    dec = pF "dec"
    sus = pF "sus"
    cutoff = pF "cutoff"
    drumMachine name ps = stack
                    (map (\ x ->
                        (# s (name ++| (extractS "s" (x)))) $ x
                        ) ps)
    drumFrom name drum = s (name ++| drum)
    drumM = drumMachine
    drumF = drumFrom
    -- Midi boolean buttons
    -- midiOn
    midiOn    ch    pat = someCyclesBy ch             pat
    midiOff   ch    pat = someCyclesBy (1 - ch)       pat
    midiNo    c1 c2 pat = someCyclesBy (1 - c1 - c2)  pat
    midiBoth  c1 c2 pat = someCyclesBy (c1 + c2 - 1)  pat
    -- Parameterized DJF
    _LPF lMin lMax ch = (# lpf (min lMax ((range lMin ((lMax*2) - lMin) ch))))
    _HPF hMin hMax ch = (# hpf (max hMin (min hMax (range (hMin - hMax) (hMax - hMin) ch))))
    midiDJF   ch lMin lMax hMin hMax = (_LPF lMin lMax ch) . (_HPF hMin hMax ch)
    -- FIXME: Seems to cut some lows when lMin != 0
    -- Midi gain control (faders)
    midiGGlobal = "^77" * 1.3
    _gainG ch     = (gain (midiGGlobal * ch)) -- gain Global
    midiG' ch l h = _gainG (range l h ch)     -- midiGain   control
    midiGdef      = midiG' 1 0 1             -- midiGain   default
    midiG  ch     = midiG' ch 0 1             -- midiGain   default
    -- Global filters
    gF1 = (# djfbus 1 (range 0.05 0.95 "^49"))
    gF2 = (# djfbus 2 (range 0.05 0.95 "^50"))
    gF3 = (# djfbus 3 (range 0.05 0.95 "^51"))
:}

:set prompt "tidal> "
-- :set prompt-cont ""
