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

dreammaster paulfgilbert at gmail.com
Thu May 7 01:57:20 UTC 2020


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:
ad80273e9d ULTIMA4: Properly implement sound manager


Commit: ad80273e9d38a912c3a8e7d09273074eba3c7522
    https://github.com/scummvm/scummvm/commit/ad80273e9d38a912c3a8e7d09273074eba3c7522
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2020-05-06T18:55:29-07:00

Commit Message:
ULTIMA4: Properly implement sound manager

Changed paths:
    engines/ultima/detection_tables.h
    engines/ultima/ultima4/sound/sound.cpp
    engines/ultima/ultima4/sound/sound.h
    engines/ultima/ultima4/ultima4.cpp
    engines/ultima/ultima4/ultima4.h


diff --git a/engines/ultima/detection_tables.h b/engines/ultima/detection_tables.h
index e1fa1beaf8..0542e578b1 100644
--- a/engines/ultima/detection_tables.h
+++ b/engines/ultima/detection_tables.h
@@ -86,7 +86,7 @@ static const UltimaGameDescription GAME_DESCRIPTIONS[] = {
 			Common::EN_ANY,
 			Common::kPlatformDOS,
 			ADGF_UNSTABLE,
-			GUIO0()
+			GUIO1(GUIO_NOSPEECH)
 		},
 		GAME_ULTIMA4,
 		0
@@ -101,7 +101,7 @@ static const UltimaGameDescription GAME_DESCRIPTIONS[] = {
 			Common::EN_ANY,
 			Common::kPlatformDOS,
 			ADGF_UNSTABLE,
-			GUIO0()
+			GUIO1(GUIO_NOSPEECH)
 		},
 		GAME_ULTIMA4,
 		GF_VGA_ENHANCED
diff --git a/engines/ultima/ultima4/sound/sound.cpp b/engines/ultima/ultima4/sound/sound.cpp
index a1e0a8276f..9b84efe883 100644
--- a/engines/ultima/ultima4/sound/sound.cpp
+++ b/engines/ultima/ultima4/sound/sound.cpp
@@ -26,51 +26,36 @@
 #include "ultima/ultima4/core/settings.h"
 #include "ultima/ultima4/filesys/u4file.h"
 #include "ultima/ultima4/core/utils.h"
