How to update a SynthDef parameter through a slider?

Hello,

I’m working on a project where I have a mixer controlled by slider GUI elements.
I’ve setup the following method to create the slider:

~makeSliderNumBoxCombo = {
arg bounds, maxVal, parent;
var view, number, slider, step;
step = ControlSpec(-50, 50, \linear, 0.01);
view = View.new(parent, bounds);
number = NumberBox(view, Rect(0, bounds.height - 20, bounds.width, 20));
~slider = Slider(view, Rect(0, 0, bounds.width, bounds.height - 20))
.action_({
number.string_(step.map(~slider.value).asString);
~slider.value.postln;
});
view.background = Color.blue;
view;
};

Then I want to reference this sliders value in my mixer SynthDef:

SynthDef(\mixer, {
arg outBus = 0;
var output, channelA;
channelA = In.ar(~mixerAsignal, 2);
output = channelA * ~slider.value; /** In.kr(~mixerAfader);*/
output.scope;
Out.kr(~mixerAvol, Amplitude.kr(output));
Out.ar(outBus, output);
}).add;
)

If I just print the slider value like I’m doing in the slider action I get some float values when moving it. Also when I replace the second term of the multiplication with a number to obtain output in the SynthDef multiplied by that number then it also works. So why can’t I just get the slider value and multiply it with the channelA signal as if it were a number?

I’ve also tried using a control bus for this but that had the issue of sending 0 values when the slider is not being moved!

how can I do this?

First, in the SynthDef, declare an argument for the slider value.

Then, the slider’s action should be to .set the argument’s value (Node | SuperCollider 3.12.2 Help).

~slider.value gets the current value. When you write it in the SynthDef, it runs only once, at SynthDef building time. This hardcodes one value into the SynthDef, so that it can never change after that. So – you need either an argument or a control bus for this.

One curious observation: This is probably the number 1 use case for a slider, but the Slider helpfile contains no example of this :astonished: so there would be a good “low hanging fruit” for a new contributor (add a “slider controlling synth parameter” example).

hjh

This is basically due to the separation between client and server, see Client vs Server | SuperCollider 3.12.2 Help

A synth is only running on the server (which generates the audio for you) and the slider is running on the client/sclang - so everytime you change the slider you should also tell the server what the current value of your desired variable is b/c otherwise the server won’t know. I tend to use Ndef | SuperCollider 3.12.2 Help and NamedControl | SuperCollider 3.12.2 Help for this with which you can build the following.

(
q = q ? ();
w = Window.new("A Slider");
q[\slider] = Slider.new(w, Rect(40, 10, 300, 30));
q[\slider].addAction({|slider|
	slider.value.postln;
	Ndef(\someSound).set(\amp, slider.value);
});
w.front
);

(
// create a sound
Ndef(\someSound, {|out|
	var sig;
	sig = SinOsc.ar(LFDNoise0.kr(3!2).exprange(100, 400));
	sig = sig * \amp.kr(1.0);
	Out.ar(out, sig);
}).play;
)

and w/o Ndefs using Bus


// start some sound
(
q = q ? ();

q[\fooSynth] = SynthDef(\foo, {|out|
	var sig;
	sig = SinOsc.ar(LFDNoise0.kr(3!2).exprange(100, 400));
	sig = sig * \amp.kr(0.2);
	Out.ar(out, sig);
}).play;
)


// create an amp bus
(
q[\ampBus] = Bus.control(s);
q[\ampBus].set(0.2);
)

// attach the control bus to the synth
q[\fooSynth].map(\amp, q[\ampBus]);


(
// create gui
w = Window.new("A Slider");
q[\slider] = Slider.new(w, Rect(40, 10, 300, 30));
q[\slider].addAction({|slider|
	slider.value.postln;
	// in this case we need the handle to 
	q[\ampBus].set(slider.value);
});
w.front
);

hope this helps :slight_smile: