[Scummvm-git-logs] scummvm master -> 5dec7446398c342c5322856dfbcbda5b1b9cbf4a

sluicebox noreply at scummvm.org
Sat Dec 14 20:05:43 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:
5dec744639 AGI: PREAGI: Improve event handling during sounds


Commit: 5dec7446398c342c5322856dfbcbda5b1b9cbf4a
    https://github.com/scummvm/scummvm/commit/5dec7446398c342c5322856dfbcbda5b1b9cbf4a
Author: sluicebox (22204938+sluicebox at users.noreply.github.com)
Date: 2024-12-14T11:56:02-08:00

Commit Message:
AGI: PREAGI: Improve event handling during sounds

Games can now control event processing and interrupt behavior
during sounds and waits.

Fixes Mickey unresponsiveness during sounds and introduction.

Changed paths:
    engines/agi/preagi/mickey.cpp
    engines/agi/preagi/mickey.h
    engines/agi/preagi/preagi.cpp
    engines/agi/preagi/preagi.h
    engines/agi/preagi/troll.cpp


diff --git a/engines/agi/preagi/mickey.cpp b/engines/agi/preagi/mickey.cpp
index 6cbf34ad543..118a6847e91 100644
--- a/engines/agi/preagi/mickey.cpp
+++ b/engines/agi/preagi/mickey.cpp
@@ -635,18 +635,19 @@ void MickeyEngine::printDatMessage(int iStr) {
 
 // Sound
 
-void MickeyEngine::playNote(MSA_SND_NOTE note) {
-	if (!note.counter) {
-		// Pause
-		_system->delayMillis((uint)(note.length / IDI_SND_TIMER_RESOLUTION));
-	} else {
-		playSpeakerNote(IDI_SND_OSCILLATOR_FREQUENCY / note.counter, (int32)(note.length / IDI_SND_TIMER_RESOLUTION));
+bool MickeyEngine::playNote(MSA_SND_NOTE note, WaitOptions options) {
+	int16 frequency = 0;
+	if (note.counter != 0) {
+		frequency = IDI_SND_OSCILLATOR_FREQUENCY / note.counter;
 	}
+	int32 lengthMs = (int32)(note.length / IDI_SND_TIMER_RESOLUTION);
+	return playSpeakerNote(frequency, lengthMs, options);
 }
 
-void MickeyEngine::playSound(ENUM_MSA_SOUND iSound) {
+bool MickeyEngine::playSound(ENUM_MSA_SOUND iSound, WaitOptions options) {
+	bool completed = true;
 	if (!getFlag(VM_FLAG_SOUND_ON))
-		return;
+		return completed;
 
 	Common::Event event;
 	MSA_SND_NOTE note;
@@ -658,7 +659,10 @@ void MickeyEngine::playSound(ENUM_MSA_SOUND iSound) {
 		for (int iNote = 0; iNote < 6; iNote++) {
 			note.counter = rnd(59600) + 59;
 			note.length = 4;
-			playNote(note);
+			if (!playNote(note, options)) {
+				completed = false;
+				break;
+			}
 		}
 		break;
 	default:
@@ -669,36 +673,19 @@ void MickeyEngine::playSound(ENUM_MSA_SOUND iSound) {
 			if (!note.counter && !note.length)
 				break;
 
-			playNote(note);
+			if (!playNote(note, options)) {
+				completed = false;
+				break;
+			}
 
 			pBuf += 3;
-
-			if (iSound == IDI_MSA_SND_THEME) {
-				while (_system->getEventManager()->pollEvent(event)) {
-					switch (event.type) {
-					case Common::EVENT_KEYDOWN:
-						// don't interrupt if a modifier is pressed
-						if (event.kbd.flags & Common::KBD_NON_STICKY) {
-							continue;
-						}
-						// fall through
-					case Common::EVENT_RETURN_TO_LAUNCHER:
-					case Common::EVENT_QUIT:
-					case Common::EVENT_LBUTTONUP:
-					case Common::EVENT_RBUTTONUP:
-						delete[] buffer;
-						return;
-					default:
-						break;
-					}
-				}
-			}
 		}
 
 		break;
 	}
 
 	delete[] buffer;
+	return completed;
 }
 
 // Graphics
@@ -801,7 +788,11 @@ void MickeyEngine::drawRoomAnimation() {
 		if (_gameStateMickey.nFrame < 0)
 			_gameStateMickey.nFrame = 15;
 
-		playSound(IDI_MSA_SND_PRESS_BLUE);
+		// play the spaceship beep but don't process events during playback.
+		// this sound plays during menu usage, so events must not be consumed
+		// while waiting or else inputs will be dropped. playing this sound
+		// does create an input lag, but that is what happened in the original.
+		playSound(IDI_MSA_SND_PRESS_BLUE, kWaitBlock);
 	}
 	break;
 
@@ -1374,14 +1365,15 @@ void MickeyEngine::intro() {
 	_gameStateMickey.iRoom = IDI_MSA_PIC_TITLE;
 	drawRoom();
 
-	// show copyright and play theme
+	// show copyright
 	printExeMsg(IDO_MSA_COPYRIGHT);
 
 	// Quit if necessary
 	if (shouldQuit())
 		return;
 
-	playSound(IDI_MSA_SND_THEME);
+	// play theme
+	playSound(IDI_MSA_SND_THEME, kWaitAllowInterrupt);
 
 	// load game
 	_gameStateMickey.fIntro = true;
diff --git a/engines/agi/preagi/mickey.h b/engines/agi/preagi/mickey.h
index 906a42c6b11..13ac1c9ef1a 100644
--- a/engines/agi/preagi/mickey.h
+++ b/engines/agi/preagi/mickey.h
@@ -717,8 +717,8 @@ protected:
 	void patchMenu(MSA_MENU *);
 	void printDatString(int);
 	void printDatMessage(int);
-	void playNote(MSA_SND_NOTE);
-	void playSound(ENUM_MSA_SOUND);
+	bool playNote(MSA_SND_NOTE note, WaitOptions options);
+	bool playSound(ENUM_MSA_SOUND iSound, WaitOptions options = kWaitProcessEvents);
 	void drawRoomAnimation();
 	void drawRoom();
 	bool drawLogo();
diff --git a/engines/agi/preagi/preagi.cpp b/engines/agi/preagi/preagi.cpp
index 49778448320..19cd455e204 100644
--- a/engines/agi/preagi/preagi.cpp
+++ b/engines/agi/preagi/preagi.cpp
@@ -287,32 +287,72 @@ int PreAgiEngine::getSelection(SelectionTypes type) {
 	return 0;
 }
 
-void PreAgiEngine::playSpeakerNote(int16 frequency, int32 length) {
-	_speakerStream->play(Audio::PCSpeaker::kWaveFormSquare, frequency, length);
+bool PreAgiEngine::playSpeakerNote(int16 frequency, int32 length, WaitOptions options) {
+	// play note, unless this is a pause
+	if (frequency != 0) {
+		_speakerStream->play(Audio::PCSpeaker::kWaveFormSquare, frequency, length);
+	}
 
-	uint32 startTime = _system->getMillis();
-	while (_system->getMillis() - startTime < (uint32)length) {
-		_system->updateScreen();
-		_system->delayMillis(10);
+	// wait for note length
+	bool completed = wait(length, options);
+
+	// stop note if the wait was interrupted
+	if (!completed) {
+		if (frequency != 0) {
+			_speakerStream->stop();
+		}
 	}
+
+	return completed;
 }
 
-void PreAgiEngine::wait(uint32 delay) {
+// A wait function that updates the screen, optionally allows events to be
+// processed, and optionally allows keyboard and mouse events to interrupt
+// the wait. Processing events keeps the program window responsive, but for
+// very short delays it may be better to not process events so that they
+// are buffered and not lost.
+bool PreAgiEngine::wait(uint32 delay, WaitOptions options) {
 	Common::Event event;
 	uint32 startTime = _system->getMillis();
 
+	bool processEvents = (options & kWaitProcessEvents) != 0;
+	bool allowInterrupt = (options == kWaitAllowInterrupt);
+
 	while (!shouldQuit()) {
 		// process events
-		while (_eventMan->pollEvent(event)) {
+		if (processEvents) {
+			while (_eventMan->pollEvent(event)) {
+				switch (event.type) {
+				case Common::EVENT_KEYDOWN:
+					// don't interrupt if a modifier is pressed
+					if (event.kbd.flags & Common::KBD_NON_STICKY) {
+						continue;
+					}
+					// fall through
+				case Common::EVENT_LBUTTONUP:
+				case Common::EVENT_RBUTTONUP:
+					if (!allowInterrupt) {
+						continue;
+					}
+					// fall through
+				case Common::EVENT_RETURN_TO_LAUNCHER:
+				case Common::EVENT_QUIT:
+					return false; // interrupted by quit or input
+				default:
+					break;
+				}
+			}
 		}
 
 		if (_system->getMillis() - startTime >= delay) {
-			return;
+			return true; // delay completed
 		}
 
 		_system->updateScreen();
 		_system->delayMillis(10);
 	}
+
+	return false; // interrupted by quit
 }
 
 } // End of namespace Agi
diff --git a/engines/agi/preagi/preagi.h b/engines/agi/preagi/preagi.h
index bf2653bf6d9..e30ed3ee1d6 100644
--- a/engines/agi/preagi/preagi.h
+++ b/engines/agi/preagi/preagi.h
@@ -50,6 +50,13 @@ enum SelectionTypes {
 	kSelBackspace
 };
 
+// Options for controlling behavior during waits and sound playback
+enum WaitOptions {
+	kWaitBlock          = 0x00, // no event processing, cannot be interrupted
+	kWaitProcessEvents  = 0x01, // process events, stops on quit
+	kWaitAllowInterrupt = 0x03  // process events, stops on input or quit
+};
+
 class PreAgiEngine : public AgiBase {
 	int _gameId;
 
@@ -101,8 +108,8 @@ protected:
 	// Saved Games
 	Common::SaveFileManager *getSaveFileMan() { return _saveFileMan; }
 
-	void playSpeakerNote(int16 frequency, int32 length);
-	void wait(uint32 delay);
+	bool playSpeakerNote(int16 frequency, int32 length, WaitOptions options);
+	bool wait(uint32 delay, WaitOptions options = kWaitProcessEvents);
 
 private:
 	int _defaultColor;
diff --git a/engines/agi/preagi/troll.cpp b/engines/agi/preagi/troll.cpp
index 35d760e8bcc..3741fc21053 100644
--- a/engines/agi/preagi/troll.cpp
+++ b/engines/agi/preagi/troll.cpp
@@ -472,7 +472,10 @@ void TrollEngine::playTune(int tune, int len) {
 		int duration = READ_LE_UINT16(_gameData + ptr);
 		ptr += 2;
 
-		playSpeakerNote(freq, duration);
+		// Play note without processing events.
+		// The sounds are so short in this game that we don't
+		// need to process events while playing notes.
+		playSpeakerNote(freq, duration, kWaitBlock);
 	}
 }
 




More information about the Scummvm-git-logs mailing list