Tidal – mini language for live coding pattern

tidal

Tidal is a mini language designed for live coding pattern, embedded in the Haskell pure functional programming language. It’s made by me (Alex), developed through a lot of performances (including as part of slub) and a few rewrites over a number of years. Now a few other people are starting to make music with it, so I thought it was about time I shared news of its existence here.

Tidal represents patterns as recipes for how to make infinitely repeating cycles, rather than as a score-like sequence of events. Time structures can be messed with freely, just by stacking extra pattern transformations on top of one another. The end result is a pretty terse way of describing, and more importantly (for live coding) changing musical patterns. Any synthesis parameter (describable as OpenSoundControl) can be patterned independently, using a variety of pattern transformations. For more info you can see some short technical demo videos, read a paper describing some of the ideas behind it, or have a look at the documentation.

This year (2014) Mike Hodnick has started putting up a Tidal pattern every day, and they’re sounding good. Here’s a couple from the start of the series, along with the Tidal code used to generate them:

d1 $ stack [ every 4 (0.25 <~) $ every 3 rev $ striate 64 $ 
sound "[lesshuman lesshuman/4 lesshuman/7 lesshuman/4]/2" 
|+| speed "[1 1 1 1.5]/8", spread' (striate) "[8 3 2 4]/2" $ 
slow 2 $ striate 64 $ sound "[[cities cities/1 cities cities/2]/4]"
|+| speed "[1.0 0.8 1.0 0.9]/4" |+| shape "-0.4"]

d1 $ every 4 rev $ stack[ smash 3 [3,1,2] $ 
sound "[~ [~ uldrums*9]]/2" |+| speed "2", every 5 rev $ 
striate 128 $ sound "[uldrums/5]/2" |+| speed "[1 2 1 1.3]/4", 
whenmod 5 3 (0.25 <~) $ striate 128 ( sound "sytrus1/6" 
|+| speed "[1 0.5, 3 1.5]/2")]

d1 $ spread' slow "[2 3 1]/4" $ jux (iter 8) $ every 4 rev $ sound "[bd*6 [sn*3 bd*2] [bd*4 sn] [sn*6]]" 
|+| speed ((+1.0) slow 1 sinewave1) |+| cutoff ((*0.5) slow 2 sinewave1) |+| resonance ((*0.5) slow 3 sinewave1)

Correct me if I'm wrong, but I don't know of anyone apart from myself who has performed live with Tidal yet, so here's a quick video clip of me playing solo late last year:

Installation instructions (currently for Linux and Mac OS), documentation, source code and discussion mailing list can be found via the project home page.

It's worth noting that many other languages, including Supercollider and Common Music, include mini languages for manipulating pattern. Laurie Spiegel wrote a nice paper motivating all this, "Manipulations of Musical Patterns", back in 1981.

17 Comments

  1. I just wanted to know why you decided to embed a big part of your DSL inside strings, instead of writing everything in Haskell. Was it difficulties with the type system?

    It seems that to program with your system, one must sometimes dynamically generate strings like “[bd*6 [sn*3 bd*2] [bd*4 sn] [sn*6]]”, which is doable but is a poor programming interface. (Plus there is no type checking for languages inside a string)

  2. Hi Eliasias,
    The quick answer is tersity. I just needed a really quick way to specify polyrhythmic and polyphonic sequences, so I can make some source material to play with within a few seconds. This is important because I use this in musical improvisations, live coding from scratch, so any delay in adding commas, quoting barewords etc is to be avoided. So I wrote a parser (https://github.com/yaxu/Tidal/blob/master/Sound/Tidal/Parse.hs).

    However, none of these pattern transformations actually work on strings, they work on patterns (which are themselves higher order functions, from time to events). I used a GHC extension to automatically parse strings into patterns when the types call for it. So where you see a string, there is a hidden function (called “p”) which is parsing that string into a pattern.

    So no, you wouldn’t ever have to (or want to) dynamically generate these strings. All the parser does is create a shorthand for underlying functions. So “*” parses to the function “density”, and “[]” parses to “cat”, and the values like “bd” are turned into patterns with the Haskell function “pure”. You could do anything in pure Haskell without using the parser at all. It would just take a bit longer.

    All that said, it would be an interesting exercise to see how far you could get with terse representation without writing a parser.

    • By the way, if I’m thinking about this right, there is type checking in the string, it’s doing monadic parsing with the excellent Parsec library.

  3. TheGoodMachine

    I don’t see any *music* in there. Only sound effects. Rather silly sound effects at that.

    You need to read up on the concept of a *groove*!

    • Thanks for sharing your clear and authoritative definition of music.

  4. TS

    Sheesh. It’s cheap to criticize. Maybe some “groove links” would be helpful. Thanks for sharing this cool project, OP.

  5. I love this project a lot. Any plans in supporting MIDI?

  6. Yes a previous version had an osc-midi bridge (well, osc-dssi-midi). Have been meaning to get tidal sending midi to my volca beats over midi so hopefully soon.

    • Johan

      +1 for midi :)

  7. '2+

    someone told me that ive gotta use emacs to take advantage of this .. is vim version already there too?

    • Hi,
      A couple of people have asked me that question.. But no vi/vim version has appeared yet. I don’t think it would be difficult to implement though, it’s just a case of sending blocks of code to the haskell interpreter (ghci).

      Someone documented how to run tidal from a plain ghci prompt here:
      https://github.com/yaxu/Tidal/wiki

    • Actually you could probably use this with some minor configuration..
      http://www.vim.org/scripts/script.php?script_id=2356

  8. very cool

  9. Shpitz

    Hi Alex, Tidal is great. I love your performance videos on youtube. the only reason that I’m not using it is because I need the ability to output more then 2 channels, so every sound would have additional processing.

    • Hey,
      It is possible to do multichannel work with tidal, I’ve done 16 channel performances.
      You would need to recompile dirt, by editing the CFLAGS line, e.g. for 8 channels:

      CFLAGS += -g -I/usr/local/include -Wall -O3 -std=gnu99 -DCHANNELS=8

      (Best to also remove -DDIRTYCOMPRESSOR from that line, as it is mono.)

      Then from the unix commandline do:
      make clean ; make

      Then pan just goes up to the number of channels you have starting with zero, i.e. to send stuff to the 4th channel you do

      d1 $ sound “bd”
      |+| pan “3”

      It does equal power panning, so for example 2.5 would be halfway between the 3rd and 4th speaker.

      This is intended for surround sound work, but you could also use it to send sounds to different effects chains, by routing the channels in jack.

      • Shpitz

        I haven’t seen “-DDIRTYCOMPRESSOR” anywhere. Anyway, I compiled it with 16 channels and it worked perfectly. Thanks.

        I think it might be a good idea to put it on the documentation so everyone would be able to benefit from it. Lack of documentation can kill good softwares.

        • Patches/pull requests for documentation improvements are very welcome

Leave a Reply