tidal 1.0.13 → 1.0.14
raw patch · 12 files changed
+239/−129 lines, 12 filesdep ~clockdep ~networkdep ~parsec
Dependency ranges changed: clock, network, parsec, semigroups, transformers
Files
- CHANGELOG.md +8/−0
- src/Sound/Tidal/Control.hs +45/−58
- src/Sound/Tidal/Params.hs +3/−0
- src/Sound/Tidal/ParseBP.hs +6/−2
- src/Sound/Tidal/Pattern.hs +35/−3
- src/Sound/Tidal/Stream.hs +49/−40
- src/Sound/Tidal/UI.hs +22/−13
- src/Sound/Tidal/Version.hs +1/−1
- test/Sound/Tidal/ParseTest.hs +30/−0
- test/Sound/Tidal/PatternTest.hs +9/−6
- test/Sound/Tidal/UITest.hs +25/−0
- tidal.cabal +6/−6
CHANGELOG.md view
@@ -1,5 +1,13 @@ # TidalCycles log of changes +## 1.0.14 - IICON++* 'chew' - like bite, but speeds playback rate up and down+* variable probability for ? in mini notation+* chooseBy takes modulo of index to avoid out of bounds errors+* 'rate' control param+* Fix dependencies for parsec/colour+ ## 1.0.13 - 🐝⌛️🦋 #2 * Simplify espgrid support - @yaxu
src/Sound/Tidal/Control.hs view
@@ -369,81 +369,68 @@ trigger :: Show a => a -> Pattern b -> Pattern b trigger k pat = pat {query = q}- where q st = query (rotR (offset st) pat) st- offset st = fromMaybe 0 $ Map.lookup ctrl (controls st) >>= getR+ where q st = query ((offset st) ~> pat) st+ offset st = fromMaybe (pure 0) $ do pat <- Map.lookup ctrl (controls st)+ return $ ((fromMaybe 0 . getR) <$> pat) ctrl = "_t_" ++ show k -cI :: String -> Pattern Int-cI s = Pattern Analog $ \(State a m) -> maybe [] (f a) $ Map.lookup s m- where f a (VI v) = [Event a a v]- f a (VF v) = [Event a a (floor v)]- f a (VR v) = [Event a a (floor v)]- f a (VS v) = maybe [] (\v' -> [Event a a v']) (readMaybe v) -_cX :: (Arc -> Value -> [Event a]) -> [a] -> String -> Pattern a-_cX f ds s = Pattern Analog $- \(State a m) -> maybe (map (Event a a) ds) (f a) $ Map.lookup s m+_getP_ :: (Value -> Maybe a) -> Pattern Value -> Pattern a+_getP_ f pat = filterJust $ f <$> pat -_cF :: [Double] -> String -> Pattern Double-_cF = _cX f- where f a (VI v) = [Event a a (fromIntegral v)]- f a (VR v) = [Event a a (fromRational v)]- f a (VF v) = [Event a a v]- f a (VS v) = maybe [] (\v' -> [Event a a v']) (readMaybe v)+_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 Analog $ \(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+ cF :: Double -> String -> Pattern Double-cF d = _cF [d]-cF0 :: String -> Pattern Double-cF0 = _cF [0]+cF d = _cX d getF cF_ :: String -> Pattern Double-cF_ = _cF []+cF_ = _cX_ getF+cF0 :: String -> Pattern Double+cF0 = _cX 0 getF +cI :: Int -> String -> Pattern Int+cI d = _cX d getI+cI_ :: String -> Pattern Int+cI_ = _cX_ getI+cI0 :: String -> Pattern Int+cI0 = _cX 0 getI+ cB :: Bool -> String -> Pattern Bool-cB b = _cB [b]-_cB :: [Bool] -> String -> Pattern Bool-_cB = _cX f- where f a (VI v) = [Event a a (v /= 0)]- f a (VF v) = [Event a a (v >= 0.5)]- f a (VR v) = [Event a a (v >= (1%2))]- f a (VS v) = maybe [] (\v' -> [Event a a (v' == "t")]) (readMaybe v)+cB d = _cX d getB+cB_ :: String -> Pattern Bool+cB_ = _cX_ getB+cB0 :: String -> Pattern Bool+cB0 = _cX False getB +cR :: Rational -> String -> Pattern Rational+cR d = _cX d getR+cR_ :: String -> Pattern Rational+cR_ = _cX_ getR+cR0 :: String -> Pattern Rational+cR0 = _cX 0 getR+ cT :: Time -> String -> Pattern Time-cT d = (toRational <$>) . cF (fromRational d)+cT = cR cT0 :: String -> Pattern Time-cT0 = (toRational <$>) . cF0+cT0 = cR0 cT_ :: String -> Pattern Time-cT_ = (toRational <$>) . cF_---cR :: Time -> String -> Pattern Rational-cR = cT-cR0 :: String -> Pattern Time-cR0 = cT0-cR_ :: String -> Pattern Time-cR_ = cT_+cT_ = cR_ -_cS :: [String] -> String -> Pattern String-_cS = _cX f- where f a (VI v) = [Event a a (show v)]- f a (VF v) = [Event a a (show v)]- f a (VR v) = [Event a a (show v)]- f a (VS v) = [Event a a v] cS :: String -> String -> Pattern String-cS d = _cS [d]+cS d = _cX d getS cS_ :: String -> Pattern String-cS_ = _cS []--_cP :: (Enumerable a, Parseable a) => [Pattern a] -> String -> Pattern a-_cP ds s = innerJoin $ _cX f ds s- where f a (VI v) = [Event a a (parseBP_E $ show v)]- f a (VF v) = [Event a a (parseBP_E $ show v)]- f a (VR v) = [Event a a (parseBP_E $ show v)]- f a (VS v) = [Event a a (parseBP_E v)]+cS_ = _cX_ getS+cS0 :: String -> Pattern String+cS0 = _cX "" getS -cP :: (Enumerable a, Parseable a) => Pattern a -> String -> Pattern a-cP d = _cP [d]-cP_ :: (Enumerable a, Parseable a) => String -> Pattern a-cP_ = _cP []+cP :: String -> Pattern String+cP s = innerJoin $ parseBP_E <$> (_cX_ getS s) -- Default controller inputs (for MIDI) in0 :: Pattern Double
src/Sound/Tidal/Params.hs view
@@ -298,6 +298,9 @@ pitch3 = pF "pitch3" portamento :: Pattern Double -> ControlPattern portamento = pF "portamento"+-- | used in SuperDirt softsynths as a control rate or "speed"+rate :: Pattern Double -> ControlPattern+rate = pF "rate" -- | a pattern of numbers to specify the release time (in seconds) of an envelope applied to each sample. Only takes effect if `attack` is also specified. release :: Pattern Double -> ControlPattern release = pF "release"
src/Sound/Tidal/ParseBP.hs view
@@ -250,7 +250,10 @@ <|> do es <- many1 (symbol "_") return [TPat_Elongate (length es)] let ps' = TPat_Cat $ map elongate $ splitFeet $ concat ps- return (length ps, ps')+ extraElongate (TPat_Elongate n) = n-1+ extraElongate _ = 0+ sumElongates x = sum (map extraElongate x)+ return (length ps + sumElongates (concat ps), ps') elongate :: [TPat a] -> TPat a elongate xs | any isElongate xs = TPat_TimeCat xs@@ -413,8 +416,9 @@ pRand :: TPat a -> Parser (TPat a) pRand thing = do char '?'+ r <- float <|> return 0.5 spaces- return $ TPat_DegradeBy 0.5 thing+ return $ TPat_DegradeBy r thing <|> return thing pE :: TPat a -> Parser (TPat a)
src/Sound/Tidal/Pattern.hs view
@@ -207,7 +207,7 @@ -- | an Arc and some named control values data State = State {arc :: Arc,- controls :: ControlMap+ controls :: StateMap } -- | A function that represents events taking place over time@@ -225,10 +225,27 @@ | VF { fvalue :: Double } | VR { rvalue :: Rational } | VI { ivalue :: Int }+ | VB { bvalue :: Bool } deriving (Typeable,Data) +class Valuable a where+ toValue :: a -> Value++instance Valuable String where+ toValue = VS+instance Valuable Double where+ toValue a = VF a+instance Valuable Rational where+ toValue a = VR a+instance Valuable Int where+ toValue a = VI a+instance Valuable Bool where+ toValue a = VB a+ instance Eq Value where (VS x) == (VS y) = x == y+ (VB x) == (VB y) = x == y+ (VF x) == (VF y) = x == y (VI x) == (VI y) = x == y (VR x) == (VR y) = x == y@@ -241,16 +258,19 @@ (VI x) == (VR y) = (toRational x) == y (VR y) == (VI x) = (toRational x) == y - (VS _) == _ = False- _ == (VS _) = False++ _ == _ = False instance Ord Value where compare (VS x) (VS y) = compare x y+ compare (VB x) (VB y) = compare x y compare (VF x) (VF y) = compare x y compare (VI x) (VI y) = compare x y compare (VR x) (VR y) = compare x y compare (VS _) _ = LT compare _ (VS _) = GT+ compare (VB _) _ = LT+ compare _ (VB _) = GT compare (VF x) (VI y) = compare x (fromIntegral y) compare (VI x) (VF y) = compare (fromIntegral x) y @@ -260,6 +280,7 @@ compare (VF x) (VR y) = compare x (fromRational y) compare (VR x) (VF y) = compare (fromRational x) y +type StateMap = Map.Map String (Pattern Value) type ControlMap = Map.Map String Value type ControlPattern = Pattern ControlMap @@ -548,6 +569,7 @@ show (VI i) = show i show (VF f) = show f ++ "f" show (VR r) = show r ++ "r"+ show (VB b) = show b instance {-# OVERLAPPING #-} Show ControlMap where show m = intercalate ", " $ map (\(name, v) -> name ++ ": " ++ show v) $ Map.toList m@@ -679,18 +701,28 @@ getI :: Value -> Maybe Int getI (VI i) = Just i+getI (VR x) = Just $ floor x+getI (VF x) = Just $ floor x getI _ = Nothing getF :: Value -> Maybe Double getF (VF f) = Just f+getF (VR x) = Just $ fromRational x+getF (VI x) = Just $ fromIntegral x getF _ = Nothing getS :: Value -> Maybe String getS (VS s) = Just s getS _ = Nothing +getB :: Value -> Maybe Bool+getB (VB b) = Just b+getB _ = Nothing+ getR :: Value -> Maybe Rational getR (VR r) = Just r+getR (VF x) = Just $ toRational x+getR (VI x) = Just $ toRational x getR _ = Nothing compressArc :: Arc -> Pattern a -> Pattern a
src/Sound/Tidal/Stream.hs view
@@ -28,7 +28,7 @@ deriving (Eq, Show) data Stream = Stream {sConfig :: Config,- sInput :: MVar ControlMap,+ sInput :: MVar StateMap, sOutput :: MVar ControlPattern, sListenTid :: Maybe ThreadId, sPMapMV :: MVar PlayMap,@@ -110,15 +110,15 @@ oTimestamp = MessageStamp } -startStream :: Config -> MVar ControlMap -> [OSCTarget] -> IO (MVar ControlPattern, MVar T.Tempo, [Cx])-startStream config cMapMV targets+startStream :: Config -> MVar StateMap -> [OSCTarget] -> IO (MVar ControlPattern, MVar T.Tempo, [Cx])+startStream config sMapMV targets = do cxs <- mapM (\target -> do u <- O.openUDP (oAddress target) (oPort target) return $ Cx {cxUDP = u, cxTarget = target } ) targets pMV <- newMVar empty- (tempoMV, _) <- T.clocked config $ onTick config cMapMV pMV cxs+ (tempoMV, _) <- T.clocked config $ onTick config sMapMV pMV cxs return $ (pMV, tempoMV, cxs) @@ -135,6 +135,9 @@ toDatum (VF x) = O.float x toDatum (VI x) = O.int32 x toDatum (VS x) = O.string x+toDatum (VR x) = O.float $ ((fromRational x) :: Double)+toDatum (VB True) = O.int32 (1 :: Int)+toDatum (VB False) = O.int32 (0 :: Int) toData :: OSCTarget -> Event ControlMap -> Maybe [O.Datum] toData target e@@ -171,14 +174,14 @@ return () doCps _ _ = return () -onTick :: Config -> MVar ControlMap -> MVar ControlPattern -> [Cx] -> MVar T.Tempo -> T.State -> IO ()-onTick config cMapMV pMV cxs tempoMV st =+onTick :: Config -> MVar StateMap -> MVar ControlPattern -> [Cx] -> MVar T.Tempo -> T.State -> IO ()+onTick config sMapMV pMV cxs tempoMV st = do p <- readMVar pMV- cMap <- readMVar cMapMV+ sMap <- readMVar sMapMV tempo <- readMVar tempoMV now <- O.time- let cMap' = Map.insert "_cps" (VF $ T.cps tempo) cMap- es = filter eventHasOnset $ query p (State {arc = T.nowArc st, controls = cMap'})+ let sMap' = Map.insert "_cps" (pure $ VF $ T.cps tempo) sMap+ es = filter eventHasOnset $ query p (State {arc = T.nowArc st, controls = sMap'}) on e = (sched tempo $ start $ whole e) + eventNudge e eventNudge e = fromJust $ getF $ fromMaybe (VF 0) $ Map.lookup "nudge" $ value e messages target = catMaybes $ map (\e -> do m <- toMessage (on e + latency target) target tempo e@@ -237,9 +240,9 @@ input <- takeMVar $ sInput s -- put change time in control input now <- O.time- let cycle = T.timeToCycles tempo now+ let cyc = T.timeToCycles tempo now putMVar (sInput s) $- Map.insert ("_t_all") (VR cycle) $ Map.insert ("_t_" ++ show k) (VR cycle) input+ Map.insert ("_t_all") (pure $ VR cyc) $ Map.insert ("_t_" ++ show k) (pure $ VR cyc) input -- update the pattern itself pMap <- seq x $ takeMVar $ sPMapMV s let playState = updatePS $ Map.lookup (show k) pMap@@ -269,7 +272,7 @@ streamOnce :: Stream -> ControlPattern -> IO () streamOnce st p- = do cMap <- readMVar (sInput st)+ = do sMap <- readMVar (sInput st) tempo <- readMVar (sTempoMV st) now <- O.time let fakeTempo = T.Tempo {T.cps = T.cps tempo,@@ -278,9 +281,9 @@ T.paused = False, T.nudged = 0 }- cMap' = Map.insert "_cps" (VF $ T.cps tempo) cMap+ sMap' = Map.insert "_cps" (pure $ VF $ T.cps tempo) sMap es = filter eventHasOnset $ query p (State {arc = (Arc 0 1),- controls = cMap'+ controls = sMap' } ) at e = sched fakeTempo $ start $ whole e@@ -328,6 +331,27 @@ streamAll s f = do _ <- swapMVar (sGlobalFMV s) f calcOutput s +streamSet :: Valuable a => Stream -> String -> Pattern a -> IO ()+streamSet s k pat = do sMap <- takeMVar $ sInput s+ let pat' = toValue <$> pat+ sMap' = Map.insert k pat' sMap+ putMVar (sInput s) $ sMap'++streamSetI :: Stream -> String -> Pattern Int -> IO ()+streamSetI = streamSet++streamSetF :: Stream -> String -> Pattern Double -> IO ()+streamSetF = streamSet++streamSetS :: Stream -> String -> Pattern String -> IO ()+streamSetS = streamSet++streamSetB :: Stream -> String -> Pattern Bool -> IO ()+streamSetB = streamSet++streamSetR :: Stream -> String -> Pattern Rational -> IO ()+streamSetR = streamSet+ calcOutput :: Stream -> IO () calcOutput s = do pMap <- readMVar $ sPMapMV s globalF <- (readMVar $ sGlobalFMV s)@@ -344,13 +368,13 @@ startMulti :: [OSCTarget] -> Config -> IO Stream startMulti targets config =- do cMapMV <- newMVar (Map.empty :: ControlMap)- listenTid <- ctrlListen cMapMV config- (pMV, tempoMV, cxs) <- startStream config cMapMV targets+ do sMapMV <- newMVar (Map.empty :: StateMap)+ listenTid <- ctrlListen sMapMV config+ (pMV, tempoMV, cxs) <- startStream config sMapMV targets pMapMV <- newMVar Map.empty globalFMV <- newMVar id return $ Stream {sConfig = config,- sInput = cMapMV,+ sInput = sMapMV, sListenTid = listenTid, sOutput = pMV, sPMapMV = pMapMV,@@ -359,8 +383,8 @@ sCxs = cxs } -ctrlListen :: MVar ControlMap -> Config -> IO (Maybe ThreadId)-ctrlListen cMapMV c+ctrlListen :: MVar StateMap -> Config -> IO (Maybe ThreadId)+ctrlListen sMapMV c | cCtrlListen c = do putStrLn $ "Listening for controls on " ++ cCtrlAddr c ++ ":" ++ show (cCtrlPort c) catchAny run (\_ -> do putStrLn $ "Control listen failed. Perhaps there's already another tidal instance listening on that port?" return Nothing@@ -383,27 +407,12 @@ = add (O.ascii_to_string k) (VI $ fromIntegral v) act m = putStrLn $ "Unhandled OSC: " ++ show m add :: String -> Value -> IO ()- add k v = do cMap <- takeMVar cMapMV- putMVar cMapMV $ Map.insert k v cMap+ add k v = do sMap <- takeMVar sMapMV+ putMVar sMapMV $ Map.insert k (pure v) sMap return () catchAny :: IO a -> (E.SomeException -> IO a) -> IO a catchAny = E.catch -{--listenCMap :: MVar ControlMap -> IO ()-listenCMap cMapMV = do sock <- O.udpServer "127.0.0.1" (6011)- _ <- forkIO $ loop sock- return ()- where loop sock =- do ms <- O.recvMessages sock- mapM_ readMessage ms- loop sock- readMessage (O.Message _ (O.ASCII_String k:v@(O.Float _):[])) = add (O.ascii_to_string k) (VF $ fromJust $ O.datum_floating v)- readMessage (O.Message _ (O.ASCII_String k:O.ASCII_String v:[])) = add (O.ascii_to_string k) (VS $ O.ascii_to_string v)- readMessage (O.Message _ (O.ASCII_String k:O.Int32 v:[])) = add (O.ascii_to_string k) (VI $ fromIntegral v)- readMessage _ = return ()- add :: String -> Value -> IO ()- add k v = do cMap <- takeMVar cMapMV- putMVar cMapMV $ Map.insert k v cMap- return ()--}+++
src/Sound/Tidal/UI.hs view
@@ -156,7 +156,7 @@ chooseBy :: Pattern Double -> [a] -> Pattern a chooseBy _ [] = silence-chooseBy f xs = (xs !!) . floor <$> range 0 (fromIntegral $ length xs) f+chooseBy f xs = (xs !!!) . floor <$> range 0 (fromIntegral $ length xs) f {- | Like @choose@, but works on an a list of tuples of values and weights @@ -1293,17 +1293,8 @@ -- | @arpeggiate@ finds events that share the same timespan, and spreads -- them out during that timespan, so for example @arpeggiate "[bd,sn]"@ -- gets turned into @"bd sn"@. Useful for creating arpeggios/broken chords.-arpeggiate :: Pattern a -> Pattern a-arpeggiate p = withEvents munge p- where munge es = concatMap spreadOut (groupBy (\a b -> whole a == whole b) es)- spreadOut xs = mapMaybe (\(n, x) -> shiftIt n (length xs) x) $ enumerate xs- shiftIt n d (Event (Arc s e) a' v) =- do- a'' <- subArc (Arc newS newE) a'- return (Event (Arc newS newE) a'' v)- where newS = s + (dur * fromIntegral n)- newE = newS + dur- dur = (e - s) / fromIntegral d+arpeggiate :: Pattern a -> Pattern a +arpeggiate = arpWith id -- | Shorthand alias for arpeggiate arpg :: Pattern a -> Pattern a@@ -1311,7 +1302,7 @@ arpWith :: ([EventF (ArcF Time) a] -> [EventF (ArcF Time) b]) -> Pattern a -> Pattern b arpWith f p = withEvents munge p- where munge es = concatMap (spreadOut . f) (groupBy (\a b -> whole a == whole b) es)+ where munge es = concatMap (spreadOut . f) (groupBy (\a b -> whole a == whole b) $ sortOn whole es) spreadOut xs = mapMaybe (\(n, x) -> shiftIt n (length xs) x) $ enumerate xs shiftIt n d (Event (Arc s e) a' v) = do@@ -1785,3 +1776,21 @@ squeeze :: Pattern Int -> [Pattern a] -> Pattern a squeeze _ [] = silence squeeze ipat pats = squeezeJoin $ (pats !!!) <$> ipat+++squeezeJoinUp :: Pattern (ControlPattern) -> ControlPattern+squeezeJoinUp pp = pp {query = q}+ where q st = concatMap+ (\(Event w p v) ->+ mapMaybe (munge w p) $ query (compressArc (cycleArc w) (v |* P.speed (pure $ fromRational $ 1/(stop w - start w)))) st {arc = p}+ )+ (query pp st)+ munge oWhole oPart (Event iWhole iPart v) =+ do w' <- subArc oWhole iWhole+ p' <- subArc oPart iPart+ return (Event w' p' v)++chew :: Int -> Pattern Int -> ControlPattern -> ControlPattern+chew n ipat pat = (squeezeJoinUp $ zoompat <$> ipat) |/ P.speed (pure $ fromIntegral n)+ where zoompat i = zoom (i'/(fromIntegral n), (i'+1)/(fromIntegral n)) (pat)+ where i' = fromIntegral $ i `mod` n
src/Sound/Tidal/Version.hs view
@@ -1,4 +1,4 @@ module Sound.Tidal.Version where tidal_version :: String-tidal_version = "1.0.13"+tidal_version = "1.0.14"
test/Sound/Tidal/ParseTest.hs view
@@ -9,6 +9,7 @@ import Sound.Tidal.Core import Sound.Tidal.Pattern+import Sound.Tidal.UI (_degradeBy) run :: Microspec () run =@@ -34,6 +35,34 @@ compareP (Arc 0 2) ("a*8" :: Pattern String) (fast 8 "a")+ it "can elongate with _" $ do+ compareP (Arc 0 2)+ ("a _ _ b _" :: Pattern String)+ (timeCat [(3,"a"), (2,"b")])+ it "can replicate with !" $ do+ compareP (Arc 0 2)+ ("a! b" :: Pattern String)+ (fastCat ["a", "a", "b"])+ it "can replicate with ! and number" $ do+ compareP (Arc 0 2)+ ("a!3 b" :: Pattern String)+ (fastCat ["a", "a", "a", "b"])+ it "can degrade with ?" $ do+ compareP (Arc 0 1)+ ("a?" :: Pattern String)+ (degradeByDefault "a")+ it "can degrade with ? and number" $ do+ compareP (Arc 0 1)+ ("a?0.2" :: Pattern String)+ (_degradeBy 0.2 "a")+ it "can degrade with ? for double patterns" $ do+ compareP (Arc 0 1)+ ("0.4 0.5? 0.6" :: Pattern Double)+ (fastcat[0.4, degradeByDefault 0.5, 0.6])+ it "can stretch with @" $ do+ comparePD (Arc 0 1)+ ("a@2 b" :: Pattern String)+ (timeCat [(2, "a"),(1,"b")]) it "can do polymeter with {}" $ do compareP (Arc 0 2) ("{a b, c d e}" :: Pattern String)@@ -66,3 +95,4 @@ compareP (Arc 0 2) ("cp(5,c)" :: Pattern String) (silence)+ where degradeByDefault = _degradeBy 0.5
test/Sound/Tidal/PatternTest.hs view
@@ -248,7 +248,7 @@ describe "controlI" $ do it "can retrieve values from state" $- (query (pure 3 + cF_ "hello") $ State (Arc 0 1) (Map.singleton "hello" (VF 0.5)))+ (query (pure 3 + cF_ "hello") $ State (Arc 0 1) (Map.singleton "hello" (pure $ VF 0.5))) `shouldBe` [(Event (Arc (0 % 1) (1 % 1)) (Arc (0 % 1) (1 % 1)) 3.5)] describe "wholeStart" $ do @@ -480,17 +480,20 @@ it "get Just value when Int value is supplied" $ do let res = getI (VI 3) property $ (Just 3) === res- it "get Nothing if Int value is not supplied" $ do- let res = getI (VF 3)+ it "get floored value when float value is supplied" $ do+ let res = getI (VF 3.5)+ property $ (Just 3) === res+ it "get Nothing if String value is supplied" $ do+ let res = getI (VS "3") property $ Nothing === res - describe "getf" $ do + describe "getF" $ do it "get Just value when Float value is supplied" $ do let res = getF (VF 3) property $ (Just 3.0) === res- it "get Nothing if Int value is not supplied" $ do+ it "get converted value if Int value is supplied" $ do let res = getF (VI 3)- property $ Nothing === res+ property $ (Just 3.0) === res describe "getS" $ do it "get Just value when String value is supplied" $ do
test/Sound/Tidal/UITest.hs view
@@ -119,6 +119,7 @@ it "at 1/2 of a cycle" $ (queryArc (Sound.Tidal.UI.range 10 10 saw) (Arc 0.5 0.5)) `shouldBe` fmap toEvent [(((0.5, 0.5), (0.5, 0.5)), 10 :: Float)]+ describe "rot" $ do it "rotates values in a pattern irrespective of structure" $ property $ comparePD (Arc 0 2)@@ -249,3 +250,27 @@ compareP (Arc 0 4) (bite 4 "0 2*2" (Sound.Tidal.Core.run 8)) ("[0 1] [4 5]*2" :: Pattern Int)++ describe "chooseBy" $ do+ it "chooses from elements based on closest scaled double value" $ do+ compareP (Arc 0 4)+ (("0"::Pattern Int) |+ chooseBy ((/ 4)$(sig fromRational)) [0,1,2,3])+ ("<0 1 2 3>"::Pattern Int)+ it "never gets an index out of bounds" $ do+ compareP (Arc 0 4)+ (("0"::Pattern Int) |+ chooseBy (sig fromRational) [0,1,2,3])+ ("<0>"::Pattern Int)++ describe "arpeggiate" $ do + it "can arpeggiate" $ do + compareP (Arc 0 1) + (arpeggiate ("[bd, sn] [hh:1, cp]" :: Pattern String))+ ("bd sn hh:1 cp" :: Pattern String)+ it "can arpeggiate" $ do+ compareP (Arc 0 4)+ (arpeggiate $ "[0,0] [0,0]")+ ("0 0 0 0" :: Pattern Int)+ it "can arpeggiate a 'sped up' pattern" $ do+ compareP (Arc 0 4)+ (arpeggiate $ "[0,0]*2")+ ("0 0 0 0" :: Pattern Int)
tidal.cabal view
@@ -1,5 +1,5 @@ name: tidal-version: 1.0.13+version: 1.0.14 synopsis: Pattern language for improvised music -- description: homepage: http://tidalcycles.org/@@ -54,18 +54,18 @@ , colour < 2.4 , hosc < 0.18 , text < 1.3- , parsec < 3.2- , network < 3.1+ , parsec >= 3.1.12 && < 3.2+ , network < 3.2 , mwc-random < 0.15 , vector < 0.13 , bifunctors < 5.6- , transformers < 0.5.7+ , transformers >= 0.5 && < 0.5.7 , template-haskell >= 2.10.0.0 && < 2.15 , bytestring < 0.11- , clock < 0.8+ , clock < 0.9 if !impl(ghc >= 8.4.1)- build-depends: semigroups == 0.18.*+ build-depends: semigroups >= 0.18 && < 0.20 test-suite tests type: exitcode-stdio-1.0