Autonomous Live Coding: Summer of Haskell Project

This summer, I was fortunate enough to get the chance to work on a project as part of the Summer of Haskell. This allowed me to work on the TidalCycles (Tidal) live coding software: free/open source software for pattern generation with code. Often this is used to create musical pattern, although increasingly it has been used for other things too, e.g. pattern visualisation, weaving. It is a language that is regularly used in live coding, a subset of artistic programming which looks at live improvisation and performance of algorithms to produce artistic outputs such as music, visuals or dance (to name a few).

I was mentored for this project by Alex McLean, the creator of TidalCycles and was provided with some real insight into the innards of the software. I’ve also been making and performing music with TidalCycles myself for a little while now (since around 2017) and so I’ve come to know it well enough, and have in the past looked at ways to shape it around my own practice. As TidalCycles is a domain-specific language embedded in the functional language of Haskell, it makes writing functions on the fly a possibility for people wanting to customise their own pattern creation, if they have the time and interest to get into the Haskell side.

In this project, I wanted to both expand TidalCycles in new directions and tie it in with the work that I am currently doing on my own PhD based in computational creativity. My initial project proposal aimed to tie these together, whilst trying to learn some Haskell too by perhaps leveraging existing Haskell libraries.

Why create an autonomous live code agent? Why use Tidal?

Machine Learning models tend to deal with processes that are static. Typical symbolic representations are in MIDI format (which in itself is quite a limiting representation of musical content, usually reducing the complexities of music to only pitch number and velocity and therefore losing a lot of nuance around timbre and expression). Moreover, most are trained on scores of musical information: pieces in which the outcome has already been predetermined (usually by a composer). Machine Learning of Indeterminate Music is also an area that has been underexplored, perhaps due to the complexities that arise, however Tidal could be a particularly useful software to explore these ideas.

How do we want autonomous agents to behave?

One of the first things we considered was the behaviour of our autonomous coder- how do we want it to behave and, maybe more importantly, how do we want to interact with it? Is it going to be standalone "intelligent" agent (musical intelligence would, arguably, have to include a strong focus on emotional intelligence) or is it augmenting the work of the live coder? How much autonomy can we (and do we want to) give it? Something that was also discussed was whether the agent would behave constructively or destructively? Arguably, both are equally valid forms of creative input and the latter presents an interesting challenge too: most computationally creative systems tend only to focus on the creation of new material. But, depending on our definition of human creativity, can we posit destruction as a form of creativity too?

About the project

The initial project proposal submitted in April 2020 looked at creating functional machine learning algorithms in the Haskell language for autonomous generation of new, syntactically correct Tidal Code. Hasktorch is an ongoing project that aims to leverage the core C++ libraries shared by PyTorch for ML/neural network architectures written using Haskell. Although this might be useful in future iterations of the project, the work ended up moving away from this, partly due to the challenge of having to implement a new NN architecture for this specific project, which seemed a little out of scope for a three month project.

To initiate this project, my mentor Alex also put me in touch with members of the community who were already working on similar projects during the community bonding period. This allowed me to reach out to others who were working in the area already, as there have been a few projects that have attempted to tackle this problem. I also started the Summer of Code by seeing what other things had been going on in the area by posting a thread on the TidalCycles forum. This flagged a few various interesting things, including an autonomous agent in Python using sequence-to-sequence neural network algorithm to autonomously generate Tidal Code and grammar-based agents, such as this auto-evaluating autonomous coding agent or evolutionary-based algorithms for autonomous code generation.

Tidal Development

Getting involved in the open source development of TidalCycles was one of the first things that I did during the summer of code, allowing me to understand more about both the contribution process and the innards of how TidalCycles applies the Haskell type system to represent the generation of patterns. I worked on fixing a couple of issues, like altering and adding new functions for better representations of an existing function, working on running tests for functions and changing the input type for other functions.

Further to this, I started working with my mentor on some work on development of a Tidal API. This was an experimental project that was creating a Haskell-based listener and receiver for interacting with Tidal. This followed the need to support messages sent between Tidal and autonomous agents running in a different process and/or language, but turned out to also be useful for human user interaction, allowing more feedback between user and software. For example, the user could run code and error check (where > represents an outgoing message and < an incoming message):

> /code <id> <source>

< /code/ok

