Open Stage Control + TidalCycles = ❤️

Hi everybody, I made a quick tutorial on setting up Open Stage Control to control TidalCycles variables. It's very useful to me and I hope you may find it too


1. Open Stage Control Mixer

  • Choose the port of your preference for OSC communication
  • Create widgets, and set their preArgs to /ctrl

2. SuperCollider Boot File

  • Add the following to your startup.scd (you can find it by clicking on **File > **)
OSCdef(\controltidal, { arg msg;"localhost", 6010).sendMsg("/ctrl", *msg); }, '/ctrl', NetAddr.localAddr );
  • Remember to set the port (6010) according to the one you chose in step 1

3. Tidalcycles Boot File

  • Add the following to your boot.tidal`. In case you don't have one, you can start with the default one provided on its website.
tidal <- startTidal (superdirtTarget { oLatency = 0.1, oAddress = "", oPort = 57120}) (defaultConfig { cFrameTimespan = 1/20 , cCtrlAddr = "" , cCtrlPort = 6010 })
  • Remember to set the port (6010) according to the one you chose in step 1

Link to full post:


Very cool thanks.

Small point of clarification, but I think the initialism stands for Open "Sound" Control?

Open Stage Control is just the name of the software, that may be a little bit confusing.

1 Like

Man, that software works so great with Tidal ! A huge thank to you for your tutorial too :slight_smile:

Did you ever try to insert a X/Y Controller widget and feed Tidal with "rangeX" and "rangeY" values ? It would be awesome in term of possibilities I guess.

1 Like

it really is, thanks for confirming!

Not yet, but it's a great idea!!

So, I've found a way to send OSC with a XY Controller in Open Stage Control.

  • Add a widget > Pads > xy
    Take note of its ID (in example : xy_1).

  • Contrary to a knob or a fader, the XY widget returns 2 values : rangeX and rangeY. However, the "preArgs" field in OSC parameters doesn't seem to accept many values. So we'll have to recover each value separately.
    The trick is to create 2 new input elements. Do this twice : Add a widget > Basics > Input

  • Affect each input element to a preArgs (for example : Pad_X and Pad_Y)

  • Set this value to Pad_X : #{@{xy_1}[0]}
    It returns the abscissa value from the XY widget.

  • And this value to Pad_Y : #{@{xy_1}[1]}
    = the ordinate value from the XY widget.

That's done.

An example with Tidal :

d1 $ sound "bev" # distort (cF 0 "pad_X") # accelerate (cF 0 "pad_Y")

You can now control both parameters in real time :slight_smile:
I let you imagine the world of awesomeness made possible with the multiXY widget !

1 Like

If you have an incoming control value from 0 to 1, then you can use it to select a function from a list:

d1 $ selectF (cF0 "pad_X") [id, fast 2, hurry 2, every 3 (iter 4)]
  $ sound "bd sn mt ht"

To use it as a time pattern, for example the first input to 'fast', you can use cT:

d1 $ fast (range 1 4 $ cT0 "pad_Y") $ sound "bd mt ht lt"

By the way cF takes a default value, e.g. cF 0 "foo" to use the 'foo' pattern, or 0 if it's not yet set.

cF_ "foo" is the same but doesn't take a value, it just returns silence until the "foo" pattern is set.

cF0 is the same as cF 0


I had no idea this was possible. That's brutal.
You should also be able to pick samples / synths using it, too, right? Like:

d1 $ n "0(3,8)"
  # (selectF (cF0 "pad_X") . map s) ["bd", "sn", "superpiano"]
1 Like

This is amazing.

It seems even more useful to send an integer over OSC so that we can pick the functions by whole number (at least this was my small discovery):

d1 $ pickF (cI0 "testI") [id, fast 2, hurry 2, every 3 (iter 4)]
  $ sound "bd sn mt ht"

PS: How is everyone getting the syntax highlighting in the forum?

1 Like

Type "```" (unquoted) on lines above and below your actual code :sparkles:

1 Like

If you set up a XY Controller in Open Stage Control in the way that I explained, think about bypassing the widget's OSC parameters (osc > bypass > true) because it will unnecessarily flood Tidal's console with "unhandled OSC values" (with many decimals).

