Mute/Unmute via OSC/MIDI

I've written up some documentation for the new OSC API for controlling playback, with example SuperCollider code for listening to MIDI controller input.

The example code is pretty configurable, so it wound up being pretty long, but I hope that it's easy enough to follow. Please let me know if you have any questions or issues with the documentation. Also, any contributions/edits on the wiki are very much appreciated!

https://tidalcycles.org/Playback_Controllers

(Tagging @TimPuk and @cleary, who I remember have specifically asked about this)

11 Likes

Legend! Thank you. Will check tomorrow. Tidal Cycles meet atm.

Beautiful, thank you!

Super grateful for all your work implementing and documenting this!

I've given it a run and while the mutes are working beautifully, I've found the solo mappings are not working - has anyone else tested (@ben )?

I think I've figured out your issue, if I'm reading the photo of your setup correctly.

From my sense of the documentation floating around online, the top row of buttons on the Launchpad don't send MIDI Note On/Off messages, but rather Controller messages (I think because those buttons are usually used for transport control, etc, rather than triggering clips?)

So, the quick solution is to use another row of buttons for the soloing. I can help develop some code if you want to use those buttons for anything, but I'm not sure if it makes sense to expand the example code, just because at that point it seems too unwieldy for documentation and should probably just be a library.

(btw, thanks so much for catching the non-existent "soloAll" thing! I think I missed it because of copy-paste blindness or something)

Wowsers - you've gone above and beyond here, I am incredibly grateful. I'll give it a test later but I'm confident you're correct :pray:

[edit] you nailed it, I have happily functioning solo/mute switches on my board :smiley: thanks again

Anyone have this working for TouchOSC? I have the messages from ToggleButtons coming in as binary but I'm too newbish with SC/Dirt to figure out how to actually send muteAll/unmuteAll, soloAll/unsoloAll and the individual mutes/solos.
I imagine it's something similar to this that i have for the volume fader controls?

   ~dirt.orbits.collect ({ |x, i |
	var faderPath = '/1/fader' ++ (i + 1);
	OSCdef(faderPath.asSymbol, { |msg| x.set(\amp, msg[1]); }, faderPath);
});

i have all the mutes and solos defined in the same way, e.g.:

OSCdef.new(
	\fader1,
	{

		arg msg, time, addr, port;
		"fader1:".postln;
		msg[1].postln;

    },
	'/1/fader1',
	n,
	8000
);


OSCdef.new(
	\muteAll,
	{

		arg msg, time, addr, port;
		"muteAll:".postln;
		msg[1].postln;
    },
	'/1/muteAll',
	n,
	8000
);

I'm not sure where to take msg[1] and turn it into '/muteAll' or '/unmuteAll', for example, and how to actually send these new msgs to SuperDirt

Thanks!

I just got nanokontrol2 and based on examples managed to make it work perfectly with GitHub - davidgranstrom/NanoKontrol2: SuperCollider interface for NanoKONTROL2.

However I also want to light LEDs when using commands mute/silence in Tidal directly (e.g. mute 1). Is there a way to get those messages from Tidal to SC so I could light LEDs using NanoKontrol2 quark. Maybe trough OSC?

The mute messages don't get sent directly to SuperDirt, they go back to Tidal. To do that, you'll need to create a new connection to port 6010 (or however your Tidal is configured):

// This SuperCollider block creates the address:
(
var osc;
osc = NetAddr.new("127.0.0.1", 6010);
)

// And this would send a /muteAll message for example:
osc.sendMsg("/muteAll");

Combining that with the OSCdef you've described above, then something like this should work for toggling muteAll and unmuteAll:

(
var osc;
osc = NetAddr.new("127.0.0.1", 6010);

OSCdef(\muteAll, { |msg|
	if (msg[1] > 0, {osc.sendMsg("/muteAll")}, {osc.sendMsg("/unmuteAll")})
}, "/1/muteAll");
);

Let me know if you have any other questions or run into any issues with the code!

1 Like