expand the notation into a different format (e.g. from Tidal’s “mininotation” to Haskell):

> /expand <code> 

< /expand/ok <expanded code>

or get the cycles per second value

> /cps

< /cps <number>

Autocompleter

As the work previously mentioned by Stewart et al. seemed particularly close to what I was initially proposing for the Summer of Code, we got in contact with them to arrange a few meetings to discuss any areas of overlap and potential collaborations. Their work however looked at building the architecture within Python, leveraging the tensorflow library and neural nets used commonly for speech translation problems. Rather than simply attempt the problem again within Haskell, we decided to alter some of this brief, perhaps looking to see how we could leverage some of their work to build a creativity support tool for Tidal users looking for some creative inspiration. The idea that came from discussions was building an "autocomplete" agent, one that could take an incomplete string of TidalCycles code and return suggestions of functions or parameters

Leveraging the existing work done by Stewart and Lawson meant adapting some of the code for use in an autocomplete agent became part of the scope of this work. To do so, in collaboration with the other researchers, we ended up building a repository for the two-way communication between the machine learning agent in python and the atom editor commonly used for evaluating TidalCode. This was done building a node server in atom and a mock python server, and hot key evaluation to select certain lines/words from the editor and send to the python server.

As the auto-completer’s ML backend was running in Python and we were sending OSC messages between a test python server and currently only an atom editor, the earlier discussed Tidal API would attempt to make this interaction more transparent and universal.

Tidal Walker

One issue flagged with the autocomplete agent was the nature of the corpus used for generation of new pattern, based on the code of a small set of live-coders. This would be able to create ‘statistically probable’ code, which might not have been seen before but would be unlikely to introduce radically new ideas. We wanted a way to expand the ‘search space’ of the machine learning agent, by adding combinations of functions to the corpus that had not been seen before.

This led to a related work that used random walks, Haskell’s strict type-checking system and n-gram models from a corpus of existing patterns, to create a potentially infinite number of possible Tidal patterns. The ‘walker’ takes a haskell type signature as a target – in this case a pattern of synthesiser control messages, and chooses a function that can ultimately produce that target. It then recursively fills in any missing arguments of that function. This takes account of partial evaluation, and the specialisation of polymorphic types as arguments as they are applied.

The aim was to create a walker agent that could navigate through the conceptual space of all possible Tidal code, modelling Haskell’s type system to ensure anything generated would be syntactically valid. To ‘steer’ this walk, we weighted its decisions based on n-gram data, created realistic code that could then be used to train the autocomplete agent. There were various steps taken to implement this. Below shows the architecture of such a program.

Tokenising Code

One of the first things that had to be done to achieve this was to correctly tokenise the patterns for the ngrams to be generated upon. The tokenisation process is described as below, with various functions having been written in Haskell to achieve the various steps.

Calculating Ngrams on Data

Once the dataset was correctly tokenised, it ended up being used to create the weightings for the ngram walker as follows. The tokenised code is then imported into a separate Haskell module, the frequency of ngrams is generated by calculating the frequency of occurrence of n-pairs of functions in the tokenised data. From the frequency distribution of n-pairs of consecutive functions, this can then sort these into a data structure that can be accessed later on by the walker to calculate the associated transition probabilities.

Weighted Walking for Unique Outputs.

Once the code has been tokenised and analysed, it can be used by a walking agent to generate new sequences of syntactically correct code. The inherent type signature structures are used as a framework for generating all the possible options that can occur after an initial function is chosen at random, thus ensuring the final code output generated can be evaluated. The weightings are then applied to their corresponding potential next functions in the sequence given the current function is known from the ngram data structure (this is applied as a Maybe value to denote that values are optional as there may not be some corresponding values from the dataset for the set of all possible next functions).

A variable is also implemented that could be a user controlled feature of any further iterations of the project, called "adherence." This allows control over how the weightings are structured, whether they adhere to the corresponding dataset, especially wherein a "Nothing" data type is generated for functions that are possible but unlikely.

Future Works

Currently, the tokenisation is only working on the Haskell functions of the TidalCycles domain specific language. There is, however, another aspect to writing TidalCycles known as its mini-notation. In brief, the mininotation is a mini-language within Tidal, allowing polyrhythmic sequences to be efficiently expressed. They are denoted by overridden strings, which are parsed into Tidal patterns. At this stage of this project, these strings have been treated as single tokens. However, this does not capture the inherent structures from the mini-notation and future work should look at how to correctly tokenise and model these too. Perhaps one way around this would be in creating a function that could expand these mininotation expressions directly into executable Haskell code.

