4. Notes and MIDI


The previous chapters introduced the basic language structures and user interface of OSW. The following chapters describe how to use its features to write programs that manipulate events and signals in musically interesting ways. This chapter describes methods for describing and manipulating musical events (notes and MIDI), and the next chapter introduces signal processing.

4.1. Notes

Making music usually means writing notes. Exactly what constitutes a musical note is a matter of some debate, but in OSW, notes are property lists (i.e., Blobs) with special temporal attributes. In particular, each note has a duration and a time until the beginning of the next note should be played. A sequence of notes, or a score is specified using the Notes transform. The Notes transform takes a list of arguments as follows:

        Notes  pitch-or-properties1 duration1 next1 pitch-or-properties2 duration2 next2

Every three arguments specifies one note. The first argument is either the pitch or a list of properties for the note, the second is the duration and the third is the time until the next note. Pitches can be specified as Floats representing frequency, Integers representing MIDI note numbers, or Strings representing note names (pitch class and octave). The duration and next properties represent relative times as fractions or multiples of whole notes (e.g. a duration of .25 is a quarter note) using Floats or Strings representing standard note durations. The following Strings can be used instead of Floats for the time properties:

l: long (4.0)
b: breve (2.0)
w: whole note (1.0)
h: half note (0.5)
q: quarter note (0.25)
e: eighth note (0.125)
s: sixteenth (0.0625)
t: thirty-second note (0.03125)
x: sixty-fourth note (0.015625)

Additionally, if a name is followed by one or more periods, it represents a dotted-note (e.g., “e.” is a dotted eighth note and “h..” is a double-dotted half note).

For example, the following phrase in traditional music notation:

can be specified using any of the following equivalent note commands.

           Notes c4 0.5 0.5 ef4 0.25 0.25 g4 0.25 0.25

           Notes c4 h h eb4 q q g4 q q

           Notes 60 h h 63 q q 67 q q

           Notes 261.625 h h 311.127 q q 391.995 q q

Of course, there are many other ways to mix-and-match the different representations of pitch and time (one note could use Strings for pitch and time properties and the next could use Floats).

The pitch property can be replaced be a list of names of values representing properties of the note. For example, the following sequence of notes could be used with a percussion synthesizer:

           Notes {timbre timpani volume 0.75} 0.5 0.25 {timbre cymbal volume 0.85} 1.25 1.25

Since all notes are also Blobs, you can dynamically modify the properties of any note using Blob transforms.

4.1.1 Playing Notes

Okay, so now that we know how to create notes, what can we do with them? The Notes transform outputs the notes as an object called a score, which can played using the PlayScore transform, which reads a score and outputs note-onset and note-ending events at the appropriate times. At the onset of each note in a score, PlayScore sends a copy of the note object out its left (“beginNote”) outlet, and then a copy of the note object out its middle (“endNote”) outlet once the duration of the note has elapsed. The user is then free to interpret the properties at the beginning and end each note as he/she wishes.

Consider the simple example of playing a score using a MIDI device. The MidiNote transform accepts the onset and ending copies of each note from PlayScore, and outputs the corresponding MIDI Note-On and Note-Off events.

In the above example, the audio output transform is present and active in order to provide an implicit clock source for PlayScore (See “Time in OSW” for more details, and also note that this inconvenience will probably no longer be necessary in the near future.)

You can also use PlayScore to drive synthesis within OSW. The Midi2Freq and OnOffAmp transforms are helpful for implementing MIDI-like note behavior in synthesis patches.

The MIDI and synthesis examples can be found in the midi_score and synth_score tutorials, respectively.

4.2 MIDI

A programming language cannot be called a “music programming language” unless it supports MIDI. OSW meets this requirement, supporting transforms for processing MIDI messages as well as sequencing Standard MIDI files.

A MIDI message is a series of bytes, consisting of a channel, an instruction and parameters for the instruction. A synthesizer listening on a channel receives and interprets the instruction. OSW supports input and output of messages from and to MIDI devices. The following patch receives MIDI note messages, raises the note by a perfect fifth, and outputs the result to a MIDI device listening on a different channel:

The MidiInput transform receives messages and unpacks them into four integers corresponding to the channel, status (i.e., instruction) and one or two parameters. The user is then free to perform arithmetic or any other operations on these numbers, like adding seven to the pitch value in note-on messages. The MidiPackBytes transform then packs the results into a MIDI message, which is sent to a MidiOutput transform and ultimately to a MIDI device. By default, MidiInput will accept any incoming MIDI messages. You can filter the messages by channel, status or value. In the above example, we used the “-status” parameter to indicate that we only wanted to accept note messages. You can also set up filtering by doubling-clicking the MidiInput and set channel, status, parameter, and input port (i.e., “driver”) interactively.

A similar dialog box for MidiOutput transforms allows you to choose the output port.

The example patch shown in this section can be found in the midi_tranpose tutorial.

4.2.2. MIDI Note Events

You can use MidiPackBytes transform to generate MIDI events, such as note-on and note-off events. In the following example, lists of numbers representing note-on and note-off messages are converted to MIDI messages using MidiPackBytes.

This patch probably seems a bit tedious if all you want to do is turn a MIDI note on and off. Fortunately, OSW includes two transforms called NoteOn and NoteOff that more easily convert pitches and velocities into MIDI note events, as illustrated in the following patch.

The Pipe transform delays the creation of note-off until a suitable duration after the note-on message.

Similar transforms exist for other MIDI messages. Refer to Control, ProgChange, PitchBend, Touch and PolyTouch for more information.

4.2.2. MIDI Sequencing

OSW includes a MIDI sequencer called (surprisingly enough) MidiSequencer. The MidiSequencer transform reads Standard MIDI Files, and outputs MIDI events in a timely fashion:

MidiSequencer also includes parameters for changing the tempo and explicit time control.

4.2.3. Polyphony

Use the PolyManager transform to manage voices in polyphonic MIDI patches.

4.2.4. Converting Between MIDI notes and frequencies

OSW includes two utility transforms Freq2Midi and Midi2Freq that convert between MIDI note numbers and frequencies. These are useful when playing MIDI files or OSW scores.


© 2000-2003 Amar Chaudhary. All rights reserved.