tidal 1.1.2 → 1.2.0
raw patch · 9 files changed
+40/−108 lines, 9 files
Files
- CHANGELOG.md +4/−0
- src/Sound/Tidal/Control.hs +2/−2
- src/Sound/Tidal/Core.hs +3/−7
- src/Sound/Tidal/Pattern.hs +17/−85
- src/Sound/Tidal/UI.hs +6/−6
- src/Sound/Tidal/Version.hs +1/−1
- test/Sound/Tidal/CoreTest.hs +5/−5
- test/Sound/Tidal/UITest.hs +1/−1
- tidal.cabal +1/−1
CHANGELOG.md view
@@ -1,5 +1,9 @@ # TidalCycles log of changes +## 1.2.0 - Hunters Bar++* Simplify <* and *>, removing any distinction between analogue and digital patterns+ ## 1.1.2 - Eccy Road * Usability fix for `binary` / `binaryN` (use squeezeJoin on input pattern)
src/Sound/Tidal/Control.hs view
@@ -392,10 +392,10 @@ _getP d f pat = (fromMaybe d . f) <$> pat _cX :: a -> (Value -> Maybe a) -> String -> Pattern a-_cX d f s = Pattern Analog $ \(State a m) -> queryArc (maybe (pure d) (_getP d f) $ Map.lookup s m) a+_cX d f s = Pattern $ \(State a m) -> queryArc (maybe (pure d) (_getP d f) $ Map.lookup s m) a _cX_ :: (Value -> Maybe a) -> String -> Pattern a-_cX_ f s = Pattern Analog $ \(State a m) -> queryArc (maybe silence (_getP_ f) $ Map.lookup s m) a+_cX_ f s = Pattern $ \(State a m) -> queryArc (maybe silence (_getP_ f) $ Map.lookup s m) a cF :: Double -> String -> Pattern Double cF d = _cX d getF
src/Sound/Tidal/Core.hs view
@@ -17,7 +17,7 @@ -- | Takes a function from time to values, and turns it into a 'Pattern'. sig :: (Time -> a) -> Pattern a-sig f = Pattern Analog q+sig f = Pattern q where q (State (Arc s e) _) | s > e = [] | otherwise = [Event (Arc s e) (Arc s e) (f (s+((e-s)/2)))]@@ -190,8 +190,7 @@ -- in turn, then the second cycle from each, and so on. cat :: [Pattern a] -> Pattern a cat [] = silence--- TODO I *guess* it would be digital..-cat ps = Pattern Digital q+cat ps = Pattern $ q where n = length ps q st = concatMap (f st) $ arcCyclesZW (arc st) f st a = query (withResultTime (+offset) p) $ st {arc = Arc (subtract offset (start a)) (subtract offset (stop a))}@@ -234,10 +233,7 @@ -- | 'overlay' combines two 'Pattern's into a new pattern, so that -- their events are combined over time. overlay :: Pattern a -> Pattern a -> Pattern a--- Analog if they're both analog-overlay !p@(Pattern Analog _) !p'@(Pattern Analog _) = Pattern Analog $ \st -> query p st ++ query p' st--- Otherwise digital. Won't really work to have a mixture.. Hmm-overlay !p !p' = Pattern Digital $ \st -> query p st ++ query p' st+overlay !p !p' = Pattern $ \st -> query p st ++ query p' st -- | An infix alias of @overlay@ (<>) :: Pattern a -> Pattern a -> Pattern a
src/Sound/Tidal/Pattern.hs view
@@ -223,13 +223,8 @@ -- | A function that represents events taking place over time type Query a = (State -> [Event a]) --- | Also known as Continuous vs Discrete/Amorphous vs Pulsating etc.-data Nature = Analog | Digital- deriving (Eq, Show)---- | A datatype that's basically a query, plus a hint about whether its events--- are Analogue or Digital by nature-data Pattern a = Pattern {nature :: Nature, query :: Query a}+-- | A datatype that's basically a query+data Pattern a = Pattern {query :: Query a} data Value = VS { svalue :: String } | VF { fvalue :: Double }@@ -306,96 +301,39 @@ instance NFData a => NFData (Pattern a) where - rnf (Pattern _ q) = rnf $ \s -> q s+ rnf (Pattern q) = rnf $ \s -> q s instance Functor Pattern where -- | apply a function to all the values in a pattern fmap f p = p {query = fmap (fmap f) . query p} -instance Applicative Pattern where- -- | Repeat the given value once per cycle, forever- pure v = Pattern Digital $ \(State a _) ->- map (\a' -> Event a' (sect a a') v) $ cycleArcsInArc a-- (<*>) pf@(Pattern Digital _) px@(Pattern Digital _) = Pattern Digital q+applyPatToPat :: (Arc -> Arc -> Maybe Arc) -> Pattern (a -> b) -> Pattern a -> Pattern b+applyPatToPat combineWholes pf px = Pattern q where q st = catMaybes $ concatMap match $ query pf st where match (Event fWhole fPart f) = map (\(Event xWhole xPart x) ->- do whole' <- subArc xWhole fWhole+ do whole' <- combineWholes fWhole xWhole part' <- subArc fPart xPart return (Event whole' part' (f x)) )- (query px $ st {arc = fPart})- (<*>) pf@(Pattern Digital _) px@(Pattern Analog _) = Pattern Digital q- where q st = concatMap match $ query pf st- where- match (Event fWhole fPart f) =- map- (Event fWhole fPart . f . value)- (query px $ st {arc = pure (start fPart)})+ (query px $ st {arc = fWhole}) - (<*>) pf@(Pattern Analog _) px@(Pattern Digital _) = Pattern Digital q- where q st = concatMap match $ query px st- where- match (Event xWhole xPart x) =- map- (\e -> Event xWhole xPart (value e x))- (query pf st {arc = pure (start xPart)})+instance Applicative Pattern where+ -- | Repeat the given value once per cycle, forever+ pure v = Pattern $ \(State a _) ->+ map (\a' -> Event a' (sect a a') v) $ cycleArcsInArc a - (<*>) pf px = Pattern Analog q- where q st = concatMap match $ query pf st- where- match ef =- map- (Event (arc st) (arc st) . value ef . value)- (query px st)+ (<*>) = applyPatToPat subArc --- | Like <*>, but the structure only comes from the left+-- | Like <*>, but the 'wholes' come from the left (<*) :: Pattern (a -> b) -> Pattern a -> Pattern b-(<*) pf@(Pattern Analog _) px@(Pattern Analog _) = Pattern Analog q- where q st = concatMap match $ query pf st- where- match (Event fWhole fPart f) =- map- (Event fWhole fPart . f . value) $- query px st -- for continuous events, use the original query---- If one of the patterns is digital, treat both as digital.. (TODO - needs extra thought)-(<*) pf px = Pattern Digital q- where q st = catMaybes $ concatMap match $ query pf st- where- match (Event fWhole fPart f) =- map- (\(Event _ xPart x) ->- do let whole' = fWhole- part' <- subArc fPart xPart- return (Event whole' part' (f x))- )- (query px $ st {arc = fPart})+(<*) = applyPatToPat (\a _ -> Just a) --- | Like <*>, but the structure only comes from the right+-- | Like <*>, but the 'wholes' come from the right (*>) :: Pattern (a -> b) -> Pattern a -> Pattern b-(*>) pf@(Pattern Analog _) px@(Pattern Analog _) = Pattern Analog q- where q st = concatMap match $ query px st- where- match (Event xWhole xPart x) =- map- (\e -> Event xWhole xPart (value e x)) $- query pf st -- for continuous events, use the original query--(*>) pf px = Pattern Digital q- where q st = catMaybes $ concatMap match $ query pf st- where- match (Event _ fPart f) =- map- (\(Event xWhole xPart x) ->- do let whole' = xWhole- part' <- subArc fPart xPart- return (Event whole' part' (f x))- )- (query px $ st {arc = fPart})+(*>) = applyPatToPat (\_ b -> Just b) infixl 4 <*, *> @@ -659,16 +597,10 @@ -- * Internal functions empty :: Pattern a-empty = Pattern {nature = Digital, query = const []}+empty = Pattern {query = const []} queryArc :: Pattern a -> Arc -> [Event a] queryArc p a = query p $ State a Map.empty --isDigital :: Pattern a -> Bool-isDigital = (== Digital) . nature--isAnalog :: Pattern a -> Bool-isAnalog = not . isDigital -- | Splits queries that span cycles. For example `query p (0.5, 1.5)` would be -- turned into two queries, `(0.5,1)` and `(1,1.5)`, and the results
src/Sound/Tidal/UI.hs view
@@ -79,7 +79,7 @@ @ -} rand :: Fractional a => Pattern a-rand = Pattern Analog (\(State a@(Arc s e) _) -> [Event a a (realToFrac $ timeToRand $ (e + s)/2)])+rand = Pattern (\(State a@(Arc s e) _) -> [Event a a (realToFrac $ timeToRand $ (e + s)/2)]) {- | Just like `rand` but for whole numbers, `irand n` generates a pattern of (pseudo-) random whole numbers between `0` to `n-1` inclusive. Notably used to pick a random samples from a folder:@@ -987,7 +987,7 @@ -- TODO - what does this do? Something for @stripe@ .. randStruct :: Int -> Pattern Int-randStruct n = splitQueries $ Pattern {nature = Digital, query = f}+randStruct n = splitQueries $ Pattern {query = f} where f st = map (\(a,b,c) -> Event a (fromJust b) c) $ filter (\(_,x,_) -> isJust x) as where as = map (\(i, Arc s' e') -> (Arc (s' + sam s) (e' + sam s),@@ -1088,7 +1088,7 @@ markovPat = tParam2 _markovPat _markovPat :: Int -> Int -> [[Double]] -> Pattern Int-_markovPat n xi tp = splitQueries $ Pattern Digital (\(State a@(Arc s e) _) -> +_markovPat n xi tp = splitQueries $ Pattern (\(State a@(Arc s e) _) -> queryArc (listToPat $ runMarkov n tp xi (sam s)) a) {-|@@ -1281,7 +1281,7 @@ randrun :: Int -> Pattern Int randrun 0 = silence randrun n' =- splitQueries $ Pattern Digital (\(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 shuffled = map snd $ sortOn fst $ zip rs [0 .. (n'-1)] rs = timeToRands seed n'@@ -1718,7 +1718,7 @@ -- | 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 Digital $ \(State a cm) -> flatten $ query p (State a cm) where+mono p = Pattern $ \(State a cm) -> flatten $ query p (State a cm) where flatten :: [Event a] -> [Event a] flatten = mapMaybe constrainPart . truncateOverlaps . sortOn whole truncateOverlaps [] = []@@ -1739,7 +1739,7 @@ -- smooth :: Pattern Double -> Pattern Double smooth :: Fractional a => Pattern a -> Pattern a-smooth p = Pattern Analog $ \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 _ _ [] = []
src/Sound/Tidal/Version.hs view
@@ -1,4 +1,4 @@ module Sound.Tidal.Version where tidal_version :: String-tidal_version = "1.1.2"+tidal_version = "1.2.0"
test/Sound/Tidal/CoreTest.hs view
@@ -105,14 +105,14 @@ (map value $ queryArc ((+1) <$> saw) (Arc 0.5 0.5)) `shouldBe` [1.5 :: Float] it "works on the left of <*>" $ do (queryArc ((+) <$> saw <*> pure 3) (Arc 0 1))- `shouldBe` fmap toEvent [(((0,1), (0,1)), 3 :: Float)]+ `shouldBe` fmap toEvent [(((0,1), (0,1)), 3.5 :: Float)] it "works on the right of <*>" $ do (queryArc ((fast 4 $ pure (+3)) <*> saw) (Arc 0 1)) `shouldBe` fmap toEvent- [(((0,0.25), (0,0.25)), 3 :: Float),- (((0.25,0.5), (0.25,0.5)), 3.25),- (((0.5,0.75), (0.5,0.75)), 3.5),- (((0.75,1), (0.75,1)), 3.75)+ [(((0,0.25), (0,0.25)), 3.125 :: Float),+ (((0.25,0.5), (0.25,0.5)), 3.375),+ (((0.5,0.75), (0.5,0.75)), 3.625),+ (((0.75,1), (0.75,1)), 3.875) ] it "can be reversed" $ do it "works with whole cycles" $
test/Sound/Tidal/UITest.hs view
@@ -44,7 +44,7 @@ it "can hold a value over multiple cycles" $ do comparePD (Arc 0 8) (segment 0.5 saw)- (slow 2 "0.5" :: Pattern Double)+ (slow 2 "0" :: Pattern Double) {- -- not sure what this is supposed to do! it "holding values over multiple cycles works in combination" $ do
tidal.cabal view
@@ -1,5 +1,5 @@ name: tidal-version: 1.1.2+version: 1.2.0 synopsis: Pattern language for improvised music -- description: homepage: http://tidalcycles.org/