11 -Variables, Comments, Offset and Scale using Mul and Add 

Variables and Comments 

It is often useful in code to define and use your own terms and functions. Variables are used for this purpose. Remember that variable names can be anything but must begin with a lower case letter (no numbers) and they must be contiguous. It is tempting to use short cryptic names such as tri, beg, pfun, freq, or even single letters such as a, b, c. More descriptive names take more time but you will be glad you used them in the long run; firstPitch, legalDurations, maximumAttack, etc. 

Variables are declared (identified to the program) with the syntax var followed by a list of variables separated by commas and terminated by a semicolon. Variables are assigned values (the value is stored in the memory location associated with the variable) using the "=" sign followed by the value you want to store and a semicolon. The variable can then be used throughout the program. 

The code below also uses comments. Comments are identified using "//" followed by the comment. The compiler ignores everything from the "//" to the end of the line. 

11.1. Variable declaration, assignment, and comments 

//First patch

{SinOsc.ar(LFNoise0.ar(10, mul: 400, add: 800), 0, 0.3)}.play

//First patch with variables

(
{

var freqRate, freqRange, lowValue;
freqRate = 10; //rate at which new values are chosen
freqRange = 1200; //the range of frequencies chosen
lowValue = 60; //the lowest frequency

	SinOsc.ar(
		LFNoise0.ar(freqRate, freqRange/2, freqRange + lowValue),
		0, 0.3)
}.play
)

One reason for using variables is clarification. Earlier this example required explanation for arguments in LFNoise0. Variables are self-documenting. This way the programmer can 
explain not only where they are used but also what they mean. 

Variables can also be used for consistency. One variable may be used hundreds of times in a program or patch. Using a variable ensures that when a change is made all values are 
changed in the patch. 

Another important use for variables is to link arguments. Suppose you created a patch that plays a range of frequencies. You might want to reduce the volume when higher frequencies 
are played and increase the volume with lower frequencies, volume change to frequency. You might also want the cutoff for a filter to change in proportion to the fundamental 
frequency. You might want the decay rate of an envelope to decrease with higher frequencies (which is what happens on many instruments). Without a common variable you would have to change them all by hand. For example, here are two possible sets of parameters for one sound. 

100 //low frequency 

0.7 // amp 
600 //filter cutoff 
2.0 //decay rate 
1200 //higher frequency 
0.3 //lower amplitude 
7200 //higher cutoff 
0.1	//decay rate 

With a single variable, they can be linked using expressions. When frequency changes, the other variables change accordingly. 

var freq; 

freq = 100 //frequency may change 
amp = freq/1200 //amp changes as freq changes 
cut = freq*600 //cutoff changes as freq changes 
rate = 100/freq //decay changes as freq changes 

Offset and Scale using Mul and Add 

Most Ugens generate values either between –1 and 1 or 0 and 114. Earlier I used the mul argument to change the amplitude of a wave from +/-1 to +/-0.5, +/-0.3, and so on. The 
result was a change in amplitude or size of the wave. The mul argument multiplies or scales the wave. A larger scale means a louder sound, smaller scale quieter. I also said that values 
above 1.0 are inappropriate for amplitude. But you may have noticed the LFNoise has a mul value of 400. It normally generates values between –1 and 1. What happens to those values if they are multiplied, or scaled by 400? They change to +/-400. 

It is very important to remember which is which. LFNoise, SinOsc, Saw, etc. defaults are –1 and 1, but envelope, LFPulse, defaults are 0 to 1. 

The add argument offsets the output of a Ugen. It changes the center from 0 to whatever the add value is. A mul of 400 for the LFNoise0 would scale the range from +/–1 to +/–400. 
What would be the final result if that scaled output were then offset by 800? Here are three graphs illustrating how the add and mul arguments change a SinOsc wave. 

a) default SinOsc b) SinOsc scaled to 0.2 c) scaled to 0.2 offset to 0.5 

