Norns: supercollider engine fails the first time you run it [SOLVED]

wieeerd error here. the code is a midi connected polysynth + a lofi fx processor in a separate synth. the code works fine but only after the second time you run it after booting SC. the first time you don’t get any sound and you get a bunch of messages like this when you play a note to the midi in:

FAILURE IN SERVER /s_new SynthDef not found
FAILURE IN SERVER /s_new Node 1000 not found
FAILURE IN SERVER /n_mapn Node 1001 not found
FAILURE IN SERVER /n_mapn Node 1001 not found
FAILURE IN SERVER /n_mapn Node 1001 not found
FAILURE IN SERVER /n_mapn Node 1001 not found
FAILURE IN SERVER /n_mapn Node 1001 not found
FAILURE IN SERVER /n_mapn Node 1001 not found
FAILURE IN SERVER /n_mapn Node 1001 not found

then, just execute the code again & it’ll run fine until you exit supercollider and re-run the code (rebooting the server doesn’t seem to break it either)

normally I, er, wouldn’t care that much except that the issue persists after plopping the code in a norns engine, so the first time anyone runs the script after powering on it just won’t work. based on the error I’m guessing it has to do with my busses not getting allocated (there’s 1 audio bus and a bunch of control busses that get hooked up to poly-synth voices) but I can’t tell what is wrong !

here’s a gist of the .scd code:

https://gist.github.com/andr-ew/ff669cb17ceb51fe8066d545a6f1024c

and the engine, if helpful, same error in both places as far as I can tell:

https://github.com/andr-ew/porta


also just spotted this error which happens on the first execution, before any midi input:

*** ERROR: SynthDef ulaw not found
FAILURE IN SERVER /s_new SynthDef not found

on second thought it’s looking more like none of my synth defs or synths are making it to the server on the first go, thus no audio & causing mayhem for my control bus mappings

<< solved >>

the issue was playing an effect like this, as is done in most of the helpfiles:

def = SynthDef.new(\foo, {
    //yada yada
}).add;

synth = Synth.new(\foo);

rather than like this:

def = SynthDef.new(\foo, {
    //yada yada
});

synth = def.play();

seems like an important thing to know ! hopefully this information is useful for future generations ! goodnight !

1 Like

this is not unique to norns, and always using .play is deeply sub-optimal. the code you posted will not work in scide either if it is run as a single block. in helpfiles, the construct is used like this:

(
SynthDef(\help_notRand, { |out|
    Out.ar(out,
        SinOsc.ar(rrand(400, 800), 0, 0.2) * Line.kr(1, 0, 1, doneAction: Done.freeSelf)
    )
}).add;
)
a = Synth(\help_notRand);

those are two separate blocks. the block in parentheses is intended to be executed before the single-line block below.

you need to understand that whatever method you use, loading synthdefs on the server is an asynchronous process.

you should also realize that SynthDef.play and Function.play are convenience methods which do several things:

  • compile the synthdef,
  • send it to the server,
  • wait for the server (using a Condition under the hood),
  • and finally create a synth using the new definition.

if you are going to make multiple synths with the same def, it is pure waste to compile and send it multiple times. (and yes, we do this in norns engines sometimes, which is silly - a poor pedagogy that simplifies but also, apparently, misleads.)

i would strongly recommend reading these core helpfiles again, completely:
SynthDef, Server etc.

here are some examples. for each example, follow the convention of selecting the entire parenthesized block and executing it. (in scide, double-click on one of the enclosing parens.)

/// DOES NOT WORK.
(
~def = SynthDef.new(\foo, {
	Out.ar(0, SinOsc.ar(220).dup * 0.25);
}).add;

~synth = Synth.new(\foo); // << sclang immediately executes this line, 
                    // but def has not yet been compiled or sent; fails.
)


// WORKS.
// (but do read the fine print for `.add`.)
(
~def = SynthDef.new(\foo1, {
	Out.ar(0, SinOsc.ar(220).dup * 0.25);
}).add(completionMsg: ["/s_new", "foo1", -1]);
)


/// WORKS.
/// a little more efficient than .add b/c you just specify a server,
/// rather than running through SynthDescLib and checking for all running servers.
/// use this on norns.
(
s = Server.default;
~def = SynthDef.new(\foo2, {
	Out.ar(0, SinOsc.ar(220).dup * 0.25);
}).send(s, completionMsg: ["/s_new", "foo2", -1]);
)

/// WORKS.
/// same things but stores the compiled def on disk.
/// it will persist across reboots.
/// this can confuse your future self.
(
s = Server.default;
~def = SynthDef.new(\foo3, {
	Out.ar(0, SinOsc.ar(220).dup * 0.25);
}).load(s,completionMsg: ["/s_new", "foo3", -1]);
)


/// i tend to like this "big hammer" approach of using Server.sync.
// it is most flexible b/c you can execute whatever sclang code, 
// not just a single OSC message.

/// WORKS.
(
s = Server.default;
Routine {
	s.boot;
	s.sync; // << pauses sclang thread until all asynchronous server commands are complete.

	~def = SynthDef.new(\foo4, {
		Out.ar(0, SinOsc.ar(220).dup * 0.25);
	}).send(s);

	s.sync; // and again.
	~synth = Synth.new(\foo4);
}.play;
)
3 Likes