SerialOSCClient for SuperCollider

SuperCollider peeps, let me know your views on this!

See below, my (alpha-stage) SerialOSCClient library for SuperCollider. It’s mostly been tested on Windows 10 using SuperCollider 3.6.6 but it should work on OSX (and I guess Linux). My aging Macbook unibody (2008) freaks out a bit when I tried this and hot swapped devices, no idea why but this appears to be serialoscd 1.2 related as it also occurs with frequent hot swapping of devices when SuperCollider is not running.

The library is contained in this file:
SerialOSCClient.sc (26.6 KB)

Installation: download and drop SerialOSCClient.sc into your SuperCollider Extensions folder and Recompile Class Library.

SerialOSCClient works a bit like MIDIClient. You init it and use *def classes (GridKeydef, EncDeltadef, etc) for listening to buttons and encoders. There is no need for OSCdef. For setting led / ring state each attached device gets a SerialOSCGrid or SerialOSCEnc instance with methods to facilitate this.

See below code for intro:

// First, plug in a grid device. Hot swapping is implemented and might work but is not well tested.

SerialOSCClient.init; // Initialize the SerialOSCClient.

// * Connected devices should get posted in the Post Window.
// * Note that SerialOSCClient initialization is performed asynchronously.

// Boot server
s.boot;

// Hello World - pressing the top-leftmost button auditions a sinewave.
GridKeydef.press(\playSine, { a = {SinOsc.ar}.play }, 0, 0);
GridKeydef.release(\stopSine, { a.release; a=nil }, 0, 0);

// Remove GridKeydefs using .free or by pressing Cmd-.
GridKeydef.press(\playSine).free;
GridKeydef.release(\stopSine).free;

// Now, setting leds... If everything works properly and you have a grid attached, a default SerialOSCGrid instance is defined
SerialOSCGrid.default;

// Use this instance to set leds
a=SerialOSCGrid.default;
a.ledSet(0, 0, true);
a.ledSet(0, 0, false);

// The !? idiom in SuperCollider (see help on !?) can be used to set leds of the default grid, but only if it is available (if SerialOSCGrid.default is not nil)

SerialOSCGrid.default !? { |grid| grid.ledSet(1, 2, true) };

(
// Scramble 8 random leds in a 8x8 matrix
SerialOSCGrid.default !? { |grid|
	8 do: { grid.ledSet(8.rand, 8.rand, [true, false].choose) };
};
)

// Now, on handling multiple devices

// Info on what device triggered a GridKeydef is available in the function argument list.
GridKeydef(\debug, { |x, y, state, time, device| [x, y, state, time, device].debug });

// You can use a device as filter. See OSCdef help for how this works.
GridKeydef(\debug, { |x, y, state, time, device| [x, y, state, time, device].debug }, device: SerialOSCGrid.default);

// If several devices are attached you can retrieve SerialOSCGrid and SerialOSCEnc instances from SerialOSCClient.devices
SerialOSCClient.devices;

// Pick a device and set a led
a=SerialOSCClient.devices.first;
a.ledSet(1, 2, true); // this assumes first device in list is a grid (SerialOSCGrid)

Below, a monome and arc play together.

// Example, grid together with arc

(
var set_arc_led;
var scramble_8_grid_leds;
var b_spec = ControlSpec.new;

// Ensure server is running
s.serverRunning.not.if {
	Error("Boot server stored in interpreter variable s.").throw
};

// Initialize client in order to use devices
SerialOSCClient.init;

// SynthDef to server
SynthDef(\test, { |freq, gate=1| Out.ar(0, ( SinOsc.ar(Lag.kr(freq)) * EnvGen.ar(Env.cutoff, gate) ) ! 2) }).add;

// Function to visualize a float value 0 - 1.0 on first encoder ring of default arc (if attached)
set_arc_led = { |value|
	SerialOSCEnc.default !? { |enc|
		enc.clearRings;
		enc.ringSet(0, SerialOSCEnc.ledXSpec.map(value), 15);
	};
};

// Function to scramble state for 8 random buttons in a 8x8 led matrix on the default grid (if attached)
scramble_8_grid_leds = {
	SerialOSCGrid.default !? { |grid|
		8 do: { grid.ledSet(8.rand, 8.rand, [true, false].choose) };
	};
};

// Initial arc encoder setting
b = 0.5;
set_arc_led.(b);

// First Arc encoder control frequency of sinewave and scrambles 8 leds
EncDeltadef(\adjustFrequency, { |n, delta|
	b = b_spec.constrain(b + (delta/1000));
	a !? { a.set(\freq, \freq.asSpec.map(b)) };
	set_arc_led.(b);
	scramble_8_grid_leds.();
}, 0);

// Hitting any grid button auditions sinewave and scrambles 8 leds
GridKeydef.press(
	\playSine,
	{
		a ?? {
			a = Synth(\test, [\freq, \freq.asSpec.map(b)]);
			scramble_8_grid_leds.();
		};
	}
);

// Releasing any grid button stops the sinewave
GridKeydef.release(\stopSine, { a.release; a = nil });
)

