Tidal futures

Work has started on a bit of a rewrite/refactor of Tidal, I thought I’d write a quick post about how things are progressing. There’s a github project here if you’d like more info or want to get involved.

Structure comes from where you want

In current Tidal, “the structure comes from the left” has become a bit of a mantra. In the next version, it’ll come from where you want.

For example "1 2 3" + "4 5" used to give you "4 6 7", because the structure comes from the first part, and  that2 in the middle starts in the first half of the cycle, so matches with 4.

In the rewrite, by default, structure comes from both sides, so in the above example, you end up with the equivalent of "1 [6 7] 8" — the 2 gets split in two, to match with both 4 and 5.

To get the old behaviour, of structure coming from the left, you’d use |+, i.e. "1 2 3" |+ "4 5". To get structure from the right, you’d do "1 2 3" +| "4 5", which would give you "5 7".. Then |+| does exactly the same as +, i.e. it gets structure from both sides.

Unified pattern operators

|+|, |+ and +| all work on patterns of parameters (now known as control patterns) as well as patterns of numbers. So these two are the same: n ("1 2" + "3 4 5") + s "bass" and n "1 2" + n "3 4 5" + s "bass".

Of course there are also *, /, % and - versions of the above.

There is also |>| and |<| and friends; the arrow there points at where the values come from. So you could do "[1 2] [3 5 6]" |> "5 2" to take the structure from the left, and the values from the right, giving you "[5 5] [2 2 2". Aha!

|> basically does what # does now, we’ll likely keep that as an alias..

On the way.. Stateful patterns

Patterns can now respond to state, the idea being that you can do things like note "c a f e" # sound "bass" # speed (scale 1 1.6 $ control "knob1") where knob1 somehow maps to an external controller. Latency might be an issue.. It’s all in bits at the moment though, the new version doesn’t actually make sound yet.. Will update this post as things develop.

Internals

The most exciting thing for me is that the code is a bit cleaner on the inside, with fewer bugs and edge cases, and things generally make more sense. There’s even some tests, a start at creating a more complete definition of what patterns are and how they should behave. Patterns are flagged as being either continuous or discrete, which clears up a lot of ambiguity that was around before.

Keep an eye on the project for updates!

TidalCycles Extension 0.5.6 for VS Code

The TidalCycles extension for VS Code has a fresh update. A couple of improvements have been made around configuration setting errors and custom boot file path errors.

Config Setting Errors

The new update now removes errors telling you that the TidalCycles config settings were “unknown”. Now it’s just a clean config:

Neat!

Boot File Path Errors

A few minor versions ago, we introduced the ability to configure a path to a custom Tidal boot file. With that, you can now configure Tidal to load up all of your custom stuff in a seamless bootup sequence. However, if VS Code could not locate your custom bootup file it wouldn’t tell you.

Now, the Tidal console output and a VS Code message will notify you that you boot file was not found:

What’s more is that you can fix your boot file config settings and try to reboot Tidal without restarting VS Code. Fancy!

Oh Hey One More Thing!

VS Code recently released a new feature where you can dock the terminal to the right-hand side of the IDE:

So now you can put the Tidal output to the side instead of below your Tidal code, if you so desire:

TidalCycles 0.9.8

TidalCycles 0.9.8 newly out! It replaces 0.9.7 which didn’t work well with many haskell versions. Here’s a quick run through the changes since 0.9.6. Any problems or questions, join us on the #tidal channel on talk.lurk.org, or the tidal list on we.lurk.org.

How to update

If you use cabal (rather than stack) to install, it’s just a matter of running cabal update then cabal install tidal from the commandline. I’m not clear on the best way to update using stack (as tidal hasn’t yet updated on stackage LTS), if you know please leave a comment!

New Bjorklund (aka Euclidean) functions

New function einv, which fills the “blanks” left by e. For example, e 3 8 "x" gives "x ~ ~ x ~ ~ x ~", whereas einv 3 8 "x" gives "~ x x ~ x x ~ x".

Another new function efull which takes two patterns rather than one, combining e n k on the first with einv n k on the second. For example, efull 3 8 "2" "1" gives "2 1 1 2 1 1 2 1"