Furthermore, the ngram dataset at the moment is currently only generating bigrams (ngram where n=2) giving limited higher-order representation. E.g. the output of a bigrams might show the transition probabilities for functions as:

slow 8

whereas an ngram of higher order (n >2) gives a wider representation of what is happening in the pattern:

range 0.1 0.2 $ slow 8 $ sine

Similarly, other functions e.g. "weave" takes a high number of functions for achieving syntactical correctness which a bigram couldn’t directly capture. Furthermore, ngrams do not capture the hierarchical structure of a syntax tree – looking into applying hierarchical Markov models to the abstract syntax trees could be a better approach, and is also left for future work. Nonetheless, bigrams, in capturing the likelihood of two tokens appearing together, does appear to improve the overall coherence of the generated code.

Some of the issues encountered with the output of the walker’s generation were similar to problems encountered in genetic programming. One of these is the notion of bloat (i.e. where various functions are added together that end up cancelling each other out like a series of successive (+1) and (-1) functions). In the Tidal generation this occurs where a pattern could be reversed 2n or 2n+1 times and this would be the same as an identity or the reversed pattern. Another issue encountered was idempotent functions, (i.e. where f(f(x) = f(x)). This occurs in cases such as every 1 (f(x)), which means that the function would be applied as without the every. Creating a filter for these would increase the efficiency of outputted code.

Project Reflections

Other than achieving outcomes from the project, some of the main things I have learnt have been to do with collaborating on an open source project. Not coming from a traditional computer science background, this has been one of the first larger scale projects I’ve been able to work on (although what I do has meant I’ve learnt a lot of computer science over a short period of time, I still feel “new” to the area). Some things that have been particularly useful to learn are using github to collaborate on coding projects (and how to fix merge conflicts!) and on attempting to meet milestones throughout the project, including trying to organise these coherently. 

One particular problem I encountered throughout was that most of my coding experience comes from imperative coding. This meant that when trying to write code in a functional way seemed a little unintuitive for me. It took some time to work on using concepts like folds and recursions rather than concepts like iterating over a for-loop. Learning Haskell through completing a project has definitely helped me think in a more functional way.

Finally of course, there were some errors that were encountered with the project. Debugging in Haskell was a little tricky without being able to backtrace/ find breakpoints in the code. Using a lot of print statements helped conceptualise how the program was running and where things might have been going wrong.

Tidal club course

It’s not all about actual tides..

I’ve started a “Learning TidalCycles” course with support of Lucy Cheesman (aka Heavy Lifting) and other friends (newcomers – see below for video explaining what live coding and TidalCycles is). We called it “Tidal Club” after some peer learning events Lucy started in Sheffield. The course is now in the fourth week of the first group of lessons. In an effort to keep the course accessible as possible, there’s absolutely no time limit on getting through the material, which is oriented around pre-recorded video and worksheets. (more thoughts about making online courses accessible here..)

So registrations are still open, and you can join the course it at any time, (although I might have to pause signups from time to time so we don’t get overrun with new learners). Interaction is based around the Tidal Club forum, for which we’ve got a code of conduct, and Lucy has been developing guidelines for giving each other constructive feedback on our work too.

The course is “pay as you feel” via this shop, with the following guide for the first four-week block:

  • £0 – for those who wouldn’t be able to participate otherwise
  • £12 (£3 per week) – standard
  • £24 (£6 per week) – those with extra cash to spare
  • £40+ (£10 per week) – those with institutional backing

Here’s the video lessons covered so far, at the time of writing (6th May 2020):

  • Intro
    • Installation
    • Technical tour of a Tidal system
  • Week 1 – mini-notation week!
    • Tidal Interaction
    • Loading sample packs
    • Sequencing with mini-notation (parts one, two and three)
  • Week 2
    • Starting out with effects
    • Manipulating time with setcps, cps patterns and fast/slow functions
    • Combining patterns with arithmetic (plus the ‘hurry’ function)
  • Week 3
    • Exploring the ‘every’ function, including tackling that ‘$’
    • ‘cut’ vs ‘legato’
    • ‘slice’ and ‘splice’
    • ‘chop’ and ‘striate’
  • Week 4 (this week)
    • Continuous ‘waveform’ patterns – sine, square, tri, saw and random functions (with a bit on binary patterns)
    • More still to come – all the random functions, including shuffle, sometimes and someCycles
  • Plus!
    • Challenges! (so far, exploring big tempo changes, and making music from speech)
    • Live streams (at different times to reach different timezones, and archived for later viewing)
    • A performance talk-through with Antonio Roberts
    • + more to come, including reference material.

After this four-week block we’ll take a rest, so I can prepare for the next four-week batch of lessons, taking things to the next level.. For which there’ll be another opportunity to pay-as-you-feel!

If you’re unsure what live coding and/or Tidal actually is, then here’s a quick video intro about that (and the also awesome Gibber and Hydra live coding environments), which I did for the creative guild in Sheffield:

If this sounds good to you, sign up over here!

(If you don’t want to join the course, but want to join the Tidal Club forum, you can register here.)

Six Months of Tidal

I first attempted to install TidalCycles about six months ago, in May 2018. I’ve learned a lot in the past six months, and I’d like to share some of the knowledge I’ve acquired. If you are new to Tidal or you’ve tried it out in the past and got stuck, then this unnumbered list of observations is for you.

Installation can be tricky

When compared to installing software from a package manager or app store, installing TidalCycles can feel frustrating. The installation instructions are great and the people in the Tidal chatroom are friendly, but it took me a few weeks to really comprehend how TidalCycles, SuperCollider, SuperDirt, Haskell, my text editor, and JACK (because I run GNU/Linux) all work together. Tidal is not a standalone app, it’s a Haskell library.

While other free software communities repeatedly push people to “read the manual,” the Tidal community seems genuinely happy to help out folks who get stuck. They know installing Tidal can be tricky. Of course many people install Tidal without problems, but some people get stuck and the open issues tagged “Holy grail” in the Tidal code repository are each about improving the installation process. Until the Holy grail is found don’t feel afraid to ask for help if you encounter problems.

Learning tidal is fun

Once you’ve installed it, learning TidalCycles is really fun! You can do all sorts of mind blowing things with Tidal, so jump in however you like. If you like videos, you could start with an overview, some basic tutorials, get more in-depth tutorials, or just watch random videos that people upload to the Internet. If you prefer text, then definitely start with the Creating Patterns and Reference section on tidalcycles.org. For the least frustration, I’d recommend starting with the guide to Creating Patterns

The Tidals they are A-changin’

Once you start learning TidalCycles, you will quickly realize that lots of information is incomplete or outdated, and that even though people are sharing their screens and showing their code, they will do things that won’t work for you. It will serve you well to embrace the fact that TidalCycles is evolving.

For instance, this fantastic introduction to “algorithmic dance culture” is as much about TidalCycles as it is about algoraves, and it was one of the early signals to me that making music with Tidal can be distinct from other kinds of musical activities. But when I tried to recreate what happens in the video (around the 8 minute mark), I did not succeed. In the video, I saw code like this:

n "d7 a7 [c6 e] e7" # sound "rash"

This code won’t work even if you have followed the installation instructions perfectly. If you know even a little bit about Tidal, then you know that, for now at least, Tidal starts with nine connections to the SuperDirt synthesiser, named from d1 to d9, and this code does not look like even the most basic Tidal code examples, such as:

d1 $ sound "bd"

Secondly, the sound “rash” does not come with SuperDirt. About 3 or 4 months into learning Tidal I came across a link in a tidal workshop to a repository with extra-samples that included rash. It also took a few months to figure out that the talk featured an experimental editor for TidalCycles, which doesn’t require the use of d1, d2, etc.

What is more, you might think that the Reference section of the TidalCycles website would be complete, but it’s not. Perhaps you watch a video and see someone using a function such as fadeOut or spreadChoose, and you check the Tidal Reference, you might not find what you seek. Of course, this isn’t that people using Tidal want to confuse you. The TidalCycles live coding environment is evolving and that’s OK. If you find something that doesn’t make sense, feel free to look through the codebase for it or ask in the #tidal chatroom.

TidalCycles music is unique

To maximize your enjoyment of Tidal, I suggest becoming aware of your preconceptions about music. Trying to use TidalCycles to recreate existing music can prove to be difficult. In one of my early experiments I attempted to reproduce Steve Reich’s Violin Phase, which seemed perfectly suitable for TidalCycles. It was a rather difficult challenge because I was new to Tidal and trying to make it do something specific. However, once I dropped the goal of trying to create some thing, I had a lot more fun. Tidal is not designed to make it easy for you to re-create Beethoven’s 5th Symphony, your favorite Radiohead song, or pretty much any music from any period in the history of Western art music. While there is no right or wrong way to Tidal, a lot of folks seems to enjoy their experience more when they just play around with sound.

Haskell is not imperative

It is absolutely not necessary to learn the programming language Haskell to use Tidal. Unlike imperative languages such as C or Java, Haskell is a pure functional programming language created by a committee of academics. Whether you have zero experience with programming or you know more than a dozen programming languages like me, Haskell can be difficult to learn. And even if you follow all of the examples in Learn You a Haskell for Great Good!, watch a bunch of videos with the same information, read Real World Haskell, the Haskell Book, and hang out at your local Haskell user group, that might not be enough to grok the Tidal code. If reading about the theoretical background behind Tidal makes you want to learn more, then by all mean jump in to the Tidal codebase. I just want to warn you the learning curve might be rather steep.

Tidal like it’s 2018

I have greatly enjoyed learning TidalCycles and getting more involved with the live coding community. I’ve participated in a wide variety of technology and music communities and somehow this live coding group feels different from any of them. But you should not feel like your are required to get involved in the community. Many people just want to install Tidal and play around with it. For these people, and perhaps for you, it does not matter how other people on the Internet use Tidal or how much they know about Haskell. My goal here is to share some of the what I’ve learned, but ultimately what you do with Tidal is up to you. I encourage you to check it out!

SuperDirt MIDI

Remember that good old tidal-midi Haskell package? You won’t need it any more! Now you can control your favorite MIDI synth from Tidal with SuperDirt MIDI, and with no other dependencies.

If you’re more of a video-watching person, check out the video tutorial:

Ready to jump in? In this post we’ll cover prerequisites and usage.

Prerequisites

Prerequisites/installation requires later versions of Tidal and SuperDirt:

  1. Upgrade to the latest Tidal (this post assumes version 0.9.10 or greater)
  2. Make sure you have the latest SuperDirt quark. Uninstalling and reinstalling the SuperDirt quark might be easiest. See github.com/supercollider-quarks/quarks for details.

Usage

To begin, you’ll start in SuperCollider. Start up SuperDirt as you normally would. Then, in SuperCollider eval the following code:

MIDIClient.init;

You should now see a list of the system MIDI devices in SuperCollider’s post window. The output will look something like this:

MIDI Sources:
	MIDIEndPoint("LoopBe Internal MIDI", "LoopBe Internal MIDI")
	MIDIEndPoint("Focusrite USB MIDI", "Focusrite USB MIDI")
MIDI Destinations:
	MIDIEndPoint("Microsoft GS Wavetable Synth", "Microsoft GS Wavetable Synth")
	MIDIEndPoint("LoopBe Internal MIDI", "LoopBe Internal MIDI")
	MIDIEndPoint("Focusrite USB MIDI", "Focusrite USB MIDI")

Take note that these MIDI devices have two parts to their names. You will need both parts in the next step, which
is to actually connect to the MIDI device. Eval the following line:

~midiOut = MIDIOut.newByName("Focusrite USB MIDI", "Focusrite USB MIDI"); // substitute your own device here

Above, we have stored a reference to the device in a variable named ~midiOut.

Finally, define the name of the “synth” in Tidal you will use to control this device. Below, we will call it “midi”. Eval the following line:

~dirt.soundLibrary.addMIDI(\midi, ~midiOut);

Optionally, you can define a latency value on your device:

~midiOut.latency = 0.45;

That’s it for initialization. You should now have a MIDI device connected in SuperDirt, running as a synth named “midi”.

Usage in Tidal

Note Patterns

Now we can start writing some Tidal patterns to control the MIDI device. Let’s send it a trivial note pattern:

d1 $ n "0 2 4 7" # s "midi"

That should play a simple four-note pattern. Notice we’re just using the synth name “midi” to send notes to the MIDI device. Piece of cake eh?

You can also use the note-name and octave notation:

d1 $ n "c4 d4 e5 g3" # s "midi"

MIDI Channels

The default MIDI channel is 1. SuperDirt MIDI channels are indexed starting at zero, so MIDI channel 1 is `midichan 0`:

d1 $ note "0 2 4 7" # s "midi" # midichan 0

If your synth is listening on a different channel, let’s say, MIDI channel 5, you would use `midichan 4`:

d1 $ note "0 2 4 7" # s "midi" # midichan 4

Notice that `midichan` accepts a pattern of numbers, so you can use a pattern to play on different MIDI channels:

d1 $ note "0 2 4 7" # s "midi" # midichan "0 4"

The above pattern plays notes “0 2” on channel 1 and “4 7” on channel 5.

CC Params

To send a CC param to your synth, the best way to do it in the new SuperDirt MIDI is with a different Tidal pattern. To create this pattern, you’ll be using
two new SuperDirt MIDI params:

  • ccn – the CC param number you want to control: `ccn 30`
  • ccv – the value to send to the CC param, ranging from 0 to 127: `ccv 64`

Here’s a full example, sending a value of 64 to CC param 30:

d2 $ ccv 64 # ccn 30 # s "midi"

You can of course also specify the MIDI channel with `midichan`:

d2 $ ccv 64 # ccn 30 # s "midi" # midichan 4

You can specify patterns of CC values:

d2 $ ccv "20 40 60 80 100" # ccn 30 # s "midi"
d2 $ ccn "30*4" # ccv (scale 20 100 $ slow 30 sine) # s "midi"

Note that the left-most pattern defines the rhythm, as always with Tidal.

If you have a specific feature on your device that listens on a specific CC number, you can give it a friendly name if you wish:

let ringMod = 30
d2 $ ccv "0 20 50 60" # ccn ringMod # s "midi"

If you have many CC params you want to control at once, a `stack` works well:

d2 $ density 8 $ stack [
  ccn 30 # ccv (scale 0 127 $ slow 30 sine),
  ccn 31 # ccv "[0 70 30 110]/3",
  ccn 32 # ccv 10 
  ] # s "midi"

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!

Function of the Month #0 – preamble

Welcome to a new series of “Function of the month” (FotM) blog posts. We hope to build up a comprehensive picture of TidalCycles by periodically making a post with a short video. We plan to be true to the name, and do this every month, with a focus on a particular function. However allow us to deviate from this plan immediately by first taking some time to describe how the different parts of a standard Tidal system works. Take this as a hopefully illuminating preamble for this series.. We’ll get onto specific Tidal functions in FotM #1!

0. Introduction

A video accompanying the below will go here, once we’ve made it. In the meantime please feed back with comments and questions on the below, which we’ll then be able to respond to in the video itself.

A complete TidalCycles system has a few components which we’ll tour around, the TidalCycles language for generating pattern from code, the SuperCollider synthesis system which hosts SuperDirt for turning those patterns into sound, and an editor such as Atom which acts as a text editor for writing those Tidal patterns.  but lets start our tour with the TidalCycles language itself.

1) TidalCycles