SerialOSCClient.sc (26.2 KB) (obsolete, use the one at the top of the post)

4 Likes

I’ve refactored the examples slightly.

I’d love to hear from someone with a recent Mac whether this works, and whether plugging and unplugging devices works fluently.

I’d really appreciate help on testing SerialOSCClient out when hotswapping devices on Mac OSX.

I’ve uploaded a new, revised SerialOSCClient.sc (see original post) and fixed some issues in the two code samples above.

The absolute easiest test for hotswapping is, install SuperCollider, install SerialOSCClient (see above), run SuperCollider and evaluate this in the editor:

SerialOSCClient.init

Now watch the Post Window. Attach and detach your device or devices (if you have several). Does SerialOSCClient seem to pick up device changes correctly? If not, does evaluating the single line above help?

When I try to test hotswapping with my old Macbook it often errs out, kernel panics and I have to power off and on again. A modal dialog showing “You need to restart your computer. Hold down the Power button until it turns off, then press the Power button again.” appears. I thought first this was due to my SuperCollider code. However, when trying this out today it seems to be a serialoscd issue. It happens even if I do not run SuperCollider and just attach and detach devices. I run Snow Leopard and use serialoscd 1.2 as I cannot get any later version to run. My Mac is old and hotswapping devices does not seem to be enabled/supported fully in serialoscd on Windows.

Remember:
Embracing Open Source and ditching taking a pause from Proprietary Software is a good thing.

I’m not a supercollider user yet (long time lurker), but if it’s really just about connectivity, I’m happy to give this a go with my retina mac (10.10) later after work…

p.s.: Why not highlighting the strengths of SC instead of moaning about commercial software?
If it were just that aspect, Max people would need to dive into PD wouldn’t they? :slight_smile:
Monome plug 'n “play” in such a powerful environment is a big selling point though…

Thanks a lot for sharing your work!

1 Like

Oops. Sorry for the moaning. I’m trying to grab people’s attention, but it is probably working the other way.

I do respect Cycling 74.

If you can and want help out on this, I’d be thankful. If you don’t want to delve into it, don’t. Since you’re new to SuperCollider let me know if you do and run into problems. SuperCollider is tricky, it took me years to decipher the basics and I’m still learning.

My idea with SerialOSCClient is to address “Monome plug 'n play” for SuperCollider. Ideally, in the simple use case, I should be able to attach my monome and arc to my computer and a SuperCollider app written for these devices will “Just work” - just like monome modular devices. I should not have to deal with ids, ports and device selection. I do this primarily for my own sake.

Another thing with SuperCollider apps is that they mostly are code-based. I hope SuperCollider frameworks can emerge that provide graphical apps requiring no programming knowledge at all. This is probably one of the main impediments to why SuperCollider apps dont get widespread - it’s currently mostly for hackers. Underneath the confusing programming interface is a very powerful audio engine.

We’ll see what the future brings.

2 Likes

No offense! It might be even worse, a lot of peeps are too busy with their modulars these days :stuck_out_tongue:

I know it’s a huge topic and a bit of a learning curve and I sadly definitely don’t have the time for it atm…

But since it seemed you could need someone on newer mac to run your init method, I’m happy to give it a go later and see where it goes…

ok, so init seems to be working on my retina mac running 10.10.5 and serialosc 1.4

when I reattached the device, I had to wait about 4 secs with the arc and about 10 secs with the 128 for the “attached” message.

sorry I can’t be of more help as of now.

I really need to look into SC, no excuses…

Perhaps people are actually making music and not spending time just writing new programming libraries (ahem). :slight_smile: Now that’s a good thing…

Yep, discovering attached and detached devices appears to work fine. Thanks for confirming this.

From reading the contents of the Post Window I’m quite sure you also have MonoM - another SuperCollider library - installed. It also outputs discovered (attached) devices. MonoM does not seem to report detached devices. These sections are from MonoM:

Device connect on port:[port]
[id]
[type]

Wow, 10 seconds is a long time. Do you get the same delay in other programs - ie, do you use Max/MSP? Can you confirm whether the MonoM section (above) was printed at the same as the SerialOSCClient section for attached devices, which looks like this:

A SerialOSC Device was attached:
SerialOSCGrid([type], [id], [port])

For arcs SerialOSCEnc() is posted.

If they are posted the same time it could mean the delay you refer to is induced by serialoscd and not SuperCollider or SerialOSCClient.

This might be a good time to describe some differences between MonoM (which I haven’t used that much) and SerialOSCClient. Code wise MonoM it’s way more lean than SerialOSCClient. That - I believe, correct me on this if I’m wrong - is due to MonoM only handling binding of devices to SuperCollider and output of led messages. For incoming events (key presses, encoder deltas, etc) it relies on OSCdef or OSCFunc usage. I also believe you need to bind devices explicitly by useDevice and usePort. Don’t get me wrong, this is fine and it’s a lean and mean little class which I stole some ideas from.

SerialOSCClient does autodiscovery of devices (attached and detached), maintains a list of current devices in SerialOSCClient.devices and uses that list to route incoming events (key presses, encoder deltas, etc) to SerialOSC device specific *def and *Func objects (GridKeydef/Func for incoming key presses, EncDeltadef/Func for encoder deltas, etc).

From a simple step-sequencer:

GridKeydef.press(\edit_pattern, { |x, y| ~toggle_trig.(y, x) });

As with SuperCollider OSCdef/OSCFunc classes, you can filter each def you create by different properties such as x, y, state and device (for GridKeydef). If you provide no filtering, all events will pass through.

So, in the simple case of having one device or one of each type of device - one grid and one arc is often the case for me - you can just whack some *defs out and don’t care at all about ids, ports, prefixes, device order, etc. I guess this is how the current Max/MSP serialosc stuff works, but I’m not sure.

Default grid and encoder devices are also set up automatically once attached so for prototyping (and real apps) you can code against a default grid if it’s available using a particular SuperCollider idiom:

SerialOSCGrid.default !? { |grid| grid.ledSet(0, 0, true) };

You can also listen to updates when new default grids or encoders are set to do something when a device is attached and set to default or a user explicitly change default device of a given type:

SerialOSCGrid.addDependant { |thechanged, what|
	if (what == 'default') {
		// send current grid led state as defined by app to update grid
	};
};

So, for simple device configurations I hope “plug-in device and go” is within reach.

Of course there are trade offs and a lot of unimplemented features at this point. All devices just bind to prefix “/sclang” for instance, which probably breaks some basic ideas in how serialosc routing was supposed to work. But it works pretty well for me…

This is great feedback, thanks.

Different strokes for different folks… My code sections above may be hard to grok if you’re not into SuperCollider yet I include them if some other is interested. SerialOSCClient has 0% documentation right now.

Hello, longtime monome user and about year long supercollider user here. I’m so glad you posted something using supercollider as that’s my main langauge and I’ve been struggling for months trying to use the monom class with varying results. It works but it definatly seems little light and there were some thing’s I never could figure out how to do. I’m on a mac and can attest that it works as it should. I only have one device so I have no idea about hot swapping. One thing that I’ve been trying forever and is really important to me on monome is pages. Like being able to press the top row and have the leds and functonality change, as with The party Van and i’m sure many other apps. I’ve tried a bunch of times and always get stuck with keeping the state of the leds the same on one page and changing them on the other and having supercollider respond correctly to the different pages. Any chance you’d want to take this one or could give me some hint on how it would be done? I’ve thought of switch statements but it never quite worked. Anyway, i’ll be spending more time with your class soon to dive into more of how it works, thanks a bunch. Also, i’m more than willing to beta test anything just let me know.

Thanks for the feedback.

Yeah, I have been working on and off on another SuperCollider library called Grrr that simplifies scenarios like the one you’re describing. Will clean that up and post to this forum shortly.

1 Like

d’oh, how could I missed those other prints…
yes, I also thought it’s a bit long…

will check!

I actually can’t wait to dive into SC, but I’m very busy with other languages/frameworks…
time reserved on summer holidays :slight_smile:

Hey,

Have you had any time to get Grrr together? I’d love to see it.

thanks,

Thanks for your interest, Tate. I’ve been very busy with other stuff lately but you can expect a rough version of this lib to be posted this week.

/Anton

1 Like

Excited to try this. I just started learning Supercollider a couple of days ago. It seems very powerful and intuitive to me. As a programmer it’s pretty easy to pick up too.

1 Like

I’ve been meaning to get to this but my new job has me chasing my own tail. Maybe this weekend!

the kernel panics are actually a result of the old FTDI driver. back when we first found out about them, we tried to work with FTDI and resolve them (even offering to send them hardware to test with), but that ultimately went nowhere.

apple has included their own FTDI driver since the release of 10.9, so you should ideally be using that.

I’m on Snow Leopard. Probably time for me to upgrade to a new Mac.

/Anton

I got this to run on Arch Linux with a 8x16 grid. First try!

2 Likes

:slight_smile:

s.boot after SerialOSCGrid.testLeds and demo will (well, should) emit sound too.

edit: For those interested: SerialOSCClient has gone through many revisions since my first post about it here. There’s the one liner SerialOSCGrid.testLeds / SerialOSCEnd.testLeds tests/demos, ways to spawn multiple apps and route them to devices (I believe it’s often called multiplexing) and it’s better documented.

Code posted above in this thread works but there are better ways of using the library now. Refer to the SerialOSCClient-sc github repo for the latest version.