TSE3 documentation Version 0.3.0 Index API  Version  Structure 

MIDI data and the Playable interface

MIDI data handling in TSE3

The TSE3 library has a single header file providing definitions for the elements of the standard MIDI specification. This is the file Midi.h (see the reference at the bottom of this page).

It defines the following elements:

The Clock data value type.
Describes a time value in a song, as a number of ticks. These ticks are in units of a pulse. There is a fixed number of pulses per quarter note (PPQN) defined in Clock::PPQN. (A quarter note is another name for a crotchet.)
The Event template data value type.
Provides a standard way to generate object which associate a data value (for example, a tempo change) with a time in Clocks.
The MidiCommands and other similar definitions.
Definitions of all the MIDI status bytes (e.g. MidiCommand_NoteOn, system commands, controller values etc. These are: MidiCommands, MidiSystemCommands, and MidiControlChanges.
The MidiCommand data value class.
This is the basic value type used to describe a single MIDI command, including it's statub byte, channel and port pair (which describe where the MIDI command should be sent), and any data bytes.
The MidiEvent data value class.
This is built upon the MidiCommand class, but associates it with an event time in Clocks.
Note that here we do not use the Event template class as a definition. This is because the MidiEvent contains a second MidiCommand, used if the first is a MidiCommand_NoteOn. If so, the second command holds the related MidiCommand_NoteOff event. This can be used by the TSE3 library to ensure that all MIDI note off events are sent for any scheduled note on event.
The TSE3MetaMidiCommand definitions.
These are a number of extension status bytes only understood by the TSE3 library which are used internally.

Used together, these definitions describe standard MIDI data, scheduled to some clock source. The TSE3 song components generate musical data in this format.

The kdoc documentation describes these classes. You can find further information about them there.

The playable interface

Each component that comprises a Song can produce some sort of stream of MIDI data that needs to be scheduled to a timed output. To simplify this process they implement the Playable interface. This makes the Song structure use a form of the composite design pattern (GoF book).

The PlayablePlayableIterator that can iterate over the MIDI data in the output stream. This is a form of the iterator design pattern.

Each different kind of Playable object provides it's own implementation of the PlayableIterator interface that knows how to generate the MIDI events.

The user can ignore the individual song components Playable interface, and meerly use the Song's PlayableIterator that will in turn use the Playable iterators of all sub components to create a MIDI data stream for the whole song.

+------------\     +------------+      creates +--------------------+
| Interface  |_\   |  Playable  |--------------|  PlayableIterator  |
|              |   +------------+              +--------------------+
+------------- +         ^                               ^
                         |                               |
+------------\           |                               |
|   Example  |_\   +------------+              +--------------------+
| Implemenation |  |    Song    |              |    SongIterator    |
+---------------+  +------------+              +--------------------+

The data generated by a PlayableIterator object is in the form described above, as defined by the Midi.h header file.

Streaming system exclusive MIDI data

System exclusive MIDI data is a particular nuisance. All sequencer systems have this problem. If you don't care about, or know about system exclusive MIDI data (or sysex data) then you can skip this section.

Any other form of MIDI data, for example MidiCommand_NoteOn events and the like, can be interspersed in any order. They are sent in whole atomic units (the MidiEvent or MidiCommand classes). They are easy to handle and stream around the system in PlaybaleIterator objects.

However, sysex events break this simple atomic data structure. They can be of arbitrary size, with a single start of sysex system byte at the start, and an end of sysex status byte at the end.

So how do we stream these around using the PlayableIterator class? Carefully, is the answer.

Sysex data has been designed to fit into the Playable architecture rather than be handled as a special case. However, there are certain restrictions involved in their use.

The start of a sysex block is naturally defined by a MidiCommand with MidiComand_System status byte and reason code MidiSystem_SysExStart. The data1 byte contains the first data byte. data2 is not used. If the event is held in a MidiEvent (rather than a single MidiCommand - this will be true if it is streamed from a PlayableIterator) then the second (note off) field is not used to hold extra values.

The next MidiCommand may need to be another sysex data byte. In this case the same status information is put in the MidiComand - although the playing MidiScheduler object knows not to send this again. data1 contains this next data byte. More sysex data bytes may follow.

The stream carries on in this manner until the end of the sysex data block, when a MidiComand containing the MidiSystem_SysExEnd status information is put in the stream.

As stated above, sysex data cannot be rearranged. Nor can other MIDI events occur in the middle of them (you cannot shove a note on in the middle of a block of sysex). For this reason any PlayableIterator must take care to give each sysex MidiCommand exactly the same clock time to ensure no other events can get into the middle of the sysex stream.

The standard TSE3 PlayableIterator objects are designed in such a way that if all events have the same event time, events from other sources will not interrupt the stream.

See also

  • Midi.h for descriptions of the TSE3 representation of MIDI data.
  • Playable.h for the definition of the Playable class.
 © Pete Goodliffe, 2001-2003 Copyright Psalm 150