It sounds like your issue is caused by SynthDef.add
being an asynchronous operation (like anything that changes or queries the state of the Server). You’ll have this issue whether you’re calling SynthDef.add
followed by Synth.new
in a method or in any other Function.
The solution is essentially the same in either case, but it’s slightly more complex to implement in a method. With a Function, you’d either call fork
to create a Routine or wrap the Function in a Routine directly. Either will allow you to call instance methods of Server that block the thread pending the results of asynchronous operations (like SynthDef.add). The simplest one of these methods is sync
:
{
SynthDef.new(\foo, { /* graph function */ }).add;
s.sync; // wait for async actions to complete before proceeding
Synth.new(\foo)
}.fork
Without the sync
, the client calls SynthDef.add
, which hands work off to the Server, then continues evaluation without waiting for the Server-side operation to complete, which is why you’re getting “SynthDef not found.”
If you want to do this in a method of some Class you’re writing, you can’t fork the method itself, but you can fork a Function from within the method:
init {|server| // pass Server as an arg
server = server ? Server.default; // fall back on default Server if nil
{
server.waitForBoot({ // make sure Server is booted
SynthDef.new(\foo, { /* graph function */ }).add;
server.sync;
bar = Synth.new(\foo) // assuming your class has an instance var "bar"
})
}.fork
}
As for whether this is the right approach, I don’t think of it as being “idiomatic sclang”, and it does have some gotchas – because a method like the example above does all its work through side effects of the forked Function and because you can’t reason deterministically from the client about how long the Server will take to complete a task, it’s probably best to restrict this technique to methods that do not need to return values. Also, because forking a Function creates a Routine, you can’t return a value from it as you would a normal Function, though you can assign values to variables above the scope of the forked Function, such as the instance variables of your Class.
Having said all that, I personally think the benefits outweigh the disadvantages if you’re careful and I personally use this pattern quite a lot. Hope that helps!