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)