:set -XOverloadedStrings
:set prompt ""

import Sound.Tidal.Context
import System.IO (hSetEncoding, stdout, utf8)

hSetEncoding stdout utf8

-- Metadata & Visualization OSC setup
:{
-- Target for visualizer metadata OSC messages
metadataTarget = Target { oName = "ParVaguesViz", 
                          oAddress = "127.0.0.1", 
                          oPort = 57120, 
                          oBusPort = Nothing,
                          oLatency = 0.1, 
                          oWindow = Nothing, 
                          oSchedule = Live,
                          oHandshake = False }

-- DPV visualization target
targetdpv = Target {oName = "didacticpatternvisualizer",
                   oAddress = "127.0.0.1",
                   oPort = 1818,
                   oLatency = 0.2,
                   oWindow = Nothing,
                   oSchedule = Live,
                   oBusPort = Nothing,
                   oHandshake = False
                  }
formatsdpv = [OSC "/delivery" Named {requiredArgs = []} ]

-- SuperDirt target
superdirtTarget' = superdirtTarget {oLatency = 0.1, oAddress = "127.0.0.1", oPort = 57120}

-- Set up targets for both SuperDirt, DPV, and metadata
oscmapdpv = [(targetdpv, formatsdpv),
            (superdirtTarget', [superdirtShape]),
            (metadataTarget, [])
            ]
:}

-- Initialize TidalCycles with all targets
tidal <- startStream defaultConfig {cFrameTimespan = 1/20} oscmapdpv

:{
-- Simpler metadata system using parameters that get sent through normal patterns
let trackName = pS "trackName"    -- Custom parameter for track name
    trackType = pS "trackType"    -- Custom parameter for track type
    trackSubtype = pS "trackSubtype"  -- For variants like bass2, fx2, etc.
    
    -- Simple shorthands - add these to ANY pattern
    labelKick n = (# trackName n) . (# trackType "kick")
    labelSnare n = (# trackName n) . (# trackType "snare")
    labelHihat n = (# trackName n) . (# trackType "hihat")
    labelBreak n = (# trackName n) . (# trackType "breaks")
    
    -- ParVagues specific shorthands
    labelBass n = (# trackName n) . (# trackType "bass")
    labelBass2 n = (# trackName n) . (# trackType "bass") . (# trackSubtype "bass2")
    labelMelody n = (# trackName n) . (# trackType "melodic")
    labelMelody2 n = (# trackName n) . (# trackType "melodic") . (# trackSubtype "melody2")
    labelFX n = (# trackName n) . (# trackType "fx")
    labelFX2 n = (# trackName n) . (# trackType "fx") . (# trackSubtype "fx2")
    labelFX3 n = (# trackName n) . (# trackType "fx") . (# trackSubtype "fx3")
    labelVocal n = (# trackName n) . (# trackType "vocals")
    labelVocal2 n = (# trackName n) . (# trackType "vocals") . (# trackSubtype "vocal2")
:}

:{
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 -- DPV specific parameters
    grid = pS "grid"
    connectionN = pI "connectionN"
    connectionMax = pI "connectionMax"
    speedSequenser = pF "speedSequenser"
    clear = pI "clear"
    sizeMin = pF "sizeMin"
    sizeMax = pF "sizeMax"
    figure = pS "figure"
    color = pS "color"
    -- Other parameters
    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"))
:}

-- FIXME: STALE EXAMPLES
-- :{
-- -- Example metadata setup for common tracks
-- -- Run these at the start of your session
-- setupMetadata = do
--   labelKick 0 "Kick"            -- d1: Kick
--   labelSnare 1 "Snare"          -- d2: Snare
--   labelHihat 2 "Drums"          -- d3: Drums
--   labelBass 3 "Bass"            -- d4: Bass
--   labelMelody 4 "Synth"         -- d5: Synth
--   labelFX 5 "FX"                -- d6: FX
--   labelVocal 8 "Vocals"         -- d9: Vocals
--   labelBreak 7 "Breakbeats"     -- d8: Breaks
-- 
-- -- For BLUE GOLD tracks
-- setupBlueGold = do
--   labelKick 0 "Kick"
--   labelSnare 1 "Snare" 
--   labelHihat 2 "Hihats"
--   labelBass 3 "Bass"
--   labelMelody 4 "Suns Keys"
--   labelFX2 5 "Guitars 1"
--   labelFX3 6 "Guitars 2"
--   labelBreak 7 "Breakbeats"
--   labelVocal 8 "Father Voice"
--   labelFX 9 "Cues & Noise"
-- :}

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