Controlling filter parameters using NodeProxy roles

Hello, I’ve been experimenting with NodeProxy roles and would like to control the filter parameters without reevaluating the filter:

a = Ndef(\test).play;
a[0] = { Pulse.ar([86, 87]) };
a[1] = \filterIn -> { |in| RHPF.ar(in, Ndef(\freq, 600), rq: 0.1) };

First, I tried using named controls, but it didn’t work:

a[1].set(\freq, 1200);

Ndef works fine:

Ndef(\freq, 1200);

I also would like to pass Ugens:

Ndef(\freq, SinOsc.kr(1/8).range(400, 1200))

But I get this error:

Cannot share UGens between NodeProxies: a MulAdd

Is there a way to pass a UGen to a filtered nodeproxy?

Thank you!

To pass a UGen to a NodeProxy you need to put it inside a function:

Ndef(\freq, {SinOsc.kr(1/8).range(400, 1200)});

To use the set method on a NodeProxy, it needs to have a control with that name:

a[1] = \filterIn -> { |in| RHPF.ar(in, \freq.kr(600), rq: 0.1) };
a.set(\freq, 900);

But keep in mind this will set the \freq control on ALL slots of the NodeProxy, so you might want to use a more specific name, like \ffreq1.

Also, you can pass a NodeProxy to the set method if you’d like:

a.set(\freq, Ndef(\freq, {SinOsc.kr(1/8).range(400, 1200)}));
1 Like

FWIW, here is how to model “source → filter” as distinct entities in my ddwPlug quark.

(
a = Syn({ |ffreq = 600, rq = 0.1|
	var in = NamedControl.ar(\in, 0 ! 2);
	RHPF.ar(in, ffreq, rq)
}, [in: Plug { |freq = #[86, 87], amp = 0.1|
	Pulse.ar(freq) * amp
}]);
)

a.set(\ffreq, 1200);  // set number

// "plug" in a signal
a.set(\ffreq, Plug { LFDNoise3.kr(3.5).exprange(200, 1200) });

// sub-nodes' controls are addressed tree-style
a.set("in/freq", [300, 301]);

// and these can plug in signals too
// (your responsibility to match rate and numChannels)
a.set("in/freq", Plug {
	LFNoise0.kr(7).exprange(100, 800).lag(0.05) + #[0, 1]
});

// find a plug by path
a.argAtPath("in/freq")  // a Plug

// ... and overwrite its source
// (EDIT: now works for the top-level Syn as well as Plugs)
a.argAtPath("in/freq").source = {
	Latch.kr(
		LFSaw.kr(1.2).exprange(100, 800),
		Impulse.kr(9)
	).lag(0.05) + #[0, 1]
};

a.free;

Syn and Plug sources can be synthdef names too.

This structure can be played polyphonically; Ndefs can’t (at least not easily).

(Not strictly a JITLib answer, but… the general problem in the initial post is “how to set a synth control to either a value or a signal” and this is an alternate solution.)

hjh

1 Like

Very interesting. Can you compose more Syns together? Does it add to latency as jitlib?

I think a nice design would be to evaluate as many SynthDefs early (with some kind of macro, to produce variations of the functions); but also allow low latency and composability

Super helpful. Thank you very much!

I’ll move my response over to the ddwPlug thread, seems to make more sense there.

hjh