diff --git a/src/music/music_driver.hpp b/src/music/music_driver.hpp index b5984a4d82..93928cd141 100644 --- a/src/music/music_driver.hpp +++ b/src/music/music_driver.hpp @@ -12,6 +12,14 @@ #include "../driver.h" +#include +#include +#if defined(__MINGW32__) +#include "../3rdparty/mingw-std-threads/mingw.mutex.h" +#endif + +extern std::mutex _music_driver_mutex; + struct MusicSongInfo; /** Driver for all music playback. */ @@ -46,10 +54,20 @@ public: */ virtual bool IsInFailedState() { return false; } + static std::unique_ptr ExtractDriver() + { + Driver **dptr = DriverFactoryBase::GetActiveDriver(Driver::DT_MUSIC); + Driver *driver = *dptr; + *dptr = nullptr; + return std::unique_ptr(static_cast(driver)); + } + /** * Get the currently active instance of the music driver. */ static MusicDriver *GetInstance() { + std::unique_lock lock(_music_driver_mutex); + return static_cast(*DriverFactoryBase::GetActiveDriver(Driver::DT_MUSIC)); } }; diff --git a/src/music_gui.cpp b/src/music_gui.cpp index 0215b17e34..a89c8ccb20 100644 --- a/src/music_gui.cpp +++ b/src/music_gui.cpp @@ -174,6 +174,7 @@ void MusicSystem::ChangePlaylist(PlaylistChoices pl) */ void MusicSystem::ChangeMusicSet(const std::string &set_name) { + if (set_name != "NoMusic") InitMusicDriver(true); BaseMusic::SetSet(set_name); BaseMusic::ini_set = set_name; diff --git a/src/openttd.cpp b/src/openttd.cpp index e7730c9439..314e49f812 100644 --- a/src/openttd.cpp +++ b/src/openttd.cpp @@ -97,6 +97,7 @@ #include "3rdparty/cpp-btree/btree_set.h" +#include #include #if defined(__MINGW32__) #include "3rdparty/mingw-std-threads/mingw.mutex.h" @@ -135,6 +136,10 @@ NewGRFScanCallback *_request_newgrf_scan_callback = nullptr; SimpleChecksum64 _state_checksum; +std::mutex _music_driver_mutex; +static std::string _music_driver_params; +static std::atomic _music_inited; + /** * Error handling for fatal user errors. * @param s the string to print. @@ -1010,7 +1015,13 @@ int openttd_main(int argc, char *argv[]) DriverFactoryBase::SelectDriver(sounddriver, Driver::DT_SOUND); if (musicdriver.empty() && !_ini_musicdriver.empty()) musicdriver = _ini_musicdriver; - DriverFactoryBase::SelectDriver(musicdriver, Driver::DT_MUSIC); + _music_driver_params = std::move(musicdriver); + if (_music_driver_params.empty() && BaseMusic::GetUsedSet()->name == "NoMusic") { + DEBUG(driver, 1, "Deferring loading of music driver until a music set is loaded"); + DriverFactoryBase::SelectDriver("null", Driver::DT_MUSIC); + } else { + InitMusicDriver(false); + } GenerateWorld(GWM_EMPTY, 64, 64); // Make the viewport initialization happy LoadIntroGame(false); @@ -1041,6 +1052,22 @@ int openttd_main(int argc, char *argv[]) return ret; } +void InitMusicDriver(bool init_volume) +{ + if (_music_inited.exchange(true)) return; + + { + std::unique_lock lock(_music_driver_mutex); + + static std::unique_ptr old_driver; + old_driver = std::move(MusicDriver::ExtractDriver()); + + DriverFactoryBase::SelectDriver(_music_driver_params, Driver::DT_MUSIC); + } + + if (init_volume) MusicDriver::GetInstance()->SetVolume(_settings_client.music.music_vol); +} + void HandleExitGameRequest() { if (_game_mode == GM_MENU || _game_mode == GM_BOOTSTRAP) { // do not ask to quit on the main screen diff --git a/src/openttd.h b/src/openttd.h index 26743a0104..1148da8e36 100644 --- a/src/openttd.h +++ b/src/openttd.h @@ -91,6 +91,7 @@ void AskExitToGameMenu(); int openttd_main(int argc, char *argv[]); void StateGameLoop(); void HandleExitGameRequest(); +void InitMusicDriver(bool init_volume); void SwitchToMode(SwitchMode new_mode);