NamedControl: a better way to write SynthDef arguments


#22

Hi again,

Only saw this now. Looks like an interesting approach! Will chew on it when I have a bit more time on my hands to see how this would fit into my overall setup…


#23

Started using this as soon as I saw this post. Definitely a nicer way to plug controls into the SynthDef. I’m sold! Thanks!


#24

Hi there -
This is an amazing resource - thank you for posting it.
I did want to ask a question, though, since I am currently a few months into a project with many NamedControls.
I’m finding that I have many of the same arguments, ultimately, for each Synth… and they’re all getting numbered in order to keep up with all of the controls. So, for instance, a cutoff frequency argument on different filters is becoming \cutoff1.kr, \cutoff2.kr, \cutoff3.kr…

Are there ways to make NamedControl more linked to the Synth instance directly?


#25

hi, glad to hear you’re enjoying NamedControls.

i’m not 100% sure what you mean — do you mean “SynthDef” rather than “Synth”? if that’s the case, you can freely reuse the same NamedControl across different SynthDefs. they won’t interfere. if i guessed wrong, maybe a short code example would help clarify.


#26

A SynthDef is an abstraction, you are going to mix the levels of abstract definition (SynthDef) and concrete instantiation (Synths), where the differentiation should be done.

To be more concrete, you could arrange your data like this:

// containers for data

~synths = […, …, …, … ]

~cutoff = […, …, …, … ]

then actions can be defined like this (and easily itereated over all indices)

~synths[0].set(\cutoff, ~cutoff[0])

// let n be the number of synths

n.do { |i| ~synths[i].set(\cutoff, ~cutoff[i]) }

Greetings

Daniel


#27

Thank you! I got it now.


#28

Not only that:

f = { |a = true, b = false, c = true, d = a | b | c | ... };

// vs
f = { |a = true, b = false, c = true, d = (a | b | c) | ... };

f = { |a = true, b = false, c = true, d = a | (b | c) | ... some other boolean... };

WRT NamedControls, what I would really like is a preprocessor that could associate all of these for a control:

  • name
  • default value
  • ControlSpec to be used later for GUI

E.g.,

SynthDef(\name, {
	## INPUT freq 440 \freq;
	## INPUT ffreq 2000 \freq;
	## INPUT rq 0.2 [1.0, 0.05, \exp];
	...
}).add

Now, that specific syntax is ugly and needs to be rethought, but that’s purely cosmetic. The main idea is: nobody uses specs in SynthDefs because currently you have to dump the specs into metadata at the end, separated from the input declarations. Specs, of course, would be optional but more people would use them if you include them in the same place where you write the default value. Then, if more people are using them, it’s easier to support better auto-GUI features.

IMO in freq = \freq.kr(440), I quite strongly dislike the redundancy of providing a variable name and symbol and I anticipate not using this option. But I could be persuaded to switch over if we used the opportunity of proposing a change in recommended syntactical practice to provide a currently missing feature (synth auto-GUI).

hjh


#29

With https://github.com/supercollider/supercollider/pull/3814 I believe you can do:

SynthDef(\foo, {
    |freq, amp|
   freq.spec = ControlSpec(20, 20000, default:440): 
   amp.spec = \db;
});

… or the equivalent via symbols - maybe more readable and straightforward than your macro example, even.


#30

And - iirc you can use \symbol.kr notation for the same symbol multiple times in a SynthDef and it works as you would expect? If this doesn’t work now, it’s something worth fixing (and not so difficult, engineering-wise).


#31

Hi! Thanks for the NamedControl tutorial! Great tool!
I wonder if it is possibe to have kind of multi type NamedControls

Starting from here

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

Which kind of solution would be able to send an audio rate ugen to \freq.kr?
Better said how could a \freq.kr and a \freq.ar live together in the same SynthDef?
AFAIK that’s a good reason to use Instr instead SynthDef even if i know that using Quarks can be a can of worms.
I guess i’m looking for a kind of polymorphism, like sending a polymorph object as an argument to a polymorph object as almost all SC UGen are with their double kr/ar nature.


#32

An important point is this: the structure of a synthdef on the server is totally fixed. Once you decide for kr it’s kr forever, no way to extend on that base.

That said, there is some kr / ar flexibility: e.g. you can map an audio bus to a kr control. But you must expect artefacts with non-LFO controls (with standard settings kr results in a nyquist frequency of ca 350 Hz which is often forgotten):

(
SynthDef(\test_kr, {
	Out.ar(0, LeakDC.ar(SinOsc.ar(\freq.kr(400), 0, 0.1)))
}).add;

SynthDef(\test_ar, {
	Out.ar(0, LeakDC.ar(SinOsc.ar(\freq.ar(400), 0, 0.1)))
}).add;
)

(
x = Synth(\test_kr);
a = Bus.audio(s, 1);
)

x.map(\freq, a);

// distorted FM
y = { Out.ar(a, SinOsc.ar(1000, 0, 1000)) }.play

y.free
x.free


(
x = Synth(\test_ar);
a = Bus.audio(s, 1);
)

x.map(\freq, a);

// clean FM
y = { Out.ar(a, SinOsc.ar(1000, 0, 1000)) }.play

y.free
x.free

Furthermore you can use A2K and go via a control bus (or K2A on other occasion).

But again: if you intend to go essentially into ar, e.g. do something like FM via buses you need ar args and ar buses.


#33

Thanks @dkmayer
that’s the reason because i was looking into Instr…as reported in help doc

" Instr SynthDefs

Unlike SynthDef, Instr can take any kind of input for its arguments, not just (including an Integer quantity, symbols or even other functions) and so while a SynthDef has a fixed architecture for a Synth, an Instr can generate multiple SynthDefs of varying architectures. For instance you could specify an Env or a fixed time duration or a quantity (how many parallel voices to create, detuned against each other) or even the name of a UGen (LFSaw, Pulse) to use for the oscillator."