aboutsummaryrefslogtreecommitdiff
path: root/audio/midiparser_qt.cpp
diff options
context:
space:
mode:
authorMatthew Hoops2012-09-09 14:59:05 -0400
committerMatthew Hoops2012-09-09 14:59:05 -0400
commitcfe6a2b640e91cf11a32017e79966121bf357cc7 (patch)
treee3f26d24b3168393d61cff589dae6ae250bd62b5 /audio/midiparser_qt.cpp
parent4a458236f625d28706cfe4560690770a395ee6e3 (diff)
downloadscummvm-rg350-cfe6a2b640e91cf11a32017e79966121bf357cc7.tar.gz
scummvm-rg350-cfe6a2b640e91cf11a32017e79966121bf357cc7.tar.bz2
scummvm-rg350-cfe6a2b640e91cf11a32017e79966121bf357cc7.zip
AUDIO: Fix QuickTime MIDI with extra info in the header
The 11th Hour Mac MIDI's now play
Diffstat (limited to 'audio/midiparser_qt.cpp')
-rw-r--r--audio/midiparser_qt.cpp126
1 files changed, 49 insertions, 77 deletions
diff --git a/audio/midiparser_qt.cpp b/audio/midiparser_qt.cpp
index 65ca64a7f4..5148ed74b1 100644
--- a/audio/midiparser_qt.cpp
+++ b/audio/midiparser_qt.cpp
@@ -69,9 +69,9 @@ bool MidiParser_QT::loadFromTune(Common::SeekableReadStream *stream, DisposeAfte
stream->readUint16BE(); // reserved
stream->readUint16BE(); // index
- MIDITrackInfo trackInfo;
- trackInfo.noteRequests = readNoteRequestList(stream);
+ stream->readUint32BE(); // flags, ignore
+ MIDITrackInfo trackInfo;
trackInfo.size = stream->size() - stream->pos();
assert(trackInfo.size > 0);
@@ -105,27 +105,19 @@ bool MidiParser_QT::loadFromContainerFile(const Common::String &fileName) {
return true;
}
-void MidiParser_QT::resetTracking() {
- _loadedInstruments = 0;
-}
-
void MidiParser_QT::parseNextEvent(EventInfo &info) {
- if (_position._playPos >= _trackInfo[_activeTrack].data + _trackInfo[_activeTrack].size) {
- // Manually insert end of track when we reach the end
- info.event = 0xFF;
- info.ext.type = 0x2F;
- return;
- }
+ info.event = 0;
+
+ while (info.event == 0) {
+ if (_position._playPos >= _trackInfo[_activeTrack].data + _trackInfo[_activeTrack].size) {
+ // Manually insert end of track when we reach the end
+ info.event = 0xFF;
+ info.ext.type = 0x2F;
+ return;
+ }
- if (_loadedInstruments < _trackInfo[_activeTrack].noteRequests.size()) {
- // Load instruments first
- info.event = 0xC0 | _loadedInstruments;
- info.basic.param1 = _trackInfo[_activeTrack].noteRequests[_loadedInstruments].tone.gmNumber;
- _loadedInstruments++;
- return;
+ info.delta = readNextEvent(info);
}
-
- info.delta = readNextEvent(info);
}
uint32 MidiParser_QT::readNextEvent(EventInfo &info) {
@@ -210,19 +202,50 @@ uint32 MidiParser_QT::readNextEvent(EventInfo &info) {
break;
case 0xF:
// General
- error("Encountered general event in QuickTime MIDI");
+ handleGeneralEvent(info, control);
break;
}
return 0;
}
+void MidiParser_QT::handleGeneralEvent(EventInfo &info, uint32 control) {
+ uint32 part = (control >> 16) & 0xFFF;
+ uint32 dataSize = ((control & 0xFFFF) - 2) * 4;
+ byte subType = READ_BE_UINT16(_position._playPos + dataSize) & 0x3FFF;
+
+ switch (subType) {
+ case 1:
+ // Note Request
+ // Currently we're only using the GM number from the request
+ assert(dataSize == 84);
+ info.event = 0xC0 | part;
+ info.basic.param1 = READ_BE_UINT32(_position._playPos + 80);
+ break;
+ case 5: // Tune Difference
+ case 8: // MIDI Channel
+ case 10: // No-op
+ case 11: // Used Notes
+ // Should be safe to skip these
+ break;
+ default:
+ warning("Unhandled general event %d", subType);
+ }
+
+ _position._playPos += dataSize + 4;
+}
+
Common::QuickTimeParser::SampleDesc *MidiParser_QT::readSampleDesc(Track *track, uint32 format, uint32 descSize) {
if (track->codecType == CODEC_TYPE_MIDI) {
debug(0, "MIDI Codec FourCC '%s'", tag2str(format));
+ _fd->readUint32BE(); // flags, ignore
+ descSize -= 4;
+
MIDISampleDesc *entry = new MIDISampleDesc(track, format);
- entry->_noteRequests = readNoteRequestList(_fd);
+ entry->_requestSize = descSize;
+ entry->_requestData = (byte *)malloc(descSize);
+ _fd->read(entry->_requestData, descSize);
return entry;
}
@@ -233,58 +256,6 @@ MidiParser_QT::MIDISampleDesc::MIDISampleDesc(Common::QuickTimeParser::Track *pa
Common::QuickTimeParser::SampleDesc(parentTrack, codecTag) {
}
-Common::String MidiParser_QT::readString31(Common::SeekableReadStream *stream) {
- byte size = stream->readByte();
- assert(size < 32);
-
- Common::String string;
- for (byte i = 0; i < size; i++)
- string += (char)stream->readByte();
-
- stream->skip(31 - size);
- return string;
-}
-
-Common::Rational MidiParser_QT::readFixed(Common::SeekableReadStream *stream) {
- int16 integerPart = stream->readSint16BE();
- uint16 fractionalPart = stream->readUint16BE();
- return integerPart + Common::Rational(fractionalPart, 0x10000);
-}
-
-MidiParser_QT::NoteRequestList MidiParser_QT::readNoteRequestList(Common::SeekableReadStream *stream) {
- NoteRequestList requests;
-
- /* uint32 flags = */ stream->readUint32BE(); // always 0
-
- for (;;) {
- uint32 event = stream->readUint32BE();
-
- if (event == 0x60000000) // marker event
- break;
- else if ((event & 0xF000FFFF) != 0xF0000017) // note request event
- error("Invalid note request event");
-
- NoteRequest request;
- request.part = (event >> 16) & 0xFFF;
- request.info.flags = stream->readByte();
- request.info.reserved = stream->readByte();
- request.info.polyphony = stream->readUint16BE();
- request.info.typicalPolyphony = readFixed(stream);
- request.tone.synthesizerType = stream->readUint32BE();
- request.tone.synthesizerName = readString31(stream);
- request.tone.instrumentName = readString31(stream);
- request.tone.instrumentNumber = stream->readUint32BE();
- request.tone.gmNumber = stream->readUint32BE();
-
- if (stream->readUint32BE() != 0xC0010017) // general event note request
- error("Invalid instrument end event");
-
- requests.push_back(request);
- }
-
- return requests;
-}
-
void MidiParser_QT::initFromContainerTracks() {
const Common::Array<Common::QuickTimeParser::Track *> &tracks = Common::QuickTimeParser::_tracks;
@@ -295,10 +266,7 @@ void MidiParser_QT::initFromContainerTracks() {
if (tracks[i]->editCount != 1)
warning("Unhandled QuickTime MIDI edit lists, things may go awry");
- MIDISampleDesc *entry = (MIDISampleDesc *)tracks[i]->sampleDescs[0];
-
MIDITrackInfo trackInfo;
- trackInfo.noteRequests = entry->_noteRequests;
trackInfo.data = readWholeTrack(tracks[i], trackInfo.size);
trackInfo.timeScale = tracks[i]->timeScale;
_trackInfo.push_back(trackInfo);
@@ -330,6 +298,10 @@ byte *MidiParser_QT::readWholeTrack(Common::QuickTimeParser::Track *track, uint3
Common::MemoryWriteStreamDynamic output;
uint32 curSample = 0;
+ // Read in the note request data first
+ MIDISampleDesc *entry = (MIDISampleDesc *)track->sampleDescs[0];
+ output.write(entry->_requestData, entry->_requestSize);
+
for (uint i = 0; i < track->chunkCount; i++) {
_fd->seek(track->chunkOffsets[i]);