[Scummvm-git-logs] scummvm master -> 98627e8de0cdd6dde66052a9b0c0159bcb2a8b78
dreammaster
noreply at scummvm.org
Tue Jul 28 21:00:07 UTC 2026
This automated email contains information about 1 new commit which have been
pushed to the 'scummvm' repo located at https://api.github.com/repos/scummvm/scummvm .
Summary:
98627e8de0 MADS: Added sendSysExSequence to RSound initialization
Commit: 98627e8de0cdd6dde66052a9b0c0159bcb2a8b78
https://github.com/scummvm/scummvm/commit/98627e8de0cdd6dde66052a9b0c0159bcb2a8b78
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-07-29T06:59:51+10:00
Commit Message:
MADS: Added sendSysExSequence to RSound initialization
Assisted-by: Claude Code:claude-opus-4.8
Changed paths:
engines/mads/dragonsphere/sound/rsound.cpp
engines/mads/dragonsphere/sound/rsound.h
engines/mads/nebular/sound/rsound.cpp
engines/mads/nebular/sound/rsound.h
engines/mads/phantom/sound/rsound.cpp
engines/mads/phantom/sound/rsound.h
diff --git a/engines/mads/dragonsphere/sound/rsound.cpp b/engines/mads/dragonsphere/sound/rsound.cpp
index a861e5e9357..a9190e019f2 100644
--- a/engines/mads/dragonsphere/sound/rsound.cpp
+++ b/engines/mads/dragonsphere/sound/rsound.cpp
@@ -121,7 +121,12 @@ RSound::RSound(Audio::Mixer *mixer, const Common::Path &filename,
for (int i = 0; i < ARRAYSIZE(_scriptVariables); ++i)
_scriptVariables[i] = 0;
+ // Matches initDeviceOnce: command0() then sendSysExSequence(). The
+ // disassembly's _deviceInitialized guard flag is omitted - this
+ // constructor only ever runs once per driver instance, so there's
+ // nothing to guard against.
command0();
+ sendSysExSequence();
}
void RSound::validate() {
@@ -349,23 +354,36 @@ void RSound::sendGmResetRange(int high, int low) {
}
}
-void RSound::sendSysExData(const byte *pData) {
+const byte *RSound::sendSysExData(const byte *pData) {
static const byte header[] = { 0xF0, 0x41, 0x10, 0x16, 0x12 };
for (int i = 0; i < ARRAYSIZE(header); ++i)
sendMidiByte(header[i]);
_sysexChecksum = 0;
- for (int i = 0; pData[i] != 0xFF; ++i) {
+ int i = 0;
+ for (; pData[i] != 0xFF; ++i) {
sendMidiByte(pData[i]);
_sysexChecksum += pData[i];
}
sendMidiByte((~_sysexChecksum + 1) & 0x7F);
sendMidiByte(0xF7);
+
+ return &pData[i];
+}
+
+const byte *RSound::sendSysEx(int offset) {
+ return sendSysExData(loadData(offset));
}
-void RSound::sendSysEx(int offset) {
- sendSysExData(loadData(offset));
+void RSound::sendSysExSequence() {
+ const byte *pData = loadData(_sysExOffset);
+ for (;;) {
+ pData = sendSysExData(pData);
+ ++pData;
+ if (*pData == 0xFF)
+ break;
+ }
}
void RSound::sendPatchInitSequence() {
diff --git a/engines/mads/dragonsphere/sound/rsound.h b/engines/mads/dragonsphere/sound/rsound.h
index 82aff15ddbb..7ffa2098d43 100644
--- a/engines/mads/dragonsphere/sound/rsound.h
+++ b/engines/mads/dragonsphere/sound/rsound.h
@@ -483,12 +483,26 @@ protected:
* Sends a single Roland DT1-style SysEx message from a raw buffer:
* the fixed header, then bytes from pData up to (not including) a
* 0xFF terminator - each byte sent and folded into a running
- * checksum - then the checksum byte and a closing F7.
+ * checksum - then the checksum byte and a closing F7. Returns a
+ * pointer to the terminating 0xFF byte (matching the disassembly's
+ * own si register value on return), so callers walking a sequence
+ * of consecutive messages can advance past it to find the next one.
*/
- void sendSysExData(const byte *pData);
+ const byte *sendSysExData(const byte *pData);
/** sendSysExData() for a block already in this driver's own loaded sound data. */
- void sendSysEx(int offset);
+ const byte *sendSysEx(int offset);
+
+ /**
+ * Matches sendSysExSequence: repeatedly calls sendSysEx(), starting
+ * from this driver's own command0_array (_sysExOffset) and advancing
+ * past each message's terminating 0xFF to the start of the next one,
+ * until an empty message (two consecutive 0xFF bytes) marks the end
+ * of the table. Called once from the constructor (matching
+ * initDeviceOnce) - the disassembly's _deviceInitialized guard flag
+ * isn't needed since nothing else ever calls this again.
+ */
+ void sendSysExSequence();
void sendPatchInitSequence();
diff --git a/engines/mads/nebular/sound/rsound.cpp b/engines/mads/nebular/sound/rsound.cpp
index 25779cc3537..473cb5037ba 100644
--- a/engines/mads/nebular/sound/rsound.cpp
+++ b/engines/mads/nebular/sound/rsound.cpp
@@ -100,7 +100,12 @@ RSound::RSound(Audio::Mixer *mixer, const Common::Path &filename,
// MIDI channel reset messages to the device. Since we don't do real hardware
// detection here, just go straight to command0() - matches ASound's
// constructor calling command0() directly.
+ // Matches initDeviceOnce: command0() then sendSysExSequence(). The
+ // disassembly's _deviceInitialized guard flag is omitted - this
+ // constructor only ever runs once per driver instance, so there's
+ // nothing to guard against.
command0();
+ sendSysExSequence();
_midiDriver->setTimerCallback(this, &timerCallback);
}
@@ -284,38 +289,44 @@ void RSound::restoreChannelVolume(int midiChannel, int volume) {
sendVolume(midiChannel, volume);
}
-void RSound::sendSysEx(int offset) {
+byte *RSound::sendSysExData(byte *pData) {
+ // FIXME If the data is malformed, this will read out of bounds. Not sure
+ // how the original code handles this.
+ uint16 length = 0;
+ for (int i = 0; pData[i] != 0xFF; ++i) {
+ length++;
+ }
+
+ // FIXME This call adds the necessary delay for the MT-32 to process the
+ // SysEx message, which will make the engine unresponsive.
+ // This can be fixed using the SysEx queue (specify true as 3rd param).
+ // Driver status can then be checked from the main event loop using
+ // _midiDriver->isReady().
+ _midiDriver->sysExMT32(pData, length);
+
+ return &pData[length];
+}
+
+byte *RSound::sendSysEx(int offset) {
if (offset < 0) {
// _sysExOffset wasn't given a confirmed value for this driver yet
// (see the constructor) - deliberately not scanning for a 0xFF
// terminator from an unconfirmed/arbitrary offset, since that
// could read well past the actual command0_array table.
warning("RSound::sendSysEx: command0_array offset not yet known for this driver");
- return;
+ return nullptr;
}
- // There is a whole block of SysEx data at this offset that has to be
- // sent to the MT-32. Each entry is terminated by 0xFF; the block seems to
- // be terminated by a second 0xFF following the last entry.
- // FIXME If the data is malformed, this will read out of bounds. Not sure
- // how the original code handles this.
- byte *pData = loadData(offset);
- while (true) {
- uint16 length = 0;
- for (int i = 0; pData[i] != 0xFF; ++i) {
- length++;
- }
- if (length == 0) {
- // Two subsequent 0xFF bytes - end of SysEx data block.
+ return sendSysExData(loadData(offset));
+}
+
+void RSound::sendSysExSequence() {
+ byte *pData = loadData(_sysExOffset);
+ for (;;) {
+ pData = sendSysExData(pData);
+ ++pData;
+ if (*pData == 0xFF)
break;
- }
- // FIXME This call adds the necessary delay for the MT-32 to process the
- // SysEx message, which will make the engine unresponsive.
- // This can be fixed using the SysEx queue (specify true as 3rd param).
- // Driver status can then be checked from the main event loop using
- // _midiDriver->isReady().
- _midiDriver->sysExMT32(pData, length);
- pData += length + 1;
}
}
diff --git a/engines/mads/nebular/sound/rsound.h b/engines/mads/nebular/sound/rsound.h
index dfda2782a6e..1b17a0f7062 100644
--- a/engines/mads/nebular/sound/rsound.h
+++ b/engines/mads/nebular/sound/rsound.h
@@ -261,19 +261,30 @@ protected:
void sendMidiChannelReset(int first, int last);
/**
- * Sends a single Roland DT1-style SysEx message: the fixed
- * _sysExHeader (F0 41 10 16 12), then bytes from loadData(offset)
- * up to (but not including) a 0xFF terminator - each byte sent and
- * folded into a running checksum - then the two's-complement/7-bit
- * checksum byte and a closing F7. Matches sub_1041E exactly.
- *
- * The original follows this with a busy-wait delay loop
- * (_sysexDelayCount iterations) to give the MT-32 time to process
- * the message before the next one arrives; irrelevant while
- * sendMidiByte() is just a warning() stub, so not ported - will need
- * a real (non-blocking) delay once actual MIDI output exists.
+ * Sends a single SysEx message: bytes from pData up to (but not
+ * including) a 0xFF terminator, via the real MT32GM MIDI driver
+ * (_midiDriver->sysExMT32()) - this part is a work in progress and
+ * intentionally NOT shared with the Dragonsphere/Phantom RSound
+ * families, which still route through the sendMidiByte() warning()
+ * stub. Returns a pointer to the terminating 0xFF byte, so callers
+ * walking a sequence of consecutive messages can advance past it to
+ * find the next one.
*/
- void sendSysEx(int offset);
+ byte *sendSysExData(byte *pData);
+
+ /** sendSysExData() for a block already in this driver's own loaded sound data. */
+ byte *sendSysEx(int offset);
+
+ /**
+ * Matches sendSysExSequence: repeatedly calls sendSysEx(), starting
+ * from this driver's own command0_array (_sysExOffset) and advancing
+ * past each message's terminating 0xFF to the start of the next one,
+ * until an empty message (two consecutive 0xFF bytes) marks the end
+ * of the table. Called once from the constructor (matching
+ * initDeviceOnce) - the disassembly's _deviceInitialized guard flag
+ * isn't needed since nothing else ever calls this again.
+ */
+ void sendSysExSequence();
virtual int command0();
int command1();
diff --git a/engines/mads/phantom/sound/rsound.cpp b/engines/mads/phantom/sound/rsound.cpp
index 8bfcf22f065..73ce32466b9 100644
--- a/engines/mads/phantom/sound/rsound.cpp
+++ b/engines/mads/phantom/sound/rsound.cpp
@@ -120,7 +120,12 @@ RSound::RSound(Audio::Mixer *mixer, const Common::Path &filename,
for (int i = 0; i < ARRAYSIZE(_scriptVariables); ++i)
_scriptVariables[i] = 0;
+ // Matches initDeviceOnce: command0() then sendSysExSequence(). The
+ // disassembly's _deviceInitialized guard flag is omitted - this
+ // constructor only ever runs once per driver instance, so there's
+ // nothing to guard against.
command0();
+ sendSysExSequence();
}
void RSound::validate() {
@@ -331,23 +336,36 @@ void RSound::sendGmReset(int count) {
}
}
-void RSound::sendSysExData(const byte *pData) {
+const byte *RSound::sendSysExData(const byte *pData) {
static const byte header[] = { 0xF0, 0x41, 0x10, 0x16, 0x12 };
for (int i = 0; i < ARRAYSIZE(header); ++i)
sendMidiByte(header[i]);
_sysexChecksum = 0;
- for (int i = 0; pData[i] != 0xFF; ++i) {
+ int i = 0;
+ for (; pData[i] != 0xFF; ++i) {
sendMidiByte(pData[i]);
_sysexChecksum += pData[i];
}
sendMidiByte((~_sysexChecksum + 1) & 0x7F);
sendMidiByte(0xF7);
+
+ return &pData[i];
+}
+
+const byte *RSound::sendSysEx(int offset) {
+ return sendSysExData(loadData(offset));
}
-void RSound::sendSysEx(int offset) {
- sendSysExData(loadData(offset));
+void RSound::sendSysExSequence() {
+ const byte *pData = loadData(_sysExOffset);
+ for (;;) {
+ pData = sendSysExData(pData);
+ ++pData;
+ if (*pData == 0xFF)
+ break;
+ }
}
void RSound::sendPatchInitSequence() {
diff --git a/engines/mads/phantom/sound/rsound.h b/engines/mads/phantom/sound/rsound.h
index a781927492e..971262d6492 100644
--- a/engines/mads/phantom/sound/rsound.h
+++ b/engines/mads/phantom/sound/rsound.h
@@ -380,16 +380,26 @@ protected:
* checksum - then the checksum byte and a closing F7. The shared
* core of sendSysEx()/sendReverbSysEx() below - split out so
* hardcoded protocol buffers (not driver-specific loaded sound data)
- * can be sent without going through loadData().
+ * can be sent without going through loadData(). Returns a pointer to
+ * the terminating 0xFF byte (matching the disassembly's own si
+ * register value on return), so callers walking a sequence of
+ * consecutive messages can advance past it to find the next one.
*/
- void sendSysExData(const byte *pData);
+ const byte *sendSysExData(const byte *pData);
+
+ /** sendSysExData() for a block already in this driver's own loaded sound data. */
+ const byte *sendSysEx(int offset);
/**
- * sendSysExData() for a block already in this driver's own loaded
- * sound data. Matches sendSysEx exactly (same algorithm as the
- * confirmed Rex Nebular RSound::sendSysEx()).
+ * Matches sendSysExSequence: repeatedly calls sendSysEx(), starting
+ * from this driver's own command0_array (_sysExOffset) and advancing
+ * past each message's terminating 0xFF to the start of the next one,
+ * until an empty message (two consecutive 0xFF bytes) marks the end
+ * of the table. Called once from the constructor (matching
+ * initDeviceOnce) - the disassembly's _deviceInitialized guard flag
+ * isn't needed since nothing else ever calls this again.
*/
- void sendSysEx(int offset);
+ void sendSysExSequence();
/**
* TENTATIVE: matches sub_102BE - a nested loop (4 outer x 32 inner
More information about the Scummvm-git-logs
mailing list