Also, the 2 inputs which get the separate X and Y values can be settled with the number of decimals you need, and it's a seamless process for Tidal then.

I've set up a multiXY widget this morning (it's like a XY widget but with multiple points). If you're interested, I can give some further explanations to set it up (and it's a monster tool in combination of live coding ahah).

1 Like

I'm definitely interested, please share it! I tried the XY Pad and your solution works wonders, it's amazing :slight_smile:
Thanks a lot for the bypass tip, my console was going nuts without that.

Setting up a multiXY widget in Open Stage Controller :

  • add widget > Pads > multiXY
  • Choose the number of points as needed in the menu.
  • Create a pair of inputs for each point you've chosen : add widget > Basics > input
  • Affect each input element to a preArgs (e.g : "Pad_X", "Pad_Y", "Pad_2_X", "Pad_2_Y" ).
  • Set values to each input element :
    #{@{multixy_1}[0]} with "Pad_X"
    #{@{multixy_1}[1]} with "Pad_Y"
    #{@{multixy_1}[2]} with "Pad_2_X"
    #{@{multixy_1}[3]} with "Pad_2_Y"
    etc... Values are increasing with additional points.
  • Don't forget to bypass multiXY widget's OSC
1 Like

so after my initial faux pas in the thread and a couple of months of more intensive tidal cycles playing, I've finally come back to this and it looks awesome!

Thanks ghales, your video channel has some really useful stuff, and @a.d.du.nord, that real time control looks like it's going to solve one of the limitations I run across in tidal relatively regularly...

Post new-moon plans forming :smiley:


no problem dude! looking forward to see what you come up with :slight_smile:

Hey! I'm playing with Open Stage Control, it's a fantastic piece of software. Looking at the possibilities, there is one thing I'd love to do with it: do some visual feedback on euclidean rythms.

The idea is to use a matrix container and make it a row of N leds. Then, it is possible to send messages such as /matrix/5 1 and it will turn on the led at index 5. Now, that would come in handy to display how a rythm looks like, if it is bound to N steps.

So far, here is what I've got:

First, I followed the Custom OSC tutorial so I can send messages to Open Stage.

let osTarget = Target {oName = "openstage",
                       oAddress = "",
                       oPort = 8080,
                       oLatency = 0.2,
                       oSchedule = Live,
                       oWindow = Nothing}
    osFormats   = [OSC "/matrix/{index}" $ ArgList [("led", Nothing)]]
    index       = pI "index"
    led         = pI "led"
    oscmap      = [(osTarget, osFormats),
                   (superdirtTarget, [superdirtShape])]


tidal <- startStream defaultConfig oscmap

My Open Stage interface looks like this (the important part here is the row of leds, obviously):


Now, to control that row of leds, I can do this:

d1 $ index (run 16) # led "1 0 0 1" -- your sequence of 1 and 0 goes here

Now, if I use an euclidean rythm:

d1 $ index (run 16) # led "1(3,16)"

This will turn on led [0,5,10] as expected, but it won't affect the other steps, so it won't "clean" them. Snooping around I found there are a bunch of euclid functions, such as euclidInv, which led me to this:

d1 $ index (run 16) # (euclid 3 16 $ led 1)
d2 $ index (run 16) # (euclidInv 3 16 $ led 0)

That one will do the cleaning trick, but I'm sure there is a clean one-liner somewhere and I can't see it...


Awwwwww yisssssss

d1 $ index (run 16) # (euclidFull beats 16 (led 1) (led 0))

As usual, just after posting a question, I find the answer :smiley: I guess writing it down helps to reframe the problem...

EDIT: ok so the final version is this:

let beats = cI 0 "beats"
    shift = cI 0 "shift"
in d1 $ index (run 16) # (rot (-shift) $ euclidFull beats 16 (led 1 # s "bd") (led 0))

With this, I can control the number of beats and the offset from the Open Stage interface, and have the led pattern update in realtime. It would be even better if the whole led pattern could update at once, but I guess the progressive refresh is good enough!

I need your Open Stage Control CSS really bad :~~
that print looks friggin awesome. how'd you do it?