Interpolation with the function object

Image

The function object can be used to create line segment functions that control a line~ object, and it can also be used as a lookup table. A number coming in its inlet will be treated as a point on the x axis, and whatever y axis value is shown on the line segment function at that point will be sent out the leftmost outlet. This example patch demonstrates that use of function.

The function object in this patch has been saved with its domain set at 10,000 and its range set from 60 to 180. Click on the toggle to see and hear what this patch does. When the toggle is turned on, it sends out the number 1, which turns on the clocker object, which in turn begins to report the time that has elapsed (starting at 0 at the moment it’s turned on) at regular intervals specified by its argument (every 100 milliseconds in this case). The elapsed time is used to look up a tempo between 60 and 180 in the function object, and that tempo is sent to the tempo object to determine its (quarter note) beats per minute. The elapsed time value from the clocker is also used to check whether the stopping time has been reached, which initially is 10,000 milliseconds. Finally, the 1 from the toggle will be used to start the tempo object, which will have already received the correct tempo from the function. When clocker reaches 10,000, the >= object will send out the number 1, which will be detected by the sel 1 object, which will turn off the clocker and the tempoobject. Thus, as the elapsed time progressed from 0 to 10,000 (or whatever you set as the stopping time), those increasing numbers read through the function that is in the lookup table, i.e., the line segment shape designating musical tempo that is in the function object.

The upper left portion of the patch is a very simple note generator. The tempo object is set to output numbers designating sixteenth notes at whatever quarter-note tempo it receives. The first argument is the initial tempo, and the next two arguments are the numerator and denominator of a fraction saying what kind of note value it should use as its output rate, in this case 1/16 notes. The tempo object will send out the numbers 0 to 15 showing which 16th note it’s on within a standard 4/4 meter. At the downbeat of each 4/4 measure, it wraps back around to 0 and repeats. Those numbers from the tempo object are multiplied by 3, thus counting by threes from 0 to 45, and then added to 48 so that it’s now counting by threes from 48 to 93. Those numbers 48, 51, 54, 57,…93 are used as pitch values in the makenote object, which combines them with a velocity value of 127 and sends 125-ms-long MIDI notes to the noteout object. The result is a four-octave arpeggiation of a C diminished seventh chord.

Try changing the domain of the function to play phrases of different durations. Try clicking in the function to create new points, making whatever shape of tempo changes you’d like to try. (You can shift-click on points to delete them.)

Amplitude envelope with the function object

Image

In MSP, each MSP object (each object that has signal input and/or output) is always producing signal as long as audio is turned on. For example, signal generators like cycle~(sinusoidal wave generator) and saw~ (band-limited sawtooth wave generator) are always producing a full-amplitude wave. You control the amplitude of that wave with multiplication, using *~ or some other object that performs a multiplication internally (such as gain~). Multiplication by a value greater than 1 increases the amplitude (amplification), and multiplication by a value between 0 and 1 decreases the amplitude (attenuation). (Multiplication by a negative number has the same sort of effect, while also inverting the signal about the x axis.) Multiplication by 0 completely suppresses the signal (silence). In that last case, the signal generator is still working just as hard, producing its full amplitude signal, but the multiplication by 0 converts every sample to 0.

You can think of every individual sound as being surrounded by silence. You could imagine that, as in MSP, sound is always present, but during the silence its amplitude is 0 (the sound is being multiplied by 0), and when the sound is audible it is being multiplied by 1 or by some other nonzero number. Thus, the sound is audible only when its amplitude is being controlled by a nonzero value — a conceptual “window” is opened on the sound allowing it through — and the rest of the time it’s being multiplied by 0 and the conceptual window is closed. This idea of a “window” — a period of nonzero values surrounded by 0 before and after — is an important concept in digital music and in digital signal processing. A sound that is off (0), then is instantaneously switched on (1), then is later instantaneously turned off again (0) has been windowed with a rectanglar-shaped function. More commonly in music software we use a window shape that is not exactly rectangular, such as a trapezoidal window with tapered ends, to avoid clicks.

This example demonstrates the use of a function object to create a trapezoidal window signal coming out of the line~ object to control the amplitude of a sawtooth oscillator. Each time function receives a bang, it sends out a list that says, “Go to 1 in 50 milliseconds, stay at 1 for 900 milliseconds, then go to 0 in 50 milliseconds.” The changing values fromline~ are used as the multiplier controlling the amplitude of the oscillator, opening a 1-second window on the sound.

The duration of that window can be changed simply by sending a setdomain message to function. Note that the duration of each segment of the function is time-scaled proportional to the domain specified, so the fade-in and fade-out tapered ends of the function, which are 50 milliseconds initially, would last only 5 milliseconds if the duration of the window were shortened to 100 ms, and would last 500 milliseconds if the total duration (the domain) were set to 10,000 ms.

The function object

Image

The function object assists you to make shapes composed of line segments. When you send a bang to the function, it sends out of its second outlet a list of destination value andramp time pairs suitable for use as input to a line~ object. In that way, the shape shown in the function object serves as a function over time, the shape of which will be enacted by the signal coming out of the line~ object.

A two-dimensional graph like the one shown here shows the relationship between two variables, x and y, and is said to be a graph of “y as a function of x” or “y over x”. That means that it shows how the y variable changes with each corresponding x value. In most musical situations, the x axis designates time (with x=0 designating a starting point in time) while y designates a value that changes over time according to a certain shape or curve. Since the x value (time) increases at a constant rate, the shape of the function shows us how y will change over time.

In math terminology, the minimum and maximum of the numbers on the x axis are said to determine the “domain” of the function, and the minimum and maximum of the numbers on the y axis determine the “range” of the function. By default, the domain of the function object is 0 to 1000 (since it’s assumed that the domain will designate milliseconds), and the range is 0 to 1. But you can change the extent of the domain and the range with the messages setdomain and setrange. The minimum of the domain is always 0 in the functionobject, so you only need to provide the desired maximum with the setdomain message, as in setdomain 1000. For the range, you specify both the minimum and the maximum, as in setrange 0. 1.

Try changing the domain and the range, and then sending a bang to see how the resulting list changes. Notice that in this patch we use the pak object to combine the minimum and maximum values in a single setrange message. The pak object is used to combine several individual numbers together into a list, much like the pack object. The crucial difference between the two is that the pak object sends out a list any time it receives something in any inlet, whereas the pack object sends out a list only when it receives something in its leftmost inlet.