TidalCycles is a computer language for generating pattern from code. It consists of an expressive mini-language for describing polyrhythmic sequences, and a wide range of pattern operators and functions for patterning such sequences in a variety of ways. For example, by rotating them, mirroring them, shifting them in time, combining them into weird interference patterns, and ‘glitching’ the sequence with random numbers.

You’ll have noticed that we often call TidalCycles by its shorter name Tidal. That’s actually what it was originally called, until someone started up a music streaming service with the same name, and we felt the need to differentiate..

Tidal is written in a programming language called Haskell. Strictly speaking, when you’re making patterns in Tidal you’re mostly writing Haskell code, but in practice you don’t need to learn Haskell in order to be a top Tidal coder. This is because Tidal is what is called a “Domain Specific Language”, embedded in Haskell, which supplies its own model of computation, operators, function and mini-language for sequences, all centred around pattern generation. That said, are some things about the underlying Haskell language that take a bit of getting used to though, like what that mysterious $ is doing, we’ll confront this in a later episode.

It’s important to note that the Tidal language does not make sound by itself, it only makes patterns. It talks to other software or hardware to make sound (using e.g. the OSC or MIDI protocol),  usually SuperDirt running in SuperCollider. However, quite a few people have plugged Tidal into custom software in order to generate patterned visuals, lights or even choreography. For now lets focus on the common case – SuperCollider and SuperDirt.