+#include "audio/audiostream.h"
+#include "audio/decoders/flac.h"
+#include "audio/decoders/mp3.h"
+#include "audio/decoders/voc.h"
+#include "audio/decoders/vorbis.h"
+#include "audio/decoders/wave.h"
+#include "common/file.h"
 
 namespace Ultima {
 namespace Ultima4 {
 
-int soundInit(void) {
-	return SoundManager::getInstance()->init();
-}
-
-void soundDelete(void) {
-	delete SoundManager::getInstance();
-}
+SoundManager *g_sound;
 
 void soundPlay(Sound sound, bool onlyOnce, int specificDurationInTicks) {
-	SoundManager::getInstance()->play(sound, onlyOnce, specificDurationInTicks);
+	g_sound->play(sound, onlyOnce, specificDurationInTicks);
 }
 
 void soundStop(int channel) {
-	SoundManager::getInstance()->stop(channel);
+	g_sound->stop(channel);
 }
 
 /*-------------------------------------------------------------------*/
 
-SoundManager *SoundManager::_instance = 0;
-
-SoundManager::SoundManager() {
-}
-
-SoundManager::~SoundManager() {
-	del();
-	_instance = 0;
-}
-
-SoundManager *SoundManager::getInstance() {
-	if (!_instance)
-		_instance = new SoundManager();
-	return _instance;
-}
+SoundManager::SoundManager(Audio::Mixer *mixer) : _mixer(mixer) {
+	g_sound = this;
 
-int SoundManager::init() {
-	/*
-	 * load sound track filenames from xml config file
-	 */
+	// Load sound track filenames from xml config file
 	const Config *config = Config::getInstance();
 	_soundFilenames.reserve(SOUND_MAX);
-	_soundChunk.resize(SOUND_MAX);
+	_sounds.resize(SOUND_MAX);
 
 	Std::vector<ConfigElement> soundConfs = config->getElement("sound").getChildren();
 	Std::vector<ConfigElement>::const_iterator i = soundConfs.begin();
@@ -81,7 +66,14 @@ int SoundManager::init() {
 
 		_soundFilenames.push_back(i->getString("file"));
 	}
-	return init_sys();
+}
+
+SoundManager::~SoundManager() {
+	g_sound = nullptr;
+	_mixer->stopHandle(_soundHandle);
+
+	for (uint idx = 0; idx < _sounds.size(); ++idx)
+		delete _sounds[idx];
 }
 
 bool SoundManager::load(Sound sound) {
@@ -91,24 +83,24 @@ bool SoundManager::load(Sound sound) {
 	if (!Music::_functional || !settings._soundVol)
 		return false;
 
-	if (_soundChunk[sound] == nullptr) {
+	if (_sounds[sound] == nullptr) {
 		Common::String pathname(u4find_sound(_soundFilenames[sound]));
 		Common::String basename = pathname.substr(pathname.findLastOf("/") + 1);
 		if (!basename.empty())
 			return load_sys(sound, pathname);
 	}
+
 	return true;
 }
 
 void SoundManager::play(Sound sound, bool onlyOnce, int specificDurationInTicks) {
-
 	ASSERT(sound < SOUND_MAX, "Attempted to play an invalid sound in soundPlay()");
 
 	// If music didn't initialize correctly, then we can't play it anyway
 	if (!Music::_functional || !settings._soundVol)
 		return;
 
-	if (_soundChunk[sound] == nullptr) {
+	if (_sounds[sound] == nullptr) {
 		if (!load(sound)) {
 			return;
 		}
@@ -121,45 +113,69 @@ void SoundManager::stop(int channel) {
 	stop_sys(channel);
 }
 
-bool SoundManager::load_sys(Sound sound, const Common::String &pathname) {
-#ifdef TODO
-	soundChunk[sound] = Mix_LoadWAV(pathname.c_str());
-	if (!soundChunk[sound]) {
-		warning("Unable to load sound effect file %s: %s", soundFilenames[sound].c_str(), Mix_GetError());
+bool SoundManager::load_sys(Sound sound, const Common::String &filename) {
+	Common::File f;
+	if (!f.open(filename))
 		return false;
-	}
-#endif
-	return true;
-}
 
-void SoundManager::play_sys(Sound sound, bool onlyOnce, int specificDurationInTicks) {
-#ifdef TODO
-	/**
-	 * Use Channel 1 for sound effects
-	 */
-	if (!onlyOnce || !Mix_Playing(1)) {
-		if (Mix_PlayChannelTimed(1, soundChunk[sound], specificDurationInTicks == -1 ? 0 : -1, specificDurationInTicks) == -1)
-			fprintf(stderr, "Error playing sound %d: %s\n", sound, Mix_GetError());
-	}
+	Audio::SeekableAudioStream *audioStream = nullptr;
+
+#ifdef USE_FLAC
+	if (filename.hasSuffix(".fla"))
+		audioStream = Audio::makeFLACStream(f.readStream(f.size()), DisposeAfterUse::YES);
+#endif
+#ifdef USE_VORBIS
+	if (filename.hasSuffix(".ogg"))
+		audioStream = Audio::makeVorbisStream(f.readStream(f.size()), DisposeAfterUse::YES);
+#endif
+#ifdef USE_MAD
+	if (filename.hasSuffix(".mp3"))
+		audioStream = Audio::makeMP3Stream(f.readStream(f.size()), DisposeAfterUse::YES);
 #endif
+	if (filename.hasSuffix(".wav"))
+		audioStream = Audio::makeWAVStream(f.readStream(f.size()), DisposeAfterUse::YES);
+	if (filename.hasSuffix(".voc"))
+		audioStream = Audio::makeVOCStream(f.readStream(f.size()), DisposeAfterUse::YES);
+
+	_sounds[sound] = audioStream;
+	return audioStream != nullptr;
 }
 
-void SoundManager::stop_sys(int channel) {
-#ifdef TODO
-	// If music didn't initialize correctly, then we shouldn't try to stop it
-	if (!g_music->functional || !settings.soundVol)
+void SoundManager::play_sys(Sound sound, bool onlyOnce, int specificDurationMilli) {
+	// Don't allow once only sounds if another sound is already playing
+	if (onlyOnce && _mixer->isSoundHandleActive(_soundHandle))
 		return;
 
-	if (Mix_Playing(channel))
-		Mix_HaltChannel(channel);
-#endif
-}
-
-int SoundManager::init_sys() {
-	return 1;
+	// Ensure sound is stopped, and rewinded
+	_mixer->stopHandle(_soundHandle);
+	_sounds[sound]->rewind();
+
+	if (specificDurationMilli == -1) {
+		// Play a single sound effect
+		_mixer->playStream(Audio::Mixer::kSFXSoundType,
+			&_soundHandle, _sounds[sound], -1, Audio::Mixer::kMaxChannelVolume,
+			0, DisposeAfterUse::NO);
+	} else {
+		// Play a sound effect, looping if necessary, for a given duration
+		// TODO: Better handle cases where a number of loops won't fit
+		// exactly to give a desired duration
+		int duration = _sounds[sound]->getLength().msecs();
+		int loops = (specificDurationMilli + duration - 1) / duration;
+		assert(loops >= 0);
+
+		Audio::AudioStream *audioStream = new Audio::LoopingAudioStream(
+			_sounds[sound], loops, DisposeAfterUse::NO);
+
+		_mixer->playStream(Audio::Mixer::kSFXSoundType,
+			&_soundHandle, audioStream, -1, Audio::Mixer::kMaxChannelVolume,
+			0, DisposeAfterUse::NO);
+	}
 }
 
-void SoundManager::del_sys() {
+void SoundManager::stop_sys(int channel) {
+	// Channel 1 is the dummy channel number used for sound effects
+	if (channel == 1)
+		_mixer->stopHandle(_soundHandle);
 }
 
 } // End of namespace Ultima4
diff --git a/engines/ultima/ultima4/sound/sound.h b/engines/ultima/ultima4/sound/sound.h
index d2ca9883ce..f3056e8e37 100644
--- a/engines/ultima/ultima4/sound/sound.h
+++ b/engines/ultima/ultima4/sound/sound.h
@@ -24,6 +24,8 @@
 #define ULTIMA4_SOUND_H
 
 #include "ultima/shared/std/containers.h"
+#include "audio/audiostream.h"
+#include "audio/mixer.h"
 #include "common/str.h"
 
 namespace Ultima {
@@ -64,39 +66,32 @@ enum Sound {
 	SOUND_MAX
 };
 
-int soundInit();
-void soundDelete();
-
 void soundPlay(Sound sound, bool onlyOnce = true, int specificDurationInTicks = -1);
 
 void soundStop(int channel = 1);
 
-struct Mix_Chunk;
-typedef Mix_Chunk OSSoundChunk;
-
 class SoundManager {
+private:
+	Audio::Mixer *_mixer;
+	Audio::SoundHandle _soundHandle;
+	Std::vector<Common::String> _soundFilenames;
+	Std::vector<Audio::SeekableAudioStream *> _sounds;
+private:
+	bool load(Sound sound);
+
+	void play_sys(Sound sound, bool onlyOnce, int specificDurationMilli);
+	bool load_sys(Sound sound, const Common::String &filename);
+	void stop_sys(int channel);
 public:
+	SoundManager(Audio::Mixer *mixer);
 	~SoundManager();
-	static SoundManager *getInstance();
-	int init();
+
 	void play(Sound sound, bool onlyOnce = true, int specificDurationInTicks = -1);
 	void stop(int channel = 1);
-private:
-	bool load(Sound sound);
-	int init_sys();
-	void del() {
-		del_sys();
-	}
-	void del_sys();
-	void play_sys(Sound sound, bool onlyOnce, int specificDurationInTicks);
-	bool load_sys(Sound sound, const Common::String &soundPathName);
-	void stop_sys(int channel);
-	Std::vector<Common::String> _soundFilenames;
-	Std::vector<OSSoundChunk *> _soundChunk;
-	SoundManager();
-	static SoundManager *_instance;
 };
 
+extern SoundManager *g_sound;
+
 } // End of namespace Ultima4
 } // End of namespace Ultima
 
diff --git a/engines/ultima/ultima4/ultima4.cpp b/engines/ultima/ultima4/ultima4.cpp
index e3b386489b..6a2cc75758 100644
--- a/engines/ultima/ultima4/ultima4.cpp
+++ b/engines/ultima/ultima4/ultima4.cpp
@@ -62,8 +62,8 @@ Ultima4Engine::Ultima4Engine(OSystem *syst, const Ultima::UltimaGameDescription
 		_dialogueLoaders(nullptr), _game(nullptr), _items(nullptr), _music(nullptr),
 		_imageLoaders(nullptr), _mapLoaders(nullptr), _moongates(nullptr),
 		_responseParts(nullptr), _saveGame(nullptr), _screen(nullptr), _shrines(nullptr),
-		_spells(nullptr), _tileMaps(nullptr), _tileRules(nullptr), _tileSets(nullptr),
-		_weapons(nullptr) {
+		_soundManager(nullptr), _spells(nullptr), _tileMaps(nullptr), _tileRules(nullptr),
+		_tileSets(nullptr), _weapons(nullptr) {
 	g_ultima = this;
 	g_armors = nullptr;
 	g_codex = nullptr;
@@ -76,6 +76,7 @@ Ultima4Engine::Ultima4Engine(OSystem *syst, const Ultima::UltimaGameDescription
 	g_responseParts = nullptr;
 	g_screen = nullptr;
 	g_shrines = nullptr;
+	g_sound = nullptr;
 	g_spells = nullptr;
 	g_tileMaps = nullptr;
 	g_tileRules = nullptr;
@@ -100,6 +101,7 @@ Ultima4Engine::~Ultima4Engine() {
 	delete _saveGame;
 	delete _screen;
 	delete _shrines;
+	delete _soundManager;
 	delete _spells;
 	delete _tileMaps;
 	delete _tileRules;
@@ -109,7 +111,6 @@ Ultima4Engine::~Ultima4Engine() {
 	ImageMgr::destroy();
 
 	//delete g_music;
-	soundDelete();
 }
 
 bool Ultima4Engine::initialize() {
@@ -130,6 +131,7 @@ bool Ultima4Engine::initialize() {
 	_screen = new Screen();
 	_screen->init();
 	_shrines = new Shrines();
+	_soundManager = new SoundManager(_mixer);
 	_spells = new Spells();
 	_tileRules = new TileRules();
 	_tileSets = new TileSets();
@@ -141,7 +143,6 @@ bool Ultima4Engine::initialize() {
 	_weapons = new Weapons();
 
 	setDebugger(new Debugger());
-	soundInit();
 	creatureMgr->getInstance();
 
 	_saveSlotToLoad = ConfMan.hasKey("save_slot") ? ConfMan.getInt("save_slot") : -1;
@@ -152,8 +153,6 @@ bool Ultima4Engine::initialize() {
 void Ultima4Engine::startup() {
 	bool skipInfo = _saveSlotToLoad != -1;
 
-	soundInit();
-
 	if (!skipInfo) {
 		// do the intro
 		g_intro = new IntroController();
diff --git a/engines/ultima/ultima4/ultima4.h b/engines/ultima/ultima4/ultima4.h
index 4ba9a7180f..29887be0a6 100644
--- a/engines/ultima/ultima4/ultima4.h
+++ b/engines/ultima/ultima4/ultima4.h
@@ -45,6 +45,7 @@ class ResponseParts;
 struct SaveGame;
 class Screen;
 class Shrines;
+class SoundManager;
 class Spells;
 class TileMaps;
 class TileRules;
@@ -83,6 +84,7 @@ public:
 	SaveGame *_saveGame;
 	Screen *_screen;
 	Shrines *_shrines;
+	SoundManager *_soundManager;
 	Spells *_spells;
 	TileMaps *_tileMaps;
 	TileRules *_tileRules;




More information about the Scummvm-git-logs mailing list