Class:            MIDIPort

Environment:      Siren
Superclass:         Siren.PortModel
Category:         MusicIO-MIDI
Instance variables:   inputData readProcess
Class variables:      Streams
Imports:            private MIDICommands.* private MIDIioctls.*
               private GeneralMIDIMap.* private GeneralMIDIDrums.*

An instance of a subclass of MIDIPort is used for the interface betweeen Siren and external MIDI drivers and devices. It implements both note-oriented (e.g., play: pitch at: aDelay dur: aDur amp: anAmp voice: voice), and data-oriented (e.g., put: data at: delay length: size) behaviors for MIDI I/O. There is an extensive test suite and demo in the class examples method and in the Siren outline view.

There is typically only one instance of MIDIPort. The messages new, default, and instance all answer the sole instance. MIDIPorts use dependency to signal input data, objects wishing to receive input should register themselves as dependents of a port. In the default Siren implementation, the scheduler is all in Smalltalk, and only the simplest MIDI driver is assumed.

Instance Variables:
   readProcess The loop process to read input data.
   inputData ByteArray)> The available data.
   status #open or #closed
   device my IO device's index

Class Variables:
   Instance The sole instance, or nil.
   Debug Debug mode prints all I/O to the Transcript.
   UseSingleton whether to use a singleton instance (not necessary)
   DefaultInputDevice the index in the driver of the default input device
   DefaultOutputDevice see above

MIDI Commands Supported:
   0x9x pp vv -- note-on (x=channel, pp=pitch, vv=velocity)
   0x8x pp vv -- note-off (x=channel, pp=pitch, vv=velocity)
   0xCx cc -- program-change (x=channel, pp=pitch)
   0xEx ll hh -- program-change (x=channel, ll=low 7 bits, hh=high 7 bits)
   0xBx cc dd -- control change (x=channel, cc=controller, dd=data)

accessing

input
   Answer the receiver's Q of input data.

isActive
   Answer whether the receiver is active.

reader
   Answer the receiver's read process

resetInput
   Reset the receiver's Q of input data.

control commands

allNotesOff
   Turn all MIDI notes off using the channel message 123.

allNotesOffVerbose
   Turn all MIDI notes off (the verbose way).

controlChange: chan controller: controller to: value
   Send out a control-change command now.

pitchBend: chan to: value
   Send out a pitch-bend command at the given time.

programChange: chan to: value
   Send out a program-change command at the given time.

sysex: command
   Send out a MIDI system exclusive data packet at the given time.

open/close

close
   Close MIDI.

open
   Open the MIDI driver -- start the lower-level driver up.

openInput
   Open the MIDI driver -- start the lower-level driver up.

openInput: which
   Open the MIDI driver -- start the lower-level driver up.

openOutput
   Open the MIDI driver -- start the lower-level driver up.

openOutput: which
   Open the MIDI driver -- start the lower-level driver up.

reset
   Reset the port.

ioctl

eventsAvailable
   Answer the number of events in the input Q.

hasBuffer
   Answer whether the MIDI driver has a time-stamped output buffer.

hasClock
   Answer whether the MIDI driver has its own clock.

hasControllerCache
   Answer whether the MIDI driver supports a controller data buffer.

hasDurs
   Answer whether the MIDI driver supports a 1-call note-on/off command.

readLoop
   polling or waiting loop

startControllerCaching
   Start caching MIDI controller in the driver.

startMIDIEcho
   Start echoing MIDI input from the driver.

startMIDIInput
   Start the polling loop (or semaphore waiter) MIDI input.

stopControllerCaching
   Stop caching MIDI controller in the driver.

stopMIDIEcho
   Stop echoing MIDI input from the driver.

stopMIDIInput
   Stop signalling the read semaphore on MIDI input.

initialize release

initialize
   Setup the receiver's instance variables.

release
   Release--break and dependencies on the error value.

read/write

get: packet
   Read the data from the receiver into the argument (a MIDIPacket). Answer the number of data bytes read.

nextEventInto: anEventAssociation
   Record via the receiver into the argument.

nextMessage
   Answer the first (length -> bytes) association from the input data collection.

play: aPitch dur: aDur amp: anAmp voice: aVoice
   Play a note (on/off message pair) with the given parameters on the receiver.

