Hello all,
Due to the order of mul and add I am guessing this is the most concise way to make an LFO with a range from 0 to 1?
(
{
var lfo = SinOsc.ar(0.2,add:1)/2;
WhiteNoise.ar * lfo;
}.play;
)
Thanks, Dom
Hello all,
Due to the order of mul and add I am guessing this is the most concise way to make an LFO with a range from 0 to 1?
(
{
var lfo = SinOsc.ar(0.2,add:1)/2;
WhiteNoise.ar * lfo;
}.play;
)
Thanks, Dom
I realise there is this as well…
var lfo = SinOsc.ar(0.2).linlin(-1,1,0,1);
there’s SinOsc.ar(0.2).unipolar
…
its a shortcut for .range(0, mul=1)
- you can also specify a different mul
In your first example I’d also write it as SinOsc.ar(0.2) + 1 / 2
!
Thanks. That definitely qualifies!
I think * 0.5 + 0.5
is slightly more concise, and also a bit more efficient because signal * factor + offset
gets folded into a single MulAdd UGen whereas doing the addition first requires two separate UGens.
hjh
Interesting comparison! I guess the term ‘concise’ could mean different things depending on the context—either brevity in code or computational efficiency.
We have three variations of the same result:
(
{
[
SinOsc.ar(1),
SinOsc.ar(1).unipolar,
SinOsc.ar(1) * 0.5 + 0.5,
SinOsc.ar(1).range(0, 1)
]
}.plot(1)
)
While SinOsc.ar(1).range(0, 1)
is very expressive and readable, approaches like SinOsc.ar(1).unipolar
or even SinOsc.ar(1) * 0.5 + 0.5
might involve slightly simpler computations.
It’s hard to say definitively which one is most CPU-efficient without profiling, but each method seems to have its own trade-offs depending on the situation. Is the following code is correct to compare CPU-efficiency?
(
{
{ { SinOsc.ar(1) }.plot(1) }.bench;
0.1.wait;
{ { SinOsc.ar(1).unipolar }.plot(1) }.bench;
0.1.wait;
{ { SinOsc.ar(1) * 0.5 + 0.5 }.plot(1) }.bench;
0.1.wait;
{ { SinOsc.ar(1).range(0, 1) }.plot(1) }.bench;
}.fork(AppClock)
)
EDIT:
The last code in this post cannot benchmark the server-side CPU efficiency. Sorry for the wrong code…
Exactly! That’s why, in teaching, I switched to range
and mostly dropped using mul
and add
args.
SinOsc.ar(1).range(0, 1)
is SinOsc.ar(1) * 0.5 + 0.5
if (this.signalRange == \bipolar, {
mul = (hi - lo) * 0.5;
add = mul + lo;
}
mul = (1-0) * 0.5
= 0.5 and add = 0.5 + 0
= 0.5. Then it writes directly into MulAdd(this, mul, add)
.
If the arguments to range
are constant numbers, then it will always produce only a single MulAdd (as in this case). If one or both args are UGens, then the mul
and add
calculations will produce other UGens.
hjh