OSC: Tidal and Processing

Hey all,

I am trying to connect Tidal to processing, in which I'm using a Kinect v2 sensor to skeleton track people in a room.
I saw this: https://blog.tidalcycles.org/tidalcycles-and-processing/
But the GitHub looks quite old, just wondering if anyone has any good tips on using OSC with tidal, or any examples?

Thanks in advance, hope everyone is well :slight_smile:

just to be clear - I'm trying to send messages from processing to tidal, not the other way around.

Yes that post is about sending stuff from tidal to processing I think.

When you start tidal it says something about listening to port 6010 - that's where you can send OSC from processing. You basically send to the /ctrl path, and add a string that is a name for the value, and the value itself. Here's an example that sends the x position of the mouse (from 0 .. 1) when you click it on the processing window.

import oscP5.*;
import netP5.*;
OscP5 oscP5;
NetAddress tidal;

void setup() {
  oscP5 = new OscP5(this,12000);
  tidal = new NetAddress("",6010);

void draw() {

void mousePressed() {
  /* in the following different ways of creating osc messages are shown by example */
  OscMessage myMessage = new OscMessage("/ctrl");
  /* send the message */
  oscP5.send(myMessage, tidal); 

Here's an example of reading that value:

d1 $ sound "bd*8" # pan (cF0 "mousex")

There's a bit more info here:

It would be good to make this page clearer with more examples though.

1 Like

is there a way to display the current value of a control in tidal?

when I run something like show (cF0 "mousex") , it always just prints "(0>1)|0.0", no matter what value I set it to via OSC.

Yes true, a pattern doesn't have access to the control data until it's run within a tidal 'stream'.

There's no 'official' way to show the state but I've just had a look and this works:

import Control.Concurrent.MVar

readMVar $ sStateMV tidal

I'll make a note to make something friendlier..

1 Like

Edit: never mind, solved it by updating :slight_smile:

hmm, I get this error:

Variable not in scope: sStateMV :: Stream -> MVar a

even after importing Sound.Tidal.Stream .

Ah yes before 1.7.2 I think this would work instead:

import Control.Concurrent.MVar

readMVar $ sInput tidal

Hi thanks all for replying, here's my update.

I am receiving messages from processing (Kinect skeleton tracker) into tidal.

This is the part of the code in processing where I sent the message:

myMessage = new OscMessage("/ctrl");
myMessage.add("sf"); // have tried with and without this
myMessage.add(myVelocity1);// this is a float value like 0.3991282, have tried sending a string

This is my tidal script:

startTidal superdirtTarget (defaultConfig {cCtrlAddr = "", cCtrlPort = 6060})

d1 $ n "0" # s "sin1" # squiz (cF 0 "hello")

But I am getting this error message:

t>Unhandled OSC: Message {messageAddress = "/ctrl", messageDatum = [ASCII_String {d_ascii_string = "sf"},ASCII_String {d_ascii_string = "hello"},Float {d_float = 3.0124187e-2}]}

Following this info: Controller Input - TidalCycles userbase

I also saw this: https://www.reddit.com/r/TidalCycles/comments/drawql/need_help_receiving_osc_in_tidal/ and thought maybe it was something to do with using either 'sf' or 'cf'?

Any help hugely appreciated as always!

P.S. This is the supercollider code:

x = OSCdef.new(\makesynth, {arg msg;
if (msg[1]> 0, {

	SynthDef(\sin1, {|out, freq = 440.0, decay=0, sustain=1, pan|
var env = EnvGen.ar(Env.pairs([[0,0],[0.05,1],[0.2,1-decay],[0.95,1-decay],[1,0]], -3), timeScale:sustain, doneAction:2);

var sound = SinOsc.ar(freq);
Out.ar(out, DirtPan.ar(sound, ~dirt.numChannels, pan, env));



}, "/ctrl");

further clarification: So I want the number received from Processing to become the squiz number in above example.

If I remove the sf there's not error message (using show (cF 0 "hello"))

It's possible when we get the syntax right (taking sf off) that the message is received but nothing is happening with it.

I tried your tidal stream instructions above but doesn't seem to work either.

Hi @lucyjp786

That all looks fine. You're right to leave the 'sf' off, that bit is created automatically for you by the processing library (the 's' means the first parameter is a string, the 'f' means the second parameter is a float).

I think the problem could just be with 'squiz'. It doesn't have any effect (at least, none I've noticed) until you go over '1'. So you could add or multiply the value until you get the range you want, either in processing or tidal.

I could be wrong, but your code looks fine otherwise.

Hi yaxu,

Thank you for your reply.

The message is being received from processing it appears since running

readMVar $ sInput tidal

returns something like

fromList [("hello",(0>1)|19)]

19 is a value we have sent, so that is good:)


show (cF 0 "hello")

returns "(0>1)|0.0"

I run anything like even

d1 $ sound "bd" # speed (cF 0 "hello")

and the speed is not being set from the message value,


I am not sure what that means? I just ran the import, was I meant to do anything else?

Thanks again

Yes show (cF 0 "hello") will always return 0.0.

This all looks fine except it looks like processing is sending an integer not a float. That might be confusing things. Try changing myMessage.add(myVelocity1); to myMessage.add(float(myVelocity1));

I have checked this - processing is definitely sending a float.

I thought show (cF 0 "hello") would display the value being input to the pattern, since it is in place of a parameter, so, I don't get why it would always return 0.0?

But I notice that 'readMVar $ sInput tidal' returns

fromList [("hello",(0>1)|395.81597900390625f)]

the number 395.81597900390625 is what I sent from processing, and the f on the end seems to confirm it is a float?

So everything seems to be working - except the pattern doesn't receive the value still and show (cF 0 "hello") returns "(0>1)|0.0"

I am sending the osc message from another computer and using tidal <- startTidal superdirtTarget (defaultConfig {cCtrlAddr = "", cCtrlPort = 6060}), but that shouldn't make any difference or does it?

Thank you,


show (cF 0 "hello") will always return 0.0 because it doesn't have access to the number you've sent until it's running as a pattern.

You're right, the readMVar $ sInput tidal output does show that the value is set as a float, so everything looks fine in terms of processing > tidal communications. So d1 $ sound "bd" # speed (cF 0 "hello") should really work with that value. 395 is high for a 'speed' value so you would probably only her the bd as a click if at all.

I'm sorry for this. Yes, 399 was just an example, to show we are getting a value.

Here's the sequence we tested tonight, using value suitable for the pattern-

d1 $ sound "bd" # speed 3 - a low pitch

d1 $ sound "bd" # speed (cF 0 "hello") - a very high almost inaudible tick

let's see the value being received - using readMVar $ sInput tidal - to inspect the message, returns:

fromList [("hello",(0>1)|12.199999809265137f)]

Yes that's the value we send.

I also continuously send the same value 12.199999809265137 to make sure.

so it should be receiving the value 12.199999809265137 in the pattern in theory...

I test the sound it should make with a value as above

d1 $ sound "bd" # speed 12.199999809265137 I get a higher pitch but audible as expected so it doesn't mind that long pattern

I then try d1 $ sound "bd" # speed (cF 0 "hello") . This is still almost an inaudible tick.

I have set up as follows:
tidal <- startTidal superdirtTarget (defaultConfig {cCtrlAddr = "", cCtrlPort = 6060})
import Sound.Tidal.Stream

(Atom version 1.52.0 on mac.)

Hi @lucyjp786 I found some time to try to replicate this problem

I restart tidal afresh, and run this:

d1 $ sound "bd" # speed (cF 0 "hello")

I then run this in processing

import oscP5.*;
import netP5.*;
OscP5 oscP5;
NetAddress tidal;

void setup() {
  oscP5 = new OscP5(this,12000);
  tidal = new NetAddress("",6010);

void draw() {

void mousePressed() {
  OscMessage myMessage = new OscMessage("/ctrl");
  myMessage.add((float) 12.199999809265137);
  oscP5.send(myMessage, tidal); 

Then I click the processing window to send the OSC.

I then hear the pitched up 'bd'. It sounds the same as

d1 $ sound "bd" # speed 12.199999809265137

So I don't know what is going on with yours sorry. :confused: Could you try exactly the same steps?

Hi yaxu,

I'm very grateful for your help. Well I tried exactly what you said and the example you gave does work but required me to send the message from processing on the same computer using localhost. Perhaps this moves us a step closer to identifying the issue, but in my case I would like to have processing run on another computer.

The example you have worked when listening to messages from processing running locally.

d1 $ sound "bd" # speed (cF 0 "hello") - does receive the value from processing run locally so that's a good start

To see what's hapopening, I run:

import Control.Concurrent.MVar

readMVar $ sInput tidal

the input is the value sent from the local processing app. The value is 12.199999809265137 and I hear a pitched up 'bd'

I then run:

tidal <- startTidal superdirtTarget (defaultConfig {cCtrlAddr = "", cCtrlPort = 6060})

I amend the code in processing on the remote computer so that it sends a message named "hello2"


d1 $ sound "bd" # speed (cF 0 "hello2") - I just hear a faint tick so the value is now not being received

I run:

readMVar $ sInput tidal

This returns:

fromList [("hello",(0>1)|11.0f),("hello2",(0>1)|11.0f)]

  • 11 is the value I sent from the remote computer and the name was "hello2", not sure why it sees the "hello" message as the same value but that's probably irrelevant.

It seems that the issue is that the pattern does not obtain the message data when the message is sent from a different computer.

I hope you can help!

This is all very strange. You can see that the value is getting into the state there. At this point it really shouldn't matter which computer it came from. That one value seems to be set to match the other is really strange too.

I don't have access to another computer to test this myself.. But I think something else is going on here. You've described all the steps you've taken well and I just can't see why this wouldn't be working - it's really strange!