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

neuromancer noreply at scummvm.org
Wed Jan 31 20:46:50 UTC 2024


This automated email contains information about 1 new commit which have been
pushed to the 'scummvm' repo located at https://github.com/scummvm/scummvm .

Summary:
b92a630099 FREESCAPE: better sounds for the dos releases


Commit: b92a63009922bae248379391000a7974a160953b
    https://github.com/scummvm/scummvm/commit/b92a63009922bae248379391000a7974a160953b
Author: neuromancer (gustavo.grieco at gmail.com)
Date: 2024-01-31T21:31:40+01:00

Commit Message:
FREESCAPE: better sounds for the dos releases

Changed paths:
  A engines/freescape/sound.h
    engines/freescape/freescape.h
    engines/freescape/games/dark/dos.cpp
    engines/freescape/games/driller/dos.cpp
    engines/freescape/games/eclipse/dos.cpp
    engines/freescape/movement.cpp
    engines/freescape/sound.cpp


diff --git a/engines/freescape/freescape.h b/engines/freescape/freescape.h
index 2780eab2391..b45c6757323 100644
--- a/engines/freescape/freescape.h
+++ b/engines/freescape/freescape.h
@@ -38,6 +38,7 @@
 #include "freescape/objects/entrance.h"
 #include "freescape/objects/geometricobject.h"
 #include "freescape/objects/sensor.h"
