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.cpp248
1 files changed, 125 insertions, 123 deletions
diff --git a/engines/sci/sound/drivers/midi.cpp b/engines/sci/sound/drivers/midi.cpp
index 7b2b102284..b9035b07ea 100644
--- a/engines/sci/sound/drivers/midi.cpp
+++ b/engines/sci/sound/drivers/midi.cpp
@@ -70,18 +70,18 @@ public:
void playSwitch(bool play);
private:
- bool isMt32GmPatch(const byte *data, int size);
- void readMt32GmPatch(const byte *data, int size);
- void readMt32Patch(const byte *data, int size);
+ bool isMt32GmPatch(const SciSpan<const byte> &data);
+ void readMt32GmPatch(const SciSpan<const byte> &data);
+ void readMt32Patch(const SciSpan<const byte> &data);
void readMt32DrvData();
- void mapMt32ToGm(byte *data, size_t size);
+ void mapMt32ToGm(const SciSpan<const byte> &data);
uint8 lookupGmInstrument(const char *iname);
uint8 lookupGmRhythmKey(const char *iname);
uint8 getGmInstrument(const Mt32ToGmMap &Mt32Ins);
- void sendMt32SysEx(const uint32 addr, Common::SeekableReadStream *str, int len, bool noDelay);
- void sendMt32SysEx(const uint32 addr, const byte *buf, int len, bool noDelay);
+ void sendMt32SysEx(const uint32 addr, Common::SeekableReadStream &data, const int len, bool noDelay);
+ void sendMt32SysEx(const uint32 addr, const SciSpan<const byte> &data, bool noDelay);
void setMt32Volume(byte volume);
void resetMt32();
@@ -382,8 +382,9 @@ int MidiPlayer_Midi::getVolume() {
void MidiPlayer_Midi::setReverb(int8 reverb) {
assert(reverb < kReverbConfigNr);
- if (_hasReverb && (_reverb != reverb))
- sendMt32SysEx(0x100001, _reverbConfig[reverb], 3, true);
+ if (_hasReverb && _reverb != reverb) {
+ sendMt32SysEx(0x100001, SciSpan<const byte>(_reverbConfig[reverb], 3), true);
+ }
_reverb = reverb;
}
@@ -398,7 +399,9 @@ void MidiPlayer_Midi::playSwitch(bool play) {
}
}
-bool MidiPlayer_Midi::isMt32GmPatch(const byte *data, int size) {
+bool MidiPlayer_Midi::isMt32GmPatch(const SciSpan<const byte> &data) {
+ uint32 size = data.size();
+
// 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)
@@ -419,21 +422,21 @@ bool MidiPlayer_Midi::isMt32GmPatch(const byte *data, int size) {
// 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)
+ if (data.getUint16LEAt(1153) + 1155U == size)
isMt32Gm = true;
// 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;
+ uint pos = 492 + 246 * timbresNr;
// Patches 49-96
- if ((size >= (pos + 386)) && (READ_BE_UINT16(data + pos) == 0xabcd))
+ if (size >= pos + 386 && data.getUint16BEAt(pos) == 0xabcd)
pos += 386; // 256 + 128 + 2
// Rhythm key map + partial reserve
- if ((size >= (pos + 267)) && (READ_BE_UINT16(data + pos) == 0xdcba))
+ if (size >= pos + 267 && data.getUint16BEAt(pos) == 0xdcba)
pos += 267; // 256 + 9 + 2
if (size == pos)
@@ -445,7 +448,7 @@ bool MidiPlayer_Midi::isMt32GmPatch(const byte *data, int size) {
return isMt32Gm;
}
-void MidiPlayer_Midi::sendMt32SysEx(const uint32 addr, Common::SeekableReadStream *str, int len, bool noDelay = false) {
+void MidiPlayer_Midi::sendMt32SysEx(const uint32 addr, Common::SeekableReadStream &stream, int len, bool noDelay = false) {
if (len + 8 > kMaxSysExSize) {
warning("SysEx message exceed maximum size; ignoring");
return;
@@ -457,8 +460,7 @@ void MidiPlayer_Midi::sendMt32SysEx(const uint32 addr, Common::SeekableReadStrea
_sysExBuf[5] = (addr >> 8) & 0xff;
_sysExBuf[6] = addr & 0xff;
- for (int i = 0; i < len; i++)
- _sysExBuf[7 + i] = str->readByte();
+ stream.read(_sysExBuf + 7, len);
for (int i = 4; i < 7 + len; i++)
chk -= _sysExBuf[i];
@@ -471,81 +473,82 @@ void MidiPlayer_Midi::sendMt32SysEx(const uint32 addr, Common::SeekableReadStrea
sysEx(_sysExBuf, len + 8);
}
-void MidiPlayer_Midi::sendMt32SysEx(const uint32 addr, const byte *buf, int len, bool noDelay = false) {
- Common::MemoryReadStream *str = new Common::MemoryReadStream(buf, len);
- sendMt32SysEx(addr, str, len, noDelay);
- delete str;
+void MidiPlayer_Midi::sendMt32SysEx(const uint32 addr, const SciSpan<const byte> &buf, bool noDelay = false) {
+ Common::MemoryReadStream stream(buf.toStream());
+ sendMt32SysEx(addr, stream, buf.size(), noDelay);
}
-void MidiPlayer_Midi::readMt32Patch(const byte *data, int size) {
+
+void MidiPlayer_Midi::readMt32Patch(const SciSpan<const byte> &data) {
// 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
+ // - 0-19 after-SysEx message
+ // - 20-39 before-SysEx message
+ // - 40-59 goodbye SysEx message
+ // - 60-61 volume
+ // - 62 reverb
+ // - 63-73 reverb Sysex message
+ // - 74-106 [3 * 11] reverb data
+ // - 107-490 [256 + 128] 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
+ // - 491 number of timbres (64 max)
+ // - 492..n [246 * number of timbres] timbre data
+ // - n-n+1 flag (0xabcd)
+ // - n+2-n+385 [256 + 128] patches 49-96
+ // - n+386-n+387 flag (0xdcba)
+ // - n+388-n+643 rhythm key map
+ // - n+644-n+652 partial reserve
- Common::MemoryReadStream *str = new Common::MemoryReadStream(data, size);
+ Common::MemoryReadStream stream(data.toStream());
// Send before-SysEx text
- str->seek(20);
- sendMt32SysEx(0x200000, str, 20);
+ stream.seek(20);
+ sendMt32SysEx(0x200000, stream, 20);
// Save goodbye message
- str->read(_goodbyeMsg, 20);
+ assert(sizeof(_goodbyeMsg) == 20);
+ stream.read(_goodbyeMsg, 20);
- byte volume = CLIP<uint16>(str->readUint16LE(), 0, 100);
+ const uint8 volume = MIN<uint16>(stream.readUint16LE(), 100);
setMt32Volume(volume);
// Reverb default only used in (roughly) SCI0/SCI01
- byte reverb = str->readByte();
+ byte reverb = stream.readByte();
_hasReverb = true;
// Skip reverb SysEx message
- str->seek(11, SEEK_CUR);
+ stream.seek(11, SEEK_CUR);
// Read reverb data (stored vertically - patch #3117434)
for (int j = 0; j < 3; ++j) {
for (int i = 0; i < kReverbConfigNr; i++) {
- _reverbConfig[i][j] = str->readByte();
+ _reverbConfig[i][j] = stream.readByte();
}
}
// Patches 1-48
- sendMt32SysEx(0x50000, str, 256);
- sendMt32SysEx(0x50200, str, 128);
+ sendMt32SysEx(0x50000, stream, 256);
+ sendMt32SysEx(0x50200, stream, 128);
// Timbres
- byte timbresNr = str->readByte();
+ const uint8 timbresNr = stream.readByte();
for (int i = 0; i < timbresNr; i++)
- sendMt32SysEx(0x80000 + (i << 9), str, 246);
+ sendMt32SysEx(0x80000 + (i << 9), stream, 246);
- uint16 flag = str->readUint16BE();
+ uint16 flag = stream.readUint16BE();
- if (!str->eos() && (flag == 0xabcd)) {
+ if (!stream.eos() && flag == 0xabcd) {
// Patches 49-96
- sendMt32SysEx(0x50300, str, 256);
- sendMt32SysEx(0x50500, str, 128);
- flag = str->readUint16BE();
+ sendMt32SysEx(0x50300, stream, 256);
+ sendMt32SysEx(0x50500, stream, 128);
+ flag = stream.readUint16BE();
}
- if (!str->eos() && (flag == 0xdcba)) {
+ if (!stream.eos() && flag == 0xdcba) {
// Rhythm key map
- sendMt32SysEx(0x30110, str, 256);
+ sendMt32SysEx(0x30110, stream, 256);
// Partial reserve
- sendMt32SysEx(0x100004, str, 9);
+ sendMt32SysEx(0x100004, stream, 9);
}
// Reverb for SCI0
@@ -553,16 +556,15 @@ void MidiPlayer_Midi::readMt32Patch(const byte *data, int size) {
setReverb(reverb);
// Send after-SysEx text
- str->seek(0);
- sendMt32SysEx(0x200000, str, 20);
+ stream.seek(0);
+ sendMt32SysEx(0x200000, stream, 20);
// Send the mystery SysEx
- sendMt32SysEx(0x52000a, (const byte *)"\x16\x16\x16\x16\x16\x16", 6);
-
- delete str;
+ Common::MemoryReadStream mystery((const byte *)"\x16\x16\x16\x16\x16\x16", 6);
+ sendMt32SysEx(0x52000a, mystery, 6);
}
-void MidiPlayer_Midi::readMt32GmPatch(const byte *data, int size) {
+void MidiPlayer_Midi::readMt32GmPatch(const SciSpan<const byte> &data) {
// GM patch contents:
// - 128 bytes patch map
// - 128 bytes key shift
@@ -573,21 +575,21 @@ void MidiPlayer_Midi::readMt32GmPatch(const byte *data, int size) {
// - 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);
+ data.subspan(0, sizeof(_patchMap)).unsafeCopyDataTo(_patchMap);
+ data.subspan(128, sizeof(_keyShift)).unsafeCopyDataTo(_keyShift);
+ data.subspan(256, sizeof(_volAdjust)).unsafeCopyDataTo(_volAdjust);
+ data.subspan(384, sizeof(_percussionMap)).unsafeCopyDataTo(_percussionMap);
_channels[MIDI_RHYTHM_CHANNEL].volAdjust = data[512];
- memcpy(_velocityMapIdx, data + 513, 128);
- memcpy(_velocityMap, data + 641, 512);
+ data.subspan(513, sizeof(_velocityMapIdx)).unsafeCopyDataTo(_velocityMapIdx);
+ data.subspan(641, sizeof(_velocityMap)).unsafeCopyDataTo(_velocityMap);
- uint16 midiSize = READ_LE_UINT16(data + 1153);
+ uint16 midiSize = data.getUint16LEAt(1153);
if (midiSize > 0) {
- if (size < midiSize + 1155)
+ if (data.size() < midiSize + 1155U)
error("Failed to read MIDI data");
- const byte *midi = data + 1155;
+ const SciSpan<const byte> midi = data.subspan(1155, midiSize);
byte command = 0;
uint i = 0;
@@ -599,15 +601,16 @@ void MidiPlayer_Midi::readMt32GmPatch(const byte *data, int size) {
switch (command & 0xf0) {
case 0xf0: {
- const byte *sysExEnd = (const byte *)memchr(midi + i, 0xf7, midiSize - i);
+ const byte *sysExStart = midi.getUnsafeDataAt(i, midiSize - i);
+ const byte *sysExEnd = (const byte *)memchr(sysExStart, 0xf7, midiSize - i);
if (!sysExEnd)
error("Failed to find end of sysEx");
- int len = sysExEnd - (midi + i);
- sysEx(midi + i, len);
+ int len = sysExEnd - sysExStart;
+ sysEx(sysExStart, len);
- i += len + 1; // One more for the 0x7f
+ i += len + 1; // One more for the 0xf7
break;
}
case 0x80:
@@ -656,13 +659,13 @@ void MidiPlayer_Midi::readMt32DrvData() {
f.seek(-2, SEEK_CUR);
// Send before-SysEx text
- sendMt32SysEx(0x200000, &f, 20);
+ sendMt32SysEx(0x200000, f, 20);
if (size != 2271) {
// Send after-SysEx text (SSCI sends this before every song).
// There aren't any SysEx calls in old drivers, so this can
// be sent right after the before-SysEx text.
- sendMt32SysEx(0x200000, &f, 20);
+ sendMt32SysEx(0x200000, f, 20);
} else {
// Skip the after-SysEx text in the newer patch version, we'll send
// it after the SysEx messages are sent.
@@ -696,14 +699,14 @@ void MidiPlayer_Midi::readMt32DrvData() {
f.skip(2235); // skip driver code
// Patches 1-48
- sendMt32SysEx(0x50000, &f, 256);
- sendMt32SysEx(0x50200, &f, 128);
+ sendMt32SysEx(0x50000, f, 256);
+ sendMt32SysEx(0x50200, f, 128);
setReverb(reverb);
// Send the after-SysEx text
f.seek(0x3d);
- sendMt32SysEx(0x200000, &f, 20);
+ sendMt32SysEx(0x200000, f, 20);
} else {
byte reverbSysEx[13];
// This old driver should have a full reverb SysEx
@@ -775,11 +778,11 @@ uint8 MidiPlayer_Midi::getGmInstrument(const Mt32ToGmMap &Mt32Ins) {
return Mt32Ins.gmInstr;
}
-void MidiPlayer_Midi::mapMt32ToGm(byte *data, size_t size) {
+void MidiPlayer_Midi::mapMt32ToGm(const SciSpan<const byte> &data) {
// FIXME: Clean this up
int memtimbres, patches;
uint8 group, number, keyshift, /*finetune,*/ bender_range;
- uint8 *patchpointer;
+ SciSpan<const byte> patchpointer;
uint32 pos;
int i;
@@ -791,10 +794,10 @@ void MidiPlayer_Midi::mapMt32ToGm(byte *data, size_t size) {
for (i = 0; i < 128; i++)
_percussionMap[i] = Mt32PresetRhythmKeymap[i];
- memtimbres = *(data + 0x1eb);
+ memtimbres = data[0x1eb];
pos = 0x1ec + memtimbres * 0xf6;
- if (size > pos && ((0x100 * *(data + pos) + *(data + pos + 1)) == 0xabcd)) {
+ if (data.size() > pos && data.getUint16BEAt(pos) == 0xabcd) {
patches = 96;
pos += 2 + 8 * 48;
} else {
@@ -807,18 +810,18 @@ void MidiPlayer_Midi::mapMt32ToGm(byte *data, size_t size) {
debugC(kDebugLevelSound, "\n[MT32-to-GM] Mapping patches..");
for (i = 0; i < patches; i++) {
- char name[11];
+ Common::String name;
if (i < 48)
- patchpointer = data + 0x6b + 8 * i;
+ patchpointer = data.subspan(0x6b + 8 * i);
else
- patchpointer = data + 0x1ec + 8 * (i - 48) + memtimbres * 0xf6 + 2;
+ patchpointer = data.subspan(0x1ec + 8 * (i - 48) + memtimbres * 0xf6 + 2);
- group = *patchpointer;
- number = *(patchpointer + 1);
- keyshift = *(patchpointer + 2);
- //finetune = *(patchpointer + 3);
- bender_range = *(patchpointer + 4);
+ group = patchpointer[0];
+ number = patchpointer[1];
+ keyshift = patchpointer[2];
+ //finetune = patchpointer[3];
+ bender_range = patchpointer[4];
debugCN(kDebugLevelSound, " [%03d] ", i);
@@ -832,10 +835,9 @@ void MidiPlayer_Midi::mapMt32ToGm(byte *data, size_t size) {
break;
case 2:
if (number < memtimbres) {
- strncpy(name, (const char *)data + 0x1ec + number * 0xf6, 10);
- name[10] = 0;
- _patchMap[i] = lookupGmInstrument(name);
- debugCN(kDebugLevelSound, "%s -> ", name);
+ name = data.getStringAt(0x1ec + number * 0xf6, 10);
+ _patchMap[i] = lookupGmInstrument(name.c_str());
+ debugCN(kDebugLevelSound, "%s -> ", name.c_str());
} else {
_patchMap[i] = 0xff;
debugCN(kDebugLevelSound, "[Invalid] -> ");
@@ -865,21 +867,19 @@ void MidiPlayer_Midi::mapMt32ToGm(byte *data, size_t size) {
_pitchBendRange[i] = CLIP<uint8>(bender_range, 0, 24);
}
- if (size > pos && ((0x100 * *(data + pos) + *(data + pos + 1)) == 0xdcba)) {
+ if (data.size() > pos && data.getUint16BEAt(pos) == 0xdcba) {
debugC(kDebugLevelSound, "\n[MT32-to-GM] Mapping percussion..");
for (i = 0; i < 64; i++) {
- number = *(data + pos + 4 * i + 2);
+ number = data[pos + 4 * i + 2];
byte ins = i + 24;
debugCN(kDebugLevelSound, " [%03d] ", ins);
if (number < 64) {
- char name[11];
- strncpy(name, (const char *)data + 0x1ec + number * 0xf6, 10);
- name[10] = 0;
- debugCN(kDebugLevelSound, "%s -> ", name);
- _percussionMap[ins] = lookupGmRhythmKey(name);
+ Common::String name = data.getStringAt(0x1ec + number * 0xf6, 10);
+ debugCN(kDebugLevelSound, "%s -> ", name.c_str());
+ _percussionMap[ins] = lookupGmRhythmKey(name.c_str());
} else {
if (number < 94) {
debugCN(kDebugLevelSound, "%s -> ", Mt32RhythmTimbreMaps[number - 64].name);
@@ -897,17 +897,19 @@ void MidiPlayer_Midi::mapMt32ToGm(byte *data, size_t size) {
debugC(kDebugLevelSound, "%s", GmPercussionNames[_percussionMap[ins]]);
#endif
- _percussionVelocityScale[ins] = *(data + pos + 4 * i + 3) * 127 / 100;
+ _percussionVelocityScale[ins] = data[pos + 4 * i + 3] * 127 / 100;
}
}
}
void MidiPlayer_Midi::setMt32Volume(byte volume) {
- sendMt32SysEx(0x100016, &volume, 1);
+ Common::MemoryReadStream s(&volume, 1);
+ sendMt32SysEx(0x100016, s, 1);
}
void MidiPlayer_Midi::resetMt32() {
- sendMt32SysEx(0x7f0000, (const byte *)"\x01\x00", 2, true);
+ Common::MemoryReadStream s((const byte *)"\x01\x00", 2);
+ sendMt32SysEx(0x7f0000, s, 2, true);
// This seems to require a longer delay than usual
g_system->delayMillis(150);
@@ -937,11 +939,11 @@ int MidiPlayer_Midi::open(ResourceManager *resMan) {
_percussionVelocityScale[i] = 127;
}
- Resource *res = NULL;
+ Resource *res = nullptr;
if (g_sci && g_sci->_features->useAltWinGMSound()) {
- res = resMan->findResource(ResourceId(kResourceTypePatch, 4), 0);
- if (!(res && isMt32GmPatch(res->data, res->size))) {
+ res = resMan->findResource(ResourceId(kResourceTypePatch, 4), false);
+ if (!res || !isMt32GmPatch(*res)) {
// Don't do any mapping when a Windows alternative track is selected
// and no MIDI patch is available
_useMT32Track = false;
@@ -953,15 +955,15 @@ int MidiPlayer_Midi::open(ResourceManager *resMan) {
// MT-32
resetMt32();
- res = resMan->findResource(ResourceId(kResourceTypePatch, 1), 0);
+ res = resMan->findResource(ResourceId(kResourceTypePatch, 1), false);
if (res) {
- if (isMt32GmPatch(res->data, res->size)) {
- readMt32GmPatch(res->data, res->size);
+ if (isMt32GmPatch(*res)) {
+ readMt32GmPatch(*res);
// Note that _goodbyeMsg is not zero-terminated
memcpy(_goodbyeMsg, " ScummVM ", 20);
} else {
- readMt32Patch(res->data, res->size);
+ readMt32Patch(*res);
}
} else {
// Early SCI0 games have the sound bank embedded in the MT-32 driver
@@ -969,22 +971,22 @@ int MidiPlayer_Midi::open(ResourceManager *resMan) {
}
} else {
// General MIDI
- res = resMan->findResource(ResourceId(kResourceTypePatch, 4), 0);
+ res = resMan->findResource(ResourceId(kResourceTypePatch, 4), false);
- if (res && isMt32GmPatch(res->data, res->size)) {
+ if (res && isMt32GmPatch(*res)) {
// There is a GM patch
- readMt32GmPatch(res->data, res->size);
+ readMt32GmPatch(*res);
if (g_sci && g_sci->_features->useAltWinGMSound()) {
// Always use the GM track if an alternative GM Windows soundtrack is selected
_useMT32Track = false;
} else {
// Detect the format of patch 1, so that we know what play mask to use
- res = resMan->findResource(ResourceId(kResourceTypePatch, 1), 0);
+ res = resMan->findResource(ResourceId(kResourceTypePatch, 1), false);
if (!res)
_useMT32Track = false;
else
- _useMT32Track = !isMt32GmPatch(res->data, res->size);
+ _useMT32Track = !isMt32GmPatch(*res);
// Check if the songs themselves have a GM track
if (!_useMT32Track) {
@@ -1013,17 +1015,17 @@ int MidiPlayer_Midi::open(ResourceManager *resMan) {
_velocityMap[3][i] = 0x20 + (i - 1) / 2;
}
- res = resMan->findResource(ResourceId(kResourceTypePatch, 1), 0);
+ res = resMan->findResource(ResourceId(kResourceTypePatch, 1), false);
if (res) {
- if (!isMt32GmPatch(res->data, res->size)) {
- mapMt32ToGm(res->data, res->size);
+ if (!isMt32GmPatch(*res)) {
+ mapMt32ToGm(*res);
} else {
if (getSciVersion() < SCI_VERSION_3) {
error("MT-32 patch has wrong type");
} else {
// Happens in the SCI3 interactive demo of Lighthouse
- warning("TODO: Ignoring new SCI3 type of MT-32 patch for now (size = %d)", res->size);
+ warning("TODO: Ignoring new SCI3 type of MT-32 patch for now (size = %lu)", res->size());
}
}
} else {
@@ -1053,7 +1055,7 @@ int MidiPlayer_Midi::open(ResourceManager *resMan) {
void MidiPlayer_Midi::close() {
if (_isMt32) {
// Send goodbye message
- sendMt32SysEx(0x200000, _goodbyeMsg, 20, true);
+ sendMt32SysEx(0x200000, SciSpan<const byte>(_goodbyeMsg, 20), true);
}
_driver->close();