TidalCycles – mini language for live coding pattern


TidalCycles (or just ‘Tidal’ for short) is a mini language designed for live coding pattern, embedded in the Haskell pure functional programming language. It was originally 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 lot of other people are starting to make diverse music with it, and it’s a fully fledged free/open source project with many contributors.

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 or MIDI) can be patterned independently, using a variety of pattern transformations. For more info you can see some videos, or have a look at the documentation on tidalcycles.org.

At the time of writing (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 [ 
whenmod 4 3 (stut 4 0.5 0.33) $ sound (samples "[[kv kv:2]/2 ~ ~ tite:1] [sv tite:2] [hh ~ tite:4 tite:3]" (run 44)) 
|+| speed "[1 [1,1.5] [0.8,2] [0.8 1 0.5 1.2]]/4", 
whenmod 7 5 (trunc 0.25) $ slowspread (slow) [1,2,1.5,1,3,0.5] $ chop 64 $ 
sound "[~ bass2] bass2:1*4 [[bass2 bass2:1] [bass2:0 bass2:1]]" |+| speed "[1, 0.5]"]

d1 $ whenmod 8 6 (|+| speed "0.9") $ every 4 (0.25 <~) $ every 3 (0.25 <~) $ 
stack [
slow 16 $ (trunc 0.25 $ striate 16 $ sound "k*24 s:4*16 hh*12 perc*16")
|+| delay "0.4" |+| gain "0.7", 
whenmod 7 6 (striate 2) $ slow 2 $ sound (samples "[~ kh] [~ kh? ~ kh] [cp:3 s] [ kh]" (run 18)), 
whenmod 6 5 (striate 2) $ slow 4 $ sound (samples "hh*6 hh*4 hh*3 hh*2 hh*2 hh*3 hh*4 hh*6" "3") 
|+| cutoff (scale 0.07 0.3 $ slow 5 sine1) |+| speed (scale 0.5 1 $ slow 4.1 sine1) |+| resonance "0.4" |+| delay "0.2" ]
|+| delaytime "0.4"
|+| delayfeedback "0.5"

Here’s a video of Kindohm performing live with Tidal in an algorave in Hamilton:

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.

21 thoughts on “TidalCycles – mini language for live coding pattern

  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.

    1. 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. 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*!

    1. You obviously missed out on the last 50 years or so of music composition. Sounds like you need to read up on just about everything.

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

  5. 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.

    1. 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:

  6. 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.

    1. 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.

      1. 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.

  7. Saturday night I was at a noise show here in Pittsburgh where one of the performers was working with Tidal, and it was impressive. Impressive enough that I looked up the file extension and have started playing with it. Nice work!

  8. Interesting to see the negative criticisms here. I would think musicians versed in the digital realm could appreciate this unique platform. I have been using hardware since EMU and DAWs of all sorts forever. This language has already helped me break out of the box. I’m creating my own workflow with it, and making great things. To those saying there are silly effects etc., or no “groove” (wtf kind of elitist cookie-cutter response is that) you obviously haven’t tried it using your own sounds, nor do you understand OSC, or synthesis in general. If you did, you would understand that the demos listed here are of that persons style, and not necessarily tidal’s “sound”. It would be like discrediting a project like Cockos’ Reaper because it sounds “shitty” or something. In fact, anyone talking crap on an open source project really sucks. They have enough time to troll, but not enough time to develop their own code. Great job on this unique way to make music! As a tabla player working in the Hindustani rhythm system of Taala, I can use this to bridge the gap between my love for cyclic patterns and digital music.

Leave a Reply

Your email address will not be published. Required fields are marked *

Translate »