packages feed

tidal 0.4.30 → 0.4.31

raw patch · 6 files changed

+435/−52 lines, 6 filesdep +alsa-coredep +alsa-seqdep ~hosc

Dependencies added: alsa-core, alsa-seq

Dependency ranges changed: hosc

Files

Sound/Tidal/Dirt.hs view
@@ -12,6 +12,7 @@ import Data.Hashable import Data.Bits import Data.Maybe+import Data.Fixed import System.Process  import Sound.Tidal.Stream@@ -44,7 +45,8 @@                             F "hresonance" (Just 0),                             F "bandf" (Just 0),                             F "bandq" (Just 0),-                            S "unit" (Just "rate")+                            S "unit" (Just "rate"),+                            I "loop" (Just 1)                           ],                  cpsStamp = True,                  timestamp = MessageStamp,@@ -137,6 +139,7 @@ bandf        = makeF dirt "bandf" bandq        = makeF dirt "bandq" unit         = makeS dirt "unit"+loop         = makeI dirt "loop"  cut :: Pattern Int -> OscPattern cut = makeI dirt "cut"@@ -162,5 +165,9 @@ striateO :: OscPattern -> Int -> Double -> OscPattern striateO p n o = cat $ map (\x -> off (fromIntegral x) p) [0 .. n-1]   where off i p = p |+| begin ((atom $ (fromIntegral i / fromIntegral n) + o) :: Pattern Double) |+| end ((atom $ (fromIntegral (i+1) / fromIntegral n) + o) :: Pattern Double)++striateL :: Int -> Int -> OscPattern -> OscPattern+striateL n l p = striate n p |+| loop (atom $ fromIntegral l)+striateL' n f l p = striate' n f p |+| loop (atom $ fromIntegral l)  metronome = slow 2 $ sound (p "[odx, [hh]*8]")
Sound/Tidal/Pattern.hs view
@@ -27,26 +27,37 @@ -- | @show (p :: Pattern)@ returns a text string representing the -- event values active during the first cycle of the given pattern. instance (Show a) => Show (Pattern a) where-  show p@(Pattern _) = show $ arc p (0, 1)+  show p@(Pattern _) = intercalate " " $ map showEvent $ arc p (0, 1) +showTime t | denominator t == 1 = show (numerator t)+           | otherwise = show (numerator t) ++ ('/':show (denominator t))++showArc a = concat[showTime $ fst a, (' ':showTime (snd a))]++showEvent (a, b, v) | a == b = concat["(",show v,+                                      (' ':showArc a),+                                      ")"+                                     ]+                    | otherwise = show v+ instance Functor Pattern where   fmap f (Pattern a) = Pattern $ fmap (fmap (mapThd' f)) a  -- | @pure a@ returns a pattern with an event with value @a@, which -- has a duration of one cycle, and repeats every cycle. instance Applicative Pattern where-  pure x = Pattern $ \(s, e) -> map -                                (\t -> ((t%1, (t+1)%1), +  pure x = Pattern $ \(s, e) -> map+                                (\t -> ((t%1, (t+1)%1),                                         (t%1, (t+1)%1),                                         x                                        )-                                ) +                                )                                 [floor s .. ((ceiling e) - 1)]-  (Pattern fs) <*> (Pattern xs) = +  (Pattern fs) <*> (Pattern xs) =     Pattern $ \a -> concatMap applyX (fs a)-    where applyX ((s,e), (s', e'), f) = -            map (\(_, _, x) -> ((s,e), (s', e'), f x)) -                (filter +    where applyX ((s,e), (s', e'), f) =+            map (\(_, _, x) -> ((s,e), (s', e'), f x))+                (filter                  (\(_, a', _) -> isIn a' s)                  (xs (s',e'))                 )@@ -59,13 +70,15 @@  instance Monad Pattern where   return = pure+  -- Pattern a -> (a -> Pattern b) -> Pattern b+  -- Pattern Char -> (Char -> Pattern String) -> Pattern String+     p >>= f = -- unwrap (f <$> p)     Pattern (\a -> concatMap-                   -- TODO - this is a total guess-                   (\((s,e), (s',e'), x) -> mapSnds' (const (s',e')) $+                   (\((s,e), (s',e'), x) -> map (\ev -> ((s,e), (s',e'), thd' ev)) $                                             filter-                                            (\(_, a', _) -> isIn a' s)-                                            (arc (f x) (s',e'))+                                            (\(a', _, _) -> isIn a' s)+                                            (arc (f x) (s,e))                    )                    (arc p a)              )@@ -76,7 +89,7 @@ -- Take a pattern, and function from elements in the pattern to another pattern, -- and then return that pattern --bind :: Pattern a -> (a -> Pattern b) -> Pattern b---bind p f = +--bind p f =  -- this is actually join unwrap :: Pattern (Pattern a) -> Pattern a@@ -144,7 +157,7 @@   splitAtSam :: Pattern a -> Pattern a-splitAtSam p = +splitAtSam p =   splitQueries $ Pattern $ \(s,e) -> mapSnds' (trimArc (sam s)) $ arc p (s,e)   where trimArc s' (s,e) = (max (s') s, min (s'+1) e) @@ -203,11 +216,11 @@ -- return a pattern that is half the speed. slow :: Time -> Pattern a -> Pattern a slow 0 = id-slow t = density (1/t) +slow t = density (1/t)  -- | The @<~@ operator shifts (or rotates) a pattern to the left (or--- counter-clockwise) by the given @Time@ value. For example --- @(1%16) <~ p@ will return a pattern with all the events moved +-- counter-clockwise) by the given @Time@ value. For example+-- @(1%16) <~ p@ will return a pattern with all the events moved -- one 16th of a cycle to the left. (<~) :: Time -> Pattern a -> Pattern a (<~) t p = withResultTime (subtract t) $ withQueryTime (+ t) p@@ -333,7 +346,7 @@ -- todo - triangular waves again  squarewave1 :: Pattern Double-squarewave1 = sig $ +squarewave1 = sig $               \t -> fromIntegral $ floor $ (mod' (fromRational t) 1) * 2 square1 = squarewave1 @@ -371,12 +384,12 @@  -- Filter out events that have had their onsets cut off filterOnsets :: Pattern a -> Pattern a-filterOnsets (Pattern f) = +filterOnsets (Pattern f) =   Pattern $ (filter (\e -> eventOnset e >= eventStart e)) . f  -- Filter events which have onsets, which are within the given range filterStartInRange :: Pattern a -> Pattern a-filterStartInRange (Pattern f) = +filterStartInRange (Pattern f) =   Pattern $ \(s,e) -> filter ((>= s) . eventOnset) $ f (s,e)  filterOnsetsInRange = filterOnsets . filterStartInRange@@ -452,7 +465,7 @@ superimpose f p = stack [p, f p]  -- | @splitQueries p@ wraps `p` to ensure that it does not get--- queries that | span arcs. For example `arc p (0.5, 1.5)` would be+-- queries that span arcs. For example `arc p (0.5, 1.5)` would be -- turned into two queries, `(0.5,1)` and `(1,1.5)`, and the results -- combined. Being able to assume queries don't span cycles often -- makes transformations easier to specify.@@ -481,8 +494,8 @@ -- for example, @within (1%2) (3%4) ((1%8) <~) "bd sn bd cp"@ would shift only -- the second @bd@ within :: Arc -> (Pattern a -> Pattern a) -> Pattern a -> Pattern a-within (s,e) f p = stack [sliceArc (0,s) p, -                           compress (s,e) $ f $ zoom (s,e) p, +within (s,e) f p = stack [sliceArc (0,s) p,+                           compress (s,e) $ f $ zoom (s,e) p,                            sliceArc (e,1) p                           ] @@ -498,3 +511,93 @@ index :: Real b => b -> Pattern b -> Pattern c -> Pattern c index sz indexpat pat = spread' (zoom' $ toRational sz) (toRational . (*(1-sz)) <$> indexpat) pat   where zoom' sz start = zoom (start, start+sz)++-- | @prr rot (blen, vlen) beatPattern valuePattern@: pattern rotate/replace.+prrw :: (a -> b -> c) -> Int -> (Time, Time) -> Pattern a -> Pattern b -> Pattern c+prrw f rot (blen, vlen) beatPattern valuePattern =+  let+    ecompare (_,e1,_) (_,e2,_) = compare (fst e1) (fst e2)+    beats  = sortBy ecompare $ arc beatPattern (0, blen)+    values = fmap thd' . sortBy ecompare $ arc valuePattern (0, vlen)+    cycles = blen * (fromIntegral $ lcm (length beats) (length values) `div` (length beats))+  in+    slow cycles $ stack $ zipWith+    (\( _, (start, end), v') v -> (start ~>) $ densityGap (1 / (end - start)) $ pure (f v' v))+    (sortBy ecompare $ arc (density cycles $ beatPattern) (0, blen))+    (drop (rot `mod` length values) $ cycle values)++-- | @prr rot (blen, vlen) beatPattern valuePattern@: pattern rotate/replace.+prr :: Int -> (Time, Time) -> Pattern a -> Pattern a -> Pattern a+prr = prrw $ flip const++{-|+@preplace (blen, plen) beats values@ combines the timing of @beats@ with the values+of @values@. Other ways of saying this are:+* sequential convolution+* @values@ quantized to @beats@.++Examples:+@+d1 $ sound $ preplace (1,1) "x [~ x] x x" "bd sn"+d1 $ sound $ preplace (1,1) "x(3,8)" "bd sn"+d1 $ sound $ "x(3,8)" <~> "bd sn"+d1 $ sound "[jvbass jvbass:5]*3" |+| (shape $ "1 1 1 1 1" <~> "0.2 0.9")+@++It is assumed the pattern fits into a single cycle. This works well with+pattern literals, but not always with patterns defined elsewhere. In those cases+use @prr@ and provide desired pattern lengths:+@+let p = slow 2 $ "x x x"++d1 $ sound $ prr 0 (2,1) p "bd sn"+@+-}+preplace :: (Time, Time) -> Pattern a -> Pattern a -> Pattern a+preplace = preplaceWith $ flip const++prep = preplace++preplace1 :: Pattern a -> Pattern a -> Pattern a+preplace1 = prr 0 (1, 1)++preplaceWith :: (a -> b -> c) -> (Time, Time) -> Pattern a -> Pattern b -> Pattern c+preplaceWith f (blen, plen) = prrw f 0 (blen, plen)++prw = preplaceWith++preplaceWith1 :: (a -> b -> c) -> Pattern a -> Pattern b -> Pattern c+preplaceWith1 f = prrw f 0 (1, 1)++prw1 = preplaceWith1++(<~>) :: Pattern a -> Pattern a -> Pattern a+(<~>) = preplace (1, 1)++-- | @protate len rot p@ rotates pattern @p@ by @rot@ beats to the left.+-- @len@: length of the pattern, in cycles.+-- Example: @d1 $ every 4 (protate 2 (-1)) $ slow 2 $ sound "bd hh hh hh"@+protate :: Time -> Int -> Pattern a -> Pattern a+protate len rot p = prr rot (len, len) p p++prot = protate+prot1 = protate 1++{-| The @<<~@ operator rotates a unit pattern to the left, similar to @<~@,+but by events rather than linear time. The timing of the pattern remains constant:++@+d1 $ (1 <<~) $ sound "bd ~ sn hh"+-- will become+d1 $ sound "sn ~ hh bd"+@ -}++(<<~) :: Int -> Pattern a -> Pattern a+(<<~) = protate 1++(~>>) :: Int -> Pattern a -> Pattern a+(~>>) = (<<~) . (0-)++-- | @pequal cycles p1 p2@: quickly test if @p1@ and @p2@ are the same.+pequal :: Ord a => Time -> Pattern a -> Pattern a -> Bool+pequal cycles p1 p2 = (sort $ arc p1 (0, cycles)) == (sort $ arc p2 (0, cycles))
+ Sound/Tidal/VolcaKeys.hs view
@@ -0,0 +1,161 @@+  +module Sound.Tidal.VolcaKeys where++import qualified Sound.ALSA.Sequencer.Address as Addr+import qualified Sound.ALSA.Sequencer.Client as Client+import qualified Sound.ALSA.Sequencer.Port as Port+import qualified Sound.ALSA.Sequencer.Event as Event+import qualified Sound.ALSA.Sequencer as SndSeq+import qualified Sound.ALSA.Exception as AlsaExc+import qualified Sound.ALSA.Sequencer.Connect as Connect+import GHC.Word+import GHC.Int++import Sound.OSC.FD+import qualified Data.Map as Map+import Control.Applicative+import Control.Concurrent.MVar+--import Visual+import Data.Hashable+import Data.Bits+import Data.Maybe+import System.Process+import Control.Concurrent++import Sound.Tidal.Stream+import Sound.Tidal.Pattern+import Sound.Tidal.Parse++channel = Event.Channel 0++keys :: OscShape+keys = OscShape {path = "/note",+                 params = [ I "note" Nothing,+                            F "dur" (Just (0.05)),+                            F "portamento" (Just (-1)),+                            F "expression" (Just (-1)),+                            F "voice" (Just (-1)),+                            F "octave" (Just (-1)),+                            F "detune" (Just (-1)),+                            F "vcoegint" (Just (-1)),+                            F "kcutoff" (Just (-1)),+                            F "vcfegint" (Just (-1)),+                            F "lforate" (Just (-1)),+                            F "lfopitchint" (Just (-1)),+                            F "lfocutoffint" (Just (-1)),+                            F "attack" (Just (-1)),+                            F "decay" (Just (-1)),+                            F "sustain" (Just (-1)),+                            F "dtime" (Just (-1)),+                            F "dfeedback" (Just (-1))+                          ],+                 cpsStamp = False,+                 timestamp = NoStamp,+                 latency = 0,+                 namedParams = False,+                 preamble = []+                }++keyStream = stream "127.0.0.1" 7303 keys++note         = makeI keys "note"+dur          = makeF keys "dur"+portamento   = makeF keys "portamento"+expression   = makeF keys "expression"+octave       = makeF keys "octave"+voice        = makeF keys "voice"+detune       = makeF keys "detune"+vcoegint     = makeF keys "vcoegint"+kcutoff      = makeF keys "kcutoff"+vcfegint     = makeF keys "vcfegint"+lforate      = makeF keys "lforate"+lfopitchint  = makeF keys "lfopitchint"+lfocutoffint = makeF keys "lfocutoffint"+attack       = makeF keys "attack"+decay        = makeF keys "decay"+sustain      = makeF keys "sustain"+dtime        = makeF keys "dtime"+dfeedback    = makeF keys "dfeedback"+++keynames = map name (tail $ tail $ params keys)++keyproxy latency midiport = +   do h <- SndSeq.openDefault SndSeq.Block+      Client.setName (h :: SndSeq.T SndSeq.OutputMode) "Tidal"+      c <- Client.getId h+      p <- Port.createSimple h "out"+           (Port.caps [Port.capRead, Port.capSubsRead]) Port.typeMidiGeneric+      conn <- Connect.createTo h p =<< Addr.parse h midiport+      x <- udpServer "127.0.0.1" 7303+      forkIO $ loop h conn x+      return ()+         where loop h conn x = do m <- recvMessage x+                                  act h conn m+                                  loop h conn x+               act h conn (Just (Message "/note" (note:dur:ctrls))) = +                   do -- print $ "Got note " ++ show note+                      let note' = (fromJust $ d_get note) :: Int+                          dur' = (fromJust $ d_get dur) :: Float+                          ctrls' = (map (fromJust . d_get) ctrls) :: [Float]+                      sendmidi latency h conn (fromIntegral note', dur') ctrls'+                      return ()+++sendmidi latency h conn (note,dur) ctrls = +  do forkIO $ do threadDelay latency+                 Event.outputDirect h $ noteOn conn note 60+                 threadDelay (floor $ 1000000 * dur)+                 Event.outputDirect h $ noteOff conn note+                 return ()+     let ctrls' = map (floor . (* 127)) ctrls+         ctrls'' = filter ((>=0) . snd) (zip keynames ctrls')+         --ctrls''' = map (\x -> (x, fromJust $ lookup x ctrls'')) usectrls+     --putStrLn $ show ctrls''+     sequence_ $ map (\(name, ctrl) -> Event.outputDirect h $ makeCtrl conn (ctrlN name ctrl)) ctrls''+     return ()++ctrlN "portamento" v    = (5, v)+ctrlN "expression" v    = (11, v)+ctrlN "voice" v         = (40, v)+ctrlN "octave" v        = (41, v)+ctrlN "detune" v        = (42, v)+ctrlN "vcoegint" v      = (43, v)+ctrlN "kcutoff" v        = (44, v)+ctrlN "vcfegint" v      = (45, v)+ctrlN "lforate" v       = (46, v)+ctrlN "lfopitchint" v   = (47, v)+ctrlN "lfocutoffint" v  = (48, v)+ctrlN "attack" v        = (49, v)+ctrlN "decay" v         = (50, v)+ctrlN "sustain" v       = (51, v)+ctrlN "dtime" v         = (52, v)+ctrlN "dfeedback" v     = (53, v)+ctrlN s _               = error $ "no match for " ++ s+++++noteOn :: Connect.T -> Word8 -> Word8 -> Event.T+noteOn conn val vel = +  Event.forConnection conn +  $ Event.NoteEv Event.NoteOn+  $ Event.simpleNote channel+                     (Event.Pitch (val))+                     (Event.Velocity vel)++noteOff :: Connect.T -> Word8 -> Event.T+noteOff conn val = +  Event.forConnection conn +  $ Event.NoteEv Event.NoteOff+  $ Event.simpleNote channel+                     (Event.Pitch (val))+                     (Event.normalVelocity)++makeCtrl :: Connect.T -> (Word32, GHC.Int.Int32) -> Event.T+makeCtrl conn (c, n) = +  Event.forConnection conn +  $ Event.CtrlEv Event.Controller $ Event.Ctrl +                                    channel +                                    (Event.Parameter c) +                                    (Event.Value n)
doc/tidal.md view
@@ -1,6 +1,6 @@ <img src="https://raw2.github.com/yaxu/Tidal/master/doc/tidal.png" /> -# Tidal: Domain specific language for live coding of pattern +# Tidal: Domain specific language for live coding of pattern  Homepage and mailing list: <http://yaxu.org/tidal/> @@ -274,7 +274,7 @@  Note the use of parenthesis around `(density 4)`, this is needed, to group together the function `density` with its parameter `4`, before-being passed as a parameter to the function `every`. +being passed as a parameter to the function `every`.  Instead of putting transformations up front, separated by the pattern by the `$` symbol, you can put them inside the pattern, for example:@@ -316,7 +316,7 @@  # Synth Parameters -Synth parameters generate or affect sample playback. These are the +Synth parameters generate or affect sample playback. These are the synthesis parameters you can use:  * `accelerate` - a pattern of numbers that speed up (or slow down) samples while they play.@@ -325,14 +325,14 @@ * `begin` - a pattern of numbers from 0 to 1. Skips the beginning of each sample, e.g. `0.25` to cut off the first quarter from each sample. * `crush` - bit crushing, a pattern of numbers from 1 for drastic reduction in bit-depth to 16 for barely no reduction. * `coarse` - fake-resampling, a pattern of numbers for lowering the sample rate, i.e. 1 for original 2 for half, 3 for a third and so on.-* `cutoff` - a pattern of numbers from 0 to 1. Applies the cutoff frequency of the low-pass filter. +* `cutoff` - a pattern of numbers from 0 to 1. Applies the cutoff frequency of the low-pass filter. * `delay` - a pattern of numbers from 0 to 1. Sets the level of the delay signal. * `delayfeedback` - a pattern of numbers from 0 to 1. Sets the amount of delay feedback. * `delaytime` - a pattern of numbers from 0 to 1. Sets the length of the delay. * `end` - the same as `begin`, but cuts the end off samples, shortening them;   e.g. `0.75` to cut off the last quarter of each sample. * `gain` - a pattern of numbers that specify volume. Values less than 1 make the sound quieter. Values greater than 1 make the sound louder.-* `hcutoff` - a pattern of numbers from 0 to 1. Applies the cutoff frequency of the high-pass filter. +* `hcutoff` - a pattern of numbers from 0 to 1. Applies the cutoff frequency of the high-pass filter. * `hresonance` - a pattern of numbers from 0 to 1. Applies the resonance of the high-pass filter. * `pan` - a pattern of numbers between 0 and 1, from left to right (assuming stereo) * `resonance` - a pattern of numbers from 0 to 1. Applies the resonance of the low-pass filter.@@ -576,13 +576,13 @@ slowspread :: (a -> t -> Pattern b) -> [a] -> t -> Pattern b ~~~~ -`slowspread` takes a list of pattern transforms and applies them one at a time, per cycle, +`slowspread` takes a list of pattern transforms and applies them one at a time, per cycle, then repeats.  Example:  ~~~~ {.haskell}-d1 $ slowspread ($) [density 2, rev, slow 2, striate 3, (|+| speed "0.8")] +d1 $ slowspread ($) [density 2, rev, slow 2, striate 3, (|+| speed "0.8")]     $ sound "[bd*2 [~ bd]] [sn future]*2 cp jvbass*4" ~~~~ @@ -632,7 +632,7 @@ sometimesBy :: Double -> (Pattern a -> Pattern a) -> Pattern a -> Pattern a ~~~~ -Use `sometimesBy` to apply a given function "sometimes". For example, the +Use `sometimesBy` to apply a given function "sometimes". For example, the following code results in `density 2` being applied about 25% of the time:  ~~~~ {.haskell}@@ -756,7 +756,7 @@ stut :: Integer -> Double -> Rational -> OscPattern -> OscPattern ~~~~ -Stut applies a type of delay to a pattern. It has three parameters, +Stut applies a type of delay to a pattern. It has three parameters, which could be called depth, feedback and time. Depth is an integer and the others floating point. This adds a bit of echo: @@ -764,7 +764,7 @@ d1 $ stut 4 0.5 0.2 $ sound "bd sn" ~~~~ -The above results in 4 echos, each one 50% quieter than the last, +The above results in 4 echos, each one 50% quieter than the last, with 1/5th of a cycle between them. It is possible to reverse the echo:  ~~~~ {.haskell}@@ -777,7 +777,7 @@ trunc :: Time -> Pattern a -> Pattern a ~~~~ -Truncates a pattern so that only a fraction of the pattern is played. +Truncates a pattern so that only a fraction of the pattern is played. The following example plays only the first three quarters of the pattern:  ~~~~ {.haskell}@@ -805,7 +805,7 @@ whenmod :: Int -> Int -> (Pattern a -> Pattern a) -> Pattern a -> Pattern a ~~~~ -`whenmod` has a similar form and behavior to `every`, but requires an +`whenmod` has a similar form and behavior to `every`, but requires an additional number. Applies the function to the pattern, when the remainder of the current loop number divided by the first parameter, is less than the second parameter.@@ -882,35 +882,35 @@ playing all of the patterns in the list simultaneously.  ~~~~ {.haskell}-d1 $ stack [ -  sound "bd bd*2", -  sound "hh*2 [sn cp] cp future*4", +d1 $ stack [+  sound "bd bd*2",+  sound "hh*2 [sn cp] cp future*4",   sound (samples "arpy*8", (run 16)) ] ~~~~ -This is useful if you want to use a transform or synth parameter on the entire +This is useful if you want to use a transform or synth parameter on the entire stack:  ~~~~ {.haskell}-d1 $ whenmod 5 3 (striate 3) $ stack [ -  sound "bd bd*2", -  sound "hh*2 [sn cp] cp future*4", +d1 $ whenmod 5 3 (striate 3) $ stack [+  sound "bd bd*2",+  sound "hh*2 [sn cp] cp future*4",   sound (samples "arpy*8", (run 16)) ] |+| speed "[[1 0.8], [1.5 2]*2]/3" ~~~~  There is a similar function named `seqP` which allows you to define when a sound within a list starts and ends. The code below contains three-separate patterns in a "stack", but each has different start times +separate patterns in a "stack", but each has different start times (zero cycles, eight cycles, and sixteen cycles, respectively). All patterns stop after 128 cycles:  ~~~~ {.haskell}-d1 $ seqP [ -  (0, 128, sound "bd bd*2"), -  (8, 128, sound "hh*2 [sn cp] cp future*4"), -  (16, 128, sound (samples "arpy*8", (run 16)))+d1 $ seqP [+  (0, 128, sound "bd bd*2"),+  (8, 128, sound "hh*2 [sn cp] cp future*4"),+  (16, 128, sound (samples "arpy*8" (run 16))) ] ~~~~ @@ -933,6 +933,117 @@  ~~~~ {.haskell} d1 $ slow 32 $ jux ((|+| speed "0.5") . rev) $ striate' 32 (1/16) $ sound "bev"+~~~~+++# Quantization, event shifting, and patterns as sequences++Patterns are not _really_ sequences, but sometimes you may wish they+were. The functions `preplace` and `protate` let you treat them as+sequences.++Tidal patterns are formally infinite, but usually they repeat after some+time (which is often some integer multiple of cycles). Since a pattern does not+know how long it is, you'll have to specify. Each function comes with a+companion operator which assumes your pattern repeats after one cycle. This+is the case with pattern literals (i.e., `sound "bd bd"` is always a+one cycle pattern).++## preplace and `<~>`++~~~~ {.haskell}+preplace :: (Time, Time) -> Pattern a -> Pattern a -> Pattern a+~~~~++The `preplace` (shorthand `prep`) function combines the timing of one+pattern (the trigger pattern) with event values of another (the sequence+pattern). It does so by replacing the trigger pattern event values with+values, repeating the latter until it has enough. Note that it does not+matter what the values of the trigger pattern are, but the patterns must be+of the same _type_.++Additionally, `preplace` takes a `(Time, Time)` tuple of pattern+lengths (doesn't have to be correct). If you are fine with constraining this+effect to a single cycle you can use `<~>`:++~~~~ {.haskell}+(<~>) :: Pattern a -> Pattern a -> Pattern a+~~~~++Example replacements (`=>` means "becomes"):++~~~~ {.haskell}+"x x" <~> "bd"          => "bd bd"+"x" <~> "bd sn"         => "bd"+"x x ~ x" <~> "bd sn"   => "bd sn ~ bd sn bd ~ sn"+"x(3,8)" <~> "bd"       => "bd ~ ~ bd ~ ~ b ~"+"x(3,8)" <~> "bd bd sn" => "bd ~ ~ bd ~ ~ sn ~"++preplace (1,1) "x [~ x] x x" "bd sn"+  => "bd {~ sn] bd sn"++preplace (1,3) "x x x ~" $ samples "bd sn" $ slow 3 $ run 3+  => "bd:0 sn:0 bd:1 ~ sn:1  bd:2 sn:2 ~ bd:3  ..."+~~~~++Any pattern will do:++~~~~ {.haskell}+d1 $ sound "[jvbass jvbass:5]*3" |+| (shape $ "1 1 1 1 1" <~> "0.2 0.9")+~~~~++## preplaceWith (prw)++`preplaceWith` (shorthand `prw`) is similar to `replace` but takes an+additional combinator function:++~~~~ {.haskell}+preplaceWith :: (a -> b -> c) -> (Time, Time) -> Pattern a -> Pattern b -> Pattern c+preplaceWith1 :: (a -> b -> c) -> Pattern a -> Pattern b -> Pattern c++prw = preplaceWith+prw1 = preplaceWith1+~~~~++`preplaceWith1` assumes both patterns are of length 1. Also note that+patterns don't have to be of the same type anymore.++This can be quite powerful:++~~~~ {.haskell}+prw1 (+) "1 2 3" "2"    => "3 4 5"+prw1 (+) "1 2 3" "1 -1" => "2 1 4 0 3 2"+~~~~++## protate and `<<~`/`~>>`++~~~~ {.haskell}+protate :: Time -> Int -> Pattern a -> Pattern a+protate len rot p = ...+~~~~++The `protate` (shorthand `prot`) function takes a pattern of length `len`+and shifts the events `rot` times to the left without disturbing the time signature.++~~~~ {.haskell}+prot 1 "1 2 ~ 3"                => "2 3 ~ 1"+1 <<~ "1 2 ~ 3"                 => "2 3 ~ 1"+1 ~>> "1 2 ~ 3"                 => "3 1 ~ 2"+2 ~>> "[bd bd] sn ~ hh [~ can]" => "[hh can] bd ~ bd [~ sn]"+~~~~++## prr and prrw++All the above functions rely on `prrw` (pattern replate rotate with) and its+alias `prr`. If you find yourself having to do combinations of the above,+you can use these directly.++~~~~ {.haskell}+-- | @prr rot (blen, vlen) beatPattern valuePattern@: pattern rotate/replace.+prrw :: (a -> b -> c) -> Int -> (Time, Time) -> Pattern a -> Pattern b -> Pattern c+prrw f rot (blen, vlen) beatPattern valuePattern = ...++prr :: Int -> (Time, Time) -> Pattern a -> Pattern a -> Pattern a ~~~~  # Plus more to be discovered!
tidal.cabal view
@@ -1,5 +1,5 @@ name:                tidal-version:         0.4.30+version:         0.4.31 synopsis:            Pattern language for improvised music -- description:          homepage:            http://tidal.lurk.org/@@ -28,5 +28,6 @@                        Sound.Tidal.Context                        Sound.Tidal.Utils                        Sound.Tidal.SuperCollider+                       Sound.Tidal.VolcaKeys -  Build-depends: base < 5, process, parsec, hosc > 0.13, hashable, colour, containers, time, websockets > 0.8, text, mtl >=2.1, transformers, mersenne-random-pure64,binary, bytestring, hmt+  Build-depends: base < 5, process, parsec, hosc > 0.13, hashable, colour, containers, time, websockets > 0.8, text, mtl >=2.1, transformers, mersenne-random-pure64,binary, bytestring, hmt, alsa-seq, alsa-core
tidal.el view
@@ -72,8 +72,8 @@   (tidal-send-string "d8 <- dirtStream")   (tidal-send-string "d9 <- dirtStream")   (tidal-send-string "d10 <- dirtStream")-;  (tidal-send-string "k1 <- keyStream")-;  (tidal-send-string "keyproxy 150000 \"24:0\"")+  (tidal-send-string "k1 <- keyStream")+  (tidal-send-string "keyproxy 150000 \"24:0\"")   (tidal-send-string "(cps, getNow) <- bpsUtils")   (tidal-send-string "let bps x = cps (x/2)") ;  (tidal-send-string "let hush = mapM_ ($ silence) [d1,d2,d3,d4,d5,d6,d7,d8,d9,d10,k1]")