Scaling ranges

The real fun starts when you use some UGens to control the parameters of other UGens. The theremin example did just that. Now you have all the tools to understand exactly what was going on in one of the examples of section \ref{sec:first-sine}:

{SinOsc.ar(freq: LFNoise0.kr(12).range(500, 1500), mul: 0.1)}.play;

// Breaking it down:
{LFNoise0.kr(1).poll}.play; // watch a simple LFNoise0 in action
{LFNoise0.kr(1).range(500, 1500).poll}.play; // now with .range
{LFNoise0.kr(12).range(500, 1500).poll}.play; // now faster

The three last lines of the example demonstrate step-by-step how the LFNoise0 is used to control frequency. The message range simply rescales the output of a UGen. Remember, LFNoise0 produces numbers between -1 and +1 (it is a bipolar UGen). Those raw numbers would not be very useful to control frequency (we need sensible numbers in the human hearing range). The .range takes the output betwen -1 and +1 and scales it to whatever low and high values you provide as arguments (in this case, 500 and 1500). The number 12, which is the argument to LFNoise0.kr, specifies the frequency of the UGen: how many times per second it will pick a new random number.

In short: in order to use a UGen to control some parameter of another UGen, first you need to know what range of numbers you want. Are the numbers going to be frequencies? Do you want them between, say, 100 and 1000? Less? More? Or are they amplitudes? Perhaps you want them to be between 0.1 (soft) and 0.5 (half the maximum)? Or are you trying to control number of harmonics? Do you want it to be between 5 and 19?

Once you know the range you need, use the .range method to make the controlling UGen do the right thing.

Exercise: write a simple line code that plays a sine wave, the frequency of which is controlled by a LFPulse.kr. Provide appropriate arguments inside after the kr. Then, use the .range method to scale the output of LFPulse into something that you want to hear.

Scale with mul and add

You already know how to scale the output of UGens in the server using the method .range. The same thing can be accomplished on a more fundamental level by using the arguments mul and add, which pretty much all UGens have. The code below shows the equivalence between range and mul/add approaches, both with a bipolar UGen and a unipolar UGen.

// This:
{SinOsc.kr(1).range(100, 200).poll}.play;
// ...is the same as this:
{SinOsc.kr(1, mul: 50, add: 150).poll}.play;

// This:
{LFPulse.kr(1).range(100, 200).poll}.play;
// ...is the same as this:
{LFPulse.kr(1, mul: 50, add: 100).poll}.play;

Figure \ref{fig:mul-add-scale} helps visualize how mul and add work in rescaling UGen outputs (a SinOsc is used as demonstration).