[Scummvm-git-logs] scummvm master -> b6fdfa0e2e422a90b46cb9ee5c7e641fb476dc65
neuromancer
noreply at scummvm.org
Wed Jun 3 13:56:44 UTC 2026
This automated email contains information about 3 new commits which have been
pushed to the 'scummvm' repo located at https://api.github.com/repos/scummvm/scummvm .
Summary:
7a5821d116 SCUMM: RA2: missing line in chapter titles
a53dad284d SCUMM: RA2: refined controls for level 5
b6fdfa0e2e SCUMM: RA2: correctly decode audio tracks on 22hz
Commit: 7a5821d1160dc5752854db2d931e782a6c3fb770
https://github.com/scummvm/scummvm/commit/7a5821d1160dc5752854db2d931e782a6c3fb770
Author: neuromancer (gustavo.grieco at gmail.com)
Date: 2026-06-03T14:39:18+02:00
Commit Message:
SCUMM: RA2: missing line in chapter titles
Changed paths:
engines/scumm/insane/rebel2/render.cpp
diff --git a/engines/scumm/insane/rebel2/render.cpp b/engines/scumm/insane/rebel2/render.cpp
index 5724492124b..db4780badeb 100644
--- a/engines/scumm/insane/rebel2/render.cpp
+++ b/engines/scumm/insane/rebel2/render.cpp
@@ -2739,16 +2739,26 @@ void InsaneRebel2::renderTextOverlay(byte *renderBitmap, int pitch, int width, i
return fc == -2;
};
- // The TRS parser joins multi-line strings with spaces (stripping \n//),
- // so " ^f" marks where a line break was in the original TRS file.
// Split into lines, then render each centered at textX (FUN_004341a0).
+ // Older RA2 text loading joined multi-line strings with spaces, leaving
+ // " ^f" as the separator; current TRES loading preserves real newlines.
Common::Array<Common::String> lines;
{
Common::String cur;
const char *s = text;
while (*s) {
+ if (*s == '\n' || *s == '\r') {
+ if (!cur.empty())
+ lines.push_back(cur);
+ cur.clear();
+ if (*s == '\r' && s[1] == '\n')
+ s++;
+ s++;
+ continue;
+ }
if (*s == ' ' && s[1] == '^' && s[2] == 'f') {
- lines.push_back(cur);
+ if (!cur.empty())
+ lines.push_back(cur);
cur.clear();
s++; // skip the space, keep ^f for the next line
continue;
Commit: a53dad284d71c190f4ab548e37e49ff2a30cbf65
https://github.com/scummvm/scummvm/commit/a53dad284d71c190f4ab548e37e49ff2a30cbf65
Author: neuromancer (gustavo.grieco at gmail.com)
Date: 2026-06-03T14:57:17+02:00
Commit Message:
SCUMM: RA2: refined controls for level 5
Changed paths:
engines/scumm/insane/rebel2/rebel.cpp
diff --git a/engines/scumm/insane/rebel2/rebel.cpp b/engines/scumm/insane/rebel2/rebel.cpp
index eef134ae7aa..080f47e9165 100644
--- a/engines/scumm/insane/rebel2/rebel.cpp
+++ b/engines/scumm/insane/rebel2/rebel.cpp
@@ -55,6 +55,10 @@ const int kRA2MenuAxisThreshold = Common::JOYAXIS_MAX / 5;
const uint32 kRA2MenuGamepadNavigationDebounceMs = 250;
const uint32 kRA2MenuGamepadMouseSuppressMs = 250;
+bool rebel2UsesRelativeGamepadAim(int selectedLevel) {
+ return selectedLevel == 1 || selectedLevel == 5;
+}
+
bool isRebel2RawMenuAxis(int axis) {
return axis == Common::JOYSTICK_AXIS_LEFT_STICK_X ||
axis == Common::JOYSTICK_AXIS_LEFT_STICK_Y ||
@@ -618,12 +622,12 @@ bool InsaneRebel2::notifyEvent(const Common::Event &event) {
// kScummActionInsaneAttack action, not the pointer, so this does not affect shots.
// A genuine mouse/touch motion (nonzero relative delta) normally hands control
// back; handler 0x26 keeps ownership until its gamepad reticle returns to center,
- // except for Level 1's relative gamepad aiming where the reticle deliberately holds.
+ // except for relative gamepad aiming levels where the reticle deliberately holds.
if (_gamepadAimActive && _gameState == kStateGameplay && !_menuInputActive) {
switch (event.type) {
case Common::EVENT_MOUSEMOVE:
if (event.relMouse.x != 0 || event.relMouse.y != 0) {
- if (_rebelHandler == 0x26 && _selectedLevel != 1)
+ if (_rebelHandler == 0x26 && !rebel2UsesRelativeGamepadAim(_selectedLevel))
return true;
_gamepadAimActive = false; // real pointer motion takes over
break;
@@ -1636,7 +1640,7 @@ Common::Point InsaneRebel2::getGameplayAimPoint() {
// Apply the user's configured analog deadzone so a resting stick reports no
// motion. Mirrors RA1's applyRebel1AnalogDeadzone (iact.cpp).
-static inline int16 applyRebel2AnalogDeadzone(int16 axisValue) {
+int16 applyRebel2AnalogDeadzone(int16 axisValue) {
const int deadZone = MAX(0, ConfMan.getInt("joystick_deadzone")) * 1000;
return (ABS((int)axisValue) <= deadZone) ? 0 : axisValue;
}
@@ -1659,8 +1663,8 @@ void InsaneRebel2::updateGameplayAimFromGamepad() {
int deltaY = 0;
bool activeGamepadAim = false;
- if (_rebelHandler == 0x26 && _selectedLevel == 1) {
- // Level 1 plays best with the older mouse-like gamepad behavior from
+ if (_rebelHandler == 0x26 && rebel2UsesRelativeGamepadAim(_selectedLevel)) {
+ // Levels 1 and 5 play best with the older mouse-like gamepad behavior from
// ec305dee371/0025c4e1086: pan the reticle directly and leave it where
// the player releases the stick. Later handler 0x26 levels keep the
// original-style centered mapping for obstacle avoidance.
Commit: b6fdfa0e2e422a90b46cb9ee5c7e641fb476dc65
https://github.com/scummvm/scummvm/commit/b6fdfa0e2e422a90b46cb9ee5c7e641fb476dc65
Author: neuromancer (gustavo.grieco at gmail.com)
Date: 2026-06-03T15:56:25+02:00
Commit Message:
SCUMM: RA2: correctly decode audio tracks on 22hz
Changed paths:
engines/scumm/insane/rebel/rebel_audio.cpp
engines/scumm/insane/rebel/rebel_audio.h
engines/scumm/insane/rebel2/rebel.cpp
engines/scumm/smush/rebel/smush_player_ra2.cpp
diff --git a/engines/scumm/insane/rebel/rebel_audio.cpp b/engines/scumm/insane/rebel/rebel_audio.cpp
index 07204d4806d..6c1f85d4bf2 100644
--- a/engines/scumm/insane/rebel/rebel_audio.cpp
+++ b/engines/scumm/insane/rebel/rebel_audio.cpp
@@ -61,10 +61,12 @@ void RebelAudio::terminate() {
}
}
-void RebelAudio::queueData(int trackIdx, const uint8 *data, int32 size, int volume, int pan) {
+void RebelAudio::queueData(int trackIdx, const uint8 *data, int32 size, int volume, int pan, int sampleRate) {
if (!_vm || trackIdx < 0 || trackIdx >= kMaxTracks || size <= 0 || !data)
return;
+ const int sourceRate = sampleRate > 0 ? sampleRate : _sampleRate;
+
if (!_streams[trackIdx]) {
debug(1, "RebelAudio: Creating audio stream for track %d at %d Hz", trackIdx, _sampleRate);
_streams[trackIdx] = Audio::makeQueuingAudioStream(_sampleRate, false);
@@ -74,12 +76,29 @@ void RebelAudio::queueData(int trackIdx, const uint8 *data, int32 size, int volu
DisposeAfterUse::NO);
}
- byte *audioCopy = (byte *)malloc(size);
+ int32 queueSize = size;
+ if (sourceRate != _sampleRate) {
+ queueSize = ((int64)size * _sampleRate + sourceRate / 2) / sourceRate;
+ if (queueSize <= 0)
+ queueSize = 1;
+ }
+
+ byte *audioCopy = (byte *)malloc(queueSize);
if (!audioCopy)
return;
- memcpy(audioCopy, data, size);
- _streams[trackIdx]->queueBuffer(audioCopy, size, DisposeAfterUse::YES, Audio::FLAG_UNSIGNED);
+ if (sourceRate == _sampleRate) {
+ memcpy(audioCopy, data, queueSize);
+ } else {
+ for (int32 i = 0; i < queueSize; i++) {
+ int32 srcPos = ((int64)i * sourceRate) / _sampleRate;
+ if (srcPos >= size)
+ srcPos = size - 1;
+ audioCopy[i] = data[srcPos];
+ }
+ }
+
+ _streams[trackIdx]->queueBuffer(audioCopy, queueSize, DisposeAfterUse::YES, Audio::FLAG_UNSIGNED);
const int scaledVolume = (volume * Audio::Mixer::kMaxChannelVolume) / 127;
const int scaledPan = (pan * 127) / 128;
@@ -210,7 +229,7 @@ bool RebelAudio::processAudioCodes(SmushPlayer *player, int idx, int32 &tmpFeedS
buf = player->_smushDispatch[idx].headerPtr;
player->_smushDispatch[idx].audioRemaining = READ_BE_UINT32(buf + 2);
player->_smushDispatch[idx].currentOffset = READ_BE_UINT32(buf + 6);
- player->_smushDispatch[idx].sampleRate = player->_smushAudioSampleRate;
+ player->_smushDispatch[idx].sampleRate = READ_BE_UINT32(buf + 10);
player->_smushDispatch[idx].headerPtr += player->_smushDispatch[idx].headerPtr[1] + 2;
if (player->_smushDispatch[idx].audioRemaining < player->_smushTracks[idx].availableSize + (player->_smushTracks[idx].availableSize >= player->_smushTracks[idx].sdatSize ? 0 : 15000) - player->_smushTracks[idx].dataSize) {
@@ -240,7 +259,7 @@ bool RebelAudio::processAudioCodes(SmushPlayer *player, int idx, int32 &tmpFeedS
if (player->_smushDispatch[idx].currentOffset > player->_smushDispatch[idx].audioLength)
player->_smushDispatch[idx].currentOffset = player->_smushDispatch[idx].audioLength;
- player->_smushDispatch[idx].sampleRate = player->_smushAudioSampleRate;
+ player->_smushDispatch[idx].sampleRate = READ_BE_UINT32(buf + 10);
player->_smushDispatch[idx].audioLength -= player->_smushDispatch[idx].currentOffset;
player->_smushDispatch[idx].elapsedAudio += player->_smushDispatch[idx].currentOffset;
@@ -349,7 +368,8 @@ void RebelAudio::processFrame(SmushPlayer *player, int16 feedSize) {
int32 offset = dispatch.audioRemaining % dispatch.dataSize;
if (dispatch.sampleRate > 0 && player->_smushAudioSampleRate > 0) {
- int32 maxFrames = dispatch.sampleRate * tmpFeedSize / player->_smushAudioSampleRate;
+ int32 maxFrames = ((int64)dispatch.sampleRate * tmpFeedSize +
+ player->_smushAudioSampleRate - 1) / player->_smushAudioSampleRate;
if (mixInFrameCount > maxFrames)
mixInFrameCount = maxFrames;
}
@@ -370,13 +390,14 @@ void RebelAudio::processFrame(SmushPlayer *player, int16 feedSize) {
break;
track.state = TRK_STATE_PLAYING;
- queueData(i, &dispatch.dataBuf[offset], mixInFrameCount, mixVolume, track.pan);
+ queueData(i, &dispatch.dataBuf[offset], mixInFrameCount, mixVolume, track.pan, dispatch.sampleRate);
dispatch.currentOffset -= mixInFrameCount;
dispatch.audioRemaining += mixInFrameCount;
if (dispatch.sampleRate > 0) {
- int32 consumedFeed = mixInFrameCount * player->_smushAudioSampleRate / dispatch.sampleRate;
+ int32 consumedFeed = ((int64)mixInFrameCount * player->_smushAudioSampleRate +
+ dispatch.sampleRate - 1) / dispatch.sampleRate;
tmpFeedSize -= consumedFeed;
} else {
tmpFeedSize -= mixInFrameCount;
diff --git a/engines/scumm/insane/rebel/rebel_audio.h b/engines/scumm/insane/rebel/rebel_audio.h
index 10e0548bf71..a91ef4f28dc 100644
--- a/engines/scumm/insane/rebel/rebel_audio.h
+++ b/engines/scumm/insane/rebel/rebel_audio.h
@@ -42,7 +42,7 @@ public:
void terminate();
int sampleRate() const { return _sampleRate; }
- void queueData(int trackIdx, const uint8 *data, int32 size, int volume, int pan);
+ void queueData(int trackIdx, const uint8 *data, int32 size, int volume, int pan, int sampleRate = 0);
void processFrame(SmushPlayer *player, int16 feedSize);
private:
diff --git a/engines/scumm/insane/rebel2/rebel.cpp b/engines/scumm/insane/rebel2/rebel.cpp
index 080f47e9165..0585d558df7 100644
--- a/engines/scumm/insane/rebel2/rebel.cpp
+++ b/engines/scumm/insane/rebel2/rebel.cpp
@@ -420,8 +420,9 @@ InsaneRebel2::InsaneRebel2(ScummEngine_v7 *scumm) {
_hudOverlayNut = nullptr; // DAT_0047fe78 - Primary HUD overlay (GRD files, animated)
_hudOverlay2Nut = nullptr; // DAT_0047fe80 - Secondary HUD overlay
- // Initialize audio system for RA2 (since we don't use iMUSE)
- initAudio(11025); // RA2 audio is 11025 Hz, not 22050 Hz
+ // Initialize audio system for RA2 (since we don't use iMUSE).
+ // Individual SMUSH audio blocks carry their own source rate.
+ initAudio(11025);
// Initialize and load sound effects (SYSTM/*.SAD files)
for (i = 0; i < kRA2NumSfx; i++) {
diff --git a/engines/scumm/smush/rebel/smush_player_ra2.cpp b/engines/scumm/smush/rebel/smush_player_ra2.cpp
index 58d1c3fdf18..232ab3d9c92 100644
--- a/engines/scumm/smush/rebel/smush_player_ra2.cpp
+++ b/engines/scumm/smush/rebel/smush_player_ra2.cpp
@@ -772,8 +772,8 @@ void SmushPlayerRebel2::ra2HandleGost(int32 subSize, Common::SeekableReadStream
* RA2 per-frame audio processing.
*/
void SmushPlayerRebel2::handleGameParseNextFrame() {
- // Call processDispatches directly since RA2 has no iMUSE
- // 11025 Hz / 12 fps = ~918 samples per frame
+ // Call processDispatches directly since RA2 has no iMUSE.
+ // This is the mixer cadence; SAUD opcodes provide per-block source rates.
processDispatches(_smushAudioSampleRate / 12);
}
More information about the Scummvm-git-logs
mailing list