diff options
Diffstat (limited to 'audio')
-rw-r--r-- | audio/midiparser_qt.cpp | 55 | ||||
-rw-r--r-- | audio/midiparser_qt.h | 9 |
2 files changed, 58 insertions, 6 deletions
diff --git a/audio/midiparser_qt.cpp b/audio/midiparser_qt.cpp index 5148ed74b1..5ea94a4afe 100644 --- a/audio/midiparser_qt.cpp +++ b/audio/midiparser_qt.cpp @@ -133,7 +133,7 @@ uint32 MidiParser_QT::readNextEvent(EventInfo &info) { case 0x2: case 0x3: // Note event - info.event = 0x90 | ((control >> 24) & 0x1F); + info.event = 0x90 | getChannel((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); @@ -143,7 +143,7 @@ uint32 MidiParser_QT::readNextEvent(EventInfo &info) { // Controller if (((control >> 16) & 0xFF) == 32) { // Pitch bend - info.event = 0xE0 | ((control >> 24) & 0x1F); + info.event = 0xE0 | getChannel((control >> 24) & 0x1F); // Actually an 8.8 fixed point number int16 value = (int16)(control & 0xFFFF); @@ -162,7 +162,7 @@ uint32 MidiParser_QT::readNextEvent(EventInfo &info) { info.basic.param2 = value >> 7; } else { // Regular controller - info.event = 0xB0 | ((control >> 24) & 0x1F); + info.event = 0xB0 | getChannel((control >> 24) & 0x1F); info.basic.param1 = (control >> 16) & 0xFF; info.basic.param2 = (control >> 8) & 0xFF; } @@ -175,7 +175,7 @@ uint32 MidiParser_QT::readNextEvent(EventInfo &info) { case 0x9: { // Extended note event uint32 extra = readUint32(); - info.event = 0x90 | ((control >> 16) & 0xFFF); + info.event = 0x90 | getChannel((control >> 16) & 0xFFF); info.basic.param1 = (control >> 8) & 0xFF; info.basic.param2 = (extra >> 22) & 0x7F; info.length = (info.basic.param2 == 0) ? 0 : (extra & 0x3FFFFF); @@ -184,7 +184,7 @@ uint32 MidiParser_QT::readNextEvent(EventInfo &info) { case 0xA: { // Extended controller uint32 extra = readUint32(); - info.event = 0xB0 | ((control >> 16) & 0xFFF); + info.event = 0xB0 | getChannel((control >> 16) & 0xFFF); info.basic.param1 = (extra >> 16) & 0x3FFF; info.basic.param2 = (extra >> 8) & 0xFF; // ??? break; @@ -219,7 +219,12 @@ void MidiParser_QT::handleGeneralEvent(EventInfo &info, uint32 control) { // Note Request // Currently we're only using the GM number from the request assert(dataSize == 84); - info.event = 0xC0 | part; + + // We have to remap channels because GM needs percussion to be on the + // percussion channel but QuickTime can have that anywhere. + allocateChannel(part, READ_BE_UINT32(_position._playPos + 80)); + + info.event = 0xC0 | getChannel(part); info.basic.param1 = READ_BE_UINT32(_position._playPos + 80); break; case 5: // Tune Difference @@ -235,6 +240,44 @@ void MidiParser_QT::handleGeneralEvent(EventInfo &info, uint32 control) { _position._playPos += dataSize + 4; } +void MidiParser_QT::allocateChannel(uint32 part, uint32 instrument) { + if (instrument == 0x4001) { + // Drum Kit -> Percussion Channel + if (isChannelAllocated(9)) + warning("Multiple QuickTime MIDI percussion channels"); + + _channelMap[part] = 9; + } else { + // Normal Instrument -> First Free Channel + for (uint32 i = 0; i < 16; i++) { + // 9 is reserved for Percussion + if (i == 9 || isChannelAllocated(i)) + continue; + + _channelMap[part] = i; + return; + } + + error("Failed to allocate channel for QuickTime MIDI"); + } +} + +byte MidiParser_QT::getChannel(uint32 part) const { + return _channelMap[part]; +} + +bool MidiParser_QT::isChannelAllocated(byte channel) const { + for (ChannelMap::const_iterator it = _channelMap.begin(); it != _channelMap.end(); it++) + if (it->_value == channel) + return true; + + return false; +} + +void MidiParser_QT::resetTracking() { + _channelMap.clear(); +} + 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)); diff --git a/audio/midiparser_qt.h b/audio/midiparser_qt.h index 5ab89bd4e7..25c2ae99fb 100644 --- a/audio/midiparser_qt.h +++ b/audio/midiparser_qt.h @@ -25,6 +25,7 @@ #include "audio/midiparser.h" #include "common/array.h" +#include "common/hashmap.h" #include "common/quicktime.h" /** @@ -57,6 +58,7 @@ public: protected: // MidiParser void parseNextEvent(EventInfo &info); + void resetTracking(); // QuickTimeParser SampleDesc *readSampleDesc(Track *track, uint32 format, uint32 descSize); @@ -80,10 +82,17 @@ private: uint32 readNextEvent(EventInfo &info); void handleGeneralEvent(EventInfo &info, uint32 control); + void allocateChannel(uint32 part, uint32 instrument); + byte getChannel(uint32 part) const; + bool isChannelAllocated(byte channel) const; + byte *readWholeTrack(Common::QuickTimeParser::Track *track, uint32 &trackSize); Common::Array<MIDITrackInfo> _trackInfo; + typedef Common::HashMap<uint, uint> ChannelMap; + ChannelMap _channelMap; + void initFromContainerTracks(); void initCommon(); uint32 readUint32(); |