Skip to content
This repository was archived by the owner on Jun 13, 2025. It is now read-only.
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions tidal-core/src/Sound/Tidal/Core.hs
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ import Prelude hiding ((*>), (<*))
--
-- > saw = sig $ \t -> mod' (fromRational t) 1
sig :: (Time -> a) -> Pattern a
sig f = pattern q
sig f = pattern_ q
where
q (State (Arc s e) _)
| s > e = []
Expand Down Expand Up @@ -336,7 +336,7 @@ append a b = cat [a, b]
cat :: [Pattern a] -> Pattern a
cat [] = silence
cat (p : []) = p
cat ps = pattern q
cat ps = pattern_ q
where
n = length ps
q st = concatMap (f st) $ arcCyclesZW (arc st)
Expand Down Expand Up @@ -433,7 +433,7 @@ overlay = (<>)
-- | Serialises a pattern so there's only one event playing at any one
-- time, making it /monophonic/. Events which start/end earlier are given priority.
mono :: Pattern a -> Pattern a
mono p = pattern $ \(State a cm) -> flatten $ query p (State a cm)
mono p = pattern_ $ \(State a cm) -> flatten $ query p (State a cm)
where
flatten :: [Event a] -> [Event a]
flatten = mapMaybe constrainPart . truncateOverlaps . sortOn whole
Expand Down Expand Up @@ -692,10 +692,10 @@ _getP :: a -> (Value -> Maybe a) -> Pattern Value -> Pattern a
_getP d f pat = fromMaybe d . f <$> pat

_cX :: a -> (Value -> Maybe a) -> String -> Pattern a
_cX d f s = pattern $ \(State a m) -> queryArc (maybe (pure d) (_getP d f . valueToPattern) $ Map.lookup s m) a
_cX d f s = pattern_ $ \(State a m) -> queryArc (maybe (pure d) (_getP d f . valueToPattern) $ Map.lookup s m) a

_cX_ :: (Value -> Maybe a) -> String -> Pattern a
_cX_ f s = pattern $ \(State a m) -> queryArc (maybe silence (_getP_ f . valueToPattern) $ Map.lookup s m) a
_cX_ f s = pattern_ $ \(State a m) -> queryArc (maybe silence (_getP_ f . valueToPattern) $ Map.lookup s m) a

