packages feed

zwirn-0.2.3.1: src/zwirn-stream/Zwirn/Stream/UI.hs

module Zwirn.Stream.UI where

import Control.Concurrent.MVar (modifyMVar_, newMVar)
import qualified Data.Map as Map
import Data.Text (pack)
import qualified Data.Text as T
import qualified Sound.Osc.Transport.Fd.Udp as O
import Sound.Tidal.Clock
import qualified Sound.Tidal.Clock as Clock
import Zwirn.Core.Lib.Core (zipApply)
import Zwirn.Core.Lib.Modulate (shift, slow)
import Zwirn.Core.Lib.Number (firstCyclesThen)
import qualified Zwirn.Core.Time as Zwirn
import Zwirn.Language.Evaluate.Expression
import Zwirn.Language.Play (Identifier (..), PlayState (..), TargetName, Targeted (..))
import Zwirn.Stream.Process
import Zwirn.Stream.Target
import Zwirn.Stream.Types

streamDefaultBPM :: Double
streamDefaultBPM = 138

streamSet :: Stream -> T.Text -> Expression -> IO ()
streamSet str x ex = modifyMVar_ (sState str) (return . Map.insert x ex)

streamSetCPS :: Stream -> Time -> IO ()
streamSetCPS str c = streamSetBPM str (c * toRational (clockBeatsPerCycle (streamConfigClock $ sConfig str) * 60))

-- | set the bpm in the clock
streamSetBPM :: Stream -> Time -> IO ()
streamSetBPM s = Clock.setBPM (sClockRef s)

streamGetBPM :: Stream -> IO Double
streamGetBPM str = realToFrac <$> Clock.getBPM (sClockRef str)

streamResetCycles :: Stream -> IO ()
streamResetCycles s = streamSetCycle s 0

streamSetCycle :: Stream -> Time -> IO ()
streamSetCycle s = Clock.setClock (sClockRef s)

streamEnableLink :: Stream -> IO ()
streamEnableLink s = Clock.enableLink (sClockRef s)

streamDisableLink :: Stream -> IO ()
streamDisableLink s = Clock.disableLink (sClockRef s)

streamGetNow :: Stream -> IO Time
streamGetNow s = Clock.getCycleTime (streamConfigClock $ sConfig s) (sClockRef s)

streamFirst :: Stream -> Zwirn Expression -> IO ()
streamFirst str = streamFirstTarget str (sDefaultTarget str)

streamFirstTarget :: Stream -> TargetName -> Zwirn Expression -> IO ()
streamFirstTarget str targ z = do
  dummy <- newMVar $ Map.singleton (TextID $ pack "_streamOnceDummy_") (Targeted [targ] (Normal, z, Nothing))
  Clock.clockOnce (tickActionOnce dummy (sState str) (sTargetMap str) (sLocal str) (streamConfigPrecision $ sConfig str)) (streamConfigClock $ sConfig str) (sClockRef str)

startStream :: StreamConfig -> IO Stream
startStream config = do
  let targetConfigs = streamConfigTargets config
      conf = (streamConfigClock config) {clockFrameTimespan = 10 * realToFrac (streamConfigPrecision config)}
  targetMap <- getTargetMap targetConfigs
  local <- O.udp_server (streamConfigLocalPort config)

  zMV <- newMVar Map.empty
  stMV <- newMVar Map.empty
  busMapMV <- newMVar Map.empty
  actionMapMV <- newMVar Map.empty
  bussesMV <- newMVar []

  cref <- clocked conf (tickAction zMV actionMapMV busMapMV stMV bussesMV targetMap local (streamConfigPrecision config))
  let str = Stream zMV actionMapMV busMapMV stMV bussesMV targetMap "superdirt" local cref config

  -- set the default bpm
  streamSetBPM str (realToFrac streamDefaultBPM)
  return str

transition :: Stream -> Identifier -> (Zwirn Double -> Zwirn (Zwirn Expression -> Zwirn Expression)) -> IO ()
transition str key mapper = do
  now <- realToFrac <$> streamGetNow str
  modifyMVar_ (sPlayMap str) (return . Map.update (\(Targeted ts (ps, ex, fx)) -> Just $ Targeted ts (ps, mapper (pure now) `zipApply` ex, fx)) key)

transition' :: Stream -> Identifier -> Zwirn Zwirn.Time -> Zwirn Expression -> Zwirn Expression -> Zwirn (Zwirn Expression -> Zwirn (Zwirn Expression -> Zwirn Expression)) -> IO ()
transition' str key dur def sig mapper = do
  now <- realToFrac <$> streamGetNow str
  let shifted = shift (pure now) $ firstCyclesThen dur def (slow dur sig)
  modifyMVar_ (sPlayMap str) (return . Map.update (\(Targeted ts (ps, ex, fx)) -> Just $ Targeted ts (ps, mapper `zipApply` ex `zipApply` shifted, fx)) key)