packages feed

tidal 0.2.9 → 0.2.10

raw patch · 9 files changed

+431/−152 lines, 9 files

Files

Sound/Tidal/Dirt.hs view
@@ -32,7 +32,9 @@                             F "resonance" (Just 0),                             F "accellerate" (Just 0),                             F "shape" (Just 0),-                            I "kriole" (Just 0)+                            I "kriole" (Just 0),+                            F "gain" (Just 0),+                            I "cutgroup" (Just 0)                           ],                  timestamp = True                 }@@ -98,6 +100,8 @@ resonance    = makeF dirt "resonance" accellerate  = makeF dirt "accellerate" shape        = makeF dirt "shape"+gain         = makeF dirt "gain"+cutgroup     = makeI dirt "cutgroup"  ksymbol      = makeF kriole "ksymbol" kpitch       = makeF kriole "kpitch"
Sound/Tidal/Pattern.hs view
@@ -16,14 +16,24 @@ import Sound.Tidal.Time import Sound.Tidal.Utils +-- | The pattern datatype, a function from a time @Arc@ to @Event@+-- values. For discrete patterns, this returns the events which are+-- active during that time. For continuous patterns, events with+-- values for the midpoint of the given @Arc@ is returned.+ data Pattern a = Pattern {arc :: Arc -> [Event a]} +-- | @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)-  + instance Functor Pattern where   fmap f (Pattern a) = Pattern $ fmap (fmap (mapSnd 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), x)) @@ -37,10 +47,13 @@                  (xs (s,e))                 ) +-- | @mempty@ is a synonym for @silence@.+-- | @mappend@ is a synonym for @overlay@. instance Monoid (Pattern a) where     mempty = silence     mappend x y = Pattern $ \a -> (arc x a) ++ (arc y a) + instance Monad Pattern where   return = pure   p >>= f = @@ -53,50 +66,79 @@                    (arc p a)              ) +-- | @atom@ is a synonym for @pure@. atom :: a -> Pattern a atom = pure +-- | @silence@ returns a pattern with no events. silence :: Pattern a silence = Pattern $ const [] +-- | @mapQueryArc f p@ returns a new @Pattern@ with function @f@+-- applied to the @Arc@ values passed to the original @Pattern@ @p@. mapQueryArc :: (Arc -> Arc) -> Pattern a -> Pattern a mapQueryArc f p = Pattern $ \a -> arc p (f a) +-- | @mapQueryTime f p@ returns a new @Pattern@ with function @f@+-- applied to the both the start and end @Time@ of the @Arc@ passed to+-- @Pattern@ @p@. mapQueryTime :: (Time -> Time) -> Pattern a -> Pattern a mapQueryTime = mapQueryArc . mapArc +-- | @mapResultArc f p@ returns a new @Pattern@ with function @f@+-- applied to the @Arc@ values in the events returned from the+-- original @Pattern@ @p@. mapResultArc :: (Arc -> Arc) -> Pattern a -> Pattern a mapResultArc f p = Pattern $ \a -> mapFsts f $ arc p a +-- | @mapResultTime f p@ returns a new @Pattern@ with function @f@+-- applied to the both the start and end @Time@ of the @Arc@ values in+-- the events returned from the original @Pattern@ @p@. mapResultTime :: (Time -> Time) -> Pattern a -> Pattern a mapResultTime = mapResultArc . mapArc +-- | @overlay@ combines two @Pattern@s into a new pattern, so that+-- their events are combined over time. overlay :: Pattern a -> Pattern a -> Pattern a overlay p p' = Pattern $ \a -> (arc p a) ++ (arc p' a)- (>+<) = overlay +-- | @stack@ combines a list of @Pattern@s into a new pattern, so that+-- their events are combined over time. stack :: [Pattern a] -> Pattern a stack ps = foldr overlay silence ps -cat :: [Pattern a] -> Pattern a-cat ps = density (fromIntegral $ length ps) $ slowcat ps+-- | @append@ combines two patterns @Pattern@s into a new pattern, so+-- that the events of the second pattern are appended to those of the+-- first pattern, within a single cycle  append :: Pattern a -> Pattern a -> Pattern a append a b = cat [a,b] +-- | @append'@ does the same as @append@, but over two cycles, so that+-- the cycles alternate between the two patterns. append' :: Pattern a -> Pattern a -> Pattern a append' a b  = slow 2 $ cat [a,b] -slowcat' ps = Pattern $ \a -> concatMap f (arcCycles a)+-- | @cat@ returns a new pattern which interlaces the cycles of the+-- given patterns, within a single cycle. It's the equivalent of+-- @append@, but with a list of patterns.+cat :: [Pattern a] -> Pattern a+cat ps = density (fromIntegral $ length ps) $ slowcat ps++{-slowcat' ps = Pattern $ \a -> concatMap f (arcCycles a)   where l = length ps         f (s,e) = arc p (s,e)           where p = ps !! n-                n = (floor s) `mod` l+                n = (floor s) `mod` l-}  -- Concatenates so that the first loop of each pattern is played in -- turn, second loop of each pattern, and so on.. +-- | @slowcat@ does the same as @cat@, but maintaining the duration of+-- the original patterns. It is the equivalent of @append'@, but with+-- a list of patterns.+ slowcat :: [Pattern a] -> Pattern a slowcat [] = silence slowcat ps = Pattern $ \a -> concatMap f (arcCycles a)@@ -108,76 +150,143 @@                 offset = (fromIntegral $ r - ((r - n) `div` l)) :: Time                 (s', e') = (s-offset, e-offset) +-- | @listToPat@ turns the given list of values to a Pattern, which+-- cycles through the list. listToPat :: [a] -> Pattern a listToPat = cat . map atom -run n = listToPat [0 .. n-1]-+-- | @maybeListToPat@ is similar to @listToPat@, but allows values to+-- be optional using the @Maybe@ type, so that @Nothing@ results in+-- gaps in the pattern. maybeListToPat :: [Maybe a] -> Pattern a maybeListToPat = cat . map f   where f Nothing = silence         f (Just x) = atom x +-- | @run@ @n@ returns a pattern representing a cycle of numbers from @0@ to @n-1@.+run n = listToPat [0 .. n-1]++-- | @density@ returns the given pattern with density increased by the+-- given @Time@ factor. Therefore @density 2 p@ will return a pattern+-- that is twice as fast, and @density (1%3) p@ will return one three+-- times as slow. density :: Time -> Pattern a -> Pattern a density 0 p = p density 1 p = p density r p = mapResultTime (/ r) $ mapQueryTime (* r) p +-- | @slow@ does the opposite of @density@, i.e. @slow 2 p@ will+-- return a pattern that is half the speed. slow :: Time -> Pattern a -> Pattern a slow 0 = id slow t = density (1/t)  ++-- | The @<~@ operator shift (or rotate) 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 +-- one 16th of a cycle to the left. (<~) :: Time -> Pattern a -> Pattern a (<~) t p = filterOffsets $ mapResultTime (+ t) $ mapQueryTime (subtract t) p +-- | The @~>@ operator does the same as @~>@ but shifts events to the+-- right (or clockwise) rather than to the left. (~>) :: Time -> Pattern a -> Pattern a (~>) = (<~) . (0-) +-- | @rev p@ returns @p@ with the event positions in each cycle+-- reversed (or mirrored). rev :: Pattern a -> Pattern a rev p = Pattern $ \a -> concatMap                          (\a' -> mapFsts mirrorArc $                                  (arc p (mirrorArc a')))                         (arcCycles a) +-- | @palindrome p@ applies @rev@ to @p@ every other cycle, so that+-- the pattern alternates between forwards and backwards.+palindrome p = append' p (rev p)++-- | @when test f p@ applies the function @f@ to @p@, but in a way+-- which only affects cycles where the @test@ function applied to the+-- cycle number returns @True@. when :: (Int -> Bool) -> (Pattern a -> Pattern a) ->  Pattern a -> Pattern a when test f p = Pattern $ \a -> concatMap apply (arcCycles a)   where apply a | test (floor $ fst a) = (arc $ f p) a                 | otherwise = (arc p) a +-- | @every n f p@ applies the function @f@ to @p@, but only affects+-- every @n@ cycles. every :: Int -> (Pattern a -> Pattern a) -> Pattern a -> Pattern a every 0 f p = p every n f p = when ((== 0) . (`mod` n)) f p -palindrome :: Pattern a -> Pattern a-palindrome p = slowcat [p, rev p]-+-- | @sig f@ takes a function from time to values, and turns it into a+-- @Pattern@. sig :: (Time -> a) -> Pattern a sig f = Pattern f'   where f' (s,e) | s > e = []                  | otherwise = [((s,e), f s)] +-- | @sinewave@ returns a @Pattern@ of continuous @Double@ values following a+-- sinewave with frequency of one cycle, and amplitude from -1 to 1. sinewave :: Pattern Double sinewave = sig $ \t -> sin $ pi * 2 * (fromRational t)+-- | @sine@ is a synonym for @sinewave. sine = sinewave-ratsine = fmap toRational sine+-- | @sinerat@ is equivalent to @sinewave@ for @Rational@ values,+-- suitable for use as @Time@ offsets.+sinerat = fmap toRational sine+ratsine = sinerat +-- | @sinewave1@ is equivalent to @sinewave@, but with amplitude from 0 to 1. sinewave1 :: Pattern Double sinewave1 = fmap ((/ 2) . (+ 1)) sinewave++-- | @sine1@ is a synonym for @sinewave1@. sine1 = sinewave1-ratsine1 = fmap toRational sine1 -sinePhase1 :: Double -> Pattern Double-sinePhase1 offset = (+ offset) <$> sinewave1+-- | @sinerat1@ is equivalent to @sinerat@, but with amplitude from 0 to 1.+sinerat1 = fmap toRational sine1 -triwave1 :: Pattern Double-triwave1 = sig $ \t -> mod' (fromRational t) 1-tri1 = triwave1-rattri1 = fmap toRational tri1+-- | @sineAmp1 d@ returns @sinewave1@ with its amplitude offset by @d@.+sineAmp1 :: Double -> Pattern Double+sineAmp1 offset = (+ offset) <$> sinewave1 +-- | @sawwave@ is the equivalent of @sinewave@ for sawtooth waves.+sawwave :: Pattern Double+sawwave = ((subtract 1) . (* 2)) <$> sawwave1++-- | @saw@ is a synonym for @sawwave@.+saw = sawwave++-- | @sawrat@ is the same as @sawwave@ but returns @Rational@ values+-- suitable for use as @Time@ offsets.+sawrat = fmap toRational saw++sawwave1 :: Pattern Double+sawwave1 = sig $ \t -> mod' (fromRational t) 1+saw1 = sawwave1+sawrat1 = fmap toRational saw1++-- | @triwave@ is the equivalent of @sinewave@ for triangular waves. triwave :: Pattern Double triwave = ((subtract 1) . (* 2)) <$> triwave1++-- | @tri@ is a synonym for @triwave@. tri = triwave-rattri = fmap toRational tri++-- | @trirat@ is the same as @triwave@ but returns @Rational@ values+-- suitable for use as @Time@ offsets.+trirat = fmap toRational tri++triwave1 :: Pattern Double+triwave1 = append sawwave1 (rev sawwave1)++tri1 = triwave1+trirat1 = fmap toRational tri1+++-- todo - triangular waves again  squarewave1 :: Pattern Double squarewave1 = sig $ 
Sound/Tidal/Strategies.hs view
@@ -91,7 +91,7 @@  spin16 step p = stack $ map (\n -> ((toRational n)/16) <~ p |+| pan (pure $ n)) [0,step .. 15] -triwave4 = ((*4) <$> triwave1)+sawwave4 = ((*4) <$> sawwave1) sinewave4 = ((*4) <$> sinewave1) rand4 = ((*4) <$> rand) @@ -105,3 +105,4 @@   where flt = f . cyclePos . fst . fst  inside n f p = density n $ f (slow n p)+
Sound/Tidal/Stream.hs view
@@ -157,7 +157,7 @@ makeS = make string makeF = make float -makeI = make int32+makeI = make (int32 . fromIntegral)  param :: OscShape -> String -> Param param shape n = head $ filter (\x -> name x == n) (params shape)
Sound/Tidal/Time.hs view
@@ -1,41 +1,64 @@ module Sound.Tidal.Time where +-- | Time is represented by a rational number. Each natural number+-- represents both the start of the next rhythmic cycle, and the end+-- of the previous one. Rational numbers are used so that subdivisions+-- of each cycle can be accurately represented. type Time = Rational++-- | @(s,e) :: Arc@ represents a time interval with a start and end value.+-- @ { t : s <= t && t < e } @ type Arc = (Time, Time)++-- | An Event is a value that occurs during the given @Arc@ type Event a = (Arc, a) +-- | The starting point of the current cycle. A cycle occurs from each+-- natural number to the next, so this is equivalent to @floor@. sam :: Time -> Time sam = fromIntegral . floor +-- | The end point of the current cycle (and starting point of the next cycle) nextSam :: Time -> Time nextSam = (1+) . sam ++-- | The position of a time value relative to the start of its cycle. cyclePos :: Time -> Time cyclePos t = t - sam t +-- | @isIn a t@ is @True@ iff @t@ is inside +-- the arc represented by @a@. isIn :: Arc -> Time -> Bool isIn (s,e) t = t >= s && t < e --- chop arc into arcs within unit cycles+-- | Splits the given @Arc@ into a list of @Arc@s, at cycle boundaries. arcCycles :: Arc -> [Arc] arcCycles (s,e) | s >= e = []                 | sam s == sam e = [(s,e)]                 | otherwise = (s, nextSam s) : (arcCycles (nextSam s, e)) ++-- | @subArc i j@ is the arc that is the intersection of @i@ and @j@. subArc :: Arc -> Arc -> Maybe Arc subArc (s, e) (s',e') | s'' < e'' = Just (s'', e'')                       | otherwise = Nothing   where s'' = max s s'         e'' = min e e' +-- | Map the given function over both the start and end @Time@ values+-- of the given @Arc@. mapArc :: (Time -> Time) -> Arc -> Arc mapArc f (s,e) = (f s, f e) +-- | Returns the `mirror image' of an @Arc@, used by @Sound.Tidal.Pattern.rev@. mirrorArc :: Arc -> Arc mirrorArc (s, e) = (sam s + (nextSam s - e), nextSam s - (s - sam s)) +-- | The start time of the given @Event@ eventStart :: Event a -> Time eventStart = fst . fst +-- | The midpoint of an @Arc@ midPoint :: Arc -> Time midPoint (s,e) = s + ((e - s) / 2)
doc/tidal.md view
@@ -1,5 +1,7 @@-% Tidal -- Domain specific language for live coding of pattern +<img src="https://raw2.github.com/yaxu/Tidal/master/doc/tidal.png" /> +# Tidal: Domain specific language for live coding of pattern + Homepage and mailing list: <http://yaxu.org/tidal/>  Tidal is a language for live coding pattern, embedded in the Haskell@@ -11,104 +13,14 @@  # Installation -Tidal is developed under Linux, and although some have got it to work-under Macs, the process hasn't been fully documented, and Dirt-synthesiser has not yet been ported to Windows. Feel free to ask-questions and share problems and success stories on the mailing list.--## Installing Dirt--Tidal does not include a synthesiser, but instead communicates with an-external synthesiser using the Open Sound Control protocol. It has-been developed for use with a particular software sampler called-"dirt". You'll need to run it with "jack audio". Here's an example of-the commands needed to compile it under a debian-derived linux-distribution (including ubuntu and mint):--~~~~-    sudo apt-get install build-essential libsndfile1-dev libsamplerate0-dev \-                         liblo-dev libjack-jackd2-dev qjackctl jackd git-    git clone https://github.com/yaxu/Dirt.git-    cd Dirt-    make clean; make-~~~~--Then you'll have to start jack, using the 'qjackctl' app under Linux,-or otherwise from the commandline:--~~~~-    jackd -d alsa &-~~~~--(On MacOS X, you would do this instead: jackd -d coreaudio & )--If that doesn't work, you might well have something called-"pulseaudio" in control of your sound. In that case, this should work:--~~~~-    /usr/bin/pasuspender -- jackd -d alsa &-~~~~--And finally you should be able to start dirt with this:--~~~~-    ./dirt &-~~~~--If you have problems with jack, try enabling realtime audio, and-adjusting the settings by installing and using the "qjackctl"-software. Some more info is here: <https://help.ubuntu.com/community/HowToJACKConfiguration>---## Tidal--Tidal is embedded in the Haskell language, so you'll have to install-the haskell interpreter and some libraries, including tidal-itself. Under debian, you'd install haskell like this:--~~~~-   sudo apt-get install ghc6 cabal-install-~~~~--Or otherwise you could grab it from <http://www.haskell.org/platform/>--Once Haskell is installed, you can install tidal like this:--~~~~-   cabal update-   cabal install tidal-~~~~--## Emacs--Currently about the only interface to Tidal is the emacs-editor. Debian users can install emacs, along with its haskell-front-end, this way:--~~~~-    sudo apt-get install emacs24 haskell-mode-~~~~--To install the emacs interface to tidal, you'll need to edit a-configuration file in your home folder called `.emacs`. If it doesn't-exist, create it. Then, add the following, replacing-`~/projects/tidal` with the location of the `tidal.el` file.--~~~~-    (add-to-list 'load-path "~/projects/tidal")-    (require 'tidal)-~~~~--If tidal.el did not come with this document, you can grab it here: <https://raw.github.com/yaxu/Tidal/master/tidal.el>--## Testing, testing...+Linux installation:+<https://github.com/yaxu/Tidal/blob/master/doc/install-linux.md> -Now start emacs, and open a new file called something like-"helloworld.tidal". Once the file is opened, you still have to start-tidal, you do that by typing `Ctrl-C` then `Ctrl-S`.+Mac OS X installation:+<https://github.com/yaxu/Tidal/blob/master/doc/install-osx.md> -All being well you should now be able to start making some sounds,-lets start with some simple sequences.+Feel free to ask questions and share problems and success stories on+the mailing list.  # Sequences @@ -219,6 +131,22 @@ d1 $ sound "[bd sn sn*3]/2 [bd sn*3 bd*4]/3" ~~~~ +# Peace and quiet with silence and hush++An empty pattern is defined as `silence`, so if you want to 'switch+off' a pattern, you can just set it to that:++~~~~ {#mycode .haskell}+d1 silence+~~~~++If you want to set all the connections (from `d1` to `d9`) to silence+at once, there's a single-word shortcut for that:++~~~~ {#mycode .haskell}+hush+~~~~+ # Beats per second  You can change the beats per second (bps) like this:@@ -370,12 +298,18 @@  # Pattern transformers +In the following, functions are shown with their Haskell type and a+short description of how they work.+ ## brak -~~~~-brak <pattern>+~~~~ {#mycode .haskell}+brak :: Pattern a -> Pattern a ~~~~ +(The above means that `brak` is a function from patterns of any type,+to a pattern of the same type.)+ Make a pattern sound a bit like a breakbeat  Example:@@ -384,18 +318,36 @@ d1 $ sound (brak "bd sn kurt") ~~~~ -## Beat rotation+## Reversal +~~~~ {#mycode .haskell}+rev :: Pattern a -> Pattern a ~~~~-<number> <~ <pattern>++Reverse a pattern++Examples:++~~~~ {#mycode .haskell}+d1 $ every 3 (rev) $ sound (density 2 "bd sn kurt") ~~~~ -or+## Beat rotation +~~~~ {#mycode .haskell}+(<~) :: Time -> Pattern a -> Pattern a ~~~~-<number> ~> <pattern>++or++~~~~ {#mycode .haskell}+(~>) :: Time -> Pattern a -> Pattern a ~~~~ +(The above means that `<~` and `~>` are functions that are given a+time value and a pattern of any type, and returns a pattern of the+same type.)+ Rotate a loop either to the left or the right.  Example:@@ -404,70 +356,260 @@ d1 $ every 4 (0.25 <~) $ sound (density 2 "bd sn kurt") ~~~~ -## Reversal+## Increase or decrease density +~~~~ {#mycode .haskell}+density :: Time -> Pattern a -> Pattern a ~~~~-rev <pattern>++or++~~~~ {#mycode .haskell}+slow :: Time -> Pattern a -> Pattern a ~~~~ -Reverse a pattern+Speed up or slow down a pattern. -Examples:+Example:  ~~~~ {#mycode .haskell}-d1 $ every 3 (rev) $ sound (density 2 "bd sn kurt")+d1 $ sound (density 2 "bd sn kurt")+   |+| slow 3 (vowel "a e o") ~~~~ -## Increase/decrease density+## Every nth repetition, do this +~~~~ {#mycode .haskell}+every :: Int -> (Pattern a -> Pattern a) -> Pattern a -> Pattern a ~~~~-density <number> <pattern>++(The above means `every` is a function that is given an integer number, a+function which transforms a pattern, and an actual pattern, and+returns a pattern of the same type.)++Transform the given pattern using the given function, but only every+given number of repetitions.++Example:++~~~~ {#mycode .haskell}+d1 $ sound (every 3 (density 2) "bd sn kurt") ~~~~ -or+~~~~ {#mycode .haskell}+whenmod :: Int -> Int -> (Pattern a -> Pattern a) -> Pattern a -> Pattern a+~~~~ +(The above has a similar form to `every`, but requires an additional+number.)++Similar to `every`, but 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.++For example the following makes every other block of four loops twice+as dense:++~~~~ {#mycode .haskell}+d1 $ whenmod 8 4 (density 2) (sound "bd sn kurt") ~~~~-slow <number> <pattern>++# Interlace++~~~~ {#mycode .haskell}+interlace :: OscPattern -> OscPattern -> OscPattern ~~~~ -Speed up or slow down a pattern.+(A function that takes two OscPatterns, and blends them together into+a new OscPattern. An OscPattern is basically a pattern of messages to+a synthesiser.) +Shifts between the two given patterns, using distortion.+ Example:  ~~~~ {#mycode .haskell}-d1 $ sound (density 2 "bd sn kurt")-   |+| slow 3 (vowel "a e o")+d1 $ interlace (sound  "bd sn kurt") (every 3 rev $ sound  "bd sn/2") ~~~~ -## Every nth repetition, do this+# Spread +~~~~ {#mycode .haskell}+spread :: (a -> t -> Pattern b) -> [a] -> t -> Pattern b ~~~~-every <number> <function> <pattern>++(The above is difficult to describe, if you don't understand Haskell,+just read the description and examples..)++The `spread` function allows you to take a pattern transformation+which takes a parameter, such as `slow`, and provide several+parameters which are switched between. In other words it 'spreads' a+function across several values.++Taking a simple high hat loop as an example:++~~~~ {#mycode .haskell}+d1 $ sound "ho ho/2 ho/3 hc" ~~~~ -Applies <function> to <pattern>, but only every <number> repetitions.+We can slow it down by different amounts, such as by a half: -Example:+~~~~ {#mycode .haskell}+  d1 $ slow 2 $ sound "ho ho/2 ho/3 hc"+~~~~ +Or by four thirds (i.e. speeding it up by a third; `4%3` means four over+three):+ ~~~~ {#mycode .haskell}-d1 $ sound (every 3 (density 2) "bd sn kurt")+  d1 $ slow (4%3) $ sound "ho ho/2 ho/3 hc" ~~~~ -# Interlace+But if we use `spread`, we can make a pattern which alternates between+the two speeds: +~~~~ {#mycode .haskell}+d1 $ spread slow [2,4%3] $ sound "ho ho/2 ho/3 hc" ~~~~-interlace <pattern> <pattern>++There's a version of this function, `spread'` (pronounced "spread prime"), which takes a *pattern* of parameters, instead of a list:++~~~~ {#mycode .haskell}+d1 $ spread' slow "2 4%3" $ sound "ho ho/2 ho/3 hc" ~~~~ -Shifts between two patterns, using distortion.+This is quite a messy area of Tidal - due to a slight difference of+implementation this sounds completely different! One advantage of+using `spread'` though is that you can provide polyphonic parameters, e.g.: -Example:+~~~~ {#mycode .haskell}+d1 $ spread' slow "[2 4%3, 3]" $ sound "ho ho/2 ho/3 hc"+~~~~ +# Striate+ ~~~~ {#mycode .haskell}-d1 $ interlace (sound  "bd sn kurt") (every 3 rev $ sound  "bd sn/2")+striate :: Int -> OscPattern -> OscPattern ~~~~ -Plus more to be discovered!+Striate is a kind of granulator, for example:++~~~~ {#mycode .haskell}+d1 $ striate 3 $ sound "ho ho/2 ho/3 hc"+~~~~++This plays the loop the given number of times, but triggering+progressive portions of each sample. So in this case it plays the loop+three times, the first time playing the first third of each sample,+then the second time playing the second third of each sample, etc..+With the highhat samples in the above example it sounds a bit like+reverb, but it isn't really.++You can also use striate with very long samples, to cut it into short+chunks and pattern those chunks. This is where things get towards+granular synthesis. The following cuts a sample into 128 parts, plays+it over 8 cycles and manipulates those parts by reversing and rotating+the loops.++~~~~ {#mycode .haskell}+d1 $  slow 8 $ striate 128 $ sound "bev"+~~~~++The `striate'` function is a variant of `striate` with an extra+parameter, which specifies the length of each part. The `striate'`+function still scans across the sample over a single cycle, but if+each bit is longer, it creates a sort of stuttering effect. For+example the following will cut the bev sample into 32 parts, but each+will be 1/16th of a sample long:++~~~~ {#mycode .haskell}+d1 $ slow 32 $ striate' 32 (1/16) $ sound "bev"+~~~~++# Smash++~~~~ {#mycode .haskell}+smash :: Int -> [Time] -> OscPattern -> OscPattern+~~~~++Smash is a combination of `spread` and `striate` - it cuts the samples+into the given number of bits, and then cuts between playing the loop+at different speeds according to the values in the list.++So this:++~~~~ {#mycode .haskell}+  d1 $ smash 3 [2,3,4] $ sound "ho ho/2 ho/3 hc"+~~~~++Is a bit like this:++~~~~ {#mycode .haskell}+  d1 $ spread (slow) [2,3,4] $ striate 3 $ sound "ho ho/2 ho/3 hc"+~~~~++This is quite dancehall:++~~~~ {#mycode .haskell}+d1 $ (spread' slow "1%4 2 1 3" $ spread (striate) [2,3,4,1] $ sound+"sn/2 sid/3 cp sid/4")+  |+| speed "[1 2 1 1]/2"+~~~~++# Combining patterns++Because Tidal patterns are defined as something called an "applicative+functor", it's easy to combine them. For example, if you have two+patterns of numbers, you can combine the patterns by, for example,+multiplying the numbers inside them together, like this:++~~~~ {#mycode .haskell}+d1 $ (brak (sound "bd sn/2 bd sn"))+   |+| pan ((*) <$> sinewave1 <*> (slow 8 $ "0 0.25 0.75"))+~~~~++In the above, the `sinewave1` and the `(slow 8 $ "0 0.25 0.75")`+pattern are multiplied together. Using the <$> and the <*> in this way+turns the `*` operator, which normally works with two numbers, into a+function that instead works on two *patterns* of numbers.++Here's another example of this technique:++~~~~ {#mycode .haskell}+d1 $ sound (pick <$> "kurt mouth can*3 sn" <*> slow 7 "0 1 2 3 4")+~~~~++The `pick` function normally just takes the name of a set of samples+(such as `kurt`), and a number, and returns a sample with that+number. Again, using <$> and <*> turns `pick` into a function that+operates on patterns, rather than simple values. In practice, this+means you can pattern sample numbers separately from sample+sets. Because the sample numbers have been slowed down in the above,+an interesting texture results.++By the way, "0 1 2 3 4" in the above could be replaced with the+pattern generator `run 5`.++# Juxtapositions++The `jux` function creates strange stereo effects, by applying a+function to a pattern, but only in the right-hand channel. For+example, the following reverses the pattern on the righthand side:++~~~~ {#mycode .haskell}+d1 $ slow 32 $ jux (rev) $ striate' 32 (1/16) $ sound "bev"+~~~~++When passing pattern transforms to functions like `jux` and `every`,+it's possible to chain multiple transforms together with `.`, for+example this both reverses and halves the playback speed of the+pattern in the righthand channel:++~~~~ {#mycode .haskell}+d1 $ slow 32 $ jux ((|+| speed "0.5") . rev) $ striate' 32 (1/16) $ sound "bev"+~~~~++# Plus more to be discovered!  You can find a stream of minimal cycles written in Tidal in the following twitter feed:
doc/tidal.pdf view

binary file changed (63645 → 99443 bytes)

tidal.cabal view
@@ -1,5 +1,5 @@ name:                tidal-version:             0.2.9+version:             0.2.10 synopsis:            Pattern language for improvised music -- description:          homepage:            http://yaxu.org/tidal/
tidal.el view
@@ -55,7 +55,7 @@      tidal-interpreter-arguments)     (tidal-see-output))   (tidal-send-string ":set prompt \"\"")-  (tidal-send-string ":module Sound.Tidal.Context")+  (tidal-send-string ":load Sound.Tidal.Context")   (tidal-send-string "d1 <- dirtstream \"d1\"")   (tidal-send-string "d2 <- dirtstream \"d2\"")   (tidal-send-string "d3 <- dirtstream \"d3\"")