cF :: Double -> String -> Pattern Double
cF d = _cX d getF
Expand Down
2 changes: 1 addition & 1 deletion tidal-core/src/Sound/Tidal/ParseBP.hs
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,8 @@ import Data.Functor.Identity (Identity)
import Data.List (intercalate)
import Data.Maybe (fromMaybe)
import Data.Ratio ((%))
import Data.String (IsString (..))
import Data.Typeable (Typeable)
import GHC.Exts (IsString (..))
import Sound.Tidal.Chords
( Modifier (..),
chordTable,
Expand Down
63 changes: 43 additions & 20 deletions tidal-core/src/Sound/Tidal/Pattern.hs
Original file line number Diff line number Diff line change
Expand Up @@ -57,12 +57,26 @@ data State = State

-- | A datatype representing events taking place over time
data Pattern a = Pattern {query :: State -> [Event a], steps :: Maybe (Rational), pureValue :: Maybe a}
deriving (Generic, Functor)
deriving (Generic)

instance Functor Pattern where
fmap f p =
Pattern
{ query = map (fmap f) . query p,
steps = steps p,
pureValue = fmap f (pureValue p)
}

instance (NFData a) => NFData (Pattern a)

pattern :: (State -> [Event a]) -> Pattern a
pattern f = Pattern f Nothing Nothing
polymorphic :: Pattern a -> Pattern b
polymorphic = fmap (const undefined)

polymorphicEvent :: Event a -> Event b
polymorphicEvent = fmap (const undefined)

pattern_ :: (State -> [Event a]) -> Pattern a
pattern_ f = Pattern f Nothing Nothing

setSteps :: Maybe Rational -> Pattern a -> Pattern a
setSteps r p = p {steps = r}
Expand Down Expand Up @@ -145,7 +159,7 @@ instance Applicative Pattern where
infixl 4 <*, *>, <<*

applyPatToPat :: (Maybe Arc -> Maybe Arc -> Maybe (Maybe Arc)) -> Pattern (a -> b) -> Pattern a -> Pattern b
applyPatToPat combineWholes pf px = pattern q
applyPatToPat combineWholes pf px = pattern_ q
where
q st = catMaybes $ concatMap match $ query pf st
where
Expand All @@ -160,7 +174,7 @@ applyPatToPat combineWholes pf px = pattern q
(query px $ st {arc = wholeOrPart ef})

applyPatToPatBoth :: Pattern (a -> b) -> Pattern a -> Pattern b
applyPatToPatBoth pf px = pattern q
applyPatToPatBoth pf px = pattern_ q
where
q st = catMaybes $ (concatMap match $ query pf st) ++ (concatMap matchX $ query (filterAnalog px) st)
where
Expand All @@ -177,7 +191,7 @@ applyPatToPatBoth pf px = pattern q
return (Event (combineContexts [context ef, context ex]) whole' part' (value ef $ value ex))

applyPatToPatLeft :: Pattern (a -> b) -> Pattern a -> Pattern b
applyPatToPatLeft pf px = pattern q
applyPatToPatLeft pf px = pattern_ q
where
q st = catMaybes $ concatMap match $ query pf st
where
Expand All @@ -188,7 +202,7 @@ applyPatToPatLeft pf px = pattern q
return (Event (combineContexts [context ef, context ex]) whole' part' (value ef $ value ex))

applyPatToPatRight :: Pattern (a -> b) -> Pattern a -> Pattern b
applyPatToPatRight pf px = pattern q
applyPatToPatRight pf px = pattern_ q
where
q st = catMaybes $ concatMap match $ query px st
where
Expand Down Expand Up @@ -225,7 +239,7 @@ instance Monad Pattern where
--
-- TODO - what if a continuous pattern contains a discrete one, or vice-versa?
unwrap :: Pattern (Pattern a) -> Pattern a
unwrap pp = pp {query = q, pureValue = Nothing}
unwrap pp = (polymorphic pp) {query = q, pureValue = Nothing}
where
q st =
concatMap
Expand All @@ -242,7 +256,7 @@ unwrap pp = pp {query = q, pureValue = Nothing}
-- | Turns a pattern of patterns into a single pattern. Like @unwrap@,
-- but structure only comes from the inner pattern.
innerJoin :: Pattern (Pattern b) -> Pattern b
innerJoin pp' = pp' {query = q, pureValue = Nothing}
innerJoin pp' = (polymorphic pp') {query = q, pureValue = Nothing}
where
q st =
concatMap
Expand All @@ -258,7 +272,7 @@ innerJoin pp' = pp' {query = q, pureValue = Nothing}
-- | Turns a pattern of patterns into a single pattern. Like @unwrap@,
-- but structure only comes from the outer pattern.
outerJoin :: Pattern (Pattern a) -> Pattern a
outerJoin pp = pp {query = q, pureValue = Nothing}
outerJoin pp = (polymorphic pp) {query = q, pureValue = Nothing}
where
q st =
concatMap
Expand All @@ -277,7 +291,7 @@ outerJoin pp = pp {query = q, pureValue = Nothing}
-- TODO - what if a continuous pattern contains a discrete one, or vice-versa?
-- TODO - steps
squeezeJoin :: Pattern (Pattern a) -> Pattern a
squeezeJoin pp = pp {query = q, pureValue = Nothing}
squeezeJoin pp = (polymorphic pp) {query = q, pureValue = Nothing}
where
q st =
concatMap
Expand All @@ -292,7 +306,7 @@ squeezeJoin pp = pp {query = q, pureValue = Nothing}
return (Event (combineContexts [iContext, oContext]) w' p' v)

_trigJoin :: Bool -> Pattern (Pattern a) -> Pattern a
_trigJoin cycleZero pat_of_pats = pattern q
_trigJoin cycleZero pat_of_pats = pattern_ q
where
q st =
concatMap
Expand Down Expand Up @@ -384,7 +398,7 @@ instance Monoid (Pattern a) where

instance Semigroup (Pattern a) where
(<>) :: Pattern a -> Pattern a -> Pattern a
(<>) !p !p' = pattern $ \st -> query p st ++ query p' st
(<>) !p !p' = pattern_ $ \st -> query p st ++ query p' st

