tidal-core 1.10.1 → 1.10.2
raw patch · 7 files changed
+83/−22 lines, 7 files
Files
- src/Sound/Tidal/ParseBP.hs +4/−1
- src/Sound/Tidal/Pattern.hs +18/−3
- src/Sound/Tidal/Stepwise.hs +25/−9
- src/Sound/Tidal/UI.hs +24/−7
- test/Sound/Tidal/StepwiseTest.hs +7/−1
- test/Sound/Tidal/UITest.hs +4/−0
- tidal-core.cabal +1/−1
src/Sound/Tidal/ParseBP.hs view
@@ -685,7 +685,10 @@ ] fromNote :: (Num a) => Pattern String -> Pattern a-fromNote pat = fromRight 0 . runParser parseNote 0 "" <$> pat+fromNote pat = _fromNote <$> pat++_fromNote :: (Num a) => String -> a+_fromNote str = fromRight 0 . runParser parseNote 0 "" $ str pColour :: MyParser (TPat ColourD) pColour = wrapPos $ do
src/Sound/Tidal/Pattern.hs view
@@ -31,7 +31,10 @@ ) where -import Control.Applicative (liftA2)+-- Backward compatibility for liftA2+--- https://github.com/haskell/core-libraries-committee/blob/main/guides/export-lifta2-prelude.md++import Control.Applicative (Applicative (..)) import Control.DeepSeq (NFData) import Control.Monad ((>=>)) import Data.Data (Data)@@ -43,7 +46,7 @@ import Data.Word (Word8) import GHC.Generics (Generic) import Sound.Tidal.Time-import Prelude hiding ((*>), (<*))+import Prelude hiding (Applicative (..), (*>), (<*)) ------------------------------------------------------------------------ @@ -56,7 +59,7 @@ } -- | A datatype representing events taking place over time-data Pattern a = Pattern {query :: State -> [Event a], steps :: Maybe (Rational), pureValue :: Maybe a}+data Pattern a = Pattern {query :: State -> [Event a], steps :: Maybe Rational, pureValue :: Maybe a} deriving (Generic, Functor) instance (NFData a) => NFData (Pattern a)@@ -73,6 +76,9 @@ withSteps :: (Rational -> Rational) -> Pattern a -> Pattern a withSteps f p = p {steps = fmap f $ steps p} +hasSteps :: Pattern a -> Bool+hasSteps = isJust . steps+ pace :: Rational -> Pattern a -> Pattern a pace target p@(Pattern _ (Just t) _) = setSteps (Just target) $ _fast (target / t) p -- raise error?@@ -613,6 +619,9 @@ withEvent :: (Event a -> Event b) -> Pattern a -> Pattern b withEvent f p = p {query = map f . query p, pureValue = Nothing} +withEventArc :: (Arc -> Arc) -> Pattern a -> Pattern a+withEventArc f pat = withEvent (\(Event c w p v) -> Event c (f <$> w) (f p) v) pat+ -- | @withEvent f p@ returns a new @Pattern@ with each value mapped over -- function @f@. withValue :: (a -> b) -> Pattern a -> Pattern b@@ -850,6 +859,12 @@ as' = as $ start $ wholeOrPart ex as s = query pa $ fQuery s fQuery s = st {arc = Arc s s}++-- Like `rev`, but reverses the whole pattern, rather than every cycle in the pattern.+revv :: Pattern a -> Pattern a+revv pat = withEventArc negateArc $ withQueryArc negateArc pat+ where+ negateArc (Arc s e) = Arc (negate e) (negate s) -- ** Event filters
src/Sound/Tidal/Stepwise.hs view
@@ -18,14 +18,14 @@ module Sound.Tidal.Stepwise where -import Data.List (sort, sortOn, transpose)-import Data.Maybe (catMaybes, fromJust, fromMaybe, isJust, mapMaybe)-import Sound.Tidal.Core (stack, timecat, zoom, zoompat)+import Data.List (sort, transpose)+import Data.Maybe (fromMaybe, isJust, mapMaybe)+import Sound.Tidal.Core (slowcat, stack, timecat, zoom) import Sound.Tidal.Pattern-import Sound.Tidal.Utils (enumerate, nubOrd, pairs)+import Sound.Tidal.Utils (nubOrd, pairs) --- _lcmsteps :: [Pattern a] -> Maybe Time--- _lcmsteps pats = foldl1 lcmr <$> (sequence $ map steps pats)+-- _lcmsteps :: [Pattern a] -> Pattern Time+-- _lcmsteps pats = foldl1 (liftA2 lcmr) $ mapMaybe steps pats s_patternify :: (a -> Pattern b -> Pattern c) -> (Pattern a -> Pattern b -> Pattern c) s_patternify f (Pattern _ _ (Just a)) b = f a b@@ -37,6 +37,7 @@ stepJoin :: Pattern (Pattern a) -> Pattern a stepJoin pp = Pattern q first_t Nothing where+ -- TODO - use context? q st@(State a c) = query (timecat $ retime $ slices $ query (rotL (sam $ start a) pp) (st {arc = Arc 0 1})) st first_t :: Maybe Rational first_t = steps $ timecat $ retime $ slices $ queryArc pp (Arc 0 1)@@ -89,9 +90,9 @@ _stepdrop _ pat@(Pattern _ Nothing _) = pat _stepdrop n pat@(Pattern _ (Just t) _) = steptake (pure $ f t) pat where- f t- | n >= 0 = t - n- | otherwise = negate (t + n)+ f t'+ | n >= 0 = t' - n+ | otherwise = negate (t' + n) stepdrop :: Pattern Time -> Pattern a -> Pattern a stepdrop = s_patternify _stepdrop@@ -114,11 +115,26 @@ extend :: Pattern Rational -> Pattern a -> Pattern a extend = s_patternify _extend +-- polymeter :: [Pattern a] -> Pattern a+-- polymeter pats = stack $ map (pace targetSteps) pats'+-- where+-- targetSteps = _lcmsteps pats'+-- pats' = filter hasSteps pats++-- pm :: [Pattern a] -> Pattern a+-- pm = polymeter+ -- | Successively plays a pattern from each group in turn stepalt :: [[Pattern a]] -> Pattern a stepalt groups = stepcat $ concat $ take (fromIntegral $ c * length groups) $ transpose $ map cycle groups where c = foldl1 lcm $ map length groups++stepzip :: [Pattern a] -> Pattern a+stepzip pats = setSteps (Just s) $ _fast s zipped+ where+ zipped = slowcat $ map (pace 1) $ filter hasSteps pats+ s = foldl1 lcmr $ mapMaybe steps pats {- s_while :: Pattern Bool -> (Pattern a -> Pattern a) -> Pattern a -> Pattern a
src/Sound/Tidal/UI.hs view
@@ -1434,9 +1434,9 @@ where r = timeToRand seed' renorm :: IM.IntMap (Map.Map Double Int)- renorm = IM.fromList $ zip [0 ..] [Map.fromList $ zip (tail $ scanl (+) 0 x) [0 ..] | x <- tp]+ renorm = IM.fromList $ zip [0 ..] [Map.fromListWith (\new old -> old) $ zip (tail $ scanl (+) 0 x) [0 ..] | x <- tp] findIndex :: Double -> Map.Map Double Int -> Int- findIndex x v = maybe 0 snd (Map.lookupGE x v)+ findIndex x v = maybe (snd (Map.findMax v)) snd (Map.lookupGT x v) delta = 1 / fromIntegral n -- | @markovPat n xi tp@ generates a one-cycle pattern of @n@ steps in a Markov@@ -1606,6 +1606,20 @@ _chunk' :: (Integral a) => a -> (Pattern b -> Pattern b) -> Pattern b -> Pattern b _chunk' n f p = _chunk (-n) f p +chunkinto :: Pattern Int -> (Pattern b -> Pattern b) -> Pattern b -> Pattern b+chunkinto npat f p = innerJoin $ (\n -> _chunkinto n f p) <$> npat++chunkInto :: Pattern Int -> (Pattern b -> Pattern b) -> Pattern b -> Pattern b+chunkInto = chunkinto++_chunkinto :: Int -> (Pattern a -> Pattern a) -> Pattern a -> Pattern a+_chunkinto 0 _ pat = pat+_chunkinto n f pat = into (iterf n $ fastcat $ map pure (True : replicate (abs n - 1) False)) f pat+ where+ iterf+ | n > 0 = _iter'+ | otherwise = _iter+ -- | -- @inside@ carries out an operation /inside/ a cycle. -- For example, while @rev "0 1 2 3 4 5 6 7"@ is the same as @"7 6 5 4 3 2 1 0"@,@@ -3000,14 +3014,17 @@ rib = ribbon -- | Turns a pattern into a pattern of patterns, according to the structure of another given pattern.-unjoin :: Pattern Bool -> Pattern b -> Pattern (Pattern b)-unjoin pieces pat = withEvent snip pieces+unjoinfunc :: Pattern Bool -> (Pattern a -> Pattern a) -> Pattern a -> Pattern (Pattern a)+unjoinfunc pieces f pat = withEvent snip pieces where -- If true, set value to the part of pattern looped at event boundaries- snip e@Event {value = True} = e {value = _ribbon (wholeStart e) (wholeStop e - wholeStart e) pat}+ snip e@Event {value = True} = e {value = f $ _ribbon (wholeStart e) (wholeStop e - wholeStart e) pat} -- Otherwise, set value to unchanged pattern snip e = e {value = pat} +unjoin :: Pattern Bool -> Pattern a -> Pattern (Pattern a)+unjoin pieces pat = unjoinfunc pieces id pat+ -- | Applies a function to subcycles of a pattern, as defined by the structure of another given pattern.-into :: Pattern Bool -> (Pattern a -> Pattern b) -> Pattern a -> Pattern b-into pieces func pat = innerJoin $ fmap func $ unjoin pieces pat+into :: Pattern Bool -> (Pattern b -> Pattern b) -> Pattern b -> Pattern b+into pieces func pat = innerJoin $ unjoinfunc pieces func pat
test/Sound/Tidal/StepwiseTest.hs view
@@ -15,7 +15,7 @@ import Sound.Tidal.Stepwise (expand, stepcat, stepdrop, steptake) import Sound.Tidal.UI (inv, iter, linger, segment) import Test.Hspec (Spec, describe, it, shouldBe)-import TestUtils (compareP)+import TestUtils (compareP, firstCycleValues) import Prelude hiding ((*>), (<*)) run :: Spec@@ -47,3 +47,9 @@ it "invert" $ steps (inv "1 0 1" :: Pattern Bool) `shouldBe` Just 3 it "chop" $ steps (chop 3 $ sound "a b") `shouldBe` Just 6 it "chop" $ steps (striate 3 $ sound "a b") `shouldBe` Just 6++-- describe "polymeter" $ do+-- it "can repeat patterns to step count lcm" $+-- compareP (Arc 0 8) (polymeter ["a b c" :: Pattern Char, "d e"]) "{a b c, d e}%6"+-- it "can work with 3 patterns" $+-- compareP (Arc 0 8) (polymeter ["a b c" :: Pattern Char, "d e", "f g h i"]) "{a b c, d e, f g h i}%12"
test/Sound/Tidal/UITest.hs view
@@ -488,3 +488,7 @@ (Arc 0 1) (_ribbon 0.25 0.25 ("a b c d" :: Pattern String)) "b b b b"+ describe "runMarkov" $ do+ it "deterministic transition matrix" $ do+ runMarkov 4 [[0,1],[1,0]] 0 0+ `shouldBe` [0,1,0,1]
tidal-core.cabal view
@@ -1,7 +1,7 @@ cabal-version: 2.0 name: tidal-core-version: 1.10.1+version: 1.10.2 license: GPL-3 copyright: (c) Alex McLean and other contributors, 2025