this is not unique to norns. 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.
)
// 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 specify a server.
/// 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;
)