Yet another function distrib, which is similar to e, but takes a list of numbers. distrib [5,8] "x" is the same as e 5 8 "x", but distrib [2,5,8] will  do something rather freaky.. It will take the (5,8) pattern as a starting point (which is "x ~ x x ~ x x ~") and then attempt to distribute two events evenly over those five xs as though they were contiguous,  creating "x ~ ~ x ~ ~ ~ ~"). Basically, give it a list of numbers which increase in value and you’ll find some interesting off-kilter rhythms.

d1 $ distrib [5,7,16] $ sound "bd:7"

Sequence parser

Now you can give * and / subpatterns in the parser. For example "[a b]*[2 3]" would be the same as "[a b] [b a b]" (i.e. the first half of "a b a b", which is the pattern at twice the speed, and the second half of "a b a b b a b", which is the pattern at three times the speed).

Floating point notes

Now notes are floating point. This means that you can do things like d1 $ s "drum*8" # n (sine * 8). It also means that for some synthesised sounds you can play between the notes (microtones?), e.g. d1 $ sound "supermandolin*8" # n sine. There have been other adjustments in this area, so previously where you had to do fiddly conversions between integers and floats, you no longer have to.

ghc support

Tidal now supports the latest version of ghc (8.4.1). You should probably be running at least 7.10.3 by now but older versions may still work.

SuperDirt

Exciting SuperDirt update to follow soonish, including new MIDI support.

Enjoy!

TidalBot

TidalBot is back! You can tweet tidal patterns to @tidalbot on twitter, and it will give you back an mp3 of the pattern, as well as a PDF with a visualisation of it.. Here’s a couple of examples:

As a bonus, the latest pattern is currently being projected into the shop window of Access Space Labs on Fitzalan Square in Sheffield.

Atom Package v0.11.0: custom Tidal boot path

A new release (version 0.11.0) of the TidalCycles package for Atom is available today. With this version you can now specify a path to your own boot file in the package settings:

This means that you no longer need to modify the provided BootTidal.hs file in the package with your own custom logic (e.g. custom functions, additional modules, etc).

If you want to create your own boot file:

  1. Create a copy of the original (available here)
  2. Save it anywhere on your computer
  3. Modify the TidalCycles package settings to point to where you saved the new file

How to Haskell – developing a Markov chain

One of my favorite things about Tidal is that it’s inside of Haskell, a well-developed full-blown programming language, so all sorts of tricks are available.  After some discussion on Slack I developed code for making Markov chains to use in Tidal, and here I’ll try to describe the process.

First – what’s a Markov chain? Basically it’s some kind of random sequence where each step depends only on the step immediately before it. A common way to express this is to imagine several possible “states” for each step, and then write a “transition matrix” which gives the odds of going from one state to another.

How should we represent all this in Tidal/Haskell?  We ultimately want to have the chain as a Pattern, but it’ll probably be easier to start out with an ordinary list, and then use the listToPat function to turn it into a Pattern.  Let’s number the states with integers, starting at zero.  Then the chain itself will be a list of integers.  The transition matrix is a list of lists of floating point numbers – we’ll use doubles. Then one way of writing things is to have a function that takes the transition matrix and a chain as arguments, and returns a new chain which is just the old one with one new element added. Here’s just the signature:

Next let’s start the basic structure of what the function will have to do. Let’s call the transition matrix tp and the input chain xs. We need to look at the top element of the list to see what the “from” state is, and find that row of the transition matrix: tp!!(head xs). Next we need to generate a random number r (we’ll worry about how to actually do this later) and somehow use it to choose what the “to” state for the next step of the chain should be.

For example, if the row of the matrix were [0.20, 0.30, 0.50], this would mean 20% chance of transition to state zero, 30% chance to state one, and 50% chance to state two. So if our random number (between zero and one) were between 0 and 0.2, we’d pick state zero, between 0.2 and 0.5 state one, etc. This is easier to write if we take the cumulative sum of the row, and there’s a handy Haskell function we can use for that: scanl1 (+). That’ll turn the row into [0.20, 0.50, 1.00], and now when we have a random number we just need to find the index of the first element in the row larger than our random number. That’ll be the state the chain jumps to next.

