aboutsummaryrefslogtreecommitdiff
path: root/engines/sci/sound/drivers/midi.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'engines/sci/sound/drivers/midi.cpp')
-rw-r--r--engines/sci/sound/drivers/midi.cpp74
1 files changed, 60 insertions, 14 deletions
diff --git a/engines/sci/sound/drivers/midi.cpp b/engines/sci/sound/drivers/midi.cpp
index 80a72b9a6f..baf85de74c 100644
--- a/engines/sci/sound/drivers/midi.cpp
+++ b/engines/sci/sound/drivers/midi.cpp
@@ -399,24 +399,42 @@ void MidiPlayer_Midi::playSwitch(bool play) {
}
bool MidiPlayer_Midi::isMt32GmPatch(const byte *data, int size) {
- if (size < 1155)
+ // WORKAROUND: Some Mac games (e.g. LSL5) may have an extra byte at the
+ // end, so compensate for that here - bug #6725.
+ if (size == 16890)
+ size--;
+
+ // Need at least 1153 + 2 bytes for a GM patch. Check readMt32GmPatch()
+ // below for more info.
+ if (size < 1153 + 2)
return false;
+ // The maximum number of bytes for an MT-32 patch is 16889. The maximum
+ // number of timbres is 64, which leads us to:
+ // 491 + 1 + 64 * 246 + 653 = 16889
if (size > 16889)
return true;
bool isMt32 = false;
bool isMt32Gm = false;
+ // First, check for a GM patch. The presence of MIDI data after the
+ // initial 1153 + 2 bytes indicates a GM patch
if (READ_LE_UINT16(data + 1153) + 1155 == size)
isMt32Gm = true;
- int pos = 492 + 246 * data[491];
+ // Now check for a regular MT-32 patch. Check readMt32Patch() below for
+ // more info.
+ // 491 = 20 + 20 + 20 + 2 + 1 + 11 + 3 * 11 + 256 + 128
+ byte timbresNr = data[491];
+ int pos = 492 + 246 * timbresNr;
+ // Patches 49-96
if ((size >= (pos + 386)) && (READ_BE_UINT16(data + pos) == 0xabcd))
- pos += 386;
+ pos += 386; // 256 + 128 + 2
+ // Rhythm key map + partial reserve
if ((size >= (pos + 267)) && (READ_BE_UINT16(data + pos) == 0xdcba))
- pos += 267;
+ pos += 267; // 256 + 9 + 2
if (size == pos)
isMt32 = true;
@@ -460,10 +478,28 @@ void MidiPlayer_Midi::sendMt32SysEx(const uint32 addr, const byte *buf, int len,
}
void MidiPlayer_Midi::readMt32Patch(const byte *data, int size) {
+ // MT-32 patch contents:
+ // - 20 bytes unkown
+ // - 20 bytes before-SysEx message
+ // - 20 bytes goodbye SysEx message
+ // - 2 bytes volume
+ // - 1 byte reverb
+ // - 11 bytes reverb Sysex message
+ // - 3 * 11 reverb data
+ // - 256 + 128 bytes patches 1-48
+ // --> total: 491 bytes
+ // - 1 byte number of timbres (64 max)
+ // - 246 * timbres timbre data
+ // - 2 bytes flag (0xabcd)
+ // - 256 + 128 bytes patches 49-96
+ // - 2 bytes flag (0xdcba)
+ // - 256 bytes rhythm key map
+ // - 9 bytes partial reserve
+
Common::MemoryReadStream *str = new Common::MemoryReadStream(data, size);
// Send before-SysEx text
- str->seek(0x14);
+ str->seek(20);
sendMt32SysEx(0x200000, str, 20);
// Save goodbye message
@@ -527,15 +563,25 @@ void MidiPlayer_Midi::readMt32Patch(const byte *data, int size) {
}
void MidiPlayer_Midi::readMt32GmPatch(const byte *data, int size) {
- memcpy(_patchMap, data, 0x80);
- memcpy(_keyShift, data + 0x80, 0x80);
- memcpy(_volAdjust, data + 0x100, 0x80);
- memcpy(_percussionMap, data + 0x180, 0x80);
- _channels[MIDI_RHYTHM_CHANNEL].volAdjust = data[0x200];
- memcpy(_velocityMapIdx, data + 0x201, 0x80);
- memcpy(_velocityMap, data + 0x281, 0x200);
-
- uint16 midiSize = READ_LE_UINT16(data + 0x481);
+ // GM patch contents:
+ // - 128 bytes patch map
+ // - 128 bytes key shift
+ // - 128 bytes volume adjustment
+ // - 128 bytes percussion map
+ // - 1 byte volume adjust for the rhythm channel
+ // - 128 bytes velocity map IDs
+ // - 512 bytes velocity map
+ // --> total: 1153 bytes
+
+ memcpy(_patchMap, data, 128);
+ memcpy(_keyShift, data + 128, 128);
+ memcpy(_volAdjust, data + 256, 128);
+ memcpy(_percussionMap, data + 384, 128);
+ _channels[MIDI_RHYTHM_CHANNEL].volAdjust = data[512];
+ memcpy(_velocityMapIdx, data + 513, 128);
+ memcpy(_velocityMap, data + 641, 512);
+
+ uint16 midiSize = READ_LE_UINT16(data + 1153);
if (midiSize > 0) {
if (size < midiSize + 1155)