From c01dfba093f0a2506c912f644dbb44df7b877d92 Mon Sep 17 00:00:00 2001 From: Matthew Hoops Date: Fri, 7 Sep 2012 11:45:28 -0400 Subject: [PATCH] AUDIO: Begin basic playback of QuickTime MIDI files Sounds almost correct, but too fast --- audio/midiparser_qt.cpp | 109 +++++++++++++++++++++++++++++++++++++++- audio/midiparser_qt.h | 5 ++ 2 files changed, 113 insertions(+), 1 deletion(-) diff --git a/audio/midiparser_qt.cpp b/audio/midiparser_qt.cpp index 7b20f62cb7b..b7a201d801c 100644 --- a/audio/midiparser_qt.cpp +++ b/audio/midiparser_qt.cpp @@ -96,8 +96,103 @@ bool MidiParser_QT::loadFromContainerFile(const Common::String &fileName) { return true; } +void MidiParser_QT::resetTracking() { + _loadedInstruments = 0; +} + void MidiParser_QT::parseNextEvent(EventInfo &info) { - // TODO + if (_loadedInstruments < _trackInfo[_active_track].noteRequests.size()) { + // Load instruments first + info.event = 0xC0 | _loadedInstruments; + info.basic.param1 = _trackInfo[_active_track].noteRequests[_loadedInstruments].tone.gmNumber; + _loadedInstruments++; + return; + } + + info.delta = readNextEvent(info); +} + +uint32 MidiParser_QT::readNextEvent(EventInfo &info) { + uint32 control = readUint32(); + + switch (control >> 28) { + case 0x0: + case 0x1: + // Rest + // We handle this by recursively adding up all the rests into the + // next event's delta + return readNextEvent(info) + (control & 0xFFFFFF); + case 0x2: + case 0x3: + // Note event + info.event = 0x90 | ((control >> 24) & 0x1F); + info.basic.param1 = ((control >> 18) & 0x3F) + 32; + info.basic.param2 = (control >> 11) & 0x7F; + info.length = (info.basic.param2 == 0) ? 0 : (control & 0x7FF); + break; + case 0x4: + case 0x5: + // Controller + info.event = 0xB0 | ((control >> 24) & 0x1F); + info.basic.param1 = (control >> 16) & 0xFF; + info.basic.param2 = (control >> 8) & 0xFF; + break; + case 0x6: + case 0x7: + // Marker + switch ((control >> 16) & 0xFF) { + case 0: + // End + info.event = 0xFF; + info.ext.type = 0x2F; + break; + case 1: + // Beat + warning("Encountered beat marker"); + break; + case 2: + // Tempo + warning("Encountered tempo marker"); + break; + default: + warning("Unknown marker"); + } + break; + case 0x9: { + // Extended note event + uint32 extra = readUint32(); + info.event = 0x90 | ((control >> 16) & 0xFFF); + info.basic.param1 = (control >> 8) & 0xFF; + info.basic.param2 = (extra >> 22) & 0x7F; + info.length = (info.basic.param2 == 0) ? 0 : (extra & 0x3FFFFF); + break; + } + case 0xA: { + // Extended controller + uint32 extra = readUint32(); + info.event = 0xB0 | ((control >> 16) & 0xFFF); + info.basic.param1 = (extra >> 16) & 0x3FFF; + info.basic.param2 = (extra >> 8) & 0xFF; // ??? + break; + } + case 0xB: + // Knob + error("Encountered knob event in QuickTime MIDI"); + break; + case 0x8: + case 0xC: + case 0xD: + case 0xE: + // Reserved + readUint32(); + break; + case 0xF: + // General + error("Encountered general event in QuickTime MIDI"); + break; + } + + return 0; } Common::QuickTimeParser::SampleDesc *MidiParser_QT::readSampleDesc(Track *track, uint32 format) { @@ -196,9 +291,15 @@ void MidiParser_QT::initCommon() { // form, we can fill in the MidiParser tracks. _num_tracks = _trackInfo.size(); + assert(_num_tracks > 0); for (uint32 i = 0; i < _trackInfo.size(); i++) MidiParser::_tracks[i] = _trackInfo[i].data; + + _ppqn = _trackInfo[0].timeScale; + resetTracking(); + setTempo(500000); + setTrack(0); } byte *MidiParser_QT::readWholeTrack(Common::QuickTimeParser::Track *track) { @@ -229,6 +330,12 @@ byte *MidiParser_QT::readWholeTrack(Common::QuickTimeParser::Track *track) { return output.getData(); } +uint32 MidiParser_QT::readUint32() { + uint32 value = READ_BE_UINT32(_position._play_pos); + _position._play_pos += 4; + return value; +} + MidiParser *MidiParser::createParser_QT() { return new MidiParser_QT(); } diff --git a/audio/midiparser_qt.h b/audio/midiparser_qt.h index 6e4ded8e743..2dcd61b9f9c 100644 --- a/audio/midiparser_qt.h +++ b/audio/midiparser_qt.h @@ -43,6 +43,7 @@ public: protected: // MidiParser + void resetTracking(); void parseNextEvent(EventInfo &info); // QuickTimeParser @@ -86,6 +87,8 @@ private: NoteRequestList _noteRequests; }; + uint32 readNextEvent(EventInfo &info); + Common::String readString31(Common::SeekableReadStream *stream); Common::Rational readFixed(Common::SeekableReadStream *stream); NoteRequestList readNoteRequestList(Common::SeekableReadStream *stream); @@ -93,9 +96,11 @@ private: byte *readWholeTrack(Common::QuickTimeParser::Track *track); Common::Array _trackInfo; + uint32 _loadedInstruments; void initFromContainerTracks(); void initCommon(); + uint32 readUint32(); }; #endif