module Sound.Hommage.Play ( -- * Play Play (..) , getDur , resetDur , randomPlay , mix , mix' -- * Interpretation of Notation for Play , notationMono , notationStereo , notation , Mixable (..) -- , MixableL -- * Parallel played and hierarchical defined tracks , Song (..) , runSong , Track (..) , playTrack , track -- , tracks -- , (-/-) -- , (-|-) -- , (-||-) , Trackable (..) -- , notationTracks -- , ToTrack (..) -- * Environment , Environment (..) , emptyEnvironment , nextEnvironment , insertEnvironment , lookupEnvironment -- , defineEnvironment -- * Duration , Duration (..) , resetDuration , initDuration ) where import Sound.Hommage.Notation import Sound.Hommage.Signal import Sound.Hommage.Seq import Sound.Hommage.Misc --import Sound.Hommage.MList import Data.Ratio import Data.Dynamic import Data.IORef import System.IO.Unsafe import System.Random ------------------------------------------------------------------------------- newtype Environment = Environment ( Int , [(Int, [Dynamic])] ) emptyEnvironment :: Environment emptyEnvironment = Environment (0, []) nextEnvironment :: Environment -> Environment nextEnvironment (Environment (c, b)) = let b' = loop b in seq b' (Environment (c, b')) where loop [] = [] loop ((n,(_:d)):xs) = let xs' = loop xs in seq d (seq xs' ((n,d):xs')) insertEnvironment :: [Dynamic] -> Environment -> (Environment -> Dynamic, Environment) insertEnvironment d (Environment (c,b)) = seq c (lookupEnvironment c, Environment (c+1, (c,d):b)) lookupEnvironment :: Int -> Environment -> Dynamic lookupEnvironment n (Environment (_,b)) = case lookup n b of Just (d:_) -> d ------------------------------------------------------------------------------- class Typeable a => Trackable a where toNext :: a -> a instance Typeable Signal where typeOf _ = mkTyConApp (mkTyCon "Signal") [] instance Trackable Signal where toNext s = case s of Mono (x:xs) -> seq x (Mono xs) Mono [] -> Mono [] Stereo (x:xs) -> seq x (Stereo xs) Stereo [] -> Stereo [] instance Typeable a => Trackable [a] where toNext (x:xs) = seq x xs toNext [] = [] instance Typeable Stereo where typeOf _ = mkTyConApp (mkTyCon "Stereo") [] ------------------------------------------------------------------------------- defineEnvironment :: Trackable a => (Environment -> a) -> Environment -> (Environment -> a, Environment) defineEnvironment f env = (\e -> case fromDynamic $ lkup e of Just a -> a, env') where iter a = seq a (toDyn a : iter (toNext a)) (lkup, env') = insertEnvironment (iter $ f env) env defineEnvironment_ :: Trackable a => a -> Environment -> (Environment -> a, Environment) defineEnvironment_ a env = (\e -> case fromDynamic $ lkup e of Just a -> a, env') where iter a = seq a (toDyn a : iter (toNext a)) (lkup, env') = insertEnvironment (iter a) env -- (a -> a) -> Environment -> Environment, ------------------------------------------------------------------------------- data Duration = DURATION { relativeDuration :: Dur , absoluteDuration :: Dur } instance IsDur Duration where durFrom = relativeDuration durUpdate f d = d { relativeDuration = f (relativeDuration d) } resetDuration :: Duration -> Duration resetDuration d = d { relativeDuration = absoluteDuration d } initDuration :: Dur -> Duration initDuration d = DURATION d d ------------------------------------------------------------------------------- newtype Play a = PLAY { unPlay :: Duration -> Environment -> a } playToWithDur :: Play a -> WithDur Duration (Environment -> a) playToWithDur (PLAY p) = WithDur p --returnPlay :: a -> Play a --returnPlay a = PLAY $ \dur env -> case env of -- Environment (0, []) -> a -- Environment _ -> a instance Monad Play where return a = PLAY $ \dur env -> a --returnPlay a PLAY g >>= f = PLAY $ \dur env -> unPlay (f $ g dur env) dur env instance Functor Play where fmap f (PLAY g) = PLAY $ \dur env -> f (g dur env) -- fmap f p = p >>= return . f instance Stretchable (Play a) where stretch d (PLAY g) = PLAY $ \duration e -> g (durUpdate (*d) duration) e getDur :: Play Dur getDur = PLAY $ \dur _ -> durFrom dur resetDur :: Play a -> Play a resetDur (PLAY g) = PLAY $ \d e -> g (resetDuration d) e randomPlay :: Random a => (a,a) -> Play a randomPlay v = PLAY $ \_ _ -> unsafePerformIO $ randomRIO v ----------------------------------------------------------- mix :: [Play Signal] -> Play Signal mix ps = sequence ps >>= return . mergeSignals mix' :: Num a => [Play [a]] -> Play [a] mix' ps = sequence ps >>= return . mergeSet sum ------------------------------------------------------------------------------- class Mixable a where mixdown :: Seq a -> a instance Num a => Mixable [a] where mixdown = mixdownNumSeq notation :: Mixable a => Notation (Play a) -> Play a notation n = PLAY $ \dur env -> mixdown $ applySeq nextEnvironment (unWithDur (runNotation (fmap (noteSeq' . playToWithDur ) n)) dur) env notationMono :: Notation (Play Signal) -> Play [Mono] notationMono n = PLAY $ \dur env -> mixdown $ applySeq nextEnvironment (unWithDur (runNotation (fmap (noteSeq' . playToWithDur . fmap signalToMono) n)) dur) env notationStereo :: Notation (Play Signal) -> Play [Stereo] notationStereo n = PLAY $ \dur env -> mixdown $ applySeq nextEnvironment (unWithDur (runNotation (fmap (noteSeq' . playToWithDur . fmap signalToStereo) n)) dur) env ------------------------------------------------------------------------------- data Song a = SONG { unSong :: Duration -> Environment -> (a, Environment) } instance Functor Song where fmap f (SONG g) = SONG $ \d e -> let (a, e') = g d e in (f a, e') instance Monad Song where return a = SONG $ \_ e -> (a,e) SONG g >>= f = SONG $ \d e -> let (a,e') = g d e in unSong (f a) d e' runSong :: Double -> Song (Play a) -> a runSong bpm (SONG ts) = let duration = initDuration $ bpmToDur bpm (PLAY p, env) = ts duration emptyEnvironment in p duration env ------------------------------------------------------------------------------- newtype Track a = TRACK { unTrack :: Environment -> a } instance Functor Track where fmap f (TRACK g) = TRACK (f . g) playTrack :: Track a -> Play a playTrack (TRACK get) = PLAY $ \d e -> get e track :: Trackable a => Play a -> Song (Track a) track (PLAY p) = SONG $ \dur env -> let (get, env') = defineEnvironment (p dur) env in seq env' (TRACK get, env') ------------------------------------------------------------------------------- {- Causes too much memory use. Reason: More than one Reference to Environment. notationTracks :: (ToFilter a l, MixableL l) => Notation (Play a) -> Song (l Track) notationTracks n = SONG $ \dur env -> let f = toFilter (undefined :: a) (l, env') = mixdownL (applySeq nextEnvironment (runNotation (fmap (noteSeq' . unPlay) n) dur) env) f env in seq env' (l, env') aux1 :: (ToFilter a l, MixableL l) => Notation (Play a) -> Seq a -> l (Filter a) -> Environment -> (l Track, Environment) aux1 _ = mixdownL ------------------------------------------------------------------------------- class MixableL l where mixdownL :: Seq a -> l (Filter a) -> Environment -> (l Track, Environment) instance MixableL NilM where mixdownL sq NilM env = (NilM, env) instance (Mixable a, Trackable a, MixableL b) => MixableL (LM a b) where mixdownL sq (a :>> b) env = let (get, env') = defineEnvironment_ (mixdown $ filterSeq (unFilter a) sq) env (b', env'') = mixdownL sq b env' in seq env' (seq env' (TRACK get :>> b', env'')) ------------------------------------------------------------------------------- infixr 5 -|-, -||- (-/-) :: Trackable b => Song a -> Play b -> Song (L a (Track b)) SONG s -/- PLAY p = SONG $ \dur env -> let ~(a, env') = s dur env ~(get, env'') = defineEnvironment_ (p dur env) env' in seq env' (seq env'' ((a :> TRACK get), env'')) (-|-) :: Trackable a => Play a -> Song b -> Song (L (Track a) b) PLAY p -|- SONG s = SONG $ \dur env -> let ~(b, env') = s dur env ~(get, env'') = defineEnvironment_ (p dur env) env' in seq env' (seq b (seq env''(seq get (TRACK get :> b, env'')))) (-||-) :: Trackable a => Play a -> Song (b Track) -> Song (LM a b Track) PLAY p -||- SONG s = SONG $ \dur env -> let (b, env') = s dur env (get, env'') = defineEnvironment_ (p dur env) env' in seq env' $ seq env'' ((TRACK get :>> b), env'') class ToTrack l where -- toTrack :: l Play -> Duration -> Environment -> Environment -> (l Track, Environment) toTrack :: l Play -> Duration -> Environment -> (l Track, Environment) instance ToTrack NilM where -- toTrack NilM _ _ env' = (NilM, env') toTrack NilM _ env = (NilM, env) --instance (Trackable a, ToTrack b) => ToTrack (LM a b) where -- toTrack (PLAY a :>> b) dur env env' = let (get, env'') = defineEnvironment_ (a dur env) env' -- (b', env''') = toTrack b dur env env'' -- in seq env (seq env' (seq env'' (seq env''' (TRACK get :>> b', env''')))) instance (Trackable a, ToTrack b) => ToTrack (LM a b) where toTrack (PLAY a :>> b) dur env = case toTrack b dur env of ~(b', env') -> case seq b' (seq env' (defineEnvironment_ (a dur env) env')) of ~(get, env'') -> seq get (seq env'' (TRACK get :>> b', env'')) tracks :: ToTrack l => l Play -> Song (l Track) tracks l = SONG $ \dur env -> toTrack l dur env -- l Play -> Song (l Track) -} ------------------------------------------------------------------------------- -- notations :: Notation (Play a) -> Play -- Seq e -> l (Filter e) -> l Identity