instance (Num a, Ord a) => Real (Pattern a) where
toRational :: (Num a, Ord a) => Pattern a -> Rational
Expand Down Expand Up @@ -611,7 +625,7 @@ withQueryControls f pat = pat {query = query pat . (\(State a m) -> State a (f m
-- | @withEvent f p@ returns a new @Pattern@ with each event mapped over
-- function @f@.
withEvent :: (Event a -> Event b) -> Pattern a -> Pattern b
withEvent f p = p {query = map f . query p, pureValue = Nothing}
withEvent f p = (polymorphic p) {query = map f . query p, pureValue = Nothing}

-- | @withEvent f p@ returns a new @Pattern@ with each value mapped over
-- function @f@.
Expand All @@ -621,7 +635,7 @@ withValue f pat = withEvent (fmap f) pat
-- | @withEvent f p@ returns a new @Pattern@ with f applied to the resulting list of events for each query
-- function @f@.
withEvents :: ([Event a] -> [Event b]) -> Pattern a -> Pattern b
withEvents f p = p {query = f . query p, pureValue = Nothing}
withEvents f p = (polymorphic p) {query = f . query p, pureValue = Nothing}

-- | @withPart f p@ returns a new @Pattern@ with function @f@ applied
-- to the part.
Expand Down Expand Up @@ -840,7 +854,7 @@ rev p =
-- | Mark values in the first pattern which match with at least one
-- value in the second pattern.
matchManyToOne :: (b -> a -> Bool) -> Pattern a -> Pattern b -> Pattern (Bool, b)
matchManyToOne f pa pb = pa {query = q, pureValue = Nothing}
matchManyToOne f pa pb = (polymorphic pa) {query = q, pureValue = Nothing}
where
q st = map match $ query pb st
where
Expand Down Expand Up @@ -878,7 +892,7 @@ filterAnalog :: Pattern a -> Pattern a
filterAnalog = filterEvents isAnalog

playFor :: Time -> Time -> Pattern a -> Pattern a
playFor s e pat = pattern $ \st -> maybe [] (\a -> query pat (st {arc = a})) $ subArc (Arc s e) (arc st)
playFor s e pat = pattern_ $ \st -> maybe [] (\a -> query pat (st {arc = a})) $ subArc (Arc s e) (arc st)

-- | Splits a pattern into a list containing the given 'n' number of
-- patterns. Each one plays every 'n'th cycle, successfully offset by
Expand Down Expand Up @@ -981,7 +995,16 @@ data EventF a b = Event
part :: a,
value :: b
}
deriving (Eq, Ord, Functor, Generic)
deriving (Eq, Ord, Generic)

instance Functor (EventF a) where
fmap f e =
Event
{ context = context e,
whole = whole e,
part = part e,
value = f (value e)
}

instance (NFData a, NFData b) => NFData (EventF a b)

Expand Down Expand Up @@ -1282,7 +1305,7 @@ groupEventsBy f (e : es) = eqs : groupEventsBy f (es \\ eqs)
-- assumes that all events in the list have same whole/part
collectEvent :: [Event a] -> Maybe (Event [a])
collectEvent [] = Nothing
collectEvent l@(e : _) = Just $ e {context = con, value = vs}
collectEvent l@(e : _) = Just $ (polymorphicEvent e) {context = con, value = vs}
where
con = unionC $ map context l
vs = map value l
Expand All @@ -1307,7 +1330,7 @@ collect :: (Eq a) => Pattern a -> Pattern [a]
collect = collectBy sameDur

uncollectEvent :: Event [a] -> [Event a]
uncollectEvent e = [e {value = value e !! i, context = resolveContext i (context e)} | i <- [0 .. length (value e) - 1]]
uncollectEvent e = [(polymorphicEvent e) {value = value e !! i, context = resolveContext i (context e)} | i <- [0 .. length (value e) - 1]]
where
resolveContext i (Context xs) = if length xs <= i then Context [] else Context [xs !! i]

Expand Down
2 changes: 1 addition & 1 deletion tidal-core/src/Sound/Tidal/Simple.hs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@

module Sound.Tidal.Simple where

import GHC.Exts (IsString (..))
import Data.String (IsString (..))
import Sound.Tidal.Control (chop, hurry)
import Sound.Tidal.Core ((#), (<~), (|*))
import Sound.Tidal.Params (crush, gain, pan, s, speed)
Expand Down
4 changes: 3 additions & 1 deletion tidal-core/src/Sound/Tidal/Time.hs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,9 @@ data ArcF a = Arc
{ start :: a,
stop :: a
}
deriving (Eq, Ord, Functor, Show, Generic)
deriving (Eq, Ord, Show, Generic)

instance Functor ArcF where fmap f (Arc s e) = Arc (f s) (f e)

type Arc = ArcF Time

Expand Down
16 changes: 8 additions & 8 deletions tidal-core/src/Sound/Tidal/UI.hs
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ timeToRands' seed n
--
-- > jux (# ((1024 <~) $ gain rand)) $ sound "sn sn ~ sn" # gain rand
rand :: (Fractional a) => Pattern a
rand = pattern (\(State a@(Arc s _) _) -> [Event (Context []) Nothing a (realToFrac (timeToRand s :: Double))])
rand = pattern_ (\(State a@(Arc s _) _) -> [Event (Context []) Nothing a (realToFrac (timeToRand s :: Double))])

-- | Boolean rand - a continuous stream of true\/false values, with a 50\/50 chance.
brand :: Pattern Bool
Expand Down Expand Up @@ -1459,7 +1459,7 @@ _markovPat :: Int -> Int -> [[Double]] -> Pattern Int
_markovPat n xi tp =
setSteps (Just $ toRational n) $
splitQueries $
pattern
pattern_
( \(State a@(Arc s _) _) ->
queryArc (listToPat $ runMarkov n tp xi (sam s)) a
)
Expand Down Expand Up @@ -1797,7 +1797,7 @@ _scramble n = _rearrangeWith (_segment (fromIntegral n) $ _irand n) n
randrun :: Int -> Pattern Int
randrun 0 = silence
randrun n' =
splitQueries $ pattern (\(State a@(Arc s _) _) -> events a $ sam s)
splitQueries $ pattern_ (\(State a@(Arc s _) _) -> events a $ sam s)
where
events a seed = mapMaybe toEv $ zip arcs shuffled
where
Expand Down Expand Up @@ -1949,7 +1949,7 @@ spaceOut xs p = _slow (toRational $ sum xs) $ stack $ map (`compressArc` p) spac
--
-- > d1 $ n ("[0,4,7] [-12,-8,-5]") # s "superpiano" # sustain 2
flatpat :: Pattern [a] -> Pattern a
flatpat p = p {query = concatMap (\(Event c b b' xs) -> map (Event c b b') xs) . query p, pureValue = Nothing}
flatpat p = (polymorphic p) {query = concatMap (\(Event c b b' xs) -> map (Event c b b') xs) . query p, pureValue = Nothing}

-- | @layer@ takes a list of 'Pattern'-returning functions and a seed element,
-- stacking the result of applying the seed element to each function in the list.
Expand Down Expand Up @@ -2391,7 +2391,7 @@ samples' p p' = flip pick <$> p' <*> p
{-
scrumple :: Time -> Pattern a -> Pattern a -> Pattern a
scrumple o p p' = p'' -- overlay p (o `rotR` p'')
where p'' = pattern $ \a -> concatMap
where p'' = pattern_ $ \a -> concatMap
(\((s,d), vs) -> map (\x -> ((s,d),
snd x
)
Expand All @@ -2416,7 +2416,7 @@ stackwith p ps
l = fromIntegral $ length ps

{-
cross f p p' = pattern $ \t -> concat [filter flt $ arc p t,
cross f p p' = pattern_ $ \t -> concat [filter flt $ arc p t,
filter (not . flt) $ arc p' t
]
] where flt = f . cyclePos . fst . fst
Expand Down Expand Up @@ -2772,7 +2772,7 @@ inv = (not <$>)

-- TODO - test this with analog events
smooth :: (Fractional a) => Pattern a -> Pattern a
smooth p = pattern $ \st@(State a cm) -> tween st a $ query monoP (State (midArc a) cm)
smooth p = pattern_ $ \st@(State a cm) -> tween st a $ query monoP (State (midArc a) cm)
where
midArc a = Arc (mid (start a, stop a)) (mid (start a, stop a))
tween _ _ [] = []
Expand Down Expand Up @@ -2878,7 +2878,7 @@ squeeze _ [] = silence
squeeze ipat pats = squeezeJoin $ (pats !!!) <$> ipat

squeezeJoinUp :: Pattern ControlPattern -> ControlPattern
squeezeJoinUp pp = pp {query = q, pureValue = Nothing}
squeezeJoinUp pp = (polymorphic pp) {query = q, pureValue = Nothing}
where
q st = concatMap (f st) (query (filterDigital pp) st)
f st (Event c (Just w) p v) =
Expand Down
Loading