Ahhh funny I was using that exact code today but as you say it turns out i was sending the messages to the wrong place, cheers!

1 Like

There's not currently a built-in way to send that information out of Tidal, unfortunately. The best method currently would be to redefine the mute (etc) functions in your BootTidal.hs file to both perform the operation on the given pattern and also send an OSC message to SC and the quark.

If you only use the hardware buttons for muting, you can track a copy of the state in SC. That's what the playbackState variable does in the example code. This is probably the easier path for now, but I understand that you were asking about responding to changes that happen directly in your Tidal code.

1 Like

Thanks. I will try to redefine mute function in Tidal to send OSC message too. I already track state, just also want to see nice lights when using only keyboard. Btw I post my code below, maybe someone find use of it.

~nk2 = {
  var osc = NetAddr.new("127.0.0.1", 6010);
  var flash = {|bt| { bt.ledState = 1; 0.1.wait; bt.ledState = 0; }.fork};
  n = NanoKontrol2(\external);
  n.ledsOff; // turn leds off
  n.sBtns.do {|btn, i|
    btn.onPress = {|val, bt|
      bt.ledState = (bt.ledState + 1) % 2;
      if (bt.ledState == 0) { osc.sendMsg("/unsolo", i+1) } { osc.sendMsg("/solo", i+1) };
    }
  };
  n.mBtns.do {|btn, i|
    btn.onPress = {|val, bt|
      bt.ledState = (bt.ledState + 1) % 2;
      if (bt.ledState == 0) { osc.sendMsg("/unmute", i+1) } { osc.sendMsg("/mute", i+1) };
    }
  };
  n.stopBtn.onPress = {|val, bt|
    flash.(bt);
    osc.sendMsg("/muteAll");
    n.mBtns.do {|btn| btn.ledState = 1; };
  };
  n.playBtn.onPress = {|val, bt|
    flash.(bt);
    osc.sendMsg("/unmuteAll");
    n.mBtns.do {|btn| btn.ledState = 0; };
  };
  n.recBtn.onPress = {|val, bt|
    flash.(bt);
    osc.sendMsg("/unsoloAll");
    n.sBtns.do {|btn| btn.ledState = 0; };
  };
};
~nk2.value();

Hi again, i'm apologising ahead of time that i had to take you up on that offer to help haha. This is a bit convoluted since I'm sending OSC from touchOSC to Supercollider on my PC and then to my laptop which is sending the tidal OSC stream to SuperDirt and Processing on my PC

When I start i get this message in the output:
[TidalCycles version 1.7.4] Listening for external controls on 0.0.0.0:6010

Then every time i hit any of the buttons on touchOSC nothing happens and it just says
Waiting for SuperDirt (v.1.7.2 or higher).

I've updated Superdirt to
Quark: SuperDirt[1.7.3-dev]

here's how i have a button set-up:

//Send OSC to TidalCycles
var osc;
osc = NetAddr.new("192.168.1.2", 6010);

//touchOSC
n = NetAddr("192.168.0.50");

OSCdef.new(
	\muteAll,
	{

		arg msg, time, addr, port;
		"muteAll:".postln;
		msg[1].postln;
		if (msg[1] > 0, {osc.sendMsg("/muteAll")}, {osc.sendMsg("/unmuteAll")})
    },
	'/1/muteAll',
	n,
	8000
);

Here's my BootTidal.hs config:

-- Send OSC to Supercollder and Processing on PC
tidal <- startStream (defaultConfig {cCtrlAddr = "0.0.0.0", cCtrlListen = True}) [(superdirtTarget {oAddress = "192.168.1.1", oPort = 57120, oLatency = 0.5 , oSchedule = Live, oWindow = Nothing, oHandshake = False, oBusPort = Nothing}, [superdirtShape]), (superdirtTarget {oAddress = "192.168.1.1", oPort = 2020, oLatency = 0.5, oSchedule = Live, oWindow = Nothing, oHandshake = False, oBusPort = Nothing}, [superdirtShape])]`

Thanks for your help.