[Scummvm-git-logs] scummvm master -> cd502d62c41fd6680311fcce23afe2e18238477a

neuromancer noreply at scummvm.org
Tue Mar 31 17:20:37 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:
4b842f5fed FREESCAPE: better parsing for eclipse2 c64
a5b5303d6f FREESCAPE: allow to move diagonally pressing more than one key
cd502d62c4 FREESCAPE: implement sound in eclipse c64


Commit: 4b842f5feda15ed99578aef103ff18571553ead0
    https://github.com/scummvm/scummvm/commit/4b842f5feda15ed99578aef103ff18571553ead0
Author: neuromancer (gustavo.grieco at gmail.com)
Date: 2026-03-31T19:20:23+02:00

Commit Message:
FREESCAPE: better parsing for eclipse2 c64

Changed paths:
    engines/freescape/games/eclipse/c64.cpp
    engines/freescape/games/eclipse/eclipse.cpp


diff --git a/engines/freescape/games/eclipse/c64.cpp b/engines/freescape/games/eclipse/c64.cpp
index cded7fcc8a8..6e969cbc0cb 100644
--- a/engines/freescape/games/eclipse/c64.cpp
+++ b/engines/freescape/games/eclipse/c64.cpp
@@ -50,11 +50,11 @@ void EclipseEngine::loadAssetsC64FullGame() {
 		// size should be the size of the decompressed data
 		Common::MemoryReadStream dfile(_extraBuffer, size, DisposeAfterUse::NO);
 
-		loadMessagesFixedSize(&dfile, 0x1d84, 16, 30);
+		loadMessagesFixedSize(&dfile, 0x1d84, 16, isEclipse2() ? 34 : 30);
 		loadFonts(&dfile, 0xc3e);
 		load8bitBinary(&dfile, 0x9a3e, 16);
 	} else if (_variant & GF_C64_DISC) {
-		loadMessagesFixedSize(&file, 0x1534, 16, 30);
+		loadMessagesFixedSize(&file, isEclipse2() ? 0x1538 : 0x1534, 16, isEclipse2() ? 34 : 30);
 		loadFonts(&file, 0x3f2);
 		if (isEclipse2())
 			load8bitBinary(&file, 0x7ac4, 16);
@@ -85,16 +85,45 @@ void EclipseEngine::loadAssetsC64FullGame() {
 	for (auto &it : _indicators)
 		it->convertToInPlace(_gfx->_texturePixelFormat);
 
-	Common::File musicFile;
-	musicFile.open("totec1.prg");
-	if (musicFile.isOpen()) {
-		uint16 loadAddress = musicFile.readUint16LE();
-		if (loadAddress == 0x0410) {
-			_c64MusicData.resize(musicFile.size() - 2);
-			musicFile.read(_c64MusicData.data(), _c64MusicData.size());
+	if (isEclipse2()) {
+		// Eclipse 2 has music embedded in the game data file.
+		// Both disc and tape versions contain the same music engine and data.
+		if (_variant & GF_C64_DISC) {
+			// Disc data file starts at load address 0x0410, same as totec1.prg
+			file.close();
+			file.open("totaleclipse2.c64.data");
+			if (file.isOpen()) {
+				uint16 loadAddress = file.readUint16LE();
+				if (loadAddress == 0x0410) {
+					_c64MusicData.resize(file.size() - 2);
+					file.read(_c64MusicData.data(), _c64MusicData.size());
+					delete _playerC64Music;
+					_playerC64Music = new EclipseC64MusicPlayer(_c64MusicData);
+				}
+			}
+		} else if ((_variant & GF_C64_TAPE) && _extraBuffer) {
+			// Tape decompressed data has music at a 0x0C3F offset from disc addresses.
+			// The music player expects data indexed from load address 0x0410.
+			// Remap: musicData[i] = decompressed[i + 0x084E]
+			static const int kTapeMusicShift = 0x084E;
+			static const int kMusicRegionSize = 0x1100; // covers 0x0410..0x14FF
+			_c64MusicData.resize(kMusicRegionSize);
+			memcpy(_c64MusicData.data(), _extraBuffer + kTapeMusicShift, kMusicRegionSize);
 			delete _playerC64Music;
 			_playerC64Music = new EclipseC64MusicPlayer(_c64MusicData);
 		}
+	} else {
+		Common::File musicFile;
+		musicFile.open("totec1.prg");
+		if (musicFile.isOpen()) {
+			uint16 loadAddress = musicFile.readUint16LE();
+			if (loadAddress == 0x0410) {
+				_c64MusicData.resize(musicFile.size() - 2);
+				musicFile.read(_c64MusicData.data(), _c64MusicData.size());
+				delete _playerC64Music;
+				_playerC64Music = new EclipseC64MusicPlayer(_c64MusicData);
+			}
+		}
 	}
 }
 
diff --git a/engines/freescape/games/eclipse/eclipse.cpp b/engines/freescape/games/eclipse/eclipse.cpp
index a5bdef6b4fa..14edb5b6b3c 100644
--- a/engines/freescape/games/eclipse/eclipse.cpp
+++ b/engines/freescape/games/eclipse/eclipse.cpp
@@ -524,8 +524,15 @@ void EclipseEngine::drawInfoMenu() {
 					_eventManager->purgeKeyboardEvents();
 					saveGameDialog();
 					_gfx->setViewport(_viewArea);
-				} else if (isDOS() && event.customType == kActionToggleSound) {
-					playSound(_soundIndexMenu, false, _soundFxHandle);
+				} else if (event.customType == kActionToggleSound) {
+					if (isC64() && _playerC64Music) {
+						if (_playerC64Music->isPlaying())
+							_playerC64Music->stopMusic();
+						else
+							_playerC64Music->startMusic();
+					} else {
+						playSound(_soundIndexMenu, false, _soundFxHandle);
+					}
 				} else if ((isDOS() || isCPC() || isSpectrum()) && event.customType == kActionEscape) {
 					_forceEndGame = true;
 					cont = false;


Commit: a5b5303d6fc06445016d62e6bdac9df974c9a101
    https://github.com/scummvm/scummvm/commit/a5b5303d6fc06445016d62e6bdac9df974c9a101
Author: neuromancer (gustavo.grieco at gmail.com)
Date: 2026-03-31T19:20:23+02:00

Commit Message:
FREESCAPE: allow to move diagonally pressing more than one key

Changed paths:
    engines/freescape/movement.cpp


diff --git a/engines/freescape/movement.cpp b/engines/freescape/movement.cpp
index a6fe607b099..1773634a6a5 100644
--- a/engines/freescape/movement.cpp
+++ b/engines/freescape/movement.cpp
@@ -486,11 +486,11 @@ void FreescapeEngine::updatePlayerMovementSmooth(float deltaTime) {
 
 	if (_moveForward)
 		moveDir += _cameraFront;
-	else if (_moveBackward)
+	if (_moveBackward)
 		moveDir -= _cameraFront;
-	else if (_strafeLeft)
+	if (_strafeLeft)
 		moveDir += _cameraRight;
-	else if (_strafeRight)
+	if (_strafeRight)
 		moveDir -= _cameraRight;
 
 	if (_flyMode) {


Commit: cd502d62c41fd6680311fcce23afe2e18238477a
    https://github.com/scummvm/scummvm/commit/cd502d62c41fd6680311fcce23afe2e18238477a
Author: neuromancer (gustavo.grieco at gmail.com)
Date: 2026-03-31T19:20:23+02:00

Commit Message:
FREESCAPE: implement sound in eclipse c64

Changed paths:
  A engines/freescape/games/eclipse/c64.sfx.cpp
  A engines/freescape/games/eclipse/c64.sfx.h
  A engines/freescape/sid.h
    engines/freescape/games/dark/c64.sfx.cpp
    engines/freescape/games/dark/c64.sfx.h
    engines/freescape/games/driller/c64.sfx.h
    engines/freescape/games/eclipse/c64.cpp
    engines/freescape/games/eclipse/eclipse.cpp
    engines/freescape/games/eclipse/eclipse.h
    engines/freescape/module.mk


diff --git a/engines/freescape/games/dark/c64.sfx.cpp b/engines/freescape/games/dark/c64.sfx.cpp
index 9ba591e692b..06e22df9b20 100644
--- a/engines/freescape/games/dark/c64.sfx.cpp
+++ b/engines/freescape/games/dark/c64.sfx.cpp
@@ -30,7 +30,7 @@ namespace Freescape {
 // 25 SFX entries extracted from dark2.prg at $C802 (address $C802-$CBEA).
 // Each entry is 40 bytes in the original 6502 format.
 // See SOUND_ANALYSIS.md for full documentation.
-static const DarkSideSFXData kDarkSideSFXData[25] = {
+static const C64SFXData kC64SFXData[25] = {
 	// SFX #1: Shoot (Noise, high→silence)
 	{2, 1, 0,
 	 {0x00, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
@@ -244,7 +244,7 @@ void DarkSideC64SFXPlayer::initSID() {
 
 	for (int i = 0; i < 0x19; i++)
 		sidWrite(i, 0);
-	sidWrite(kDarkSIDVolume, 0x0F);
+	sidWrite(kSIDVolume, 0x0F);
 
 	_sid->start(new Common::Functor0Mem<void, DarkSideC64SFXPlayer>(this, &DarkSideC64SFXPlayer::onTimer), 50);
 }
@@ -272,7 +272,7 @@ void DarkSideC64SFXPlayer::stopAllSfx() {
 void DarkSideC64SFXPlayer::silenceV1() {
 	// $CE5C: zero V1 SID registers ($D400-$D406), clear state
 	_state = 0;
-	for (int i = kDarkSIDV1FreqLo; i <= kDarkSIDV1SR; i++)
+	for (int i = kSIDV1FreqLo; i <= kSIDV1SR; i++)
 		sidWrite(i, 0);
 }
 
@@ -281,7 +281,7 @@ void DarkSideC64SFXPlayer::silenceAll() {
 	_state = 0;
 	for (int i = 0; i <= 0x13; i++)
 		sidWrite(i, 0);
-	sidWrite(kDarkSIDVolume, 0x0F);
+	sidWrite(kSIDVolume, 0x0F);
 }
 
 // Signed 32÷16 division matching the original $2122 routine.
@@ -293,7 +293,7 @@ static int16 signedDivide(int16 dividend, uint8 divisor) {
 }
 
 void DarkSideC64SFXPlayer::setupSfx(int index) {
-	const DarkSideSFXData &sfx = kDarkSideSFXData[index];
+	const C64SFXData &sfx = kC64SFXData[index];
 
 	debugC(1, kFreescapeDebugMedia, "Dark Side C64 SFX: setup #%d (notes=%d repeat=%d wf=$%02X)",
 		   index + 1, sfx.numNotes, sfx.repeatCount, sfx.waveform);
@@ -302,13 +302,13 @@ void DarkSideC64SFXPlayer::setupSfx(int index) {
 	silenceV1();
 
 	// Gate off
-	sidWrite(kDarkSIDV1Ctrl, 0);
+	sidWrite(kSIDV1Ctrl, 0);
 
 	// Load SID registers from descriptor
-	sidWrite(kDarkSIDV1PwLo, sfx.pwLo);
-	sidWrite(kDarkSIDV1PwHi, sfx.pwHi);
-	sidWrite(kDarkSIDV1AD, sfx.attackDecay);
-	sidWrite(kDarkSIDV1SR, sfx.sustainRelease);
+	sidWrite(kSIDV1PwLo, sfx.pwLo);
+	sidWrite(kSIDV1PwHi, sfx.pwHi);
+	sidWrite(kSIDV1AD, sfx.attackDecay);
+	sidWrite(kSIDV1SR, sfx.sustainRelease);
 
 	// Store working copies
 	_numNotes = sfx.numNotes;
@@ -391,14 +391,14 @@ void DarkSideC64SFXPlayer::tickStart() {
 	uint16 freq = (uint16)_startFreqs[0];
 	_curFreqLo = freq & 0xFF;
 	_curFreqHi = (freq >> 8) & 0xFF;
-	sidWrite(kDarkSIDV1FreqLo, _curFreqLo);
-	sidWrite(kDarkSIDV1FreqHi, _curFreqHi);
+	sidWrite(kSIDV1FreqLo, _curFreqLo);
+	sidWrite(kSIDV1FreqHi, _curFreqHi);
 
 	// Load first duration
 	_durCounter = _durCopies[0];
 
 	// Gate on: waveform | 0x01
-	sidWrite(kDarkSIDV1Ctrl, _waveform | 0x01);
+	sidWrite(kSIDV1Ctrl, _waveform | 0x01);
 
 	// Transition to slide state
 	_state = 2;
@@ -422,8 +422,8 @@ void DarkSideC64SFXPlayer::tickSlide() {
 	_curFreqLo = freq & 0xFF;
 	_curFreqHi = (freq >> 8) & 0xFF;
 
-	sidWrite(kDarkSIDV1FreqLo, _curFreqLo);
-	sidWrite(kDarkSIDV1FreqHi, _curFreqHi);
+	sidWrite(kSIDV1FreqLo, _curFreqLo);
+	sidWrite(kSIDV1FreqHi, _curFreqHi);
 
 	// Decrement duration
 	_durCounter--;
@@ -445,8 +445,8 @@ void DarkSideC64SFXPlayer::tickSlide() {
 		freq = (uint16)_startFreqs[noteIdx];
 		_curFreqLo = freq & 0xFF;
 		_curFreqHi = (freq >> 8) & 0xFF;
-		sidWrite(kDarkSIDV1FreqLo, _curFreqLo);
-		sidWrite(kDarkSIDV1FreqHi, _curFreqHi);
+		sidWrite(kSIDV1FreqLo, _curFreqLo);
+		sidWrite(kSIDV1FreqHi, _curFreqHi);
 		return;
 	}
 
@@ -463,8 +463,8 @@ void DarkSideC64SFXPlayer::tickSlide() {
 		freq = (uint16)_startFreqs[0];
 		_curFreqLo = freq & 0xFF;
 		_curFreqHi = (freq >> 8) & 0xFF;
-		sidWrite(kDarkSIDV1FreqLo, _curFreqLo);
-		sidWrite(kDarkSIDV1FreqHi, _curFreqHi);
+		sidWrite(kSIDV1FreqLo, _curFreqLo);
+		sidWrite(kSIDV1FreqHi, _curFreqHi);
 
 		_durCounter = _durCopies[0];
 		return;
@@ -472,7 +472,7 @@ void DarkSideC64SFXPlayer::tickSlide() {
 
 	// Sequence finished: gate off
 	_state = 0;
-	sidWrite(kDarkSIDV1Ctrl, _waveform & 0xFE);  // Clear gate bit
+	sidWrite(kSIDV1Ctrl, _waveform & 0xFE);  // Clear gate bit
 }
 
 } // End of namespace Freescape
diff --git a/engines/freescape/games/dark/c64.sfx.h b/engines/freescape/games/dark/c64.sfx.h
index 58ec8fe9172..e57e1b42c7d 100644
--- a/engines/freescape/games/dark/c64.sfx.h
+++ b/engines/freescape/games/dark/c64.sfx.h
@@ -23,58 +23,10 @@
 #define FREESCAPE_DARK_C64_SFX_H
 
 #include "audio/sid.h"
+#include "freescape/sid.h"
 
 namespace Freescape {
 
-// SID register offsets (shared with Driller SFX player)
-enum DarkSIDRegs {
-	kDarkSIDV1FreqLo  = 0x00,
-	kDarkSIDV1FreqHi  = 0x01,
-	kDarkSIDV1PwLo    = 0x02,
-	kDarkSIDV1PwHi    = 0x03,
-	kDarkSIDV1Ctrl    = 0x04,
-	kDarkSIDV1AD      = 0x05,
-	kDarkSIDV1SR      = 0x06,
-
-	kDarkSIDV2FreqLo  = 0x07,
-	kDarkSIDV2FreqHi  = 0x08,
-	kDarkSIDV2PwLo    = 0x09,
-	kDarkSIDV2PwHi    = 0x0A,
-	kDarkSIDV2Ctrl    = 0x0B,
-	kDarkSIDV2AD      = 0x0C,
-	kDarkSIDV2SR      = 0x0D,
-
-	kDarkSIDV3FreqLo  = 0x0E,
-	kDarkSIDV3FreqHi  = 0x0F,
-	kDarkSIDV3PwLo    = 0x10,
-	kDarkSIDV3PwHi    = 0x11,
-	kDarkSIDV3Ctrl    = 0x12,
-	kDarkSIDV3AD      = 0x13,
-	kDarkSIDV3SR      = 0x14,
-
-	kDarkSIDFilterLo  = 0x15,
-	kDarkSIDFilterHi  = 0x16,
-	kDarkSIDFilterCtrl = 0x17,
-	kDarkSIDVolume    = 0x18
-};
-
-// 40-byte SFX descriptor from the data table at $C802 in dark2.prg
-struct DarkSideSFXData {
-	uint8 numNotes;        // Number of frequency transitions
-	uint8 repeatCount;     // Times to replay the full sequence
-	uint8 reserved;
-	uint8 freqWaypoints[20]; // Up to 10 frequency waypoints (lo,hi pairs)
-	uint8 padding;         // Offset 23
-	uint8 durations[9];    // Duration for each transition (in speed units)
-	uint8 speed;           // Frames per speed unit
-	uint8 padding2;        // Offset 34
-	uint8 pwLo;            // Pulse Width low byte
-	uint8 pwHi;            // Pulse Width high byte
-	uint8 waveform;        // SID control register (gate bit managed separately)
-	uint8 attackDecay;     // SID Attack/Decay register
-	uint8 sustainRelease;  // SID Sustain/Release register
-};
-
 class DarkSideC64SFXPlayer {
 public:
 	DarkSideC64SFXPlayer();
diff --git a/engines/freescape/games/driller/c64.sfx.h b/engines/freescape/games/driller/c64.sfx.h
index e63b4201323..de66d3aa485 100644
--- a/engines/freescape/games/driller/c64.sfx.h
+++ b/engines/freescape/games/driller/c64.sfx.h
@@ -23,41 +23,10 @@
 #define FREESCAPE_DRILLER_C64_SFX_H
 
 #include "audio/sid.h"
+#include "freescape/sid.h"
 
 namespace Freescape {
 
-// SID register offsets
-enum SIDRegs {
-	kSIDV1FreqLo  = 0x00,
-	kSIDV1FreqHi  = 0x01,
-	kSIDV1PwLo    = 0x02,
-	kSIDV1PwHi    = 0x03,
-	kSIDV1Ctrl    = 0x04,
-	kSIDV1AD      = 0x05,
-	kSIDV1SR      = 0x06,
-
-	kSIDV2FreqLo  = 0x07,
-	kSIDV2FreqHi  = 0x08,
-	kSIDV2PwLo    = 0x09,
-	kSIDV2PwHi    = 0x0A,
-	kSIDV2Ctrl    = 0x0B,
-	kSIDV2AD      = 0x0C,
-	kSIDV2SR      = 0x0D,
-
-	kSIDV3FreqLo  = 0x0E,
-	kSIDV3FreqHi  = 0x0F,
-	kSIDV3PwLo    = 0x10,
-	kSIDV3PwHi    = 0x11,
-	kSIDV3Ctrl    = 0x12,
-	kSIDV3AD      = 0x13,
-	kSIDV3SR      = 0x14,
-
-	kSIDFilterLo  = 0x15,
-	kSIDFilterHi  = 0x16,
-	kSIDFilterCtrl = 0x17,
-	kSIDVolume    = 0x18
-};
-
 class DrillerC64SFXPlayer {
 public:
 	DrillerC64SFXPlayer();
diff --git a/engines/freescape/games/eclipse/c64.cpp b/engines/freescape/games/eclipse/c64.cpp
index 6e969cbc0cb..59e954280fb 100644
--- a/engines/freescape/games/eclipse/c64.cpp
+++ b/engines/freescape/games/eclipse/c64.cpp
@@ -23,6 +23,7 @@
 
 #include "freescape/freescape.h"
 #include "freescape/games/eclipse/c64.music.h"
+#include "freescape/games/eclipse/c64.sfx.h"
 #include "freescape/games/eclipse/eclipse.h"
 #include "freescape/language/8bitDetokeniser.h"
 
@@ -32,6 +33,24 @@ void EclipseEngine::initC64() {
 	_viewArea = Common::Rect(32, 32, 288, 136);
 
 	_maxEnergy = 35;
+
+	// SFX indices mapped from totec1.prg disassembly (JSR $CB4B call sites)
+	_soundIndexShoot = 1;            // $5F27: opcode $16 destroy handler
+	_soundIndexCollide = 12;         // $4E80/$4F50: deferred via $1549
+	_soundIndexStepDown = 12;        // same as collide (matches CPC pattern)
+	_soundIndexStepUp = 12;          // same as collide (matches CPC pattern)
+	_soundIndexStart = 7;            // $4118: game start after title screen
+	_soundIndexAreaChange = 7;       // $66CF: FCL opcode $12 area change
+	_soundIndexStartFalling = 6;     // $790B: deferred via $1549
+	_soundIndexEndFalling = 8;       // $792D: deferred via $1549
+	_soundIndexFall = 5;             // $7C20/$7C45: death/fall animation
+	_soundIndexNoShield = 5;         // game-over conditions reuse fall sound
+	_soundIndexNoEnergy = -1;
+	_soundIndexFallen = 5;
+	_soundIndexTimeout = 5;
+	_soundIndexForceEndGame = 5;
+	_soundIndexCrushed = 5;
+	_soundIndexMissionComplete = -1;
 }
 
 extern byte kC64Palette[16][3];
@@ -125,6 +144,36 @@ void EclipseEngine::loadAssetsC64FullGame() {
 			}
 		}
 	}
+
+	// Only one SID instance can be active at a time; music is the default.
+	// Create the inactive player first so its SID is destroyed before
+	// the active player's SID is created.
+	_playerC64Sfx = new EclipseC64SFXPlayer();
+	_playerC64Sfx->destroySID();
+}
+
+void EclipseEngine::playSoundC64(int index) {
+	debugC(1, kFreescapeDebugMedia, "Playing Eclipse C64 SFX %d", index);
+	if (_playerC64Sfx && _c64UseSFX)
+		_playerC64Sfx->playSfx(index);
+}
+
+void EclipseEngine::toggleC64Sound() {
+	if (_c64UseSFX) {
+		if (_playerC64Sfx)
+			_playerC64Sfx->destroySID();
+		if (_playerC64Music) {
+			_playerC64Music->initSID();
+			_playerC64Music->startMusic();
+		}
+		_c64UseSFX = false;
+	} else {
+		if (_playerC64Music)
+			_playerC64Music->destroySID();
+		if (_playerC64Sfx)
+			_playerC64Sfx->initSID();
+		_c64UseSFX = true;
+	}
 }
 
 
diff --git a/engines/freescape/games/eclipse/c64.sfx.cpp b/engines/freescape/games/eclipse/c64.sfx.cpp
new file mode 100644
index 00000000000..e16208289af
--- /dev/null
+++ b/engines/freescape/games/eclipse/c64.sfx.cpp
@@ -0,0 +1,410 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "freescape/games/eclipse/c64.sfx.h"
+#include "freescape/freescape.h"
+
+#include "common/debug.h"
+#include "common/textconsole.h"
+
+namespace Freescape {
+
+// 21 SFX entries extracted from totec2.prg at $C802 (address $C802-$CB49).
+// Each entry is 40 bytes. Same descriptor format as Dark Side C64.
+static const C64SFXData kEclipseSFXData[21] = {
+	// SFX #1: Noise, 2 notes, repeat 1
+	{2, 1, 0,
+	 {0x00, 0x44, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, 0,
+	 {4, 0, 0, 0, 0, 0, 0, 0, 0}, 1, 0,
+	 0xEA, 0x01, 0x80, 0x15, 0x30},
+
+	// SFX #2: Pulse, 4 notes, repeat 1
+	{4, 1, 0,
+	 {0x00, 0x24, 0x00, 0x84, 0x00, 0x28, 0x00, 0x80, 0x00, 0x24,
+	  0x00, 0x94, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, 0,
+	 {2, 2, 2, 6, 1, 0, 0, 0, 0}, 1, 0,
+	 0xEA, 0x06, 0x40, 0x19, 0x13},
+
+	// SFX #3: Sawtooth, 2 notes, repeat 1
+	{2, 1, 0,
+	 {0x00, 0x08, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, 0,
+	 {8, 0, 0, 0, 0, 0, 0, 0, 0}, 1, 0,
+	 0x9E, 0x02, 0x20, 0x0C, 0x04},
+
+	// SFX #4: Triangle, 2 notes, repeat 1
+	{2, 1, 0,
+	 {0x00, 0xCC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, 0,
+	 {55, 0, 0, 0, 0, 0, 0, 0, 0}, 1, 0,
+	 0xA0, 0x00, 0x10, 0x1E, 0x11},
+
+	// SFX #5: Noise, 2 notes, repeat 1
+	{2, 1, 0,
+	 {0x00, 0x88, 0x00, 0x00, 0x00, 0x34, 0x00, 0x14, 0x00, 0x30,
+	  0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, 0,
+	 {28, 9, 4, 13, 14, 0, 0, 0, 0}, 1, 0,
+	 0x3A, 0x0D, 0x80, 0x19, 0x10},
+
+	// SFX #6: Triangle, 2 notes, repeat 1
+	{2, 1, 0,
+	 {0x00, 0xCC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, 0,
+	 {55, 0, 0, 0, 0, 0, 0, 0, 0}, 1, 0,
+	 0xA0, 0x00, 0x10, 0x1E, 0x11},
+
+	// SFX #7: Pulse, 3 notes, repeat 4
+	{3, 4, 0,
+	 {0x00, 0x00, 0x00, 0x2C, 0x00, 0x24, 0x00, 0x28, 0x00, 0x58,
+	  0x00, 0x68, 0x00, 0x6C, 0x00, 0x64, 0x00, 0x54, 0x00, 0x3C}, 0,
+	 {3, 1, 7, 7, 4, 5, 14, 8, 3}, 1, 0,
+	 0x62, 0x07, 0x40, 0x6B, 0xD4},
+
+	// SFX #8: Noise, 7 notes, repeat 1
+	{7, 1, 0,
+	 {0x00, 0x00, 0x00, 0x04, 0x00, 0x10, 0x00, 0x30, 0x00, 0x50,
+	  0x00, 0xA0, 0x00, 0xCC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, 0,
+	 {9, 12, 11, 5, 4, 2, 0, 0, 0}, 1, 0,
+	 0x80, 0x02, 0x80, 0x35, 0xF9},
+
+	// SFX #9: Triangle, 2 notes, repeat 5
+	{2, 5, 0,
+	 {0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, 0,
+	 {6, 0, 0, 0, 0, 0, 0, 0, 0}, 2, 0,
+	 0xD0, 0x02, 0x10, 0x19, 0xF7},
+
+	// SFX #10: Noise, 3 notes, repeat 1
+	{3, 1, 0,
+	 {0x00, 0x1C, 0x00, 0x00, 0x00, 0x18, 0x00, 0x7C, 0x00, 0x00,
+	  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, 0,
+	 {4, 7, 2, 21, 0, 0, 0, 0, 0}, 1, 0,
+	 0x38, 0x0F, 0x80, 0x38, 0xFC},
+
+	// SFX #11: Triangle, 4 notes, repeat 1
+	{4, 1, 0,
+	 {0x00, 0x90, 0x00, 0xC0, 0x00, 0x4C, 0x00, 0x4C, 0x00, 0x54,
+	  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, 0,
+	 {7, 10, 6, 8, 0, 0, 0, 0, 0}, 1, 0,
+	 0xC8, 0x00, 0x10, 0x32, 0xF4},
+
+	// SFX #12: Noise, 3 notes, repeat 1
+	{3, 1, 0,
+	 {0x00, 0xD4, 0x00, 0x00, 0x00, 0xD4, 0x00, 0x00, 0x00, 0x00,
+	  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, 0,
+	 {4, 5, 0, 0, 0, 0, 0, 0, 0}, 1, 0,
+	 0xA2, 0x03, 0x80, 0x2A, 0x32},
+
+	// SFX #13: Triangle, 4 notes, repeat 3
+	{4, 3, 0,
+	 {0x00, 0xAC, 0x00, 0x84, 0x00, 0xAC, 0x00, 0x84, 0x00, 0x00,
+	  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, 0,
+	 {4, 2, 5, 0, 0, 0, 0, 0, 0}, 1, 0,
+	 0xAA, 0x05, 0x10, 0x16, 0xF8},
+
+	// SFX #14: Sawtooth, 2 notes, repeat 5
+	{2, 5, 0,
+	 {0x00, 0x34, 0x00, 0x4C, 0x00, 0x50, 0x00, 0x44, 0x00, 0x00,
+	  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, 0,
+	 {7, 4, 4, 0, 0, 0, 0, 0, 0}, 1, 0,
+	 0x90, 0x01, 0x20, 0x33, 0xFA},
+
+	// SFX #15: Noise, 3 notes, repeat 1
+	{3, 1, 0,
+	 {0x00, 0xB8, 0x00, 0xD4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, 0,
+	 {8, 7, 0, 0, 0, 0, 0, 0, 0}, 1, 0,
+	 0xEA, 0x06, 0x80, 0x15, 0xF7},
+
+	// SFX #16: Sawtooth, 5 notes, repeat 1
+	{5, 1, 0,
+	 {0x00, 0x14, 0x00, 0x50, 0x00, 0x98, 0x00, 0xC4, 0x00, 0x94,
+	  0x00, 0xC0, 0x00, 0x34, 0x00, 0x74, 0x00, 0x48, 0x00, 0x88}, 0,
+	 {24, 15, 6, 6, 18, 4, 4, 5, 2}, 1, 3,
+	 0xEA, 0x0B, 0x20, 0x32, 0xF8},
+
+	// SFX #17: Sawtooth, 2 notes, repeat 1
+	{2, 1, 0,
+	 {0x00, 0x00, 0x00, 0x08, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00,
+	  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, 0,
+	 {25, 7, 0, 0, 0, 0, 0, 0, 0}, 4, 0,
+	 0x06, 0x04, 0x20, 0x65, 0xF0},
+
+	// SFX #18: Noise, 3 notes, repeat 1
+	{3, 1, 0,
+	 {0x00, 0x0C, 0x00, 0x0C, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x00,
+	  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, 0,
+	 {2, 6, 0, 0, 0, 0, 0, 0, 0}, 1, 0,
+	 0xB2, 0x02, 0x80, 0x29, 0x11},
+
+	// SFX #19: Pulse, 4 notes, repeat 1
+	{4, 1, 0,
+	 {0x00, 0x08, 0x00, 0x08, 0x00, 0x28, 0x00, 0x60, 0x00, 0x68,
+	  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, 0,
+	 {8, 18, 9, 0, 0, 0, 0, 0, 0}, 2, 0,
+	 0xEE, 0x02, 0x40, 0x4A, 0x11},
+
+	// SFX #20: Pulse, 4 notes, repeat 1
+	{4, 1, 0,
+	 {0x00, 0x00, 0x00, 0x18, 0x00, 0x50, 0x00, 0x94, 0x00, 0x00,
+	  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, 0,
+	 {21, 11, 8, 5, 0, 0, 0, 0, 0}, 2, 0,
+	 0x72, 0x06, 0x40, 0x35, 0xF4},
+
+	// SFX #21: Noise, 2 notes, repeat 1
+	{2, 1, 0,
+	 {0x00, 0x4C, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x00,
+	  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, 0,
+	 {15, 0, 0, 0, 0, 0, 0, 0, 0}, 1, 0,
+	 0x20, 0x0E, 0x80, 0x26, 0x00},
+};
+
+static int16 signedDivide(int16 dividend, uint8 divisor) {
+	if (divisor == 0)
+		return 0;
+	return dividend / (int16)divisor;
+}
+
+EclipseC64SFXPlayer::EclipseC64SFXPlayer()
+	: _sid(nullptr),
+	  _state(0),
+	  _numNotes(0), _repeatCount(0), _waveform(0), _speed(1),
+	  _repeatLeft(0), _notesLeft(0), _freqIndex(0), _durIndex(0),
+	  _durCounter(0), _speedCounter(0),
+	  _curFreqLo(0), _curFreqHi(0) {
+	memset(_startFreqs, 0, sizeof(_startFreqs));
+	memset(_deltas, 0, sizeof(_deltas));
+	memset(_durCopies, 0, sizeof(_durCopies));
+}
+
+EclipseC64SFXPlayer::~EclipseC64SFXPlayer() {
+	destroySID();
+}
+
+void EclipseC64SFXPlayer::destroySID() {
+	if (_sid) {
+		_sid->stop();
+		delete _sid;
+		_sid = nullptr;
+	}
+}
+
+void EclipseC64SFXPlayer::initSID() {
+	if (_sid) {
+		_sid->stop();
+		delete _sid;
+	}
+
+	_sid = SID::Config::create(SID::Config::kSidPAL);
+	if (!_sid || !_sid->init())
+		error("Failed to initialise SID emulator for Eclipse SFX");
+
+	for (int i = 0; i < 0x19; i++)
+		sidWrite(i, 0);
+	sidWrite(kSIDVolume, 0x0F);
+
+	_sid->start(new Common::Functor0Mem<void, EclipseC64SFXPlayer>(this, &EclipseC64SFXPlayer::onTimer), 50);
+}
+
+void EclipseC64SFXPlayer::sidWrite(int reg, uint8 data) {
+	if (_sid) {
+		debugC(4, kFreescapeDebugMedia, "Eclipse SFX SID Write: Reg $%02X = $%02X", reg, data);
+		_sid->writeReg(reg, data);
+	}
+}
+
+void EclipseC64SFXPlayer::onTimer() {
+	sfxTick();
+}
+
+bool EclipseC64SFXPlayer::isSfxActive() const {
+	return _state != 0;
+}
+
+void EclipseC64SFXPlayer::stopAllSfx() {
+	_state = 0;
+	silenceAll();
+}
+
+void EclipseC64SFXPlayer::silenceV1() {
+	_state = 0;
+	for (int i = kSIDV1FreqLo; i <= kSIDV1SR; i++)
+		sidWrite(i, 0);
+}
+
+void EclipseC64SFXPlayer::silenceAll() {
+	_state = 0;
+	for (int i = 0; i <= 0x13; i++)
+		sidWrite(i, 0);
+	sidWrite(kSIDVolume, 0x0F);
+}
+
+void EclipseC64SFXPlayer::setupSfx(int index) {
+	const C64SFXData &sfx = kEclipseSFXData[index];
+
+	debugC(1, kFreescapeDebugMedia, "Eclipse C64 SFX: setup #%d (notes=%d repeat=%d wf=$%02X)",
+		   index + 1, sfx.numNotes, sfx.repeatCount, sfx.waveform);
+
+	silenceV1();
+
+	sidWrite(kSIDV1Ctrl, 0);
+	sidWrite(kSIDV1PwLo, sfx.pwLo);
+	sidWrite(kSIDV1PwHi, sfx.pwHi);
+	sidWrite(kSIDV1AD, sfx.attackDecay);
+	sidWrite(kSIDV1SR, sfx.sustainRelease);
+
+	_numNotes = sfx.numNotes;
+	_repeatCount = sfx.repeatCount;
+	_waveform = sfx.waveform;
+	_speed = sfx.speed;
+
+	int numTransitions = sfx.numNotes;
+	for (int i = 0; i < numTransitions && i < 9; i++) {
+		uint16 freqStart = sfx.freqWaypoints[i * 2] | (sfx.freqWaypoints[i * 2 + 1] << 8);
+		uint16 freqEnd = sfx.freqWaypoints[(i + 1) * 2] | (sfx.freqWaypoints[(i + 1) * 2 + 1] << 8);
+
+		_startFreqs[i] = (int16)freqStart;
+
+		int16 diff = (int16)(freqEnd - freqStart);
+		_deltas[i] = signedDivide(diff, sfx.durations[i]);
+
+		_durCopies[i] = sfx.durations[i];
+
+		debugC(2, kFreescapeDebugMedia, "  Note %d: freq $%04X->$%04X dur=%d delta=%d",
+			   i, freqStart, freqEnd, sfx.durations[i], _deltas[i]);
+	}
+
+	_state = 1;
+}
+
+void EclipseC64SFXPlayer::playSfx(int sfxIndex) {
+	if (sfxIndex < 1 || sfxIndex > 21) {
+		debugC(1, kFreescapeDebugMedia, "Eclipse C64 SFX: invalid index %d", sfxIndex);
+		return;
+	}
+
+	if (_state != 0) {
+		debugC(2, kFreescapeDebugMedia, "Eclipse C64 SFX: busy, dropping #%d", sfxIndex);
+		return;
+	}
+
+	setupSfx(sfxIndex - 1);
+}
+
+void EclipseC64SFXPlayer::sfxTick() {
+	if (_state == 0)
+		return;
+
+	if (_state == 1) {
+		tickStart();
+		return;
+	}
+
+	if (_state == 2) {
+		tickSlide();
+		return;
+	}
+
+	_state = 0;
+}
+
+void EclipseC64SFXPlayer::tickStart() {
+	_repeatLeft = _repeatCount;
+
+	_notesLeft = _numNotes - 1;
+	_freqIndex = 0;
+	_durIndex = 0;
+
+	_speedCounter = _speed;
+
+	uint16 freq = (uint16)_startFreqs[0];
+	_curFreqLo = freq & 0xFF;
+	_curFreqHi = (freq >> 8) & 0xFF;
+	sidWrite(kSIDV1FreqLo, _curFreqLo);
+	sidWrite(kSIDV1FreqHi, _curFreqHi);
+
+	_durCounter = _durCopies[0];
+
+	sidWrite(kSIDV1Ctrl, _waveform | 0x01);
+
+	_state = 2;
+}
+
+void EclipseC64SFXPlayer::tickSlide() {
+	_speedCounter--;
+	if (_speedCounter != 0)
+		return;
+
+	_speedCounter = _speed;
+
+	int noteIdx = _freqIndex / 2;
+	uint16 freq = (_curFreqHi << 8) | _curFreqLo;
+	freq = (uint16)((int16)freq + _deltas[noteIdx]);
+	_curFreqLo = freq & 0xFF;
+	_curFreqHi = (freq >> 8) & 0xFF;
+
+	sidWrite(kSIDV1FreqLo, _curFreqLo);
+	sidWrite(kSIDV1FreqHi, _curFreqHi);
+
+	_durCounter--;
+	if (_durCounter != 0)
+		return;
+
+	_freqIndex += 2;
+	_durIndex++;
+	_notesLeft--;
+
+	if (_notesLeft != 0) {
+		noteIdx = _freqIndex / 2;
+		_durCounter = _durCopies[_durIndex];
+		_speedCounter = _speed;
+
+		freq = (uint16)_startFreqs[noteIdx];
+		_curFreqLo = freq & 0xFF;
+		_curFreqHi = (freq >> 8) & 0xFF;
+		sidWrite(kSIDV1FreqLo, _curFreqLo);
+		sidWrite(kSIDV1FreqHi, _curFreqHi);
+		return;
+	}
+
+	_repeatLeft--;
+	if (_repeatLeft != 0) {
+		_notesLeft = _numNotes - 1;
+		_freqIndex = 0;
+		_durIndex = 0;
+		_speedCounter = _speed;
+
+		freq = (uint16)_startFreqs[0];
+		_curFreqLo = freq & 0xFF;
+		_curFreqHi = (freq >> 8) & 0xFF;
+		sidWrite(kSIDV1FreqLo, _curFreqLo);
+		sidWrite(kSIDV1FreqHi, _curFreqHi);
+
+		_durCounter = _durCopies[0];
+		return;
+	}
+
+	_state = 0;
+	sidWrite(kSIDV1Ctrl, _waveform & 0xFE);
+}
+
+} // End of namespace Freescape
diff --git a/engines/freescape/games/eclipse/c64.sfx.h b/engines/freescape/games/eclipse/c64.sfx.h
new file mode 100644
index 00000000000..24cb414ed20
--- /dev/null
+++ b/engines/freescape/games/eclipse/c64.sfx.h
@@ -0,0 +1,79 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef FREESCAPE_ECLIPSE_C64_SFX_H
+#define FREESCAPE_ECLIPSE_C64_SFX_H
+
+#include "audio/sid.h"
+#include "freescape/sid.h"
+
+namespace Freescape {
+
+class EclipseC64SFXPlayer {
+public:
+	EclipseC64SFXPlayer();
+	~EclipseC64SFXPlayer();
+
+	void playSfx(int sfxIndex);
+	void sfxTick();
+	void stopAllSfx();
+
+	bool isSfxActive() const;
+	void initSID();
+	void destroySID();
+
+private:
+	SID::SID *_sid;
+
+	void sidWrite(int reg, uint8 data);
+	void onTimer();
+
+	uint8 _state;
+
+	uint8 _numNotes;
+	uint8 _repeatCount;
+	uint8 _waveform;
+	uint8 _speed;
+
+	uint8 _repeatLeft;
+	uint8 _notesLeft;
+	uint8 _freqIndex;
+	uint8 _durIndex;
+	uint8 _durCounter;
+	uint8 _speedCounter;
+
+	uint8 _curFreqLo;
+	uint8 _curFreqHi;
+
+	int16 _startFreqs[16];
+	int16 _deltas[16];
+	uint8 _durCopies[9];
+
+	void silenceV1();
+	void silenceAll();
+	void setupSfx(int index);
+	void tickStart();
+	void tickSlide();
+};
+
+} // namespace Freescape
+
+#endif // FREESCAPE_ECLIPSE_C64_SFX_H
diff --git a/engines/freescape/games/eclipse/eclipse.cpp b/engines/freescape/games/eclipse/eclipse.cpp
index 14edb5b6b3c..7bebd6313b4 100644
--- a/engines/freescape/games/eclipse/eclipse.cpp
+++ b/engines/freescape/games/eclipse/eclipse.cpp
@@ -31,6 +31,7 @@
 
 #include "freescape/freescape.h"
 #include "freescape/games/eclipse/c64.music.h"
+#include "freescape/games/eclipse/c64.sfx.h"
 #include "freescape/games/eclipse/eclipse.h"
 #include "freescape/language/8bitDetokeniser.h"
 
@@ -42,6 +43,8 @@ Audio::AudioStream *makeEclipseAtariMusicStream(const byte *data, uint32 dataSiz
 
 EclipseEngine::EclipseEngine(OSystem *syst, const ADGameDescription *gd) : FreescapeEngine(syst, gd) {
 	_playerC64Music = nullptr;
+	_playerC64Sfx = nullptr;
+	_c64UseSFX = false;
 
 	// These sounds can be overriden by the class of each platform
 	_soundIndexStartFalling = -1;
@@ -104,6 +107,7 @@ EclipseEngine::EclipseEngine(OSystem *syst, const ADGameDescription *gd) : Frees
 
 EclipseEngine::~EclipseEngine() {
 	delete _playerC64Music;
+	delete _playerC64Sfx;
 }
 
 void EclipseEngine::initGameState() {
@@ -525,11 +529,9 @@ void EclipseEngine::drawInfoMenu() {
 					saveGameDialog();
 					_gfx->setViewport(_viewArea);
 				} else if (event.customType == kActionToggleSound) {
-					if (isC64() && _playerC64Music) {
-						if (_playerC64Music->isPlaying())
-							_playerC64Music->stopMusic();
-						else
-							_playerC64Music->startMusic();
+					if (isC64() && _playerC64Sfx) {
+						toggleC64Sound();
+						_eventManager->purgeKeyboardEvents();
 					} else {
 						playSound(_soundIndexMenu, false, _soundFxHandle);
 					}
diff --git a/engines/freescape/games/eclipse/eclipse.h b/engines/freescape/games/eclipse/eclipse.h
index 5a4296bf8ee..32f0317f8a6 100644
--- a/engines/freescape/games/eclipse/eclipse.h
+++ b/engines/freescape/games/eclipse/eclipse.h
@@ -26,6 +26,7 @@
 namespace Freescape {
 
 class EclipseC64MusicPlayer;
+class EclipseC64SFXPlayer;
 
 enum EclipseReleaseFlags {
 	GF_ZX_DEMO_CRASH = (1 << 0),
@@ -115,6 +116,10 @@ public:
 	Common::Array<byte> _musicData; // TEMUSIC.ST TEXT segment (Atari ST)
 	Common::Array<byte> _c64MusicData;
 	EclipseC64MusicPlayer *_playerC64Music;
+	EclipseC64SFXPlayer *_playerC64Sfx;
+	bool _c64UseSFX;
+	void playSoundC64(int index) override;
+	void toggleC64Sound();
 
 	// Atari ST UI sprites (extracted from binary, pre-converted to target format)
 	Font _fontScore; // Font B (10 score digit glyphs, 4-plane at $249BE)
diff --git a/engines/freescape/module.mk b/engines/freescape/module.mk
index 914af1a0015..7e671a7d4b7 100644
--- a/engines/freescape/module.mk
+++ b/engines/freescape/module.mk
@@ -37,6 +37,7 @@ MODULE_OBJS := \
 	games/eclipse/atari.music.o \
 	games/eclipse/c64.o \
 	games/eclipse/c64.music.o \
+	games/eclipse/c64.sfx.o \
 	games/eclipse/dos.o \
 	games/eclipse/eclipse.o \
 	games/eclipse/cpc.o \
diff --git a/engines/freescape/sid.h b/engines/freescape/sid.h
new file mode 100644
index 00000000000..faa6acf29b5
--- /dev/null
+++ b/engines/freescape/sid.h
@@ -0,0 +1,81 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef FREESCAPE_SID_H
+#define FREESCAPE_SID_H
+
+#include "common/scummsys.h"
+
+namespace Freescape {
+
+// SID register offsets (matches C64 $D400-$D418)
+enum SIDRegs {
+	kSIDV1FreqLo   = 0x00,
+	kSIDV1FreqHi   = 0x01,
+	kSIDV1PwLo     = 0x02,
+	kSIDV1PwHi     = 0x03,
+	kSIDV1Ctrl     = 0x04,
+	kSIDV1AD       = 0x05,
+	kSIDV1SR       = 0x06,
+
+	kSIDV2FreqLo   = 0x07,
+	kSIDV2FreqHi   = 0x08,
+	kSIDV2PwLo     = 0x09,
+	kSIDV2PwHi     = 0x0A,
+	kSIDV2Ctrl     = 0x0B,
+	kSIDV2AD       = 0x0C,
+	kSIDV2SR       = 0x0D,
+
+	kSIDV3FreqLo   = 0x0E,
+	kSIDV3FreqHi   = 0x0F,
+	kSIDV3PwLo     = 0x10,
+	kSIDV3PwHi     = 0x11,
+	kSIDV3Ctrl     = 0x12,
+	kSIDV3AD       = 0x13,
+	kSIDV3SR       = 0x14,
+
+	kSIDFilterLo   = 0x15,
+	kSIDFilterHi   = 0x16,
+	kSIDFilterCtrl = 0x17,
+	kSIDVolume     = 0x18
+};
+
+// 40-byte SFX descriptor used by the Wally Beben C64 SFX engine
+// (shared by Dark Side, Total Eclipse, and possibly other Freescape titles).
+struct C64SFXData {
+	uint8 numNotes;
+	uint8 repeatCount;
+	uint8 reserved;
+	uint8 freqWaypoints[20];
+	uint8 padding;
+	uint8 durations[9];
+	uint8 speed;
+	uint8 padding2;
+	uint8 pwLo;
+	uint8 pwHi;
+	uint8 waveform;
+	uint8 attackDecay;
+	uint8 sustainRelease;
+};
+
+} // namespace Freescape
+
+#endif // FREESCAPE_SID_H




More information about the Scummvm-git-logs mailing list