2. SuperCollider

SuperCollider is the synth behind most desktop live coding systems, and by default, Tidal is no exception. As we said above, Tidal is made for generating patterns, but doesn’t itself make any sound, that’s why you need SuperCollider installed. SuperCollider is a very well developed programming language that is designed for sound synthesis (and digital signal processing in general) that can itself be live coded. By default though, you’ll just use it in order to host SuperDirt.

2a) SuperDirt

SuperDirt is a sound synthesis framework designed especially for TidalCycles, and written in SuperCollider. You don’t need to know anything about SuperCollider in order to run SuperDirt, you just have to start it up, and Tidal will by default send messages to it in order to trigger sounds. SuperDirt comes with a fairly large library of sound samples, as well as a range of synthesisers.

With the latest version it is also possible to register MIDI devices with SuperDirt, so that you can trigger external sounds on soft/hardware synthesisers. This will be the topic of a FotM post later on.

If you run some Tidal code like this:

d1 $ s "cp supermandolin"

You’re sending two trigger messages to SuperDirt per cycle, first for the cp sound, and then the supermandolin sound. In the case of cp, SuperDirt will play a short sound sample, which it will find inside a folder called cp on your computer. You can find it from SuperCollider – from the menus select ‘open user support directory’, and then open ‘downloaded-quarks’ and then ‘Dirt-Samples’. You’ll see a bunch of ‘.wav’ files inside the cp folder, because cp isn’t a single sound but a set of them known as a ‘soundbank’. By default SuperDirt will play the first one – to play the second, you can specify cp:1 in your pattern instead (it starts counting at 0).

