tidal-1.10.1: src/Sound/Tidal/Stream/UI.hs
{-# LANGUAGE BangPatterns #-}
{-# LANGUAGE ScopedTypeVariables #-}
module Sound.Tidal.Stream.UI where
import Control.Concurrent.MVar
import qualified Control.Exception as E
import qualified Data.Map as Map
import qualified Sound.Tidal.Clock as Clock
import Sound.Tidal.Config
import Sound.Tidal.ID
import Sound.Tidal.Pattern
import Sound.Tidal.Stream.Process
import Sound.Tidal.Stream.Types
import System.IO (hPutStrLn, stderr)
import System.Random (getStdRandom, randomR)
streamNudgeAll :: Stream -> Double -> IO ()
streamNudgeAll s = Clock.setNudge (sClockRef s)
streamResetCycles :: Stream -> IO ()
streamResetCycles s = streamSetCycle s 0
streamSetCycle :: Stream -> Time -> IO ()
streamSetCycle s = Clock.setClock (sClockRef s)
streamSetCPS :: Stream -> Time -> IO ()
streamSetCPS s = Clock.setCPS (toClockConfig $ sConfig s) (sClockRef s)
streamSetBPM :: Stream -> Time -> IO ()
streamSetBPM s = Clock.setBPM (sClockRef s)
streamGetCPS :: Stream -> IO Time
streamGetCPS s = Clock.getCPS (toClockConfig $ sConfig s) (sClockRef s)
-- Deprecated - compat with old style BootTidal.hs
streamGetcps :: Stream -> IO Time
streamGetcps = streamGetCPS
streamGetBPM :: Stream -> IO Time
streamGetBPM s = Clock.getBPM (sClockRef s)
streamGetNow :: Stream -> IO Time
streamGetNow s = Clock.getCycleTime (toClockConfig $ sConfig s) (sClockRef s)
-- Deprecated - compat with old style BootTidal.hs
streamGetnow :: Stream -> IO Time
streamGetnow = streamGetNow
streamEnableLink :: Stream -> IO ()
streamEnableLink s = Clock.enableLink (sClockRef s)
streamDisableLink :: Stream -> IO ()
streamDisableLink s = Clock.disableLink (sClockRef s)
streamList :: Stream -> IO ()
streamList s = do
pMap <- readMVar (sPMapMV s)
let hs = hasSolo pMap
putStrLn $ concatMap (showKV hs) $ Map.toList pMap
where
showKV :: Bool -> (PatId, PlayState) -> String
showKV True (k, (PlayState {psSolo = True})) = k ++ " - solo\n"
showKV True (k, _) = "(" ++ k ++ ")\n"
showKV False (k, (PlayState {psSolo = False})) = k ++ "\n"
showKV False (k, _) = "(" ++ k ++ ") - muted\n"
-- Evaluation of pat is forced so exceptions are picked up here, before replacing the existing pattern.
streamReplace :: Stream -> ID -> ControlPattern -> IO ()
streamReplace stream k !pat = do
t <- Clock.getCycleTime (toClockConfig $ sConfig stream) (sClockRef stream)
updatePattern stream k t pat
-- streamFirst but with random cycle instead of always first cicle
streamOnce :: Stream -> ControlPattern -> IO ()
streamOnce st p = do
i <- getStdRandom $ randomR (0, 8192)
streamFirst st $ rotL (toRational (i :: Int)) p
streamFirst :: Stream -> ControlPattern -> IO ()
streamFirst stream pat = onSingleTick (toClockConfig $ sConfig stream) (sClockRef stream) (sStateMV stream) (sPMapMV stream) (sGlobalFMV stream) (sCxs stream) pat
streamMute :: Stream -> ID -> IO ()
streamMute s k = withPatIds s [k] (\x -> x {psMute = True})
streamMutes :: Stream -> [ID] -> IO ()
streamMutes s ks = withPatIds s ks (\x -> x {psMute = True})
streamUnmute :: Stream -> ID -> IO ()
streamUnmute s k = withPatIds s [k] (\x -> x {psMute = False})
streamSolo :: Stream -> ID -> IO ()
streamSolo s k = withPatIds s [k] (\x -> x {psSolo = True})
streamUnsolo :: Stream -> ID -> IO ()
streamUnsolo s k = withPatIds s [k] (\x -> x {psSolo = False})
withPatIds :: Stream -> [ID] -> (PlayState -> PlayState) -> IO ()
withPatIds s ks f =
do
playMap <- takeMVar $ sPMapMV s
let pMap' = foldr (Map.update (\x -> Just $ f x)) playMap (map fromID ks)
putMVar (sPMapMV s) pMap'
return ()
-- TODO - is there a race condition here?
streamMuteAll :: Stream -> IO ()
streamMuteAll s = modifyMVar_ (sPMapMV s) $ return . fmap (\x -> x {psMute = True})
streamHush :: Stream -> IO ()
streamHush s = modifyMVar_ (sPMapMV s) $ return . fmap (\x -> x {psPattern = silence, psHistory = silence : psHistory x})
streamUnmuteAll :: Stream -> IO ()
streamUnmuteAll s = modifyMVar_ (sPMapMV s) $ return . fmap (\x -> x {psMute = False})
streamUnsoloAll :: Stream -> IO ()
streamUnsoloAll s = modifyMVar_ (sPMapMV s) $ return . fmap (\x -> x {psSolo = False})
streamSilence :: Stream -> ID -> IO ()
streamSilence s k = withPatIds s [k] (\x -> x {psPattern = silence, psHistory = silence : psHistory x})
streamAll :: Stream -> (ControlPattern -> ControlPattern) -> IO ()
streamAll s f = do
_ <- swapMVar (sGlobalFMV s) f
return ()
streamGet :: Stream -> String -> IO (Maybe Value)
streamGet s k = Map.lookup k <$> readMVar (sStateMV s)
streamSet :: (Valuable a) => Stream -> String -> Pattern a -> IO ()
streamSet s k pat = do
sMap <- takeMVar $ sStateMV s
let pat' = toValue <$> pat
sMap' = Map.insert k (VPattern pat') sMap
putMVar (sStateMV s) $ sMap'
streamSetI :: Stream -> String -> Pattern Int -> IO ()
streamSetI = streamSet
streamSetF :: Stream -> String -> Pattern Double -> IO ()
streamSetF = streamSet
streamSetS :: Stream -> String -> Pattern String -> IO ()
streamSetS = streamSet
streamSetB :: Stream -> String -> Pattern Bool -> IO ()
streamSetB = streamSet
streamSetR :: Stream -> String -> Pattern Rational -> IO ()
streamSetR = streamSet