NamedControl: a better way to write SynthDef arguments

I’d love to have this.
I’m personally trying to go in that direction by composing my Synthdef as a sequence of reusable wrapped functions and custom code.

We could have a new “Rate” “cr” for “Constant Rate” or “Static Rate”. Then your 3 examples woul be become
a) var a=Rand.cr() // static, same for all Synths
B)var a=Rand.ir() // constant by Synth
C)var a=Rand.kr() // new value at each control rate

thought: perhaps sythdef functions should not use arguments to make controls - there could be a fourth(?) type declaration - var, arg, ctrl, const. The current implementation is elegant when it works but brings about one user a week here with questions about why you can’t pass a symbol into a SynthDef!

Maybe SynthDef functions should have a distinguishing brace and/or be subbclassed from Function. Again to help users anticipate the constraints.

and +1 for Modules…

1 Like

You could do this with the preprocessor. It would be a tricky parsing job but it’s possible to recognize “ctrl” declarations and replace them with NamedControl syntax.

At this point it’s starting to look like over-engineering.

I’d be extremely skeptical (even hostile) toward language syntax changes in the SC3 line that break compatibility with existing SC3 code. Forbidding synth controls from being declared as arguments shouldn’t be done in SC3 (and there’s currently no proposal for an SC4).

So then we are brainstorming about adding Yet Another Way to declare synth controls… and “too many ways to do the same thing” has also been cited as a point of confusion.

If the suggestion is to increase complexity, then it should solve a real problem. Confusion over synth controls is a problem, sure, but is it a five-alarm fire, or more of a nuisance? “One user a week” strikes me as exaggerated – 50+ questions a year?

Also part of the solution would be to explain, in the documentation, the exact process of converting arguments to controls, and the constraints. I think the help doesn’t really do that, leaving users to guess.

I’d love it if someone could take that up.

In the crucial library quark, there’s Instr and Patch, but they don’t fully integrate with the event system. I found composing them to be a bit fiddly. But interested people could have a look to see some of the technical problems. For example, an Instr with a StaticIntegerSpec argument for number of channels could generate many SynthDefs, that need to be distinguished based on the value of that argument. Serializing static argument values into a SynthDef name is harder than it sounds. The time demands of technical issues like that are why I can’t take this project on, sorry.

hjh

Thinking about it some more – I don’t want to be too dismissive of the idea of an improvement in control specification. (I even started once on a preprocessor for it, but ran out of time and dropped it.)

At the same time, my experience finally coming to grips with Max/Pd style graphical patching makes me question the notion that design can significantly reduce user confusion. (It can reduce it a little, and that may be worth doing.)

After some 40 years’ exposure to programming languages, and 18+ now with SC, I wouldn’t have considered myself a novice – but I floundered for the better part of a year with Pd. In hindsight, that was an excellent, and usefully humbling experience. I found that fluency in a programming environment arises from trying and discarding wrong approaches, and I now believe there is simply no substitute for that. Design can trim away parts of the large field of wrong approaches, but every new design feature may be misunderstood in a new way, so the field never fully disappears.

A control keyword is not a bad idea (and could be implemented now with a preprocessor). OTOH, a design process for a permanent language feature should begin by researching concretely where users get tripped up with synthesis function arguments – otherwise, you end up adding something that might not address the confusion, and then it has to be permanently maintained.

I’m curious how relatively new users feel about this – big problem, minor confusion? What specifically was irritating while learning it?

hjh

1 Like

Frankly I never found the built-in lags that Control (probably via LagControl) comes with very useful. The built-in lag curve always seemed wrong somehow (it departs so sharply from the present value, i.e. at high derivative, that it easily causes audible glitching when used on a phase or frequency) so I either end up using .lag2 or lag3 often enough in their ud variation or .varlag, which is linear by default, and map that e.g. through a sine shape.

I suppose LagControl is an attempt at convenience plus optimization, but it ends up being not very useful in my experience.

I suppose an interesting application is to exploit the fact that the names are strings when passed to NamedControls do a sort of meta-programming to generate multiple controls from the same function “pattern” as discussed here. In a nutshell example:

(
f = { Poll.kr(Impulse.kr(1), ~ctrl.asSymbol.kr, ~ctrl) };

SynthDef("funny_ctrls", {
	SynthDef.wrap({ (ctrl: "boo").use { f.value } });
	SynthDef.wrap({ (ctrl: "yoo").use { f.value } })
}).add;

x = Synth("funny_ctrls");

s.queryAllNodes(true)
)

And I apologize for not reading all the 50+ messages above, where this might have been mentioned already, but NamedControl presently can’t be mixed too well with older ways of doing things if there’s expectation of a shared namespace, which the documentation alas created for me.

It’s also not the case that arg-generated Controls s mix gracefully with Control.names either, duplication-wise, or even with themselves in case of SynthDef.wrap.

I’m doin’ it. Ya can’t stop me

3 Likes

My observation, based on a couple recent threads about NamedControl, is that SynthDef arguments cause some types of confusion and NamedControls cause other types of confusion. In both cases, SynthDef and its inputs prove to be abstract concepts that often require trial and error to understand.

hjh

2 Likes

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