Tuning Instruments


Once you have created instruments and started to play them, you can specify given pitches for instrument notes (see Playing Instruments). A pitch is a discrete value that corresponds to a given frequency-you might want to think of it as an index number in a frequency lookup table. The most common example of specifying pitch is by name-middle C, for example, or G an octave and a fifth above that. You also specify pitch whenever you press a key on a standard keyboard instrument, the fifth black key from the bottom, or the white key at the top of the keyboard. In both cases, do not worry about the frequency of the note; the instrument you are using translates the specified pitch into the frequency you want.

MIDI instruments, for convention's sake, specify pitch as an integer from 0 to 127. They tie those values to the pitches used in a standard 12-tone, well-tempered tuning system (the kind you find on almost every standard western keyboard instrument). The pitch value 60 corresponds to middle C and each count up or down moves up or down one half-step in pitch. For example, 61 is a C sharp (or D flat), 62 is a D, 59 is a B, 58 is a B flat (or A sharp), and so on. A jump of 12 is an octave. For example, 69 is an A 440; 81 is an A 880, one octave above A 440.

Portfolio instruments use the standard MIDI tuning system by default, built on pitch values from 0 to 127, playing a 12-tone, equal-tempered tuning system. Not everything sounds its best in this tuning. If you want to reproduce the sounds of a Javanese gamelan or an Indian raga, the out-of-tune splendor of a honky-tonk piano, or the tight-knit harmonies of a barbershop quartet, you have to come up with some alternative tunings that assign different frequencies to the 128 MIDI pitch values.

You can, of course, specify the precise frequency as you play each note to get just the tuning you want. But if you want to play a MIDI score directly on an instrument without setting the precise frequency for each note, that will not work. You can, instead, reset the tuning of the instrument before you play. The score then plays back using the appropriate tuning system. To help you create and use alternative tunings, the Audio folio offers a set of tuning calls.

Creating a Tuning

(A note to those who are happy with standard MIDI tuning: you can skip this part of the tuning section and use instruments with their default tunings. You might be interested, however, in the final tuning topic here, bending pitch.)

To create a tuning, you must create a list of frequencies (measured in cycles per second or Hertz) that you want to associate with MIDI pitch values. Each frequency value is stored as a 16.16 value, which allows you to represent fractional frequencies such as 261.63 Hz. The list of frequencies normally goes from lowest to highest, although you can invert that or mix the frequencies to create pitch inversion or true havoc when playing back MIDI scores.

You can, of course, create a list of 128 different frequencies, one for each of the 128 MIDI pitch values. This is useful if your tuning is irregular, and does not repeat itself from one octave to the next. If, however, your tuning uses one set of frequencies within an octave, and that set repeats in higher and lower octaves, then you need only define the frequencies within that one octave. For example, if you want to create a quarter-tone tuning system with 24 pitches per octave, you need only define the 24 pitches within a single octave. The Audio folio extends the tuning to the other octaves. You can also define two or more octaves of pitches if the tuning changes from one octave to the next, but repeats every third, fourth, or fifth octave.

Before you can apply a list of frequencies to an instrument, you must create a tuning based on that frequency list by using this call:

Item CreateTuning( ufrac16 *Frequencies, int32 NumNotes, int32 NotesPerOctave, int32 BaseNote )
The first value this call accepts is a pointer (*Frequencies) to the list of frequencies. The second value (NumNotes) is the number of frequencies found in the list. The third value (NotesPerOctave) contains the number of pitches that fall within a single octave. And the final value (BaseNote) is a single MIDI pitch value that corresponds to the first frequency in the frequency list.

When CreateTuning() executes, it reads the frequencies in the list, starting at the beginning and going the number of frequencies specified by NumNotes. It is important to set NumNotes correctly to avoid losing frequencies or reading garbage values. It assigns the first frequency to the value set by BaseNote and assigns subsequent frequencies to subsequent values. For example, if a five-frequency list is assigned to pitches starting with a base pitch of 60, the five frequencies are assigned in order to 60, 61, 62, 63, and 64. CreateTuning() returns the item number of the tuning created if successful, or a negative value (an error code) if unsuccessful.

Extending Tuning

If a tuning does not contain 128 independent frequencies, then many pitch values do not have an assigned frequency. This is where the NotesPerOctave value comes into play. If an instrument plays a note that falls outside the assigned range of pitches, the Audio folio looks at the number of pitches contained in each octave and extends the defined pitches to assign an appropriate frequency to undefined pitches.

