[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