yeah, it’s not a two-way binding. when you load a script, the script loading module checks if engine.name is defined. if it is, it loads that engine. when the engine is done loading, low-level lua callback is fired and the script’s init is run.
when i made the low-level stuff i thought a single lua script might want to switch engines. but when the script management stuff was built up, the assumption was made that this will not happen. it is one of many undocumented assumptions that you will run into if you start to deeply interrogate the “middle” layers of the lua system. (and to be clear, i’m glad you are doing this!)
but sure, engine.load(name) method should update engine.name field, if it disagrees with the argument.
the .free method for engine resources should free all scsynth resources and stop all sound. if it doesnt, it’s an error. i just quickly tested this with TestSine and seems fine to me.
my test:
new test engine for switching:
Engine_TestNoise.sc
// CroneEngine_TestNoise
// variante of TestSine, for switching
// Inherit methods from CroneEngine
Engine_TestNoise : CroneEngine {
var <synth;
*new { arg context, doneCallback;
^super.new(context, doneCallback);
}
alloc {
synth = {
arg out, hz=220, amp=0.5, amplag=0.02, hzlag=0.01;
var amp_, hz_;
amp_ = Lag.ar(K2A.ar(amp), amplag);
hz_ = Lag.ar(K2A.ar(hz), hzlag);
Out.ar(out, (LPF.ar(WhiteNoise.ar, hz_) * amp_).dup);
}.play(args: [\out, context.out_b], target: context.xg);
this.addCommand("hz", "f", { arg msg;
synth.set(\hz, msg[1]);
});
this.addCommand("amp", "f", { arg msg;
synth.set(\amp, msg[1]);
});
}
free {
synth.free;
}
}
test script:
switch_engines.lua
function init()
end
function key(n,z)
if z == 1 then
if n == 2 then
engine.load('TestSine')
end
if n == 3 then
engine.load('TestNoise')
end
end
end
result: each engine correctly frees its single running Synth when the other engine is loaded. (the mechanism that calls .free on the last engine is on the supercollider side, in CroneEngine iirc.
(if you have softcut running with engine input, or reverb you may of course still hear sound from the old engine that has been captured in a buffer or something?)
(i don’t know about Why. it’s a very old “hello world” that shouldn’t even be availble in any repo and probably has outdated syntax. maybe it was just lying around on your norns’s filesystem.)
that’s an internal method for the PolySub engine, which is polyphonic.
aside: i’m wary of making too many standards for engines. standards are assumptions that change how you can make music. e.g. for some applications, you want “polyphony” to be implicit voice assignment with a single command. for others, you want it to mean a big array of oscillators that are manipulated independently.
i think we should try to preserve some of the freedom of SuperCollider and of digital instrument design in general when thinking about what engines are or should do. engine commands can take any number of arguments including strings, by design. youlu should be able to implement whatever you want in an engine, including toy languages, modular systems, or even things that execute arbitrary sclang code chunks.
not trying to start a big debate on this, BTW. obviously there are benefits to having “classes” of engines with common interface. just want to point out the other side of it.
there is more detailed discussion on this issue, mentioned above - i even did an example of how we could have an abstract class for MidiPolyEngine or whatever to enforce common API.
i’ve also just transferred the issue to the norns repo.