diff options
-rw-r--r-- | src/client/clientlauncher.cpp | 9 | ||||
-rw-r--r-- | src/game.cpp | 2 | ||||
-rw-r--r-- | src/gui/guiEngine.cpp | 2 | ||||
-rw-r--r-- | src/sound_openal.cpp | 179 | ||||
-rw-r--r-- | src/sound_openal.h | 8 |
5 files changed, 116 insertions, 84 deletions
diff --git a/src/client/clientlauncher.cpp b/src/client/clientlauncher.cpp index b02f1b438..2f8591179 100644 --- a/src/client/clientlauncher.cpp +++ b/src/client/clientlauncher.cpp @@ -35,6 +35,10 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "renderingengine.h" #include "network/networkexceptions.h" +#if USE_SOUND + #include "sound_openal.h" +#endif + /* mainmenumanager.h */ gui::IGUIEnvironment *guienv = nullptr; @@ -71,6 +75,11 @@ bool ClientLauncher::run(GameParams &game_params, const Settings &cmd_args) if (list_video_modes) return RenderingEngine::print_video_modes(); +#if USE_SOUND + if (g_settings->getBool("enable_sound")) + g_sound_manager_singleton = createSoundManagerSingleton(); +#endif + if (!init_engine()) { errorstream << "Could not initialize game engine." << std::endl; return false; diff --git a/src/game.cpp b/src/game.cpp index f1c27d3bb..fada349db 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -1219,7 +1219,7 @@ bool Game::initSound() #if USE_SOUND if (g_settings->getBool("enable_sound")) { infostream << "Attempting to use OpenAL audio" << std::endl; - sound = createOpenALSoundManager(&soundfetcher); + sound = createOpenALSoundManager(g_sound_manager_singleton.get(), &soundfetcher); if (!sound) infostream << "Failed to initialize OpenAL audio" << std::endl; } else diff --git a/src/gui/guiEngine.cpp b/src/gui/guiEngine.cpp index 3f9bcd888..00c3f85bc 100644 --- a/src/gui/guiEngine.cpp +++ b/src/gui/guiEngine.cpp @@ -137,7 +137,7 @@ GUIEngine::GUIEngine(JoystickController *joystick, //create soundmanager MenuMusicFetcher soundfetcher; #if USE_SOUND - m_sound_manager = createOpenALSoundManager(&soundfetcher); + m_sound_manager = createOpenALSoundManager(g_sound_manager_singleton.get(), &soundfetcher); #endif if(!m_sound_manager) m_sound_manager = &dummySoundManager; diff --git a/src/sound_openal.cpp b/src/sound_openal.cpp index b33a85703..853aba1cc 100644 --- a/src/sound_openal.cpp +++ b/src/sound_openal.cpp @@ -45,9 +45,29 @@ with this program; ifnot, write to the Free Software Foundation, Inc., #include <vector> #include <fstream> #include <unordered_map> +#include <unordered_set> #define BUFFER_SIZE 30000 +std::shared_ptr<SoundManagerSingleton> g_sound_manager_singleton; + +typedef std::unique_ptr<ALCdevice, void (*)(ALCdevice *p)> unique_ptr_alcdevice; +typedef std::unique_ptr<ALCcontext, void(*)(ALCcontext *p)> unique_ptr_alccontext; + +static void delete_alcdevice(ALCdevice *p) +{ + if (p) + alcCloseDevice(p); +} + +static void delete_alccontext(ALCcontext *p) +{ + if (p) { + alcMakeContextCurrent(nullptr); + alcDestroyContext(p); + } +} + static const char *alcErrorString(ALCenum err) { switch (err) { @@ -146,7 +166,7 @@ SoundBuffer *load_opened_ogg_file(OggVorbis_File *oggFile, infostream << "Audio: Error decoding " << filename_for_logging << std::endl; delete snd; - return NULL; + return nullptr; } // Append to end of buffer @@ -161,8 +181,8 @@ SoundBuffer *load_opened_ogg_file(OggVorbis_File *oggFile, ALenum error = alGetError(); if(error != AL_NO_ERROR){ - infostream<<"Audio: OpenAL error: "<<alErrorString(error) - <<"preparing sound buffer"<<std::endl; + infostream << "Audio: OpenAL error: " << alErrorString(error) + << "preparing sound buffer" << std::endl; } infostream << "Audio file " @@ -184,7 +204,7 @@ SoundBuffer *load_ogg_from_file(const std::string &path) if (ov_fopen(path.c_str(), &oggFile) != 0) { infostream << "Audio: Error opening " << path << " for decoding" << std::endl; - return NULL; + return nullptr; } return load_opened_ogg_file(&oggFile, path); @@ -237,7 +257,7 @@ long BufferSourceell_func(void *datasource) static ov_callbacks g_buffer_ov_callbacks = { &buffer_sound_read_func, &buffer_sound_seek_func, - NULL, + nullptr, &BufferSourceell_func }; @@ -250,10 +270,10 @@ SoundBuffer *load_ogg_from_buffer(const std::string &buf, const std::string &id_ s.cur_offset = 0; s.len = buf.size(); - if (ov_open_callbacks(&s, &oggFile, NULL, 0, g_buffer_ov_callbacks) != 0) { + if (ov_open_callbacks(&s, &oggFile, nullptr, 0, g_buffer_ov_callbacks) != 0) { infostream << "Audio: Error opening " << id_for_log << " for decoding" << std::endl; - return NULL; + return nullptr; } return load_opened_ogg_file(&oggFile, id_for_log); @@ -265,6 +285,43 @@ struct PlayingSound bool loop; }; +class SoundManagerSingleton +{ +public: + unique_ptr_alcdevice m_device; + unique_ptr_alccontext m_context; +public: + SoundManagerSingleton() : + m_device(nullptr, delete_alcdevice), + m_context(nullptr, delete_alccontext) + { + if (!(m_device = unique_ptr_alcdevice(alcOpenDevice(nullptr), delete_alcdevice))) + throw std::runtime_error("Audio: Global Initialization: Device Open"); + + if (!(m_context = unique_ptr_alccontext( + alcCreateContext(m_device.get(), nullptr), delete_alccontext))) { + throw std::runtime_error("Audio: Global Initialization: Context Create"); + } + + if (!alcMakeContextCurrent(m_context.get())) + throw std::runtime_error("Audio: Global Initialization: Context Current"); + + alDistanceModel(AL_INVERSE_DISTANCE_CLAMPED); + + if (alGetError() != AL_NO_ERROR) + throw std::runtime_error("Audio: Global Initialization: OpenAL Error"); + + infostream << "Audio: Global Initialized: OpenAL " << alGetString(AL_VERSION) + << ", using " << alcGetString(m_device.get(), ALC_DEVICE_SPECIFIER) + << std::endl; + } + + ~SoundManagerSingleton() + { + infostream << "Audio: Global Deinitialized." << std::endl; + } +}; + class OpenALSoundManager: public ISoundManager { private: @@ -290,68 +347,27 @@ private: std::unordered_map<int, FadeState> m_sounds_fading; float m_fade_delay; public: - bool m_is_initialized; - OpenALSoundManager(OnDemandSoundFetcher *fetcher): + OpenALSoundManager(SoundManagerSingleton *smg, OnDemandSoundFetcher *fetcher): m_fetcher(fetcher), - m_device(NULL), - m_context(NULL), + m_device(smg->m_device.get()), + m_context(smg->m_context.get()), m_next_id(1), - m_fade_delay(0), - m_is_initialized(false) + m_fade_delay(0) { - ALCenum error = ALC_NO_ERROR; - - infostream<<"Audio: Initializing..."<<std::endl; - - m_device = alcOpenDevice(NULL); - if(!m_device){ - infostream<<"Audio: No audio device available, audio system " - <<"not initialized"<<std::endl; - return; - } - - m_context = alcCreateContext(m_device, NULL); - if(!m_context){ - error = alcGetError(m_device); - infostream<<"Audio: Unable to initialize audio context, " - <<"aborting audio initialization ("<<alcErrorString(error) - <<")"<<std::endl; - alcCloseDevice(m_device); - m_device = NULL; - return; - } - - if(!alcMakeContextCurrent(m_context) || - (error = alcGetError(m_device) != ALC_NO_ERROR)) - { - infostream<<"Audio: Error setting audio context, aborting audio " - <<"initialization ("<<alcErrorString(error)<<")"<<std::endl; - alcDestroyContext(m_context); - m_context = NULL; - alcCloseDevice(m_device); - m_device = NULL; - return; - } - - alDistanceModel(AL_INVERSE_DISTANCE_CLAMPED); - - infostream<<"Audio: Initialized: OpenAL "<<alGetString(AL_VERSION) - <<", using "<<alcGetString(m_device, ALC_DEVICE_SPECIFIER) - <<std::endl; - - m_is_initialized = true; + infostream << "Audio: Initialized: OpenAL " << std::endl; } ~OpenALSoundManager() { - infostream<<"Audio: Deinitializing..."<<std::endl; - // KABOOM! - // TODO: Clear SoundBuffers - alcMakeContextCurrent(NULL); - alcDestroyContext(m_context); - m_context = NULL; - alcCloseDevice(m_device); - m_device = NULL; + infostream << "Audio: Deinitializing..." << std::endl; + + std::unordered_set<int> source_del_list; + + for (const auto &sp : m_sounds_playing) + source_del_list.insert(sp.second->source_id); + + for (const auto &id : source_del_list) + deleteSound(id); for (auto &buffer : m_buffers) { for (SoundBuffer *sb : buffer.second) { @@ -360,7 +376,8 @@ public: buffer.second.clear(); } m_buffers.clear(); - infostream<<"Audio: Deinitialized."<<std::endl; + + infostream << "Audio: Deinitialized." << std::endl; } void step(float dtime) @@ -386,7 +403,7 @@ public: std::unordered_map<std::string, std::vector<SoundBuffer*>>::iterator i = m_buffers.find(name); if(i == m_buffers.end()) - return NULL; + return nullptr; std::vector<SoundBuffer*> &bufs = i->second; int j = myrand() % bufs.size(); return bufs[j]; @@ -395,7 +412,7 @@ public: PlayingSound* createPlayingSound(SoundBuffer *buf, bool loop, float volume, float pitch) { - infostream<<"OpenALSoundManager: Creating playing sound"<<std::endl; + infostream << "OpenALSoundManager: Creating playing sound" << std::endl; assert(buf); PlayingSound *sound = new PlayingSound; assert(sound); @@ -417,8 +434,8 @@ public: PlayingSound* createPlayingSoundAt(SoundBuffer *buf, bool loop, float volume, v3f pos, float pitch) { - infostream<<"OpenALSoundManager: Creating positional playing sound" - <<std::endl; + infostream << "OpenALSoundManager: Creating positional playing sound" + << std::endl; assert(buf); PlayingSound *sound = new PlayingSound; assert(sound); @@ -486,7 +503,7 @@ public: if(buf) return buf; if(!m_fetcher) - return NULL; + return nullptr; std::set<std::string> paths; std::set<std::string> datas; m_fetcher->fetchSounds(name, paths, datas); @@ -505,8 +522,8 @@ public: verbosestream<<"OpenALSoundManager::maintain(): " <<m_sounds_playing.size()<<" playing sounds, " <<m_buffers.size()<<" sound names loaded"<<std::endl; - std::set<int> del_list; - for (auto &sp : m_sounds_playing) { + std::unordered_set<int> del_list; + for (const auto &sp : m_sounds_playing) { int id = sp.first; PlayingSound *sound = sp.second; // If not playing, remove it @@ -570,8 +587,8 @@ public: return 0; SoundBuffer *buf = getFetchBuffer(name); if(!buf){ - infostream<<"OpenALSoundManager: \""<<name<<"\" not found." - <<std::endl; + infostream << "OpenALSoundManager: \"" << name << "\" not found." + << std::endl; return -1; } int handle = -1; @@ -591,8 +608,8 @@ public: return 0; SoundBuffer *buf = getFetchBuffer(name); if(!buf){ - infostream<<"OpenALSoundManager: \""<<name<<"\" not found." - <<std::endl; + infostream << "OpenALSoundManager: \"" << name << "\" not found." + << std::endl; return -1; } return playSoundRawAt(buf, loop, volume, pos, pitch); @@ -683,12 +700,12 @@ public: } }; -ISoundManager *createOpenALSoundManager(OnDemandSoundFetcher *fetcher) +std::shared_ptr<SoundManagerSingleton> createSoundManagerSingleton() { - OpenALSoundManager *m = new OpenALSoundManager(fetcher); - if(m->m_is_initialized) - return m; - delete m; - return NULL; -}; + return std::shared_ptr<SoundManagerSingleton>(new SoundManagerSingleton()); +} +ISoundManager *createOpenALSoundManager(SoundManagerSingleton *smg, OnDemandSoundFetcher *fetcher) +{ + return new OpenALSoundManager(smg, fetcher); +}; diff --git a/src/sound_openal.h b/src/sound_openal.h index 6d538c8f9..f2cff4daa 100644 --- a/src/sound_openal.h +++ b/src/sound_openal.h @@ -19,6 +19,12 @@ with this program; if not, write to the Free Software Foundation, Inc., #pragma once +#include <memory> + #include "sound.h" -ISoundManager *createOpenALSoundManager(OnDemandSoundFetcher *fetcher); +class SoundManagerSingleton; +extern std::shared_ptr<SoundManagerSingleton> g_sound_manager_singleton; + +std::shared_ptr<SoundManagerSingleton> createSoundManagerSingleton(); +ISoundManager *createOpenALSoundManager(SoundManagerSingleton *smg, OnDemandSoundFetcher *fetcher); |