Norns - SuperCollider Engines Basics

Hi,

I can’t seem to find any basic intros to writing SuperCollider engines, and integrating them with the Norns system.

Can anyone help me out?

2 Likes

we’re planning a tutorial/study, but in the meantime check the inline comments of these:

keep in mind that these are not a supercollider tutorial— sc knowledge is a prerequisite.

4 Likes

Cool, thanks!

I’m working on that one :wink:

Slowly…

Ah, so you have to define a “synth”, but it can be a self-playing SynthDef, or a more generic function.

Presumably if it was a function, it could do general-purpose sclang stuff, before instantiating a SynthDef to create/process audio.

I guess the synth def/function has to provide the means to integrate with Lua and the wider Norns environment via its arguments.

Can you pass data back from the engine to a Lua script (for example to update onscreen parameter values on preset change?

Does SC have access to the systems MIDI io if available?

Can a Lua script communicate with an engine via an internal MIDI bus?

So many questions…

Engines basically encapsulate arbitrary sclang code. you can use as many Synths, Busses, Groups, Patterns, Events, <blahblah> as you want. the only rules are:

  • you can’t use graphics stuff
  • you must free all server resources that you allocate in the free {} method (synths, buffers &c)
  • it’s probably a good idea to allocate all resources in your engine’s init {} method

and you can use the superclass addCommand() and addPoll() methods to define your engine’s interface to norns lua.

Does SC have access to the systems MIDI io if available?

yes, though it is entirely independent of the norns UI so it may be confusing to use or customize.

Can a Lua script communicate with an engine via an internal MIDI bus?

not without some pretty lightweight hacking of linux stuff.

Can you pass data back from the engine to a Lua script (for example to update onscreen parameter values on preset change?

yes, we call an sc->lua channel a “poll”, and a lua->sc channel a “command.” polls are less flexible, basically callback for a single float or a byte array. commands are more flexible, like remote procedure calls with different parameter types. see e.g. Glut engine for example of polls (it’s how grain positions are conveyed to lua.)

1 Like

If I can help at all on this front please let me know – I’ve picked apart enough on my own to do mods of the templates @zebra and others have mentioned in other threads, but I figure if I can help with the tutorial I’ll also gain a deeper understanding of the system at large (and it will also help me keep up my SC chops)!

1 Like

This is great info, thanks @zebra!

Could you recommend an example of this?

So better to do MIDI interface stuff in the Lua scripts, then?

Do you mean “heavyweight” there?

I’m planning to use busses to communicate parameter values to the percussion synth engine I’m working on, so I can use commands to write data to the busses on Norns, and write an alternative function to consume MIDI CCs to control the kr busses, in other contexts.

Now I need to keep banging my head against SuperCollider.

Then Lua.

1 Like

Could you recommend an example of this?

literally every engine. e.g.:

in alloc{} a synth is created. in free{} it is freed.

is there some specific thing that is not making sense?

not really, but on reflection i suppose i should have.

So better to do MIDI interface stuff in the Lua scripts, then?

IMHO, generally yes, for the reasons i’ve alluded to. but if you simply want to launch existing sclang code that is self-configuring or fixed-configuration, and don’t care about the norns UI, then that would be a notable exception.

What do “ii” and “if” mean, in this context (Engine_Glut.sc)?

this.addCommand("gate", "ii", { arg msg;
			var voice = msg[1] - 1;
			voices[voice].set(\gate, msg[2]);
		});

		this.addCommand("speed", "if", { arg msg;
			var voice = msg[1] - 1;
			voices[voice].set(\speed, msg[2]);
		});

they are OSC message format strings. "ii" means that the command takes two integer arguments. (which are present in the msg argument array at locations [1] and [2] - location [0] is the name of the message, viz. "gate".)

likewise "if" is an integer argument followed by a float argument.