You won’t find a folder in Dirt-Samples called supermandolin, because that is a synthesiser rather than sample-based soundbank. You can play notes as numbers like this:

d1 $ note "0 7 12" # s "supermandolin"

or as note names like this:

d1 $ note "c gs7 c6 gf4" # s "supermandolin"

(If supermandolin isn’t working for you, it’s almost definitely because sc3-plugins isn’t installed properly, which is required by most synths.)

3. Atom

Your main interface to all this is probably Atom, or otherwise one of the other supported text editors. Atom is where you type in and run your Tidal patterns, although strictly speaking, Tidal itself doesn’t run inside Atom but in its own process. You’ll have installed a ‘tidalcycles’ extension inside Atom, but this isn’t tidal itself, but an interface to it. Clear? Hopefully!

Summary

Ok, that was a brief tour of the different components of a standard Tidal system. There’s a text editor Atom, sending code to a Tidal process to run, which in turn sends messages to SuperDirt to make sound, which in turn runs inside SuperCollider. Hopefully that’s straightened out some confusions, but feel free to ask some questions below!

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.12.1: current directory boot file

The latest version (0.12.1) of the TidalCycles package for Atom has a new option to use a bootup file in your current project directory:

What this means is that you can now have a custom bootup file for each “project” you may be working on (e.g. compositions, MIDI modules, custom OSC setups, live sets, etc).

All you need to do for this to work is to create a BootTidal.hs file at the root of your Atom project folder:

If you’re not sure where to start with a custom boot file, you can reference a sample default one on the TidalCycles Atom package page, or use this code:

:set -XOverloadedStrings
:set prompt ""
:module Sound.Tidal.Context

(cps, nudger, getNow) <- cpsUtils'

(d1,t1) <- superDirtSetters getNow
(d2,t2) <- superDirtSetters getNow
(d3,t3) <- superDirtSetters getNow
(d4,t4) <- superDirtSetters getNow
(d5,t5) <- superDirtSetters getNow
(d6,t6) <- superDirtSetters getNow
(d7,t7) <- superDirtSetters getNow
(d8,t8) <- superDirtSetters getNow
(d9,t9) <- superDirtSetters getNow


let bps x = cps (x/2)
let hush = mapM_ ($ silence) [d1,d2,d3,d4,d5,d6,d7,d8,d9]
let solo = (>>) hush

:set prompt "tidal> "

With these configuration options, you can now have complete control over your own custom Tidal boot code rather than modifying the source code of the package’s boot file.

For more information check out this video that explores all of the boot options in the Atom Tidalcycles package: