Tidal is great fun

11 May 2014

To start off this particular journey into livecoding, I shall learn yaxu's tidal. Yaxu, or Dr Alex McLean, for a time studied at the Computing Department at Goldsmiths, the same department with which I am now pursuing my BSc. It's interesting, and encouraging to see that pioneers of the field have come from a place that's familiar to me.

Tidal is based on the haskell langauge. Oh my god. Haskell. Joe Nash loves it, and it's terrifying. If you're not into your PLT, and perhaps have learned Javascript, or C, or some other imperative language, perhaps with some object oriented stuff built in, and you're like me, Haskell will sound like a weird concept language that has a bizarre feature, like Chicken (which I cannot make myself understand) or brainfuck (according to wikipedia, "noted for its extreme minimalism"). That said, using tidal today and yesterday, then looking at some haskell code, I find that it has been a 'way in' to a certain extent, to the haskell world.

Haskell is a functional language. That is to say, functions are 'first class citizens'. In fact, in haskell, everything is a function. There aren't any variables in haskell, but you can declare a function that takes no arguments and returns only one result. There are all kinds of other weird things about haskell, and I don't plan on talking about them. Suffice to say, it's weird. If you want to know more, read Learn You A Haskell For Great Good which is available for free on the internet.

Tidal code looks like this:

bps (140/60)

d1 $ every 3 (striate 4) $ sound "[[gabba gabba:1]*2,[house:3*3 house:3*2]]"
|+| slow 5 (cutoff sinewave1)
|+| slow 7 (resonance sinewave1)
|+| slow 2 (pan sinewave1)

|+| slow 5 (speed sinewave1)

d1 $ slow 4 $ sound "[bd [sn:1 ~ ~ bd] bd*2 [sn:1 ~ sn:1 sn:1], hh*8]"
|+| resonance "0.75"
|+| slow 24 (cutoff sinewave1)

|+| slow 4 (vowel "a e i [a e i o]*4")

|+| resonance "0.5"
|+| slow 7 (cutoff sinewave1)

Haskell is great for embedded domain specific languages, and I'm told Tidal is one of those. It's great fun, despite taking a while to set up. It has this excellent pattern language that looks like this: [bd sn:1,hh*4]. That particular pattern makes a basic 4 4 kick snare pattern with 4 hi hats. The :1 after sn selects the second snare sample in the list of snare samples. All the samples are managed and triggered with the Dirt synth, and communication between tidal and dirt happens over OSC. A pattern exists outside of time - other functions specify timing. To get this to play (once you have set up emacs, jack and Dirt), you need to pass it through a couple of functions.

d1 $ sound "[bd sn:1, hh*4]"

In that code snippet, the d1 function is called, with the argument (sound "[bd sn:1, hh*4"]). The $ symbol replaces the parentheses that cause a function to be evaluated in haskell. The sound function parses the pattern string, and returns a OscPattern to the d1 function that sends out a message to Dirt over OSC that gets it to make some noise into jack. I found out after a bit of messing about that the pattern string is not actually a string, but is of type pattern string. The type is infered by the context, and the pattern string type is specific to the tidal module. The consequences of this is that when you're specifying a function that returns a pattern string, you actually have to say that what that function returns is a pattern string by putting ::Pattern String at the end of the function declaration. I had just come from writing a load of Python so it seemed a bit weird, but I guess if you're used to Java or C and specifying the return types of your functions I guess it's not all that nuts at all. Given the emphasis polymorphism seems to have in the haskell community I would've thought that it wouldn't matter, but I guess it does.

Great, so I've made a four to the floor basic drum beat. Now what? Well, plenty actually. The comma in that pattern string is like Les Paul - it gives you multitracking. So really, that pattern is like two simultaneous patterns, bd sn:1 and hh*4. Tidal has a bps (beats per second), which you can use to set a bpm. A line of code like bps (160/60) will set the tempo to gabba speed. OscPatterns returned from sound run once over a beat (unless you use slow, and probably other things which I will get to later), which means that the above pattern equates to a minim length (half-note for Americans) kick followed by a minim length snare, 'overdubbed' by four crotchet (quarter-note) high hat hits. Think AC/DC. However, tidal's patterning is great because you don't have to give it a 'musically divisible' number of notes in a bar. It's just a pattern of however many notes you like. This means that with 'overdubbing', you can get to do polyrhythms very easily. For example, you could do [bd sn:1, hh*5], a pattern I would find very difficult to play on drums myself as the high hat is in 5/4 but sped up to match the bar duration of 4/4. There's probably a more musically sensical way of expressing that, but I haven't taken music theory lessons in about 5 years, so my skills are somewhat lacking I'd imagine.

Polyrhythms! Excellent. But wait, there's more. There are a load of pattern transformation tools in Tidal. I've got to grips with every, rev, striate, brak, slow, <~ and ~>, but there are more that you can find in the Tidal documentation. Just today yaxu posted another addition to the family of pattern transformers in the Tidal forum. I'll write more about these in a future blog post as there's a lot to cover and I have an exam in the morning.

Another thing to look forward to me writing about is the synthesis parameters that Tidal has. I've had particular fun with the low pass filter, as well as the vowels.

My intial impression is that this is a really powerful tool with which to make rhythmic livecoded music. I've done a couple of streams, and even recorded a few. I'll hopefully write about my setup for streaming and recording too. For now, here's the first recording of me using tidal. Apologies.