How to set oscillator signal in arg


#1

Hello.
I’m trying to set oscillator signal into “arg” parameter in SynthDef.
But this code output some error…
Anyone can help?

s.boot;

(
SynthDef(\test, {
	arg freq = 440;
	var out = {SinOsc.ar(freq!2)};
	Out.ar(0, out);
}).add;
)

x = Synth(\test);
x.set(\freq, SinOsc.ar(440)); // error!
x.free;

console:

CALL STACK:
	Exception:reportError
		arg this = <instance of Error>
	Nil:handleError
		arg this = nil
		arg error = <instance of Error>
	Thread:handleError
		arg this = <instance of Thread>
		arg error = <instance of Error>
	Object:throw
		arg this = <instance of Error>
	UGen:asControlInput
		arg this = <instance of SinOsc>
	Object:asOSCArgEmbeddedArray
		arg this = <instance of SinOsc>
		arg array = [*1]
	< FunctionDef in Method SequenceableCollection:asOSCArgArray >
		arg e = <instance of SinOsc>
	ArrayedCollection:do
		arg this = [*2]
		arg function = <instance of Function>
		var i = 1
	SequenceableCollection:asOSCArgArray
		arg this = [*2]
		var array = [*1]
	Node:set
		arg this = <instance of Synth>
		arg args = [*2]
	Interpreter:interpretPrintCmdLine
		arg this = <instance of Interpreter>
		var res = nil
		var func = <instance of Function>
		var code = "x.set(\freq, SinOsc.ar(440));"
		var doc = nil
		var ideClass = <instance of Meta_ScIDE>
	Process:interpretPrintCmdLine
		arg this = <instance of Main>
^^ The preceding error dump is for ERROR: can't set a control to a UGen

#2

Unfortunately you can’t do that… I wish it was that simple though :slight_smile:

You have two options :

Using buses

See http://doc.sccode.org/Tutorials/Getting-Started/11-Busses.html

SynthDef(\test, {
	Out.ar(\out.ar(0), SinOsc.ar(\freq.kr(440) ! 2));
}).add;

SynthDef(\modulator, {
	Out.kr(\out.kr(0), SinOsc.kr(\freq.kr(1)).range(440,600));
}).add;

~bus = Bus.control(s,1);
~testSynth = Synth(\test);
~modulatorSynth = Synth(\modulator, [out: ~bus]);
~testSynth.map(\freq, ~bus);

Using JITLib

The JIT lib makes the creation of buses invisible for this kind of use case.

See http://doc.sccode.org/Overviews/JITLib.html

Ndef(\test, {
	SinOsc.ar(\freq.kr(440) ! 2);
}).play;

Ndef(\modulator, {
	SinOsc.kr(1).range(440,600) 
});

Ndef(\test).map(\freq, Ndef(\modulator));

Good luck !


#3

(
SynthDef(\test, {
arg freq = 440;
var out = SinOsc.ar(freq!2);
Out.ar(0, out);
}).add;
)

x = Synth(\test);
x.set(\freq, 220); // put only the frequency, (not SinOsc.ar)
x.free;

But I may not have understood the question correctly?


#4

Thanks!!! I didn’t know “bus” and “JITLib”, and tutorial links are really helpful…
Its can work collectly like I thought, thank you​:sob::sob::sob:


#5

@Geoffroy I am new to the language and still getting my head around ugens and and how they are instantiated. I have some questions about your solution. See comments below. There are two things I am confused about, the use of map and setting the control bus as an argument instead of directly in the UGen.

// This is rewritten how I am used to writting sc. It works.

SynthDef(\test, {
	arg freq = 440, out = 0;
	Out.ar(out, SinOsc.ar(freq ! 2));
}).add;

SynthDef(\modulator, {
	arg freq = 1, out = 0;
	Out.kr(out, SinOsc.kr(freq).range(440,600));
}).add;

~bus = Bus.control(s,1);
~testSynth = Synth(\test);
~modulatorSynth = Synth(\modulator, [\out, ~bus]);
~testSynth.map(\freq, ~bus);

// Now, there are a couple of things here that seem odd to me. The use
// of `map` and having to set `out` to bus as an argument after the
// synth is instantiated.

// First, if `~bus` is a global variable, why can't it be used in the
// `SynthDef` directly? This does not work. I am sure there is a good
// reason, I would just like to know why.

SynthDef(\test, {
	arg freq = 440, out = 0;
	Out.ar(out, SinOsc.ar(freq ! 2));
}).add;

SynthDef(\modulator, {
	arg freq = 1;
	Out.kr(~bus, SinOsc.kr(freq).range(440,600));
}).add;

~bus = Bus.control(s,1);
~testSynth = Synth(\test);
~modulatorSynth = Synth(\modulator);
~testSynth.map(\freq, ~bus);

// Second, the use of `map` over `set`. If I look up the help for map
// I see several help files. I assume this is the map for `NodeEvent`,
// but it's unclear why `set` doesn't work here. `set` is doing
// something, I'm not sure what...

SynthDef(\test, {
	arg freq = 440, out = 0;
	Out.ar(out, SinOsc.ar(freq ! 2));
}).add;

SynthDef(\modulator, {
	arg freq = 1, out = 0;
	Out.kr(out, SinOsc.kr(freq).range(440,600));
}).add;

~bus = Bus.control(s,1);
~testSynth = Synth(\test);
~modulatorSynth = Synth(\modulator, [\out, ~bus]);
~testSynth.set(\freq, ~bus);

#6

// First, if ~bus is a global variable, why can’t it be used in the
// SynthDef directly? This does not work. I am sure there is a good
// reason, I would just like to know why.

My advice is to read http://doc.sccode.org/Guides/ClientVsServer.html and http://doc.sccode.org/Tutorials/Getting-Started/10-SynthDefs-and-Synths.html

Basically, when you create a SynthDef, the value of the variables are evaluated (i.e. “freezed”) when you evaluate the SynthDef, and the synth definition is sent to the server.

In your code, ~bus does not exist when you instantiate the SynthDef, hence the error.

// Second, the use of map over set. If I look up the help for map
// I see several help files. I assume this is the map for NodeEvent,
// but it’s unclear why set doesn’t work here. set is doing
// something, I’m not sure what…

If you “set” the value of a Synth parameter, it sets a fixed value to the parameter.
If you “map” a Synth parameter to a bus, SuperCollider will know to get the value in the bus at each processing block to update the Synth parameter.

You can read that chapter of Nick Collins tutorial on control buses.

Hope it’s a bit more clear now :slight_smile:


#7

@Geoffroy Great! Thanks for the clarifications!


#8

Sooo, kinda offtopic, but, since we’re talking about control signals and busses, is there a way to .map a param of a synth instanciated by a pbind to a control bus??


#9

Yep:

(
b = Bus.control(s, 1);
c = { Out.kr(b, LFDNoise3.kr(0.1).range(50, 90).midicps) }.play
)

(
p = Pbind(
    \freq, b.asMap,
    \dur, 0.3
).play
)


c.free;
p.stop;

#10

Awesome, now I understand those ¨c0¨ on Nick Collins tutorial