NamedControl: a better way to write SynthDef arguments

Me too. I like NamedControl very much, it aligns so well with so many other concepts in SC.

Debates about the personal preferences and aesthetics of NamedControl/arg will never come to an end. To me, the strongest point against the argument style is that it has an objective limitation where it’s impossible to specify multichannel controls with a dynamic number of channels.

My post was purely about a clear standard, which could be documentation in itself. Having multiple NamedControls spread across the SynthDef (imagine a number greater than 5) would invite errors.

But you’ve already discussed this and proposed a certain kind of convention, which is much more straightforward but also more code.

SynthDef(\sine, {
    var out = \out.kr(0), freq = \freq.kr(440), amp = \amp.kr(0.1);
    Out.ar(out, SinOsc.ar(freq) * amp);
}).add;

Maybe what’s missing is a new, concise syntax based on NamedControl…

SynthDef(\sine, { | \out.kr(0) \freq.kr(440) \amp.kr(0.1) |
    Out.ar(out, SinOsc.ar(freq) * amp);
}).add;
1 Like

I think the end to the debate is to use whichever is appropriate to the situation.

The premise of this whole thread – that argument syntax fails a few use cases, therefore it is always inadequate for every use case – was overstated from the get-go.

My ongoing practice is to use argument style for single-value arguments, and NamedControls for arrayed arguments. I agree that NamedControls are clearer for arrays. I don’t feel any particular need to pick a side.

hjh

3 Likes

Nah, it was stated fine. Studies have shown that using NamedControls exclusively makes you more attractive and increases IQ.

1 Like

My point is that this all could have been presented as “here’s a usage that I find congenial, maybe you’ll like it too,” but it was presented as “this is better (implying that the other way is worse) and y’all should make the switch, and I can’t understand why people aren’t switching” – all of which traces back to verbiage in the first post, and is extraneous to the technical arguments. So there’s extra junk in the post (which probably just reflects over-enthusiasm), and then when somebody says uh, wait up, some of this reads more judgy than you think, the reply is, no no, you should focus on the technical arguments. (In that case, the original post could have begun by sticking to the technical.)

I could write a post about patterns, comparing them to routines, pointing out some technical advantages and finishing with “you can make up your own mind.”

Or I could write a post entitled “Patterns: SC’s best sequencing framework,” expressing hope that users would switch to them, and evaluating routines’ advantages to be insignificant.

I would expect the latter format to ruffle some feathers, and it would be disingenuous afterward to (use jokes to) declare the feather-ruffling parts to be off-limits for criticism.

Framing the topic as “better-than / worse-than” places the two approaches in a competitive, rather than complementary, relationship. I found it a bit strange to speak of this “debate… [that] will never end” when… it’s not actually a debate. Is it? If so, why? Users can decide for themselves how to use the given resources. But this manufactured “debate” is a consequence of the initial framing; I disagree with both the framing and the “debate” labeling.

hjh

2 Likes

I had oatmeal for breakfast

Muting the thread now, goodbye.

hjh

1 Like

I put blueberries in the oatmeal also

1 Like

@smoge the issue for me is about staying in the moment - when I am making music I am often on a tear - trying to get something working right now.

I am often in the middle of writing a graph when I realize “Oh I need a control for this” - having to jump back up to the argument declarations and then jump back is a context switch and I just want to type right where I am.

Likewise when I want to change a hardcoded value, I just don’t want to have to type on two non-contiguous lines!!

I’ve made. a lot of little tweaks to the language that let me just keep moving forward whether I planned properly or not - for me that’s the musical mindset, the present point (the cursor location) is where I am! JMC after sc became interested in a concatenative style for just this reason.

I think that needing to declare all variables at the top of a function is a pretty lame limitation in sclang. If we could simply declare anywhere, for vars or args that might be the best of both worlds.

1 Like

I put soysauce in my oatmeal

That’s pretty messed up but I respect your choices

For readability purposes, I strongly prefer having all arguments at the top and variables mixed in the code.

For vars I regularly resort to storing variables in an event (however, one has to be careful not to reuse/overwrite existing keys in the event or things might go wrong in non-obvious ways)

(
var v = ();

v[\myvariablename] = 42;
)

1 Like

This is really interesting, but I can’t figure out how it would work. It is possible that @nathan or somebody else that knows this syntax post an example of dynamic number of channels with NamedControl please?

1 Like

“Dynamic” was probably the wrong word, since there is no dynamic multichannel in a SynthDef, but “programmatic,” yes.

(
var n;
n = 10;

SynthDef(\foo, {
    SinOsc.ar(\freq.kr(440 ! n));
});
)

You can also define a family of SynthDefs with different multichannel sizes:

(
(1..10).do { |n|
    SynthDef(("foo" ++ n.asString).asSymbol, {
        SinOsc.ar(\freq.kr(440 ! n));
    });
};
)

The above examples have no equivalent in the argument style.

3 Likes

Yes, the word “Dynamic” threw me off. Thanks for the examples. Very useful!

The minval and maxval are supposed to work like a clip ? Because we I do something like:

Ndef(\a, {SinOsc.ar(mul:1/8)*SinOsc.ar(\f1.kr(1,spec:ControlSpec(0.01, 20)),0, mul: 0.125, add: 0.5)}).play;
Ndef(\a).set(\f1, 10);
Ndef(\a).set(\f1, 25);
Ndef(\a).set(\f1, 40);

I can go beyond the limits defined in the controlspec.

If they do not work as clipping, what is their function? Assume that all the inputs will be in the range of [-1,1] and the map them into the new defined range?

For clipping values, in this case I should use .clip?

The spec parameter on controls is purely metadata - generally, you can use it to construct UI controls for a Synth. Clipping is generally better done on the language side, by limiting the values you send to a synth - though if you want to clip in the Synth obviously this works fine as well.

~def = SynthDef(\specTest, {
  Out.ar(
    \out.kr(0), 
    SinOsc.ar(\freq.kr(spec:[20, 2000])) * \amp.kr(spec:[0, 1])
  )
}).add;

~synth = Synth(\specTest);

~view = View().minHeight_(100).layout_(HLayout());
~def.specs.keysValuesDo {
    |name, spec|
    ~view.layout.add(HLayout(
        StaticText().string_(name),
        Slider().action_({
            |slider|
            ~synth.set(name, spec.map(slider.value))
        })
    ))
};
~view.front;
Ndef(\x,{ \test.kr(spec:[-5,10]) }).gui;
or
Ndef(\x,{ \test.kr(spec:ControlSpec(-5,10)) }).gui;

should set the gui slider from -5 to 10 - right ?
but it’s range is set from -0.25 to -100 !

with

Ndef(\x).addSpec(\test, [-5,10] );
or 
Ndef(\x).addSpec(\test, ControlSpec(-5,10) );

the sliders range is set correctly from -5 to 10

so what am i missing ?

(i use sc 3.14.0-dev on linux)

I’m not totally sure, but an Ndef can contain multiple Synths - I think by default it MAY not pull it’s specs from the SynthDef (sadly even in a trival case like this) given that there could be e.g. multiple synths with \test controls that have different specs. So it might be that Ndef:addSpec is somewhat decoupled from the individual SynthDef specs? I recall working around this in local code of mine to just pull the specs directly from the source SynthDef when I want to generated controls.

A reasonable workaround here if you want to use Ndef:gui is just to make a new addSynthDefSpecs method that basically finds the SynthDefs for that Ndef, iterates over the specs for that SynthDef, and sets them on the Ndef via addSpec. Check Ndef(\x).inspect to poke around and find where the SynthDef’s / SynthDesc’s are stored, I can’t recall :upside_down_face:.