/* General-MIDI Parser * By Jack Andersen */ BigEndian(); struct MidiHeader { char m_magic[4] ; uint m_seclen; enum { MIDI_SINGLE = 0, MIDI_MULTIPLE = 1, MIDI_PATTERN = 2 } m_format; short m_ntracks; short m_tickdiv; }; struct DeltaTime { local uint total = 0; char t0; total += t0 & 0x7f; if (!(t0 & 0x80)) break; total <<= 7; char t1; total += t1 & 0x7f; if (!(t1 & 0x80)) break; total <<= 7; char t2; total += t2 & 0x7f; if (!(t2 & 0x80)) break; total <<= 7; char t3; total += t3 & 0x7f; if (!(t3 & 0x80)) break; }; struct MidiMessage { DeltaTime m_dtime; char m_status; local char m_channel = m_status & 0xf; if ((m_status & 0xf0) == 0x80) { struct { char m_note; char m_velocity; } note_off_event; } else if ((m_status & 0xf0) == 0x90) { struct { char m_note; char m_velocity; } note_on_event; } else if ((m_status & 0xf0) == 0xA0) { struct { char m_note; char m_pressure; } note_pressure_event; } else if ((m_status & 0xf0) == 0xB0) { struct { char m_controller; char m_value; } controller_event; } else if ((m_status & 0xf0) == 0xC0) { struct { char m_program; } program_event; } else if ((m_status & 0xf0) == 0xD0) { struct { char m_pressure; } channel_pressure_event; } else if ((m_status & 0xf0) == 0xE0) { struct { char m_lsb; char m_msb; } pitch_bend_event; } else if (m_status == -1) { struct { enum { META_SEQUENCE_NUM = 0, META_TEXT = 1, META_COPYRIGHT = 2, META_SEQUENCE_NAME = 3, META_INSTRUMENT_NAME = 4, META_LYRIC = 5, META_MARKER = 6, META_CUE_POINT = 7, META_PROGRAM_NAME = 8, META_DEVICE_NAME = 9, META_MIDI_CHANNEL_PREFIX = 0x20, META_MIDI_PORT = 0x21, META_END_OF_TRACK = 0x2f, META_TEMPO = 0x51, META_SMPTE_OFFSET = 0x54, META_TIME_SIGNATURE = 0x58, META_KEY_SIGNATURE = 0x59, META_SEQUENCER_EVENT = 0x7f } m_type; DeltaTime m_length; if (m_type == META_SEQUENCE_NUM) { short m_seqNum; } else if (m_type == META_TEXT) { char m_text[m_length.total]; } else if (m_type == META_COPYRIGHT) { char m_copyright[m_length.total]; } else if (m_type == META_SEQUENCE_NAME) { char m_name[m_length.total]; } else if (m_type == META_INSTRUMENT_NAME) { char m_name[m_length.total]; } else if (m_type == META_LYRIC) { char m_lyric[m_length.total]; } else if (m_type == META_MARKER) { char m_marker[m_length.total]; } else if (m_type == META_CUE_POINT) { char m_cuePoint[m_length.total]; } else if (m_type == META_PROGRAM_NAME) { char m_programName[m_length.total]; } else if (m_type == META_DEVICE_NAME) { char m_deviceName[m_length.total]; } else if (m_type == META_MIDI_CHANNEL_PREFIX) { char m_channelPrefix; } else if (m_type == META_MIDI_PORT) { char m_port; } else if (m_type == META_END_OF_TRACK) { } else if (m_type == META_TEMPO) { uint m_usecPerQuarterNote : 24; local uint m_bpm = 60000000 / m_usecPerQuarterNote; FSeek(FTell() - 1); } else if (m_type == META_SMPTE_OFFSET) { char m_hours; char m_mins; char m_secs; char m_fps; char m_fracFrames; } else if (m_type == META_TIME_SIGNATURE) { char m_numerator; char m_denominator; char m_clocksPerClick; char m_32ndPer4th; } else if (m_type == META_KEY_SIGNATURE) { char m_flatsSharps; char m_majorMinor; } else { char m_data[m_length.total]; } } meta_event; } else if ((m_status & 0xf0) == 0xF0) { struct { DeltaTime m_length; char m_message[m_length.total]; } sysex_event; } }; struct MidiTrack { char m_magic[4] ; uint m_seclen; local uint remaining = m_seclen; while (remaining) { MidiMessage message; remaining -= sizeof(message); } }; struct { MidiHeader header; MidiTrack tracks[header.m_ntracks] ; } file;