aboutsummaryrefslogtreecommitdiff
path: root/audio
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
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')
-rw-r--r--audio/midiparser_qt.cpp126
-rw-r--r--audio/midiparser_qt.h34
2 files changed, 52 insertions, 108 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]);
diff --git a/audio/midiparser_qt.h b/audio/midiparser_qt.h
index f9378f9c3d..5ab89bd4e7 100644
--- a/audio/midiparser_qt.h
+++ b/audio/midiparser_qt.h
@@ -56,38 +56,13 @@ public:
protected:
// MidiParser
- void resetTracking();
void parseNextEvent(EventInfo &info);
// QuickTimeParser
SampleDesc *readSampleDesc(Track *track, uint32 format, uint32 descSize);
private:
- struct NoteRequestInfo {
- byte flags;
- byte reserved;
- uint16 polyphony;
- Common::Rational typicalPolyphony;
- };
-
- struct ToneDescription {
- uint32 synthesizerType;
- Common::String synthesizerName;
- Common::String instrumentName;
- uint32 instrumentNumber;
- uint32 gmNumber;
- };
-
- struct NoteRequest {
- uint16 part;
- NoteRequestInfo info;
- ToneDescription tone;
- };
-
- typedef Common::Array<NoteRequest> NoteRequestList;
-
struct MIDITrackInfo {
- NoteRequestList noteRequests;
byte *data;
uint32 size;
uint32 timeScale;
@@ -98,19 +73,16 @@ private:
MIDISampleDesc(Common::QuickTimeParser::Track *parentTrack, uint32 codecTag);
~MIDISampleDesc() {}
- NoteRequestList _noteRequests;
+ byte *_requestData;
+ uint32 _requestSize;
};
uint32 readNextEvent(EventInfo &info);
-
- Common::String readString31(Common::SeekableReadStream *stream);
- Common::Rational readFixed(Common::SeekableReadStream *stream);
- NoteRequestList readNoteRequestList(Common::SeekableReadStream *stream);
+ void handleGeneralEvent(EventInfo &info, uint32 control);
byte *readWholeTrack(Common::QuickTimeParser::Track *track, uint32 &trackSize);
Common::Array<MIDITrackInfo> _trackInfo;
- uint32 _loadedInstruments;
void initFromContainerTracks();
void initCommon();