MidiGenerator

The MidiGenerator emits explicitly specified Midi messages.

To use the MidiGenerator implementation, load midi.so and create an actor of type MidiGenerator.

MidiGenerator

In addition to the messages understood by all actors, the MidiGenerator understands the following messages:
SetPitch hActor pitch
Set default pitch. The argument pitch has a range of [0, 127] and defaults to 60.
SetAmp hActor amplitude
Set default amplitude. The argument amplitude has a range of [0, 127] and defaults to 80.
SetChannel hActor chan
Set default channel. The argument chan has a range of [1, 16] and defaults to 1.
SetDuration hActor dur
Set default duration (in seconds). The argument dur has a range of [.00001, 3600] and defaults to 1.
SetCtrlNum hActor ctrl
Set default control number. The argument ctrl has a range of [0, 15] and defaults to 0.
SetCtrlVal hActor ctrlval
Set default controller value. The argument ctrlval has a range of [0, 127] and defaults to 0.
SetPatchNum hActor patchnum
Set default patch number. The argument patchnum has a range of [0, 127] and defaults to 0.

MidiGenerator handler messages

In addition to the messages understood by all handlers, the handler for the MidiGenerator understands the following messages. Defaults start off with the values specified below, but are in fact whatever the handler's actor's defaults are (possibly changed by sending one of the messages listed above).

In the list below, arguments in square brackets are optional. (For example, the possible argument strings to MidiNoteOn are: hSound; hSound pitch; hSound pitch ampl; hSound pitch ampl chan.) If an argument is omitted, the MidiGenerator handler takes the default value of that argument provided by the MidiGenerator actor.

MidiNoteOn hSound [ pitch [ ampl [ chan ]]]
Send a note-on message.
The argument pitch has a range of [0, 127] and defaults to 60.
The argument ampl has a range of [0, 127] and defaults to 80.
The argument chan has a range of [1, 16] and defaults to 1.
MidiNoteOff hSound [ pitch [ chan ]]
Send a note-off message.
The argument pitch has a range of [0, 127] and defaults to 60.
The argument chan has a range of [1, 16] and defaults to 1.
MidiPlayNote hSound [ pitch [ ampl [ chan [ dur ]]]]
Send note-on, then note-off message. (Currently under construction)
The argument pitch has a range of [0, 127] and defaults to 60.
The argument ampl has a range of [0, 127] and defaults to 80.
The argument chan has a range of [1, 16] and defaults to 1.
The argument dur has a range of [.00001, 3600] and defaults to 1.
MidiPitchBend hSound [ pitchbend [ chan ]]
Send pitch-bend message.
The argument pitchbend has a range of [-8192, 8192] and defaults to 0.
The argument chan has a range of [1, 16] and defaults to 1.
MidiAllNotesOff hSound
Send note-off message to all pitches and channels. (Currently under construction)
MidiCtrlChange hSound [ ctrlval [ ctrl [ chan ]]]
Send control-change message ( MidiCtrlChange(ctrlval, ctrl, chan) ).
The argument ctrlval has a range of [0, 127] and defaults to 0.
The argument ctrl has a range of [0, 15] and defaults to 0.
The argument chan has a range of [1, 16] and defaults to 1.
MidiPatchChange hSound [ patchnum [ chan ]]
Send patch-change message.
The argument patchnum has a range of [0, 127] and defaults to 0.
The argument chan has a range of [1, 16] and defaults to 1.
MidiGeneric hSound [ x1, x2, x3... ]
Send an arbitrary array of integers [ x1, x2, x3... ] as a Midi message.

Examples

LoadDSO midi.so;
aGen = Create MidiGenerator;
sGen = BeginSound MidiGenerator;
aOut = Create MidiOutputActor;
sOut = BeginSound aOut SetInput sGen;
LoadDSO msgGroup.so;
Play individual notes from a message group:
the arguments of message group Beep represent pitch, amplitude, and channel number.

Beep = Create MessageGroup;
AddMessage Beep MidiNoteOn sGen *0 *1 *2;

Play individual short notes from a message group:
as above, but stop the note after half a second.

LoadDSO later.so;
later = Create LaterActor;
Beep = Create MessageGroup;
AddMessage Beep MidiNoteOn sGen *0 *1 *2;
AddMessage Beep AddMessage later 0.5 MidiNoteOff sGen *0 *2;

Or, more concisely:

Beep = Create MessageGroup;
AddMessage Beep MidiPlayNote sGen *0 *1 *2 0.5;

Adjust the pitch of a single instrument from a message group:
play a long note with loudness 80 (from 0 to 127) on channel 3, and change its pitch with the first argument to message group ChangePitch.

MidiNoteOn sGen 60 80 3;

ChangePitch = Create MessageGroup;
AddMessage ChangePitch MidiPitchBend sGen *0 3;

Adjust several continuous controllers:
play a long note, and change 3 of its parameters, controllers number 13, 14, and 15, with the arguments to message group MorphSound.

MidiNoteOn sGen 60 80 3;
MorphSound = Create MessageGroup;
AddMessage MorphSound MidiCtrlChange sGen *0 13 3;
AddMessage MorphSound MidiCtrlChange sGen *1 14 3;
AddMessage MorphSound MidiCtrlChange sGen *2 15 3;

Adjust continuous controllers of several notes:
play a C major chord with notes on channels 1,2,3; change controller number 7 of each one, with the arguments to message group MorphSound.

MidiNoteOn sGen 60 80 1; // C
MidiNoteOn sGen 64 80 2; // E
MidiNoteOn sGen 67 80 3; // G
MorphSound = Create MessageGroup;
AddMessage MorphSound MidiCtrlChange sGen *0 7 1;
AddMessage MorphSound MidiCtrlChange sGen *1 7 2;
AddMessage MorphSound MidiCtrlChange sGen *2 7 3;

Note to Developers

The analogy between sample-based audio and midi in VSS.

An output buffer contains 128 consecutive (8-channel) 32-bit float samples. Every actor which produces audio output sends audio to its output buffer and to VSS's main bus. (The latter can be muted with SetMute.) Output buffers can be used as sources for processor actors. The InputActor echoes the hardware input to its output buffer (and the main bus).

A midi output buffer is a list of midi messages, to be executed ASAP and in order, in parallel with audio output. It is implemented as an array of messages. A message is a 4-byte string. We allow at least 1000 messages per second. At the lowest sampling rate of 8 kHz, a 128-sample output buffer lasts .016 seconds, so the array need be no more than 16 messages long. We choose 20. Latency at 44 KHz is 2.9 msec; at 8 kHz, 16 msec; at 16 kHz, 8 msec. We recommend running VSS with a sampling rate of at least 16 kHz for best midi throughput.

Every actor which produces midi output sends midi to its output buffer, but not by default to the hardware midi output. Midi output buffers can be used as midi inputs for midi processors.

The MidiInputActor echoes the hardware midi input to its midi output buffer. The MidiOutputActor echoes its midi input to the hardware midi output.

"The" hardware midi input and output mean that VSS opens a single port (each) for midi input and output. This can be elaborated to multiple ports, later on. Midi I/O is normally done from the server, not from the client, again by analogy with regular audio. But if you want to do midi I/O on the client machine, have the client use the SGI midi libraries directly, and send messages to a MidiGenerator (and MidiClientActor, eventually).

A MidiClientActor would allow a VSS client to explicitly retrieve midi messages. Its internal midi buffer should be quite large, as it may accumulate a pile of messages before the client polls to retrieve them. Its handler understands the command "MidiReceive hSound;", which sends the midi events accumulated since the last MidiReceive back to the client in some format.