[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