+#include "freescape/sound.h"
 
 namespace Common {
 class RandomSource;
@@ -67,22 +68,11 @@ enum {
 	kFreescapeDebugMedia = 1 << 4,
 };
 
-struct soundFx {
-	int size;
-	int sampleRate;
-	byte *data;
-};
-
 struct CGAPaletteEntry {
 	int areaId;
 	byte *palette;
 };
 
-class SizedPCSpeaker : public Audio::PCSpeaker {
-public:
-	bool endOfStream() const override { return !isPlaying(); }
-};
-
 class EventManagerWrapper {
 public:
 	EventManagerWrapper(Common::EventManager *delegate);
@@ -374,11 +364,14 @@ public:
 	void playSilence(int duration, bool sync);
 	void playSoundConst(double hzFreq, int duration, bool sync);
 	void playSoundSweepIncWL(double hzFreq1, double hzFreq2, double wlStepPerMS, int resolution, bool sync);
-	void playTeleporter(int totalIters, bool sync);
+	uint16 playSoundDOSSpeaker(uint16 startFrequency, soundSpeakerFx *speakerFxInfo);
+	void playSoundDOS(soundSpeakerFx *speakerFxInfo, bool sync);
 
 	void playSoundFx(int index, bool sync);
 	void loadSoundsFx(Common::SeekableReadStream *file, int offset, int number);
 	Common::HashMap<uint16, soundFx *> _soundsFx;
+	void loadSpeakerFx(Common::SeekableReadStream *file, int offsetFreq, int offsetDuration);
+	Common::HashMap<uint16, soundSpeakerFx *> _soundsSpeakerFx;
 
 	// Rendering
 	int _screenW, _screenH;
diff --git a/engines/freescape/games/dark/dos.cpp b/engines/freescape/games/dark/dos.cpp
index 74618cec92d..c05a82596ef 100644
--- a/engines/freescape/games/dark/dos.cpp
+++ b/engines/freescape/games/dark/dos.cpp
@@ -104,6 +104,8 @@ void DarkEngine::loadAssetsDOSDemo() {
 
 		if (!file.isOpen())
 			error("Failed to open DSIDEE.EXE");
+
+		loadSpeakerFx(&file, 0x4837 + 0x200, 0x46e8 + 0x200);
 		loadMessagesFixedSize(&file, 0x4525, 16, 27);
 		loadMessagesFixedSize(&file, 0x993f - 2, 308, 5);
 		loadFonts(&file, 0xa598);
@@ -138,6 +140,7 @@ void DarkEngine::loadAssetsDOSDemo() {
 		if (!file.isOpen())
 			error("Failed to open DSIDEC.EXE");
 
+		loadSpeakerFx(&file, 0x3077 + 0x200, 0x2f28 + 0x200);
 		loadFonts(&file, 0x8907);
 		loadMessagesFixedSize(&file, 0x2d65, 16, 27);
 		loadMessagesFixedSize(&file, 0x7c3a, 308, 5);
@@ -170,6 +173,7 @@ void DarkEngine::loadAssetsDOSFullGame() {
 		if (!file.isOpen())
 			error("Failed to open DSIDEE.EXE");
 
+		loadSpeakerFx(&file, 0x4837 + 0x200, 0x46e8 + 0x200);
 		loadFonts(&file, 0xa113);
 		loadMessagesFixedSize(&file, 0x4525, 16, 27);
 		loadGlobalObjects(&file, 0x3d04, 23);
@@ -203,6 +207,7 @@ void DarkEngine::loadAssetsDOSFullGame() {
 		if (!file.isOpen())
 			error("Failed to open DSIDEC.EXE");
 
+		loadSpeakerFx(&file, 0x3077 + 0x200, 0x2f28 + 0x200);
 		loadFonts(&file, 0x8496);
 		loadMessagesFixedSize(&file, 0x2d65, 16, 27);
 		loadGlobalObjects(&file, 0x2554, 23);
diff --git a/engines/freescape/games/driller/dos.cpp b/engines/freescape/games/driller/dos.cpp
index f3b30dc5517..e5e34f2307c 100644
--- a/engines/freescape/games/driller/dos.cpp
+++ b/engines/freescape/games/driller/dos.cpp
@@ -316,6 +316,7 @@ void DrillerEngine::loadAssetsDOSFullGame() {
 		if (!file.isOpen())
 			error("Failed to open DRILLE.EXE");
 
+		loadSpeakerFx(&file, 0x4397 + 0x200, 0x4324 + 0x200);
 		loadMessagesFixedSize(&file, 0x4135, 14, 20);
 		loadFonts(&file, 0x99dd);
 		loadGlobalObjects(&file, 0x3b42, 8);
@@ -340,6 +341,8 @@ void DrillerEngine::loadAssetsDOSFullGame() {
 		if (!file.isOpen())
 			error("Failed to open DRILLC.EXE");
 
+		loadSpeakerFx(&file, 0x27e7 + 0x200, 0x2774 + 0x200);
+
 		loadFonts(&file, 0x07a4a);
 		loadMessagesFixedSize(&file, 0x2585, 14, 20);
 		load8bitBinary(&file, 0x7bb0, 4);
diff --git a/engines/freescape/games/eclipse/dos.cpp b/engines/freescape/games/eclipse/dos.cpp
index 0cb53af86e2..24aeccefb0b 100644
--- a/engines/freescape/games/eclipse/dos.cpp
+++ b/engines/freescape/games/eclipse/dos.cpp
@@ -53,6 +53,7 @@ void EclipseEngine::loadAssetsDOSFullGame() {
 		if (!file.isOpen())
 			error("Failed to open TOTEE.EXE");
 
+		loadSpeakerFx(&file, 0x7396 + 0x200, 0x72a1 + 0x200);
 		loadFonts(&file, 0xd403);
 		load8bitBinary(&file, 0x3ce0, 16);
 		for (auto &it : _areaMap) {
diff --git a/engines/freescape/movement.cpp b/engines/freescape/movement.cpp
index 347ada7fbe3..1ea6bd03086 100644
--- a/engines/freescape/movement.cpp
+++ b/engines/freescape/movement.cpp
@@ -379,7 +379,7 @@ void FreescapeEngine::resolveCollisions(Math::Vector3d const position) {
 	if ((lastPosition - newPosition).length() < 1) { // Something is blocking the player
 		if (!executed)
 			setGameBit(31);
-		playSound(4, false);
+		playSound(2, false);
 	}
 
 	lastPosition = newPosition;
@@ -391,6 +391,8 @@ void FreescapeEngine::resolveCollisions(Math::Vector3d const position) {
 		_hasFallen = !_disableFalling;
 
 	if (!_hasFallen && fallen > 0) {
+		playSound(3, false);
+
 		// Position in Y was changed, let's re-run effects
 		runCollisionConditions(lastPosition, newPosition);
 	}
diff --git a/engines/freescape/sound.cpp b/engines/freescape/sound.cpp
index ed4ee058169..9a874028a2e 100644
--- a/engines/freescape/sound.cpp
+++ b/engines/freescape/sound.cpp
@@ -27,9 +27,72 @@
 
 namespace Freescape {
 
-// If step rate for playSoundSweepIncWL calls needs adjusting,
-// can tweak wlStepPerMS parameter by the factor below.
-const double kFreescapeSweepTuneFactor = 10.0;
+void FreescapeEngine::loadSpeakerFx(Common::SeekableReadStream *file, int offsetFreq, int offsetTable) {
+	for (int i = 1; i < 20; i++) {
+		debugC(1, kFreescapeDebugParser, "Reading sound table entry: %d ", i);
+		int soundIdx = (i - 1) * 4;
+		file->seek(offsetFreq + soundIdx);
+		uint16 index = file->readByte();
+		if (index == 0xff)
+			continue;
+		uint iVar = index * 5;
+
+		uint16 frequencyStart = file->readUint16LE();
+		uint8 repetitions = file->readByte();
+		debugC(1, kFreescapeDebugParser, "Frequency start: %d ", frequencyStart);
+		debugC(1, kFreescapeDebugParser, "Repetitions: %d ", repetitions);
+
+		uint8 frequencyStepsNumber = 0;
+		uint16 frequencyStep = 0;
+
+		file->seek(offsetTable + iVar);
+		uint8 lastIndex = file->readByte();
+		debugC(1, kFreescapeDebugParser, "0x%x %d (lastIndex)", offsetTable - 0x200, lastIndex);
+
+		frequencyStepsNumber = file->readByte();
+		debugC(1, kFreescapeDebugParser, "0x%x %d (frequency steps)", offsetTable + 1 - 0x200, frequencyStepsNumber);
+
+		int basePtr = offsetTable + iVar + 1;
+		debugC(1, kFreescapeDebugParser, "0x%x (basePtr)", basePtr - 0x200);
+
+		frequencyStep = file->readUint16LE();
+		debugC(1, kFreescapeDebugParser, "0x%x %d (steps number)", offsetTable + 2 - 0x200, (int16)frequencyStep);
+
+		uint8 frequencyDuration = file->readByte();
+		debugC(1, kFreescapeDebugParser, "0x%x %d (frequency duration)", offsetTable + 4 - 0x200, frequencyDuration);
+
+		soundSpeakerFx *speakerFxInfo = new soundSpeakerFx();
+		_soundsSpeakerFx[i] = speakerFxInfo;
+
+		speakerFxInfo->frequencyStart = frequencyStart;
+		speakerFxInfo->repetitions = repetitions;
+		speakerFxInfo->frequencyStepsNumber = frequencyStepsNumber;
+		speakerFxInfo->frequencyStep = frequencyStep;
+		speakerFxInfo->frequencyDuration = frequencyDuration;
+
+		for (int j = 1; j < lastIndex; j++) {
+
+			soundSpeakerFx *speakerFxInfoAdditionalStep = new soundSpeakerFx();
+			speakerFxInfoAdditionalStep->frequencyStart = 0;
+			speakerFxInfoAdditionalStep->repetitions = 0;
+
+			file->seek(basePtr + 4 * j);
+			debugC(1, kFreescapeDebugParser, "Reading at %x", basePtr + 4 * j - 0x200);
+			frequencyStepsNumber = file->readByte();
+			debugC(1, kFreescapeDebugParser, "%d (steps number)", frequencyStepsNumber);
+			frequencyStep = file->readUint16LE();
+			debugC(1, kFreescapeDebugParser, "%d (frequency step)", (int16)frequencyStep);
+			frequencyDuration = file->readByte();
+			debugC(1, kFreescapeDebugParser, "%d (frequency duration)", frequencyDuration);
+
+			speakerFxInfoAdditionalStep->frequencyStepsNumber = frequencyStepsNumber;
+			speakerFxInfoAdditionalStep->frequencyStep = frequencyStep;
+			speakerFxInfoAdditionalStep->frequencyDuration = frequencyDuration;
+			speakerFxInfo->additionalSteps.push_back(speakerFxInfoAdditionalStep);
+		}
+		debugC(1, kFreescapeDebugParser, "\n");
+	}
+}
 
 void FreescapeEngine::playSound(int index, bool sync) {
 	debugC(1, kFreescapeDebugMedia, "Playing sound %d with sync: %d", index, sync);
@@ -40,180 +103,75 @@ void FreescapeEngine::playSound(int index, bool sync) {
 	}
 	if (_syncSound)
 		waitForSounds();
+
+	if (isDOS()) {
+		soundSpeakerFx *speakerFxInfo = _soundsSpeakerFx[index];
+		if (speakerFxInfo)
+			playSoundDOS(speakerFxInfo, sync);
+		else
+			debugC(1, kFreescapeDebugMedia, "WARNING: Sound %d is not available", index);
+
+		return;
+	}
+
 	switch (index) {
 	case 1:
-		if (_usePrerecordedSounds) {
-			playWav("fsDOS_laserFire.wav");
-			//_system->delayMillis(50);
-		} else
-			playSoundSweepIncWL(1500, 700, 5.46 * kFreescapeSweepTuneFactor, 1, sync);
+		playWav("fsDOS_laserFire.wav");
 		break;
 	case 2: // Done
-		if (_usePrerecordedSounds) {
-			playWav("fsDOS_WallBump.wav");
-			//_system->delayMillis(50);
-		} else {
-			playSoundConst(82, 60, sync);
-		}
+		playWav("fsDOS_WallBump.wav");
 		break;
 	case 3:
-		if (_usePrerecordedSounds) {
-			playWav("fsDOS_stairDown.wav");
-			//_system->delayMillis(50);
-		} else {
-			queueSoundConst(220, 50);
-			playSoundConst(185, 50, sync);
-		}
+		playWav("fsDOS_stairDown.wav");
 		break;
 	case 4:
-		if (_usePrerecordedSounds) {
-			playWav("fsDOS_stairUp.wav");
-			//_system->delayMillis(50);
-		} else {
-			queueSoundConst(220, 50);
-			playSoundConst(340, 50, sync);
-		}
+		playWav("fsDOS_stairUp.wav");
 		break;
 	case 5:
-		if (_usePrerecordedSounds) {
-			playWav("fsDOS_roomChange.wav");
-			//_system->delayMillis(50);
-		} else {
-			playSoundSweepIncWL(262, 100, 65.52 * kFreescapeSweepTuneFactor, 1, sync);
-		}
+		playWav("fsDOS_roomChange.wav");
 		break;
 	case 6:
-		if (_usePrerecordedSounds) {
-			playWav("fsDOS_configMenu.wav");
-			//_system->delayMillis(50);
-		} else {
-			playSoundConst(830, 60, sync);
-		}
+		playWav("fsDOS_configMenu.wav");
 		break;
 	case 7:
-		if (_usePrerecordedSounds) {
-			playWav("fsDOS_bigHit.wav");
-			//_system->delayMillis(50);
-		} else {
-			playSoundSweepIncWL(3000, 155, 7.28 * kFreescapeSweepTuneFactor, 1, sync);
-		}
+		playWav("fsDOS_bigHit.wav");
 		break;
 	case 8:
-		if (_usePrerecordedSounds) {
-			playWav("fsDOS_teleporterActivated.wav");
-			//_system->delayMillis(50);
-		} else {
-			playTeleporter(22, sync);
-		}
+		playWav("fsDOS_teleporterActivated.wav");
 		break;
-
 	case 9:
-		if (_usePrerecordedSounds) {
-			playWav("fsDOS_powerUp.wav");
-			//_system->delayMillis(50);
-		} else {
-			playSoundSweepIncWL(280, 5000, 9.1 * kFreescapeSweepTuneFactor, 1, sync);
-		}
+		playWav("fsDOS_powerUp.wav");
 		break;
-
 	case 10:
-		if (_usePrerecordedSounds) {
-			playWav("fsDOS_energyDrain.wav");
-			//_system->delayMillis(50);
-		} else {
-			playSoundSweepIncWL(240, 255, 1.82 * kFreescapeSweepTuneFactor, 1, sync);
-		}
+		playWav("fsDOS_energyDrain.wav");
 		break;
-
 	case 11: // ???
 		debugC(1, kFreescapeDebugMedia, "Playing unknown sound");
-		if (_usePrerecordedSounds) {
-			// TODO
-		} else {
-			// TODO
-		}
 		break;
-
 	case 12:
-		if (_usePrerecordedSounds) {
-			playWav("fsDOS_switchOff.wav");
-			//_system->delayMillis(50);
-		} else {
-			playSoundSweepIncWL(555, 440, 1.82 * kFreescapeSweepTuneFactor, 1, sync);
-		}
+		playWav("fsDOS_switchOff.wav");
 		break;
-
 	case 13: // Seems to be repeated?
-		if (_usePrerecordedSounds) {
-			playWav("fsDOS_laserHit.wav");
-			//_system->delayMillis(50);
-		} else {
-			playSoundSweepIncWL(3000, 420, 14.56 * kFreescapeSweepTuneFactor, 1, sync);
-		}
+		playWav("fsDOS_laserHit.wav");
 		break;
-
 	case 14:
-		if (_usePrerecordedSounds) {
-			playWav("fsDOS_tankFall.wav");
-			//_system->delayMillis(50);
-		} else {
-			playSoundSweepIncWL(785, 310, 1.82 * kFreescapeSweepTuneFactor, 1, sync);
-		}
+		playWav("fsDOS_tankFall.wav");
 		break;
-
 	case 15:
-		if (_usePrerecordedSounds) {
-			playWav("fsDOS_successJingle.wav");
-			//_system->delayMillis(50);
-		} else {
-			queueSoundConst(587.330, 250);
-			queueSoundConst(740, 175);
-			playSoundConst(880, 450, sync);
-		}
+		playWav("fsDOS_successJingle.wav");
 		break;
-
 	case 16: // Silence?
-		if (_usePrerecordedSounds) {
-			// TODO
-		} else {
-			playSilence(1, sync);
-		}
 		break;
-
 	case 17:
-		if (_usePrerecordedSounds) {
-			playWav("fsDOS_badJingle.wav");
-			//_system->delayMillis(50);
-		} else {
-			queueSoundConst(65, 150);
-			playSoundConst(44, 400, sync);
-		}
+		playWav("fsDOS_badJingle.wav");
 		break;
-
 	case 18: // Silence?
-		if (_usePrerecordedSounds) {
-			// TODO
-		} else {
-			// TODO
-		}
 		break;
-
 	case 19:
 		debugC(1, kFreescapeDebugMedia, "Playing unknown sound");
-		if (_usePrerecordedSounds) {
-			// TODO
-		} else {
-			// TODO
-		}
 		break;
-
 	case 20:
-		if (_usePrerecordedSounds) {
-			playWav("fsDOS_bigHit.wav");
-			//_system->delayMillis(50);
-		} else {
-			playSoundSweepIncWL(3000, 155, 7.28 * kFreescapeSweepTuneFactor, 1, sync);
-		}
+		playWav("fsDOS_bigHit.wav");
 		break;
 	default:
 		debugC(1, kFreescapeDebugMedia, "Unexpected sound %d", index);
@@ -290,94 +248,43 @@ void FreescapeEngine::playSilence(int duration, bool sync) {
 void FreescapeEngine::queueSoundConst(double hzFreq, int duration) {
 	_speaker->playQueue(Audio::PCSpeaker::kWaveFormSquare, hzFreq, 1000 * 10 * duration);
 }
-void FreescapeEngine::playSoundConst(double hzFreq, int duration, bool sync) {
-	queueSoundConst(hzFreq, duration);
-	_mixer->stopHandle(_soundFxHandle);
-	_mixer->playStream(Audio::Mixer::kSFXSoundType, &_soundFxHandle, _speaker, -1, Audio::Mixer::kMaxChannelVolume / 8, 0, DisposeAfterUse::NO);
-}
-
-void FreescapeEngine::playSoundSweepIncWL(double hzFreq1, double hzFreq2, double wlStepPerMS, int resolution, bool sync) {
-	// Play a PC speaker sweep between sound frequencies, using constant wavelength increment.
-
-	// The wavelength step-per-milliseconds value, or wlStepPerMS, describes how
-	// many PIT counter increments occur per millisecond.  This unusual metric is actually
-	// quite efficient when programming an 8086 without floating-point hardware, because
-	// the increment between counters sent to hardware can be a constant integer.
 
-	// The msResolution describes the time resolution used between frequency change events.
-	// If this is only 1 ms, frequency changes very rapidly (every millisecond).
-	// If less resolute, like 100 ms, frequency jumps less often, giving a more "racheted" sweep.
-
-	// The PIT hardware calculates frequencies as 1193180.0 / freq.
-	// Because the hardware only takes 16-bit integers as input, this can expect
-	// to cover nearly all audible frequencies with decent tonal accuracy.
-
-	// Frequencies that sweep using this algorithm will appear to advance slowly
-	// at lower frequencies and quickly at higher frequencies.
-
-	// The exact progression works like this:
-
-	// FreqNext = 1 / (1 / FreqOrig + wlStep / MagicNumber)
-
-	// ...where FreqOrig is the original frequency, FreqNext is the stepped-to frequency,
-	// wlStep is the PIT counter step value, and MagicNumber is 1193180.0.
-
-	// Option:  can round wlStep to integer to make more 16-bit-counter authentic.
-	double wlStep = wlStepPerMS * (double)resolution;
+uint16 FreescapeEngine::playSoundDOSSpeaker(uint16 frequencyStart, soundSpeakerFx *speakerFxInfo) {
+	uint8 frequencyStepsNumber = speakerFxInfo->frequencyStepsNumber;
+	int16 frequencyStep = speakerFxInfo->frequencyStep;
+	uint8 frequencyDuration = speakerFxInfo->frequencyDuration;
+
+	int16 freq = frequencyStart;
+	int waveDurationMultipler = 1800;
+	int waveDuration = waveDurationMultipler * (frequencyDuration + 1);
+
+	while (true) {
+		float hzFreq = 1193180.0 / freq;
+		debugC(1, kFreescapeDebugMedia, "raw %d, hz: %f, duration: %d", freq, hzFreq, waveDuration);
+		_speaker->playQueue(Audio::PCSpeaker::kWaveFormSquare, hzFreq, waveDuration);
+		if (frequencyStepsNumber > 0) {
+			// Ascending initial portions of cycle
+			freq += frequencyStep;
+			frequencyStepsNumber--;
+		} else
+			break;
+	}
 
-	// Option:  can round inv1 and inv2 to integer to make more 16-bit-counter authentic.
-	double inv1 = 1193180.0 / hzFreq1;
-	double inv2 = 1193180.0 / hzFreq2;
+	return freq;
+}
 
-	// Set step to correct direction
-	if (inv1 < inv2 && wlStep < 0)
-		wlStep = -wlStep;
-	if (inv1 > inv2 && wlStep > 0)
-		wlStep = -wlStep;
+void FreescapeEngine::playSoundDOS(soundSpeakerFx *speakerFxInfo, bool sync) {
+	uint freq = speakerFxInfo->frequencyStart;
 
-	// Loop over frequency range
-	int hzCounts = (int)((inv2 - inv1) / wlStep);
-	while (hzCounts-- >= 0) {
-		float hzFreq = (1193180.0 / inv1);
-		_speaker->playQueue(Audio::PCSpeaker::kWaveFormSquare, hzFreq, 1000 * 10 * resolution);
-		inv1 += wlStep;
-	}
-	_mixer->stopHandle(_soundFxHandle);
-	_mixer->playStream(Audio::Mixer::kSFXSoundType, &_soundFxHandle, _speaker, -1, Audio::Mixer::kMaxChannelVolume / 8, 0, DisposeAfterUse::NO);
-}
+	for (int i = 0; i < speakerFxInfo->repetitions; i++) {
+		freq = playSoundDOSSpeaker(freq, speakerFxInfo);
 
-void FreescapeEngine::playTeleporter(int totalIters, bool sync) {
-	// Play FreeScape DOS teleporter-like effect, which is ascending arpeggio.
-	// Length of effect is variable; provide total number of iterations.
-
-	// The general pattern is two iterations upward, one iteration downward.
-	// This means one "ascension cycle" lasts three iterations.
-	// The result is a simulated echo (a better analogy would be a piano's
-	// damper pedal) with gradual ascending frequency.
-
-	// The frequency changes using the same wavelength-shift strategy that is
-	// found in playSoundSweepIncWL.
-
-	int i;
-	double fBase = 1193180.0 / 244.607;
-	double fInc = -600.0;
-	int stepCycle = 1;
-
-	// Loop over iterations
-	for (i = 0; i < totalIters; i++) {
-		float hzFreq = 1193180.0 / fBase;
-		_speaker->playQueue(Audio::PCSpeaker::kWaveFormSquare, hzFreq, 1000 * 10 * 21);
-
-		if (stepCycle <= 1) {
-			// Ascending first two portions of cycle
-			fBase += fInc;
-			stepCycle++;
-		} else {
-			// Descending final portion of cycle
-			fBase -= fInc;
-			stepCycle = 0;
+		for (auto &it : speakerFxInfo->additionalSteps) {
+			assert(it);
+			freq = playSoundDOSSpeaker(freq, it);
 		}
 	}
+
 	_mixer->stopHandle(_soundFxHandle);
 	_mixer->playStream(Audio::Mixer::kSFXSoundType, &_soundFxHandle, _speaker, -1, Audio::Mixer::kMaxChannelVolume / 8, 0, DisposeAfterUse::NO);
 }
diff --git a/engines/freescape/sound.h b/engines/freescape/sound.h
new file mode 100644
index 00000000000..422a6f94685
--- /dev/null
+++ b/engines/freescape/sound.h
@@ -0,0 +1,52 @@
+/* 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_SOUND_H
+#define FREESCAPE_SOUND_H
+
+#include "audio/softsynth/pcspk.h"
+#include "common/array.h"
+
+namespace Freescape {
+
+struct soundFx {
+	int size;
+	float sampleRate;
+	byte *data;
+};
+
+struct soundSpeakerFx {
+	uint16 frequencyStart;
+	uint8 frequencyDuration;
+	uint8 frequencyStepsNumber;
+	uint16 frequencyStep;
+	uint8 repetitions;
+	Common::Array<struct soundSpeakerFx *>additionalSteps;
+};
+
+class SizedPCSpeaker : public Audio::PCSpeaker {
+public:
+	bool endOfStream() const override { return !isPlaying(); }
+};
+
+} // End of namespace Freescape
+
+#endif // FREESCAPE_SOUND_H
\ No newline at end of file




More information about the Scummvm-git-logs mailing list