Scale and offset can be confusing because the resulting range of the Ugen output is different from the actual offset and scale. You use an offset of 0.5 and a scale of 0.2, but the range of values ends up being 0.3 to 0.7. 

The line of code below shows an offset of 300 and scale of 100. But the range is 200 to 400.  How would you use an object that generates values between 200 and 400? How about 
frequency? In the example below a SinOsc is being used as the freq argument for another SinOsc. First calculate what values are being returned by this inner SinOsc with a mul of 100 and an add of 300. With a freq of 3 this Ugen will move between 200 and 400 3 times per second. How will that affect the freq of the outer SinOsc? 

The term for this effect is voltage control, which is discussed in more depth later. 

11.2. Offset and scale with mul and add 

{SinOsc.ar(SinOsc.ar(3, 100, 300), 0, 0.3)}.play

Here is a graph of the SinOsc.ar(3, 100, 300). 

offset (add): 300, scale (mul): 100, actual result: 200 to 400 

Offset and scale can be even more confusing because some ugens, such as an Env and 
EnvGen, or LFPulse, have a default range of 0 to 1 not +/–1. So the affects of a scale and 
offset are different (though more straightforward). An EnvGen that is scaled by 200 and 
offset by 100 will have final values of 100 to 300. If this is confusing read this section a few 
more times. You can't just glance over it and move on. The concepts of scale and offset are 
used over and over, not only in SC, but other synthesis programs. 

Our students have found it useful to think of scaling these terms: 

For Ugens with a default range of +1 to -1: 
–The add is the center value of a range. 
–The lowest value is the add minus the mul. 
–The highest value is the add plus the mul. 
–The range is the mul times 2. 

For Ugens with a default range of 0 to 1: 
-The add is the low end of the range 
-The mul + add is the high end of the range 
-The mul is the range 

It is possible to use variables for clarification, but it's usually just as easy to do the math in 
your head. The ugen will also run more efficiently without the added variables and math. 

11.3. less confusing? 

var low, high;
low = 200;
high = 400;
{SinOsc.ar(
	SinOsc.ar(3, mul: (high - low)/2, add: (high - low)/2 + low),
	mul: 0.5
)}.play

There is a ugen that can do the calculation for you. It is called LinLin and converts one range of values to another. The arguments are the input, the low and high range of the input, and the low and high range of the output, or what you want the input to become. 

11.4. Map Range with LinLin 

{
SinOsc.ar(
	LinLin.kr(
		SinOsc.kr(4), // The input to be mapped
		-1, 1, // The default output of SinOsc, what it is already
		300, 500) // The range you want it converted to
	)
}.play(s)

Practice 

11.5. Harmonic Swimming From the Examples Folder 

*/
(
// harmonic swimming
play({
	var fundamental, partials, out, offset;
	fundamental = 50;		// fundamental frequency
	partials = 20;		// number of partials per channel
	out = 0.0;		// start of oscil daisy chain
	offset = Line.kr(0, -0.02, 60); // causes sound to separate and fade
	partials.do({ arg i;
		out = FSinOsc.ar(
				fundamental * (i+1), 		// freq of partial
				0,
				max(0, 			// clip negative amplitudes to zero
					LFNoise1.kr(
						6 + [4.0.rand2, 4.0.rand2],	// amplitude rate 
						0.02, 					// amplitude scale
						offset					// amplitude offset
					)
				), 
				out
		)
	});
	out
})
)
/*

11. Exercises 

11.1. Rewrite this patch replacing all numbers with variables. 

{SinOsc.ar(freq: SinOsc.ar(512, mul: 673, LFNoise0.kr(7.5, 768, 600)), 
mul: 0.6)}.play 

This doesn't appear to work

11.2. Rewrite the patch above with variables so that the scale of the SinOsc (673) is twice 
the frequency (512), and the offset of LFNoise0 (600) is 200 greater than the scale 
(768). 

11.3. How would you offset and scale an LFNoise0 so that it returned values between the 
range of C2 and C6 (C4 is 60). 

11.4. An envelope is generating values between 400 and 1000. What is the offset and 
scale?