TidalCycles

script it…walk away.

Tidal in a nutshell is a live coding language that allows you to create complex patterns riding on the SuperDirt synth in SuperCollider.  Im not entirely sure how I found out about Tidal but since I have it’s been a bit of a journey getting things working and experimentation to fully understand some of the things that are happening.  I wanted to document some of my own findings just for the sake of reenforcing the knowledge internally as well as helping anyone that might find this while searching.

First things first, the installation is pretty straight forward.  At the time of writing this post the installation instructions are at at the Tidal site and for MacOs and Windows they work well.  Linux is a bit of a hit or miss, but I’ve had success following the instructions here.  Another option that makes things really easy to get going is to use the Docker proved by Eric Fairbank’s and try things out.  This is a quick and easy way to start up a Linux system that uses SuperCollider and Tidal.  Regardless of what you choose, run the following in your editor and make sure you hear a sound.  So far, for all of the things I’ve wanted to do, MacOs has been insanely easier than the others, so that is what I’m sticking with.

d1 $ s "bd"

If it makes a sound, then you WIN! IF not, then now is a good time to mention the live coding community talk site.  I would definitely suggest creating a user account and introducing yourself.  There are quite a few very talented live coding artists as well as some very smart people that can help you get through the errors.

From there, I would highly recommend checking out Eric Fairbank’s 3 Part Tutorial which can help bridge some gaps between Haskell and Tidal.  This was extremely useful for me, since I’m not very well versed when it comes to Haskell, but I do have experience with other languages.  After reading through the tutorials the operation of Tidal made much more sense to me.

At this point you are probably ready to go and for most people this is enough.  Personally I had wanted to see how Tidal and Live Coding in general could co-exist with Ableton live or Bitwig so I began a deep journey into synchronization and multi tracking.  I think these links will end up being helpful.

First, in order to synchronize Ableton as tightly as possible, there exists a Link plugin for Tidal that has worked pretty well for me.  The instructions are at an old Lurk mailing list page and so far have worked well for me on both MacOS and Linux.  I have not been able to get Tidalink to build on Windows (nor has anyone else as far as I know).  Once you’ve built Tidalink and have it running make sure you click into the terminal that it is running in and press the ‘w’ key which will decrease the BPM by 1 then press the ‘e’ key which will increase it back to 120.  I’ve attached a couple screenshots that show what you should see if things were successful, the second screenshot showing a message in the console “Slaving Tempo.”  At that point you can use Tidal to set the cycles per second where a setting of 0.5 is 120 bpm.

cps 0.5

Slaving Tempo…Towards the Right hand side…

You can play around with this, setting cps to 120 or something lower than 0.5 (don’t forget the ‘0.’ if you are using less than 1).  So far, Tidalink, has provided me a pretty solid sync for using time based effects in Ableton that process sound from SuperCollider and SuperDirt (remember that Tidal does not make any sounds, so SuperDirt through SuperCollider is what generates the sound).  I’ve tried to do some numbing here and there (see a later screenshot) but really Tidalink has been pretty solid.  It’s a slippery slope to full on insanity and murderous rage when try to get devices to sync perfectly so a little drift here and there is something I just deal with.

One of the largest hurdles I’ve come to with SuperCollider is multi channel configuration for processing things in Ableton.  This was important to be me because I have quite a few high quality effects and instruments, so really multi channel audio, MIDI and synchronization are top wants/needs.  After quite a few questions (possibly a barrage) in the Lurk groups, I was eventually able to get things routed out from SuperCollider through SoundFlower 64ch and into Ableton.  Most of it was trial and error and quite a bit of help from the community but it ended options that I moved into my SuperCollider startup file.

s.options.numBuffers = 1026*2;
s.options.memSize = (512*1024);
s.options.device = "Soundflower (64ch)";
s.options.numOutputBusChannels = 16;
s.waitForBoot {
	~dirt = SuperDirt(2, s);
	~dirt.loadSoundFiles("/Users/digitalohm/samples/*");
	s.sync;
	~dirt.start(57120, [0,2,4,6,8,10,12,14]);
};

