tidal 1.7.9 → 1.7.10
raw patch · 12 files changed
+403/−6 lines, 12 filesdep +asyncdep +exceptionsdep +hintnew-component:exe:tidal
Dependencies added: async, exceptions, hint, mtl
Files
- BootTidal.hs +1/−0
- CHANGELOG.md +10/−0
- main/Main.hs +139/−0
- src/Sound/Tidal/ID.hs +2/−1
- src/Sound/Tidal/Params.hs +26/−0
- src/Sound/Tidal/Pattern.hs +3/−1
- src/Sound/Tidal/Safe/Boot.hs +85/−0
- src/Sound/Tidal/Safe/Context.hs +105/−0
- src/Sound/Tidal/Transition.hs +4/−0
- src/Sound/Tidal/Version.hs +1/−1
- test/Sound/Tidal/UITest.hs +11/−1
- tidal.cabal +16/−2
BootTidal.hs view
@@ -40,6 +40,7 @@ jumpIn i t = transition tidal True (Sound.Tidal.Transition.jumpIn t) i jumpIn' i t = transition tidal True (Sound.Tidal.Transition.jumpIn' t) i jumpMod i t = transition tidal True (Sound.Tidal.Transition.jumpMod t) i+ jumpMod' i t p = transition tidal True (Sound.Tidal.Transition.jumpMod' t p) i mortal i lifespan release = transition tidal True (Sound.Tidal.Transition.mortal lifespan release) i interpolate i = transition tidal True (Sound.Tidal.Transition.interpolate) i interpolateIn i t = transition tidal True (Sound.Tidal.Transition.interpolateIn t) i
CHANGELOG.md view
@@ -1,5 +1,15 @@ # TidalCycles log of changes +## 1.7.10 - Tama b++* Derive RealFrac for Note by @ndr-brt in https://github.com/tidalcycles/Tidal/pull/876+* Add timescale and timewin control params by @yaxu in https://github.com/tidalcycles/Tidal/pull/878+* deriving typeclass memberships for ID by @polymorphicengine in https://github.com/tidalcycles/Tidal/pull/879+* Adds the jumpMod' transition by @th-four in https://github.com/tidalcycles/Tidal/pull/881+* Import safe-tidal-cli ghci simulator as tidal binary by @yaxu in https://github.com/tidalcycles/Tidal/pull/880+* Tweaks to tidal binary, and add to linux workflow by @yaxu in https://github.com/tidalcycles/Tidal/pull/882+* add tidal ghci replacement to macos and windows workflows by @yaxu in https://github.com/tidalcycles/Tidal/pull/883+ ## 1.7.9 - Tama ### What's Changed
+ main/Main.hs view
@@ -0,0 +1,139 @@+{-+ Tidal REPL - mimicking ghci++ Copyright (C) 2021 Johannes Waldmann and contributors++ Forked from:+ https://github.com/jwaldmann/safe-tidal-cli/++ This library is free software: you can redistribute it and/or modify+ it under the terms of the GNU General Public License as published by+ the Free Software Foundation, either version 3 of the License, or+ (at your option) any later version.++ This library is distributed in the hope that it will be useful,+ but WITHOUT ANY WARRANTY; without even the implied warranty of+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the+ GNU General Public License for more details.++ You should have received a copy of the GNU General Public License+ along with this library. If not, see <http://www.gnu.org/licenses/>.+-}++{-# language PatternSignatures, LambdaCase #-}++import qualified Language.Haskell.Interpreter as I+import qualified Sound.Tidal.Safe.Context as C+import Control.Monad (void)+import Control.Exception (throw)+import Control.Monad.IO.Class ( MonadIO(liftIO) )+import Control.Monad.Catch+ ( SomeException, MonadCatch(catch), catches, Handler(Handler) )+-- import qualified Mueval.Resources as MR+import System.Timeout ( timeout )+import System.IO ( hFlush, stderr, stdout, hPutStrLn, Handle )+import Data.Char (isSpace)+import Data.List (isPrefixOf)++main :: IO()+main = do+ + -- from BootTidal.hs:+ tidal <- C.startTidal+ (C.superdirtTarget+ { C.oLatency = 0.1, C.oAddress = "127.0.0.1"+ , C.oPort = 57120})+ (C.defaultConfig {C.cFrameTimespan = 1/20})+ + void $ I.runInterpreter+ $ catch (core tidal)+ $ \ (e :: SomeException) -> message stderr $ show e++core :: C.Stream -> I.InterpreterT IO ()+core tidal = do+ message stdout "[tidal] starting..."+ -- more settings at+ -- https://github.com/tidalcycles/tidali/blob/master/src/Main.hs+ I.set [ I.languageExtensions+ I.:= [ I.OverloadedStrings ]+ , I.installedModulesInScope I.:= False+ ]+ I.setImports+ [ "Prelude"+ , "Sound.Tidal.Safe.Context"+ , "Sound.Tidal.Safe.Boot"+ ]+ -- FIXME: replace lazy IO by some streaming mechanism?+ message stdout "[tidal] modules loaded..."+ input <- liftIO getContents + message stdout "[tidal] ready"+ mapM_ (work tidal . unlines) $ blocks $ lines input+ message stdout "safe-tidal-cli is done"++second :: Int+second = 10^6 :: Int++-- | will show at most 10 lines, at most 80 chars per line,+-- and run (evaluation and print) for at most 1 second+message :: Handle -> String -> I.InterpreterT IO ()+message h s = do+ let safe = unlines . safe_list 20 ["..."] . map (safe_list 120 "...") . lines+ liftIO $ void $ timeout (1 * second) $ do+ hPutStrLn h (safe s) ; hFlush h+++-- | if `length xs <= c`, then `xs`, else `xs <> msg`+safe_list :: Int -> [a] -> [a] -> [a]+safe_list n msg xs =+ let (pre,post) = splitAt n xs+ in if null post then pre+ else pre <> msg++work :: C.Stream -> String -> I.InterpreterT IO ()+work tidal contents = + ( if take 2 contents `elem` [ ":t", ":i", ":d", ":s" ]+ then do+ -- https://github.com/haskell-hint/hint/issues/101+ message stderr $ "not implemented " <> contents+ else + I.typeChecksWithDetails contents >>= \ case+ Left errs -> throw $ I.WontCompile errs+ Right s ->+ if s == "Op ()" then do -- execute, print nothing+ -- TODO: need timeout for evaluation of pattern:+ x <- I.interpret contents (I.as :: C.Op ())+ -- have timeout for execution of pattern:+ liftIO $ void $ timeout (1 * second) $ C.exec tidal x+ else do -- print type and value+ message stdout $ "type : " <> s+ if isPrefixOf "IO" s then do+ message stderr "cannot show value, will not execute action"+ else do+ v <- I.eval contents+ message stdout $ "value: " <> v+ )+ `catches`+ [ Handler $ \ (e :: I.InterpreterError) ->+ message stderr $ unlines $ case e of+ I.UnknownError s -> [ "UnknownError", s ]+ I.WontCompile gs -> "WontCompile" : map I.errMsg gs+ I.NotAllowed s -> [ "NotAllowed", s ]+ I.GhcException s -> [ "GhcException", s ]+ , Handler $ \ (e :: SomeException) ->+ message stderr $ show e+ ]++-- | Mimicking ghci, where a block is wrapped in `:{` and `:}`, on otherwise empty lines.++blocks :: [String] -> [[String]]+blocks [] = []+blocks (":{":ls) = b:(blocks ls')+ where (b, ls') = block ls+blocks (l:ls) = [l]:(blocks ls)++block :: [String] -> ([String], [String])+block [] = ([],[])+block (":}":ls) = ([],ls)+block (l:ls) = (l:b, ls')+ where (b, ls') = block ls+
src/Sound/Tidal/ID.hs view
@@ -23,7 +23,8 @@ -- | Wrapper for literals that can be coerced to a string and used as an identifier. -- | Similar to Show typeclass, but constrained to strings and integers and designed -- | so that similar cases (such as 1 and "1") convert to the same value.-newtype ID = ID { fromID :: String }+newtype ID = ID { fromID :: String } deriving (Eq, Show, Ord, Read)+ noOv :: String -> a noOv meth = error $ meth ++ ": not supported for ids"
src/Sound/Tidal/Params.hs view
@@ -2727,6 +2727,32 @@ sustainpedalrecv :: Pattern Int -> ControlPattern sustainpedalrecv busid = pI "^sustainpedal" busid +-- | time stretch amount+timescale :: Pattern Double -> ControlPattern+timescale = pF "timescale"+timescaleTake :: String -> [Double] -> ControlPattern+timescaleTake name xs = pStateListF "timescale" name xs+timescaleCount :: String -> ControlPattern+timescaleCount name = pStateF "timescale" name (maybe 0 (+1))+timescaleCountTo :: String -> Pattern Double -> Pattern ValueMap+timescaleCountTo name ipat = innerJoin $ (\i -> pStateF "timescale" name (maybe 0 ((`mod'` i) . (+1)))) <$> ipat++timescalebus :: Pattern Int -> Pattern Double -> ControlPattern+timescalebus _ _ = error $ "Control parameter 'timescale' can't be sent to a bus."++-- | time stretch window size+timescalewin :: Pattern Double -> ControlPattern+timescalewin = pF "timescalewin"+timescalewinTake :: String -> [Double] -> ControlPattern+timescalewinTake name xs = pStateListF "timescalewin" name xs+timescalewinCount :: String -> ControlPattern+timescalewinCount name = pStateF "timescalewin" name (maybe 0 (+1))+timescalewinCountTo :: String -> Pattern Double -> Pattern ValueMap+timescalewinCountTo name ipat = innerJoin $ (\i -> pStateF "timescalewin" name (maybe 0 ((`mod'` i) . (+1)))) <$> ipat++timescalewinbus :: Pattern Int -> Pattern Double -> ControlPattern+timescalewinbus _ _ = error $ "Control parameter 'timescalewin' can't be sent to a bus."+ -- | for internal sound routing to :: Pattern Double -> ControlPattern to = pF "to"
src/Sound/Tidal/Pattern.hs view
@@ -669,7 +669,9 @@ type ValueMap = Map.Map String Value -- | Note is Double, but with a different parser-newtype Note = Note { unNote :: Double } deriving (Typeable, Data, Generic, Eq, Ord, Enum, Num, Fractional, Floating, Real)+newtype Note = Note { unNote :: Double }+ deriving (Typeable, Data, Generic, Eq, Ord, Enum, Num, Fractional, Floating, Real, RealFrac)+ instance NFData Note instance Show Note where
+ src/Sound/Tidal/Safe/Boot.hs view
@@ -0,0 +1,85 @@+{-+ Safe/Boot.hs - as in BootTidal but in the Op monad+ Copyright (C) 2021 Johannes Waldmann and contributors++ Forked from:+ https://github.com/jwaldmann/safe-tidal-cli/++ This library is free software: you can redistribute it and/or modify+ it under the terms of the GNU General Public License as published by+ the Free Software Foundation, either version 3 of the License, or+ (at your option) any later version.++ This library is distributed in the hope that it will be useful,+ but WITHOUT ANY WARRANTY; without even the implied warranty of+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the+ GNU General Public License for more details.++ You should have received a copy of the GNU General Public License+ along with this library. If not, see <http://www.gnu.org/licenses/>.+-}++{-# language NoMonomorphismRestriction #-}++module Sound.Tidal.Safe.Boot where++import Sound.Tidal.Safe.Context+import qualified Sound.Tidal.Transition++-- everyone is missing the tidal :: Stream argument+-- this will be provided by the Reader monad++p = streamReplace+hush = streamHush+list = streamList+mute = streamMute+unmute = streamUnmute+solo = streamSolo+unsolo = streamUnsolo+once = streamOnce+first = streamFirst+asap = once+nudgeAll = streamNudgeAll+all = streamAll+resetCycles = streamResetCycles+setcps = asap . cps+xfade i = transition True (Sound.Tidal.Transition.xfadeIn 4) i+xfadeIn i t = transition True (Sound.Tidal.Transition.xfadeIn t) i+histpan i t = transition True (Sound.Tidal.Transition.histpan t) i+wait i t = transition True (Sound.Tidal.Transition.wait t) i+waitT i f t = transition True (Sound.Tidal.Transition.waitT f t) i+jump i = transition True (Sound.Tidal.Transition.jump) i+jumpIn i t = transition True (Sound.Tidal.Transition.jumpIn t) i+jumpIn' i t = transition True (Sound.Tidal.Transition.jumpIn' t) i+jumpMod i t = transition True (Sound.Tidal.Transition.jumpMod t) i+mortal i lifespan release = transition True (Sound.Tidal.Transition.mortal lifespan release) i+interpolate i = transition True (Sound.Tidal.Transition.interpolate) i+interpolateIn i t = transition True (Sound.Tidal.Transition.interpolateIn t) i+clutch i = transition True (Sound.Tidal.Transition.clutch) i+clutchIn i t = transition True (Sound.Tidal.Transition.clutchIn t) i+anticipate i = transition True (Sound.Tidal.Transition.anticipate) i+anticipateIn i t = transition True (Sound.Tidal.Transition.anticipateIn t) i+forId i t = transition False (Sound.Tidal.Transition.mortalOverlay t) i++d1 = p 1 . (|< orbit 0)+d2 = p 2 . (|< orbit 1)+d3 = p 3 . (|< orbit 2)+d4 = p 4 . (|< orbit 3)+d5 = p 5 . (|< orbit 4)+d6 = p 6 . (|< orbit 5)+d7 = p 7 . (|< orbit 6)+d8 = p 8 . (|< orbit 7)+d9 = p 9 . (|< orbit 8)+d10 = p 10 . (|< orbit 9)+d11 = p 11 . (|< orbit 10)+d12 = p 12 . (|< orbit 11)+d13 = p 13+d14 = p 14+d15 = p 15+d16 = p 16++setI = streamSetI+setF = streamSetF+setS = streamSetS+setR = streamSetR+setB = streamSetB
+ src/Sound/Tidal/Safe/Context.hs view
@@ -0,0 +1,105 @@+{-+ Safe/Context.hs - wraps UI functions+ Copyright (C) 2021 Johannes Waldmann and contributors++ Forked from:+ https://github.com/jwaldmann/safe-tidal-cli/++ This library is free software: you can redistribute it and/or modify+ it under the terms of the GNU General Public License as published by+ the Free Software Foundation, either version 3 of the License, or+ (at your option) any later version.++ This library is distributed in the hope that it will be useful,+ but WITHOUT ANY WARRANTY; without even the implied warranty of+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the+ GNU General Public License for more details.++ You should have received a copy of the GNU General Public License+ along with this library. If not, see <http://www.gnu.org/licenses/>.+-}++{-# language GeneralizedNewtypeDeriving #-}+{-# language NoMonomorphismRestriction #-}++module Sound.Tidal.Safe.Context+ ( Op () -- do not export constructor,+ -- so the user has no way of putting arbitraty IO stuff+ -- in "Op", and below "run"+ , exec+ , streamReplace+ , streamHush+ , streamList+ , streamMute+ , streamUnmute+ , streamSolo+ , streamUnsolo+ , streamOnce+ , streamFirst+ , streamNudgeAll+ , streamAll+ , streamResetCycles+ , streamSetI+ , streamSetF+ , streamSetS+ , streamSetR+ , streamSetB+ , transition+ , module C+ , startTidal, superdirtTarget, Target(..)+ )+where++import Data.Ratio as C+import Sound.Tidal.Carabiner as C+import Sound.Tidal.Config as C+import Sound.Tidal.Control as C+import Sound.Tidal.Core as C+import Sound.Tidal.Params as C+import Sound.Tidal.ParseBP as C+import Sound.Tidal.Pattern as C+import Sound.Tidal.Scales as C+import Sound.Tidal.Simple as C+import Sound.Tidal.Stream+ (startTidal, superdirtTarget, Target(..))+-- import Sound.Tidal.Transition as C+import Sound.Tidal.UI as C+import Sound.Tidal.Version as C+import Sound.Tidal.EspGrid as C++import qualified Sound.Tidal.Context as C+import Sound.Tidal.Context+ (Stream, Pattern, ControlPattern, Time)+import Control.Monad.Reader+import Control.Monad.Catch++newtype Op r = Op ( ReaderT Stream IO r )+ deriving (Functor, Applicative, Monad, MonadCatch,MonadThrow)++exec :: Stream -> Op r -> IO r+exec s (Op m) = runReaderT m s++op1 f = Op $ do a <- ask; lift $ f a+op2 f b = Op $ do a <- ask; lift $ f a b +op3 f b c = Op $ do a <- ask; lift $ f a b c+op4 f b c d = Op $ do a <- ask; lift $ f a b c d+op5 f b c d e = Op $ do a <- ask; lift $ f a b c d e++streamReplace = op3 C.streamReplace+streamHush = op1 C.streamHush+streamList = op1 C.streamList+streamMute = op2 C.streamMute+streamUnmute = op2 C.streamUnmute+streamSolo = op2 C.streamSolo+streamUnsolo = op2 C.streamUnsolo+streamOnce = op2 C.streamOnce+streamFirst = op2 C.streamFirst+streamNudgeAll = op2 C.streamNudgeAll+streamAll = op2 C.streamAll+streamResetCycles = op1 C.streamResetCycles+transition = op5 C.transition+streamSetI = op3 C.streamSetI+streamSetF = op3 C.streamSetF+streamSetS = op3 C.streamSetS+streamSetR = op3 C.streamSetR+streamSetB = op3 C.streamSetB
src/Sound/Tidal/Transition.hs view
@@ -143,6 +143,10 @@ jumpMod :: Int -> Time -> [ControlPattern] -> ControlPattern jumpMod n now = jumpIn' ((n-1) - ((floor now) `mod` n)) now +-- | Sharp `jump` transition at next cycle boundary where cycle mod n == p+jumpMod' :: Int -> Int -> Time -> [ControlPattern] -> ControlPattern+jumpMod' n p now = Sound.Tidal.Transition.jumpIn' ((n-1) - ((floor now) `mod` n) + p) now+ -- | Degrade the new pattern over time until it ends in silence mortal :: Time -> Time -> Time -> [ControlPattern] -> ControlPattern mortal _ _ _ [] = silence
src/Sound/Tidal/Version.hs view
@@ -21,7 +21,7 @@ -} tidal_version :: String-tidal_version = "1.7.9"+tidal_version = "1.7.10" tidal_status :: IO () tidal_status = tidal_status_string >>= putStrLn
test/Sound/Tidal/UITest.hs view
@@ -344,29 +344,39 @@ compareP (Arc 0 1) (off "-e" id $ s "0") (superimpose ("e" <~) $ s "0")+ describe "loopFirst" $ do it "plays the first cycle" $ do compareP (Arc 0 1) (loopFirst $ rotL 3 $ slow 8 $ "0 .. 7" :: Pattern Int) ("3")+ describe "loopCycles" $ do it "plays the first n cycles" $ do compareP (Arc 0 1) (loopFirst $ rotL 3 $ slow 8 $ "0 .. 7" :: Pattern Int) ("3")+ describe "timeLoop" $ do it "can loop time" $ do compareP (Arc 0 1) ((3 <~) $ (timeLoop 3 $ sound "<a b c d>")) (sound "a")+ describe "timeLoop" $ do it "can pattern time" $ do compareP (Arc 0 1) ((1 <~) $ timeLoop "<2 1>" $ sound "b") (sound "b")+ describe "necklace" $ do it "can specify rhythm by IOI" $ do compareP (Arc 0 1) (necklace 12 [4,2]) ("t f f f t f t f f f t f")- ++ describe "quantise" $ do+ it "can quantise notes" $ do+ compareP (Arc 0 1)+ (segment 2 $ quantise 1 $ sine :: Pattern Note)+ ("1 0" :: Pattern Note)
tidal.cabal view
@@ -1,5 +1,5 @@ name: tidal-version: 1.7.9+version: 1.7.10 synopsis: Pattern language for improvised music description: Tidal is a domain specific language for live coding patterns. homepage: http://tidalcycles.org/@@ -33,11 +33,14 @@ Sound.Tidal.Control Sound.Tidal.Context Sound.Tidal.Core+ Sound.Tidal.EspGrid Sound.Tidal.ID Sound.Tidal.Params Sound.Tidal.ParseBP Sound.Tidal.Pattern Sound.Tidal.Scales+ Sound.Tidal.Safe.Context+ Sound.Tidal.Safe.Boot Sound.Tidal.Show Sound.Tidal.Simple Sound.Tidal.Stream@@ -47,7 +50,6 @@ Sound.Tidal.UI Sound.Tidal.Utils Sound.Tidal.Version- Sound.Tidal.EspGrid Paths_tidal Build-depends: base >=4.8 && <5@@ -64,7 +66,19 @@ , deepseq >= 1.1.0.0 , primitive < 0.8 , random < 1.3+ , exceptions < 0.11+ , mtl >= 2.2 +executable tidal+ hs-source-dirs: main+ main-is: Main.hs+ build-depends: base >=4.8 && < 5+ , tidal+ , hint < 0.10+ , exceptions < 0.11+ , async < 2.3+ default-language: Haskell2010+ test-suite tests type: exitcode-stdio-1.0 main-is: Test.hs