Get/Address Nodes Directly?

If I use queryAllNodes, I get a representation of the tree of nodes.
If I want to get a reference to a Node directly, or get a programmatic map of the list of nodes and the groups they’re in, is there a way to do that ?

I’m trying to solve general data structure problems, and potentially move nodes around from group to group, which is why I’m asking.

Thanks!

The Server command /g_queryTree can give you the same info as queryAllNodes as an OSC message.
See Server Command Reference | SuperCollider 3.12.2 Help

Maybe you could use a similar method to the OSCFunc in Server.queryAllNodes to get the data you need :

	queryAllNodes { | queryControls = false |
		var resp, done = false;
		if(isLocal) {
			this.sendMsg("/g_dumpTree", 0, queryControls.binaryValue)
		} {
			resp = OSCFunc({ |msg|
				var i = 2, tabs = 0, printControls = false, dumpFunc;
				if(msg[1] != 0) { printControls = true };
				("NODE TREE Group" + msg[2]).postln;
				if(msg[3] > 0) {
					dumpFunc = {|numChildren|
						var j;
						tabs = tabs + 1;
						numChildren.do {
							if(msg[i + 1] >= 0) { i = i + 2 } {
								i = i + 3 + if(printControls) { msg[i + 3] * 2 + 1 } { 0 };
							};
							tabs.do { "   ".post };
							msg[i].post; // nodeID
							if(msg[i + 1] >= 0) {
								" group".postln;
								if(msg[i + 1] > 0) { dumpFunc.value(msg[i + 1]) };
							} {
								(" " ++ msg[i + 2]).postln; // defname
								if(printControls) {
									if(msg[i + 3] > 0) {
										" ".post;
										tabs.do { "   ".post };
									};
									j = 0;
									msg[i + 3].do {
										" ".post;
										if(msg[i + 4 + j].isMemberOf(Symbol)) {
											(msg[i + 4 + j] ++ ": ").post;
										};
										msg[i + 5 + j].post;
										j = j + 2;
									};
									"\n".post;
								}
							}
						};
						tabs = tabs - 1;
					};
					dumpFunc.value(msg[3]);
				};
				done = true;
			}, '/g_queryTree.reply', addr).oneShot;

			this.sendMsg("/g_queryTree", 0, queryControls.binaryValue);
			SystemClock.sched(3, {
				if(done.not) {
					resp.free;
					"Remote server failed to respond to queryAllNodes!".warn;
				};
			})
		}
	}

Hope that helps,
Paul

It definitely does. Thank you!

I’m able to get everything working, this is great.
One more Q - is there a command to get the list of loaded synthdefs (either on the client or the server) along with their parameters ?

Not that I can see. /status command will give you the number of loaded synth defs, but not the details.

Maybe someone else knows?

Best,
Paul

Exactly! Seems weird. Was digging through the code with no joy, but it seems like that level of introspection is necessary to maintain state and if you are doing automatic synthdefs generation.

Anyone know if it’s possible?

Perhaps see https://github.com/supercollider/supercollider/issues/5894?

No. But, any .add-ed SynthDefs are available in the global SynthDescLib. This doesn’t cover {}.play temp SynthDefs, or .send(s), but…

When the default event prototype was changed to depend on SynthDescLib to identify certain properties of the \instrument, SC underwent a culture shift, discouraging the use of send(s) in favor of add. Before that shift, we were using the lighter-weight command with no client-side tracking. Since then, .add-ing a def leaves a permanent trace in the client’s object space, which reduces the need for server introspection.

I think the same thing is possible for nodes, and probably better than querying the server.

It would be nice to have a synth-node registry, mirroring the node structure, perhaps with annotations (because the limitation of querying the server here is that it can tell you only what is there, not why). Synth is already its own thing, but what if there were a Syn and Grp that automatically registered themselves? Then you wouldn’t be dependent on an asynchronous server query – you could just ask the client’s object structure.

We did this kind of culture shift once before – there’s not a strong reason why it couldn’t happen again. But, whenever this question comes up, the first thought is usually “how to get the stuff from the server” rather than “how to keep relevant information in the client, which generated the information in the first place.” That is, client → server → client is a fragile information flow, but if it’s client → client and parallel-ly → server, then the client → client part could be lossless (as it very nearly is, in fact, for SynthDef / SynthDesc).

hjh

2 Likes

I like this answer! My concern is that with a generalized server/client architecture, you can always have many clients, but you can only have one server. Likewise, a client can break down and reattach to a given server, and should be able to keep on going as if nothing had happened.

With supercollider, in 99% of cases, there’s one server and one client, and they move in lockstep so there should be no information loss between the two, but the way the system is designed, it’s meant to be flexible and allow for multiple clients, which means that the server is the ultimate source of truth.

I really like how in the Github PR that there’s a notion that you could send back the bytes of the synthdef to the client so that it could reconstruct it, which would mean that you could have multiple clients connect to an existing session, grab the definitions, rebuild them, and then start working (which means you could leave a server running as a daemon, which opens up a whole other world of possibilities for scripting/etc.), but starting with just the definitions would be a really good idea.

If I were doing a many clients, one server setup, I would have one main client and have all the other clients communicate with the main client via osc. Then have only the main client talk to the server, thus keeping track of the server setup in the process.

FWIW - my setup runs 8 or more servers and one client, which may be the 1% case, but I think this setup is very intuitive. The client keeps track of the node setup on all 8 servers as a large data structure and is able to access and remove nodes in groups as it sees fit.

Sam