ERROR: SynthDef system_link_audio_1 not found

Hi all,

I noticed today that after running ServerBoot.removeAll and rebooting, NodeProxy objects don’t play. Instead, I get the error message “SynthDef system_link_audio_1 not found”. I’ve seen this error a number of times in the past, but only recently managed to pin down the cause.

So, just wondering a few things. What exactly is being removed from ServerBoot that allows NodeProxy to function? Is there a way to “reset” ServerBoot to it’s startup state, without having to quit/reopen SC? And is it considered “bad practice” to use removeAll on AbstractSystemAction classes?

Eli

s.boot;

Ndef(\a).play; //fine

Ndef(\a).clear;

ServerBoot.removeAll;

s.reboot;

Ndef(\a).play; //fails

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

SynthDescLib uses a ServerBoot function to send all .add-ed SynthDefs at boot time. (This is why it’s OK to add SynthDefs before booting the server.)

During class library initialization (*initClass), SystemSynthDefs adds many SynthDefs into the default SynthDescLib, and relies on the server boot function to transmit those to the server. If that function is removed, then the SynthDefs don’t make it over.

This is an opinion (others might disagree), but – IMO – correct functioning of SC depends upon server nodes/buffers/SynthDefs etc being in sync with the language-side objects that control them. Rebooting a server destroys the server-side structures, while leaving language-side objects in place. Those objects are then invalid, and then it gets a lot harder to make sure things will keep working.

s.boot;

b = Buffer.alloc(s, 1024, 1, { |buf| buf.sine1Msg([1], asWavetable: false) });

b.plot;  // OK

s.reboot;

b.plot;

^^ ERROR: Message '-' not understood.
RECEIVER: nil

Of course “nobody would expect b to be intact, so why would one do this” (but server/language coordination is a major point of confusion).

For that reason, at least for my own usage patterns – if I need to reboot a server, I might as well recompile the class library and start completely over from scratch. Speaking only for myself, I don’t see much benefit in rebooting only half the system. I do use reboot when I’m testing something specific that doesn’t involve language-side object cruft. I don’t use it in general (and I designed my workflow to automate the loading of complex objects, to reduce the temptation to preserve them).

I don’t think anyone thought it through far enough to discourage it “officially.”

The problem is that there is no way to distinguish your functions from classlib functions. It should be safe to remove yours, but not the ones that other classes depend on.

One solution would be to annotate the functions. If you have the JITLibExtensions quark, you could press Halo into service for this.

(
~addSystemBoot = { |func, annotation(\mine)|
	ServerBoot.addHalo(func, annotation);
	ServerBoot.add(func);
};

~removeSystemBoot = { |annotation|
	var halo = ServerBoot.getHalo;
	halo.keysDo { |func|
		if(halo[func] == annotation) {
			ServerBoot.remove(func);
			halo.removeAt(func);
		}
	};
};
)

ServerBoot.objects  // 'all' has 3

~addSystemBoot.({ "\n\ncustom boot function\n".postln; }, \mine);

ServerBoot.objects  // 'all' has 4

~removeSystemBoot.(\mine);

ServerBoot.objects  // 'all' has 3

Currently the class library doesn’t have a built-in way to annotate objects.

hjh

I see. Recompiling the class library hadn’t occurred to me, but certainly makes sense from this perspective. I wasn’t aware of this pre-loaded ServerBoot function.

I don’t deny that using removeAll is lazy of me. I should probably be tidier and make more of a habit of removing custom functions individually.

(In the distant past, I once or twice thought it would be “clever” for some reason to rely on CmdPeriod.removeAll, which did not end well…so I shouldn’t be surprised that other AbstractSystemAction classes might have similar “gotcha’s.”)

Thanks also for the extension suggestion.

Eli

FreqScopeView.initClass also adds a bunch of SynthDefs on StartUp, so ServerBoot.removeAll breaks FreqScope as well.

Just my opinion, but I’d say anything that silently breaks both NodeProxy and FreqScope is not only bad practice… it’s a bug. At the very least, I would add:

+ ServerBoot {
	*removeAll {
        "This breaks NodeProxy and FreqScope. Recompile class library to fix them".warn;
		super.removeAll;
	}
}