play: streamID pitch: aPitch dur: aDur amp: anAmp voice: aVoice
   Play a note (on/off message pair) with the given parameters on the receiver.

playOff: streamID pitch: aPitch amp: anAmp voice: aVoice
   Play a note-on command with the given parameters on the receiver.

playOn: streamID pitch: aPitch amp: anAmp voice: aVoice
   Play a note-on command with the given parameters on the receiver.

put: data length: size
   Send the argument data to the receiver now.

readController: index
   Read the given controller value.

readControllersFrom: lo to: hi into: array
   Read a range of controllers

MetaClass:         MIDIPort class

message tests

functionExample
   Demonstrate control commands by playing a note and making a crescendo with the volume pedal.

testBend
   Demonstrate pitch-bend by playing two notes and bending them.

testControlContinuous
   Demonstrate control commands by playing a note and making a crescendo with the volume pedal.

testProgramChange
   Demonstrate program change by setting up an organ instrument to play on.

testSysex
   Demonstrate system exclusive commands by loading the Santur scale
   and playing a scale.

driver performance tests

testRandomPlayHighLevel: num dur: dur
   Play 'num' random pitches (molto legato) spaced 'dur' msec apart.

testRandomPlayLowLevel: num dur: dur
   Play 'num' random pitches spaced 'dur' msec apart.

testRollLowLevel: num dur: dur
   Play a roll of 'num' notes spaced 'dur' msec apart.

output tests

testAllNotesOff
   Try to open and close the MIDI port.

testANote
   Open MIDI, play a note.

testARandomNote
   Open MIDI, play a note.

testAScale
   Open MIDI, play a fast scale.

testInspect
   Inspect a MIDI port.

testMouseMIDI
   Open MIDI, play notes based on the mouse position.

testNoteOnOff
   Open MIDI, play a note, and close it.

testOpenClose
   Try to open and close the MIDI port.

testOutput
   Open MIDI, play some random notes, and close it.

input tests

dumpExample
   Set up a MIDI dump object as a dependent of the input port. Dump for 10 seconds,
   then turn off. The default update: method just dumps the MIDI packet into the transcript;
   customize this by writing your own update: method.

testInput
   Open MIDI, try to read something--dump it to the transcript.

testInputStop
   Execute this to end the input test

controller tests

testControllerCaching
   Set up uncached controller reading--make a loop that reads and prints controller 48
      twice a second (until you press the shift button).

testControllerCaching2
   Set up uncached controller reading--read controllers 48-52 as an array and print it; stop on mouse press.

testControllerCachingFrom: lo to: hi
   Set up uncached controller reading--read controllers from lo to hi (inclusive) as an array and print it;
      stop on press.

testControllerRecording
   Set up uncached controller reading--make a loop that reads and prints controller 48
      40 times a second for 5 seconds.

utilities

allNotesOff
   MIDIPort allNotesOff

cleanUp
   Close down and clean up all MIDI, sound IO, event lists, etc.

showInput
   Open MIDI, wait to read something, then dump it to the transcript.

general MIDI patches

setAllInstrumentsTo: iname
   Set instruments 0-15 to the General MIDI name iname

setEnsemble: orch
   Down-load a general MIDI patch for the given ensemble (a collection of
   [chan -> name] associations).

setEnsembleInOrder: orch
   Down-load a general MIDI patch for the given ensemble (a collection of symbolic keys
   into the General MIDI voice map) mapping the first element to MIDI channel 1, etc.

setupDefaultGeneralMIDI
   Down-load a general MIDI patch for a 16-voice percussion ensemble.

setupOrgan
   Down-load a general MIDI patch for a 4-voice organ.

setupTunedPercussion
   Down-load a general MIDI patch for a 16-voice percussion ensemble.

setupWindOrchestra
   Down-load a general MIDI patch for a 16-voice wind ensemble.

examples

examples
   Select and execute the following for usage examples.

scaleFrom: lo to: hi in: dur
   Answer array of (start dur pitch amp)

instance creation

concreteClass
   Answer the class to use for MIDI

class initialization

initializeData
   Set up the dictionaries of commands, ioctl primitive selectors and arguments, and general MIDI maps.

initializeMIDITables
   MIDIPort initializeMIDITables