Ndef source for .kr not working

I’m trying to build a modular with Ndefs.
My plan was having a collection of module templates as synthdefs, then create the modules dynamically with Ndef, setting the sources with synthdef symbols. This works ok for .ar modules, but not for .kr. Could someone please give pointers on what I may be doing wrong? I reckon it has something to do with Out.kr, but I don’t have a clue on how to solve this. Here’s the code:

// Audio rate module
SynthDef(\sig, { Out.ar(0, SinOsc.ar(200, mul: \amp.kr(0.02))) }).add
// Control rate module
SynthDef(\lfo, { LFPulse.kr(\freq.kr(1)) }).add
// or
SynthDef(\lfo, { Out.kr(0, LFPulse.kr(\freq.kr(1))) }).add

// Setting audio module with Synthdef source works OK
Ndef(\a, \sig).play 

// Setting control module with Synthdef source doesn't work 
Ndef(\k, \lfo) 
Ndef(\a).set(\amp, Ndef(\k)) 

// Setting control module with a function works as expected
Ndef(\k, { LFPulse.kr(\freq.kr(1)) }) 
Ndef(\a).set(\amp, Ndef(\k)) 

Edit:
What I’ve found so far is that the input of the audio-rate synth should be listening to a bus like so:

SynthDef(\snd, {Out.ar(0, SinOsc.ar(mul:In.kr(\amp.kr(0.1))))}).add;
SynthDef(\ktl, {Out.kr(2, LFPulse.kr(1))}).add;
Ndef(\a, \snd).play;
Ndef(\k, \ktl);
Ndef(\a).set(\amp, 2);

You’ve got just a couple small things wrong, and one subtle trap you stepped in :slight_smile:

  1. You have no Out:
    SynthDef(\lfo, { LFPulse.kr(\freq.kr(1)) }).add
    should be:
    SynthDef(\lfo, { Out.kr(0, LFPulse.kr(\freq.kr(1))) }).add

  2. Your outs are always going to bus 0. This is a bit of a gotcha but: Ndef expects that synths have an \out parameter - this is how Ndef’s are able to route and manage the audio of the synth. You don’t have to set this - the Ndef will do it automatically. Instead of:
    SynthDef(\lfo, { Out.kr(0, LFPulse.kr(\freq.kr(1))) }).add
    you should have:
    SynthDef(\lfo, { Out.kr(\out.kr(0), LFPulse.kr(\freq.kr(1))) }).add

  3. When patching an Ndef into another Ndef, you need to use asMap:
    Ndef(\a).set(\amp, Ndef(\k).asMap);

  4. You are encountering a small bug with Ndef - if you initialize them with a \symbol, it doesn’t set the channels or rate right. I believe you can work around this by explicitly setting Ndef(\lfo).mold(1), which forces your Ndef to be 1 channel. You can also install this class extension, which fixes the problem by setting the channels count and rate from your SynthDef: https://gist.github.com/scztt/bf1796eebe015640df7bf6c1425d4906

I don’t think that’s required:

Ndef(\kr, { LFDNoise3.kr(5).exprange(200, 800) });

Ndef(\ar, { |freq = 440| SinOsc.ar(freq, 0, 0.1).dup }).play;

Ndef(\ar).set(\freq, Ndef(\kr));  // freq mod is audible, no 'asMap'

hjh

Nice!

Thank you so much @scztt! I would’ve never got there by myself : )

@jamshark70 is right, I tried using it without .asMap and it works, too. Although his example is not using a SynthDef source for the Ndef.

Here’s my test-code:

(
SynthDef(\snd, {Out.ar(\out.kr(0), SinOsc.ar * 0.2 * \mod.kr(1))}).add;
SynthDef(\ktl, {Out.kr(\out.kr(0), LFPulse.kr(\freq.kr(1)))}).add;
)
Ndef(\a, \snd).play;
Ndef(\lfo).mold(1);
Ndef(\lfo).source = \ktl;
Ndef(\a).set(\mod, Ndef(\lfo));