This is where I’d like to spend a little time explaining things, which may be incorrect and incomplete, but the options here were all crucial to getting this working.

First the s.options stuff are server options for SuperCollider.  These values were reached by trial and error, and really they were configured to get SuperDirt functioning correctly when using multiple channels.  At the default install and usage, the stock server settings worked fine for me.  Once I started increasing busses, I would get some errors (search the #tidal, #superdirt and #supercollider channels on dirt and you’ll likely find the errors I’m talking about).  So I started with the numBuffers and doubled the value until I found something that worked.  I did the same thing with memSize until finally the settings you see above are stable for what I’m doing at this time.

From there the ‘device’ option is choosing the SoundFlower 64 Channel device as my outgoing audio which is how I get things from SuperCollider into Ableton (I’m testing Bitwig next btw).  The ‘numOutputBusChannels’ is set to 16 which gives us 16 channels of outgoing audio from SuperCollider.  At this time I have not been able to successfully get more channels happening, for whatever reason when I go higher, they start to do some weird wrapping around in Ableton causing orbits to be played on the same stereo channels.  Regardless, 16 channels of outgoing audio equates to 8 stereo channel in Tidal which should be plenty for most people especially considering each stereo channel can be a synth or a multi part sample sequence.

The next block starting at ‘s.waitForBoot’ is where the startup file will wait for SuperCollider to boot with the specified settings and then boots SuperDirt.  The settings inside are obviously SuperDirt settings, hence the ~dirt prefix.  The first setting is telling SuperDirt to operate in a 2 channel per Orbit mode, so that each track (i.e. ‘d1’) has the capability to pan from left to right across a stereo field that uses 2 channels in SuperCollider starting with 0.  The next line is where you will load your sample directory (I’ll get to that more later).  The ‘sync’ waits to load the files before booting the SuperDirt server on port 57120 with Orbits of 0, 2, 4, 6, 8, 10, 12 and 14.  In order these Orbits are 0, 1, 2, 3, 4, 5, 6, and 7 and those are the number used in Tidal.

At this point if everything is still working you can open up Ableton (or other DAW) and configure your input tracks.  Select the SoundFlower (64 ch) device as your input source and then create your stereo tracks.  If you are using the referenced SuperCollider startup options then this should become 8 total stereo tracks starting with 1/2 thru 15/16.  As I mentioned earlier I was unable to get anymore to function properly but if anyone does get this working please let me know so that I can test and update the instructions.

Here are some screenshots of the Ableton configuration I’m using.

 

You can start testing your Orbits with something like:

d1 $ s "pmsin" # n "c7" # orbit 7

Where the

# orbit

is the going to be 0-7 that corresponds to your 1/2 thru 15/16 stereo input tracks. The above command gives the following screenshot where you can see audio happening on the 15/16 track.

See…it really does work!

Once you get things configured and working (testing all orbits), save your Ableton project to use as a template.  You really don’t want to have to create and map 8 tracks every time you want to use Tidal in this manner.  From here all you need to do is decide how you want to map, mix and master things from SuperCollider to Ableton, for example maybe you will use ‘d1’ as a synth track so send that to ‘#orbit 0’ and add the FX/EQ etc that you like for synths. Maybe ‘d2’ is going to be your hats and crashes, so add your favorite plugins to that track.

Next I think it is a good idea to throw out this tidbit for loading your own samples.  There are a few ways you can do this, some people like to add folders to the stock SuperDirt folder, however I’m not a fan of the stock samples so I wanted to create a new structure and go from there.  You simply need to create your directories (one level AFAIK) and put the samples in them.  From there your Tidal code should reflect the folder name.

Folders path: /samples/foldername/samplename.wav

While you are working on this you might want to test and make sure things work as you make changes.  Reloading the samples is as easy as running the following code in SuperCollider:

~dirt.loadSoundFiles("/Users/digitalohm/samples/*");

The above code reloads the sample directory and any changes you have made will be updated in SuperDirt.  If you are curious my folder naming structure is based on the typeofsound_identifier_numberofsamples.  So for example the kick_brute_24 tells me that there are kick sounds from a pack called brute and 25 files (counting from 0).  So an example to play a sound would be:

d1 $ s "kick_brute_24:2"

which simply plays the 3rd sample (counting from 0) in from the kick_brute_24 folder.  I like putting the number at the end so I know the max range of samples I can use in code.

Finally, I think we should touch on MIDI which at the time of writing this post is about to change. MIDI in Tidal is accomplished fairly easily. First you’ll want to import the MIDI.Context library and run the following lines to display your MIDI devices.

import Sound.Tidal.MIDI.Context
displayOutputDevices >>= putStrLn
devices <- midiDevices

The above code will display the MIDI devices that are available.  In my case I’m using the built in IAC driver.  When you run ‘displayOutputDevices’ you will hopefully see some output devices in your Tidal console, like you see towards the bottom the screenshot below.  For my system the “IAC Driver IAC Bus 1” is the device I will want to choose.

The next thing is to create a couple variables and assign them. From what I understand at this time you need a variable for sending notes and a second for sending CC values. This is done like so:

ccv1 <- midiStream devices "IAC Driver IAC Bus 1" 1 ccallController
m1 <- midiStream devices "IAC Driver IAC Bus 1" 1 synthController

From the above example I have assigned the variable ‘ccv1’ as to send cc values through the IAC Driver IAC Bus 1 device on Channel 1.  I chose to use ‘ccv1’ and not ‘c1’ because ‘c1’ is already in use for the Classic Dirt synthesizer and I just didn’t want to mess with it.  Note that I called out the MIDI device name as “IAC Driver IAC Bus 1” and not “1: IAC Driver IAC Bus 1”.  The “1:” is just the system numbering the results.  Now you can test by sending some notes and cc values to whatever device you have receiving data on MIDI channel 1:

m1 $ n "c3 ~ ~ ~" # dur 1 # velocity 0.8
ccv1 $ cc119 $ discretise 64 (slow 64 (scale 0.001 1 $ (sine1)))

The above code will send the c3 note with a duration of 1 and velocity of 80% (standard velocity).  The next line will send a sine wave out to cc119.  Note the use of the ‘discretise’ function.  I’ve also used in the code ‘slow’ which makes this a fairly slow moving LFO and the scale is 0.001 to 1.  These are values that I’ve used for Ableton devices and synths so YMMV.  0.001 is the value that gets the knobs back down to zero and the value of 1 is the 127 limit.  Mapping MIDI in Ableton is a big pain in the ass because you can only map from values being sent in.  So you basically have to run a single CC message (like above), go into Ableton, map it, then stop it in Tidal, change the value, rinse repeat.  It’s possible that a Python mapping can be created in Ableton that will map CC values quicker but I’m not ready to dip that deep.

Finally, if you want to send more than one CC value (which you probably do) then you can utilize the ‘stack’ command in Tidal:

ccv1 $ stack [
  cc119 $ discretise 64 (slow 48 $ (scale 0.001 1 $ (sine1))),
  cc118 $ discretise 64 (slow 24 $ (scale 0.5 1 $ (sine1)))
]

From the above code you can send sine wave LFOs to CC values 119, and 118 at the same time.

So there you have it.  My notes on getting Tidal configured for multi channel audio and other tips for getting started.  I hope this documentation finds its way into the browsers of other people going for the same setup and helps to get them started quickly.  There’s nothing more frustrating than wanting to make music and having to troubleshoot all of your spare time away.

Leave a Reply

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