{-# LANGUAGE BangPatterns #-}
module Sound.Tidal.Transition where
import Prelude hiding ((<*), (*>))
import Control.Concurrent.MVar (readMVar, takeMVar, putMVar)
import qualified Sound.OSC.FD as O
import qualified Data.Map.Strict as Map
import Sound.Tidal.Control
import Sound.Tidal.Core
import Sound.Tidal.Params (gain, pan)
import Sound.Tidal.Pattern
import Sound.Tidal.Stream
import Sound.Tidal.Tempo (timeToCycles)
import Sound.Tidal.UI (fadeOutFrom, fadeInFrom)
import Sound.Tidal.Utils (enumerate)
transition :: Show a => Stream -> (Time -> [ControlPattern] -> ControlPattern) -> a -> ControlPattern -> IO ()
transition stream f patId !pat = do pMap <- takeMVar (sPMapMV stream)
let playState = updatePS $ Map.lookup (show patId) pMap
pat' <- transition' $ history playState
let pMap' =
Map.insert (show patId) (playState {pattern = pat'}) pMap
putMVar (sPMapMV stream) pMap'
calcOutput stream
return ()
where
updatePS (Just playState) = playState {history = pat:(history playState)}
updatePS Nothing = PlayState {pattern = silence,
mute = False,
solo = False,
history = pat:silence:[]
}
transition' context = do tempo <- readMVar $ sTempoMV stream
now <- O.time
let c = timeToCycles tempo now
return $ f c context
wash :: (Pattern a -> Pattern a) -> (Pattern a -> Pattern a) -> Time -> Time -> Time -> Time -> [Pattern a] -> Pattern a
wash _ _ _ _ _ _ [] = silence
wash _ _ _ _ _ _ (pat:[]) = pat
wash fout fin delay durin durout now (pat:pat':_) =
stack [(filterWhen (< (now + delay)) pat'),
(filterWhen (between (now + delay) (now + delay + durin)) $ fout pat'),
(filterWhen (between (now + delay + durin) (now + delay + durin + durout)) $ fin pat),
(filterWhen (>= (now + delay + durin + durout)) $ pat)
]
where
between lo hi x = (x >= lo) && (x < hi)
washIn :: (Pattern a -> Pattern a) -> Time -> Time -> [Pattern a] -> Pattern a
washIn f durin now pats = wash f id 0 durin 0 now pats
xfadeIn :: Time -> Time -> [ControlPattern] -> ControlPattern
xfadeIn _ _ [] = silence
xfadeIn _ _ (pat:[]) = pat
xfadeIn t now (pat:pat':_) = overlay (pat |*| gain (now `rotR` (_slow t envEqR))) (pat' |*| gain (now `rotR` (_slow t (envEq))))
histpan :: Int -> Time -> [ControlPattern] -> ControlPattern
histpan _ _ [] = silence
histpan 0 _ _ = silence
histpan n _ ps = stack $ map (\(i,pat) -> pat # pan (pure $ (fromIntegral i) / (fromIntegral n'))) (enumerate ps')
where ps' = take n ps
n' = length ps'
wait :: Time -> Time -> [ControlPattern] -> ControlPattern
wait _ _ [] = silence
wait t now (pat:_) = filterWhen (>= (nextSam (now+t-1))) pat
waitT :: (Time -> [ControlPattern] -> ControlPattern) -> Time -> Time -> [ControlPattern] -> ControlPattern
waitT _ _ _ [] = silence
waitT f t now pats = filterWhen (>= (nextSam (now+t-1))) (f (now + t) pats)
jump :: Time -> [ControlPattern] -> ControlPattern
jump = jumpIn 0
jumpIn :: Int -> Time -> [ControlPattern] -> ControlPattern
jumpIn n = wash id id (fromIntegral n) 0 0
jumpIn' :: Int -> Time -> [ControlPattern] -> ControlPattern
jumpIn' n now = wash id id ((nextSam now) - now + (fromIntegral n)) 0 0 now
jumpMod :: Int -> Time -> [ControlPattern] -> ControlPattern
jumpMod n now = jumpIn ((n-1) - ((floor now) `mod` n)) now
mortal :: Time -> Time -> Time -> [ControlPattern] -> ControlPattern
mortal _ _ _ [] = silence
mortal lifespan release now (p:_) = overlay (filterWhen (<(now+lifespan)) p) (filterWhen (>= (now+lifespan)) (fadeOutFrom (now + lifespan) release p))
interpolate :: Time -> [ControlPattern] -> ControlPattern
interpolate = interpolateIn 4
interpolateIn :: Time -> Time -> [ControlPattern] -> ControlPattern
interpolateIn _ _ [] = silence
interpolateIn _ _ (p:[]) = p
interpolateIn t now (pat:pat':_) = f <$> pat' *> pat <* automation
where automation = now `rotR` (_slow t envL)
f = (\a b x -> Map.unionWith (fNum2 (\a' b' -> floor $ (fromIntegral a') * x + (fromIntegral b') * (1-x))
(\a' b' -> a' * x + b' * (1-x))
)
b a
)
clutch :: Time -> [Pattern a] -> Pattern a
clutch = clutchIn 2
clutchIn :: Time -> Time -> [Pattern a] -> Pattern a
clutchIn _ _ [] = silence
clutchIn _ _ (p:[]) = p
clutchIn t now (p:p':_) = overlay (fadeOutFrom now t p') (fadeInFrom now t p)
anticipateIn :: Time -> Time -> [ControlPattern] -> ControlPattern
anticipateIn t now pats = washIn (innerJoin . (\pat -> (\v -> _stut 8 0.2 v pat) <$> (now `rotR` (_slow t $ toRational <$> envLR)))) t now pats
anticipate :: Time -> [ControlPattern] -> ControlPattern
anticipate = anticipateIn 8