For example, consider the five-frequency list used above. Assume there are five pitches per octave. If an instrument using the tuning is asked to play pitch value 65 (which is unassigned), the Audio folio looks down five pitches (the span of an octave), finds the frequency assigned to 60, and doubles it to produce an octave-higher frequency for 65. To play pitch value 70, the Audio folio drops down 10 pitches (the span of two octaves) to 65 and quadruples the frequency there to produce a frequency two octaves higher.

If you are working with a sampled sound instrument, it typically has a pitch range that extends no higher than one octave above its recorded pitch. Below its recorded pitch, its pitch range descends into the depths of inaudibility.

Applying a Tuning

Once you have created a tuning, you can use it by applying it either to an instrument, which affects notes played only by that instrument, or to an instrument template, which affects notes played by all instruments created using that template.

To apply a tuning to one instrument, use this call:

Err TuneInstrument( Item Instrument, Item Tuning )
The call accepts the item number of the instrument and the item number of the tuning you want to apply to the instrument. When it executes, it applies the tuning to the instrument so the instrument plays with that tuning. The call returns 0 if successful, or a negative value (an error code) if unsuccessful.

To apply a tuning to an instrument template (thereby applying it to all instruments created using that template), use this call:

Err TuneInsTemplate( Item InsTemplate, Item Tuning )
The call accepts the item number of the instrument template and the item number of the tuning you want to apply to the template. When it executes, it applies the tuning to the instrument template so that all instruments associated with the template play using that tuning. The call returns 0 if successful, and a negative value (an error code) if unsuccessful.

After tuning an instrument template, all instruments created from the template use the tuned template.

Deleting a Tuning

When a task finishes using a tuning, it should delete it to free system resources. To do so, use this call:

Err DeleteTuning( Item Tuning )
The call accepts the item number of the tuning. When executed, it deletes the tuning. It returns 0 if successful, or a negative value (an error code) if unsuccessful.

If an instrument is using a tuning and the tuning is deleted, the instrument returns to its default tuning.

Bending Pitch

Most standard MIDI synthesizers contain a device called a pitch wheel. When you move the pitch wheel up or down, it bends the overall pitch of the synthesizer up or down. The current setting of the wheel determines how much the overall pitch of the synthesizer bends up or down.

The Audio folio provides a similar mechanism for audio instruments. Each instrument stores a bend value (a frac16 value) that multiplies the instrument's output frequency, bending any pitches played up or down by an amount corresponding to the multiplier. For example, if an instrument has a bend value of 2, then all output frequencies are doubled, so the instrument's output pitches bend up by an octave in pitch. If an instrument has a bend value of 0.5, then all output frequencies are halved, so the instrument's pitches bend down by an octave in pitch. And if an instrument has a bend value of 1 (the default value), the output frequencies do not change, and the instrument's output pitches are not bent.

To set an instrument's bend value, use this call:

Err BendInstrumentPitch( Item Instrument, frac16 BendFrac )
The call accepts two arguments: Instrument, the item number of an instrument; and BendFrac, a bend value to apply to that instrument. When it executes, the call applies the bend value to the instrument. All notes played on that instrument are then bent by the amount specified. The call returns 0 if successful, or a negative value (an error code) if unsuccessful.

An instrument's bend value affects all pitches equally, so it does not affect the instrument's relative tuning. For example, if you set an instrument's tuning to a 24-step quarter-tone scale and then you bend the instrument up by a minor third, the instrument still plays a 24-step quarter-tone scale. It simply plays all the pitches in the scale a minor third higher than specified in the tuning.

DSP sampled sound instruments cannot bend up by more than one octave.

Creating a Bend Value

Because most musically astute humans tend to think of pitch intervals as a number of half-steps fine-tuned up or down by cents (100 cents equal a half-step), determining a frac16 bend value may not be a simple matter. To easily create a frac16 bend value, use this call:

Err Convert12TET_F16( int32 Semitones, int32 Cents, frac16 *FractionPtr )
The call accepts three arguments: Semitones, an integer number of half-steps (semitones) to bend up or down; Cents, an integer number of cents to bend up or down; and *FractionPtr, a pointer to a frac16 variable where the created bend value is stored. When Convert12TET_F16() executes, it combines the number of half-steps and the number of cents to determine the final bend interval, creates a bend value that matches that interval, and then writes the bend value to the variable provided. If successful, it returns 0; if unsuccessful, it returns a negative value (an error code).

The Semitones and Cents arguments used for Convert12TET_F16() can be negative or positive. Negative values bend pitch down, positive values bend pitch up. The two arguments need not both be positive or both be negative, one can be positive while the other is negative. For example, -5 semitones and +30 cents specifies a downward pitch interval of 4 semitones and 70 cents (an interval that is a little less than a fourth).