midi-combine-bytes Combine two eight bit bytes (seven bit unsigned integers) into an unsigned integer of at most fourteen bits of precision, ie. in the range 0 to 16384. Some controller data is encoded in this manner. midi-uncombine-value Uncombine the integer `z' (a fourteen bit unsigned integer) into two eight bit bytes (seven bit unsigned integers). This is the inverse of the 'midi-combine-bytes' operation. midi-status-byte-construct Combine the major and minor parts of a status byte. Typically the major is the message type, the minor the channel number. This is simply a bitwise exclusive-or operation. midi-integer-to-byte-list Evaluates to the list of the `n' bytes encoding the integer `z'. Midi sends and store the most significant byte first. Legal values for `n' are one, two, three and four. This procedure raises an error if it is not possible to encode `z' in `n' bytes. midi-status-check Evalutes to '#t' iff `data' is a status byte of `type'. A midi event is of the form (STATUS-BYTE [DATA-BYTES...]). Type predicates for the four basic midi event types. CHANNEL, SYSEX and ARBITRARY events are transmissable and storable, META events are defined for storage in midi files. Generic predicate for META events. The `event-type' is an eight-bit integer. It is important to note that the event length is not explicitly stated in the lisp form. This is permissable since the lisp form allows the length to be determined easily. It is useful since the length value is stored as a variable length integer, and as such is error prone to handle where not required. Predicates for common META events. The names are those given in the published specification. encode-midi-meta-event-time-signature A constructor for time signature META events. The input `numerator' and `denominator' are written as in a score, ie. 4/4 or 6/8. The `pulse-at' input indicates the relation of the pulse and is written as 1/4 for quarter-note (ie. crotchet) and so forth. Time signatures are encoded in four bytes: nn dd cc bb. The denominator, 'dd', is encoded as an exponent of a base two integer. The value 'cc' expresses the number of MIDI CLOCKS in a metronome click. There are in all cases twenty-four MIDI CLOCKS per quarter note. Therefore, to set the metronome to tick every eighth note this value would be sixteen, to tick every dotted quarter note thirty-two, and so forth. The value 'bb' expresses the number of notated thirty-second notes in a MIDI quarter note. In all ordinary cases this value is eight. Returns the integer value of the Set Tempo event. The tempo is stored in usecs per quarter note (upq). The standard user level notation is in quarter notes per minute (qpm). Return the midi META event to set the tempo to `qpm', quarter-notes per minute. MIDI has a complicated notion of time. A midi file defines a DIVISION value that determines either: 1. the number of MIDI DELTA TICKS in a quarter note or 2. the number of MIDI DELTA TICKS per SMPTE frame, and the SMPTE format. A TEMPO META-EVENT sets the number of microseconds (usecs) per MIDI quarter note. Some devices send a MIDI CLOCK event (status #xF8) at regular intervals to set a tempo. There are in all cases twenty-four MIDI CLOCKS per quarter note. Some devices send a MIDI TICK event (status #xF9) at regular intervals of ten milliseconds. There are therefore one hundred MIDI TICKS arriving per second. The SONG POSITION POINTER event sets the location in MIDI BEATS. There are six MIDI CLOCKS per MIDI BEAT. Thus a MIDI BEAT represents a sixteenth note. Predicates to determine the class of `division'. This value is stored at the start of a midi file. midi-division-time-code-format Iff `division' is SMPTE based return the format code, which should be 24, 25, 29 or 30 (29 corresponds to 30 drop frame rate). Iff `division' is SMPTE based return the number of ticks per frame. midi-delta-ticks-to-seconds Convert the delta time `ticks' into seconds in relation to `division' and 'tempo'. The `tempo' is given in quarter notes per minute. The if statement is needed because the formula is different for tracks based on metrical time and tracks based on SMPTE time. The inverse operation of 'midi-delta-ticks-to-seconds'. The result is rounded to the nearest exact integer. This is trivial multiplication, and not valid for no-metrical divisions. Convert the quarter notes per minute tempo `qpm' to the value required by a TEMPO META EVENT. This value is the number of microseconds per MIDI quarter note. The tempo value is sent/stored as a twenty four bit value, ie as a sequence of three bytes. The inverse of 'midi-qpm-to-upq'. This is in fact the same operation, ie. the operation is symetric. NOTE: This implementation rounds to the nearest exact integer. This is not correct if the encoded tempo was not an integer, a rare but important case. Without the rounding however the encoding of the 90 will be read as 89.999955. Midifiles consist of a HEADER followed by an arbitrary number of TRACKS. This parser transforms the entire midi file into a . The first element is the header, which is a of three s: the FILE-FORMAT-TYPE, the NUMBER-OF-TRACKS, and the DIVISION. This last specifies the meaning of DELTA times within the file and specifies the resolution of the timing information. It is either the number of ticks per quarter-note, or a subdivision of a SMPTE frame. Each subsequent element is a track, which is a of track events. Each track event is a of the form (DELTA-TIME MIDI-EVENT). A midi event is a of the form (STATUS-BYTE [DATA-BYTE ...]). NOTE: Importantly the length value of META EVENTS is not explicitly stated in the lisp form of the event. NOTE: The midifile spec allows other types of chunks to be encoded in the file, and that parsers should ignore unknown chunks. This implementation does not do that at present. Each midifile chunk starts with a four byte 'magic' string. Midifiles encode some values as variable length integers. Only seven bits of each byte are significant, the eighth bit is set to indicate the end of the integer. I believe that the integer will have at most twenty-eight bits of precision, that is will be encoded in at most four bytes. This procedure returns the encoded number, the approach taken by this parser does not require knowing the number of bytes used to encode the number. Read a midifile header chunk. The result is a list of integers: format, number of tracks, and division. The header should consist of six bytes, any further bytes are discarded. Returns '#f' iff `status-byte' does not indicate a channel message, otherwise returns the number of data bytes associated with the message. The return value is always either '#f', one, or two. Evaluates to the unsigned integer value represented by the next `n' bytes in network order. Midifiles encode some values as two byte and some as four byte integers. Returns the next status byte. Because of running status this may or may not actually read a byte, it always needs to peek a byte. Raise an error if the next byte indicates that running status is active, but the `last-status' value is zero. Otherwise return the status byte, either by actually reading the next byte, or by returning the `last-status'. Because the size of sysex messages is encoded in at most a 28bit integer, large messages are broken into segments. This procedure glues such events together into a single event. This is called immediately after a sysex status byte has been read. Write the unsigned integer value `z' in encoded in `n' bytes in network order. Midifiles encode some values as two byte and some as four byte integers. Write the variable length encoding of `z'. See the documentation of 'read-variable-length-integer' above for details. Write the `header-data' preceded by the appropriate magic. Write the track described by `event-list' to. This writes the magic, collects the u8l for the track data so that its length can be dicovered, writes that length and then the byte string. Write the midi file represenation of `lisp-data'. The lisp data is in the exact format produced by 'midi-file-read'. Write the MIDI file at `lisp-data' to `file-name'. Basic constants and some comments on MMC. Basic MMC support is not difficult to provide using the standard receiver mechanism. The set of MMC commands. The mmc-shuttle command provides two values: the shuttle speed, forwards #t or reverse #f. The mmc-masked-write has the message length in the first byte and the message type in the second byte. A masked write of type #x4f is a 'Track Record Ready Status' message and provides REC-ENABLE status for a set of tracks in the form: track number, record status. The mmc-locate command provides one value: a byte array containing the locate target value in MMC Standard Time Code format (5 bytes, roughly: hrs/mins/secs/frames/subframes). Return the list: (DELTA-TIME (STATUS-BYTE [DATA-BYTES...])). `last-status' is used when the next event is in running status, the event returned by this procedure always includes the status byte at 'caadr'. This procedure always merges sysex messages. Read a midifile track chunk. The is known to have exactly the number of bytes of the track, so a peek operation can determine if we are at the end of a track. The result is a list of events. Events are of three basic types, channel events, meta events and system exclusive messages. Read the header, construct the track s, open each string as a, parse the string, and construct the result. #xf7: Arbitrary data event. This is also the byte associated with continued sysex messages, but these are merged above, so this is an 'arbitrary' event. There are three message types: 1. META-EVENTS write the status byte, the event type, the number of data bytes, then the data bytes; 2. SYS-EX and ARBITRARY events write the status byte, the number of data bytes, and the data bytes; 3. CHANNEL events write the status byte and any data bytes.