There’s a handy Haskell function for finding things in lists too: findIndex. While it doesn’t quite work yet, we have most of our function:

(the : xs at the end adds the existing chain after the new element we just made)

One problem is that findIndex doesn’t actually return an Int. It returns a Maybe Int, because it might not find anything.  If our transition probabilities for each row add to one we’ll always be safe, but if we mess up or make a typo things might go wrong.  We have two options, (1) choose a safe default or (2) throw an exception and halt.  For the first option we could use fromMaybe 0 (to default to state zero), and for the second we’d use fromJust. Both require us to import the Data.Maybe module. Since I like to immediately know when I’ve made a math mistake and don’t mind if my performance grinds to a halt, I’m choosing the second option:

The final thing to take care of is the random number. While it’s not quite the intended use, we can use the timeToRand function, which takes a rational number as an argument and hashes it to a pseudorandom result. We just have to make sure we get a different number for each step of the chain by using the length of the chain, and do type conversion as necessary:

The last touch to make this a bit more usable is to wrap markovStep in a function that will repeat the step process to build a chain n numbers long from an initial state xi, flip it around so the most recent element is at the end, and turn the whole thing into a pattern with one number per cycle.

Now it’s ready to use in Tidal:

The chain states are always integers starting at zero, and that seems rather limiting.  But we can treat the chain as an index to some other array of our choice, which needn’t even be numerical:

I’m sure there are still improvements we could make, but this is a pretty fun start!

TidalCycles Winter Solstice, Sheffield UK

We’re having a Winter Solstice party in Sheffield on 21st December at Access Space, tickets now up! Featuring some of the leading lights from the local tidalcycles community Heavy Lifting, Tich, Digital Selves, Class-Compliant Audio Interfaces, Co(n)de Zero and Nullish. It will get algorave-y at some point.. There’s a facebook event for those who are that way inclined..

Some experiments: Reified duration, multi-parameter sequences in a single String, and chord sequences

These are a few new language features in an experimental branch of Tidal[1]. It uses a variant of the Pattern type called Epic. (It’s called an Epic because rather than having an implicit fixed duration of one, it can have an explicit duration of any length, including potentially infinite.)

Reified duration allows an Epic a of duration n can be glued (using the +- operator) to an Epic of duration k, to create one of duration n+k. (The duration of an Epic can be determined using the “period” function.)

Here’s the multi-parameter sequence idiom:

melody = p0 “t1%8 _bow d0 ,, d2 ,, _flute ,, t1%4 d5”

p0 turns the string into a ParamEpic, that is, something of type Epic ParamMap. The string descrbes four events, in sequence, separated by the “,,” symbol. The “t1%8” says “the following events have duration 1/8”. The subsequent “_bow d0” says “play the bow sample on scale degree 0.” The “,,” indicates that that’s the end of the description of the first event. The next event uses scale degree 2. Since the sample (bow) and duration (1/8) were specified already, those parameters carry over, so the next event is just like the first except it differs in scale degree. Then the flute plays, on (since it isn’t specified) degree 2 again, and again for a duration of 1/8. Last the duration switches to 1/4, and (because it’s not specified) the flute plays, on scale degree 5.

Other parameters (gain, speed, sustain …) can be specified in that notation — see Sound.Tidal.Epic.Parse.Cmd to see how each is written.

Here’s the scale sequence idiom:

scaleCycle = cata 1 [dim,lyd,aug]

“cata t as” turns a list (“as”) into the type “Epic a”, where each “a” has a duration of “t”. In this case, we’re creating a cycle of three scales — diminished, lydian and augmented — each with a duration of 1.

The scale cycle can be applied to the melody like this:

scaledMelody = scaleCycle <*> melody

or this:

v3 $ scaleCycle <*> melody

This code is very incomplete. In the issue tracker[2] I’ve listed some of the directions in which I’d like to take the code. Suggestions, quesitons and contributions are eagerly invited.

[1] https://github.com/JeffreyBenjaminBrown/Tidal/tree/epic
[2] https://github.com/JeffreyBenjaminBrown/Tidal/issues