From db526ef68b89c49bb3c1d5226fbca155648669c5 Mon Sep 17 00:00:00 2001 From: Nimetu Date: Wed, 3 Nov 2021 15:39:39 +0200 Subject: [PATCH 1/3] Runtime discovery of available sound drivers --- nel/include/nel/sound/driver/sound_driver.h | 7 +- nel/include/nel/sound/u_audio_mixer.h | 14 +- nel/samples/sound/sound_sources/main.cpp | 19 +- nel/src/sound/audio_mixer_user.cpp | 77 +++++++- nel/src/sound/driver/sound_driver.cpp | 198 ++++++++++++++------ 5 files changed, 235 insertions(+), 80 deletions(-) diff --git a/nel/include/nel/sound/driver/sound_driver.h b/nel/include/nel/sound/driver/sound_driver.h index ebe904cb8..1b63a0417 100644 --- a/nel/include/nel/sound/driver/sound_driver.h +++ b/nel/include/nel/sound/driver/sound_driver.h @@ -127,6 +127,12 @@ public: /// Return driver name from type. static const char *getDriverName(TDriver driverType); + /// Return driver dll filename, empty if unsupported driver + static std::string getDriverFileName(TDriver driverType); + /** Return possibly available drivers for current platform. + * If no drivers are available, return empty list. + */ + static std::vector getAvailableDrivers(); /** The static method which builds the sound driver instance * In case of failure, can throw one of these ESoundDriver exception objects: * ESoundDriverNotFound, ESoundDriverCorrupted, ESoundDriverOldVersion, ESoundDriverUnknownVersion @@ -204,7 +210,6 @@ public: private: std::string _DllName; - }; diff --git a/nel/include/nel/sound/u_audio_mixer.h b/nel/include/nel/sound/u_audio_mixer.h index 84257e8ce..9e87901da 100644 --- a/nel/include/nel/sound/u_audio_mixer.h +++ b/nel/include/nel/sound/u_audio_mixer.h @@ -90,6 +90,13 @@ public: NumDrivers }; + struct TDriverInfo + { + TDriver ID; + const char *Name; + TDriverInfo(TDriver id, const char *name) : ID(id), Name(name) + {} + }; /** Structure that contain the background flags.*/ struct TBackgroundFlags @@ -162,7 +169,10 @@ public: /// I forgot what this does, but it's fairly important. bool AutoLoadSample; }; - + + /// Return list of available sound drivers + static std::vector getDrivers(); + //@{ //@name Init methods /// Create the audio mixer singleton and return a pointer to its instance @@ -212,7 +222,7 @@ public: * \param forceSoftware: to force the driver to load in software buffer, not hardware */ virtual void init(uint maxTrack = 32, bool useEax = true, bool useADPCM = true, NLMISC::IProgressCallback *progressCallBack = NULL, bool autoLoadSample = false, TDriver driverType = DriverAuto, bool forceSoftware = false, bool manualRolloff = true) = 0; - + /// Initialize the NeL Sound Driver with given driverName. virtual void initDriver(const std::string &driverName) = 0; /// Get the available devices on the loaded driver. diff --git a/nel/samples/sound/sound_sources/main.cpp b/nel/samples/sound/sound_sources/main.cpp index 502d02dfb..b4eddf610 100644 --- a/nel/samples/sound/sound_sources/main.cpp +++ b/nel/samples/sound/sound_sources/main.cpp @@ -67,16 +67,23 @@ void Init() AudioMixer->setPackedSheetOption("data", true); printf("Select NLSOUND Driver:\n"); - printf(" [1] FMod\n"); - printf(" [2] OpenAl\n"); - printf(" [3] DSound\n"); - printf(" [4] XAudio2\n"); + std::vector drivers = UAudioMixer::getDrivers(); + if (drivers.size() == 0) + nlerror("No sound drivers available"); + + for(uint i = 0; i < drivers.size(); ++i) + printf(" [%d] %s\n", i, drivers[i].Name); + printf("> "); - int selection = getchar(); + int selection = getchar() - '0'; printf("\n"); + UAudioMixer::TDriver selectedDriver = UAudioMixer::DriverAuto; + if (selection >= 0 && selection < drivers.size()) + selectedDriver = drivers[selection].ID; + // init with 32 tracks, EAX enabled, no ADPCM, and activate automatic sample bank loading - AudioMixer->init(32, true, false, NULL, true, (UAudioMixer::TDriver)(selection - '0')/*UAudioMixer::DriverFMod*/); + AudioMixer->init(32, true, false, NULL, true, selectedDriver); /* * 2. Initialize listener's position and orientation (in NeL coordinate system). diff --git a/nel/src/sound/audio_mixer_user.cpp b/nel/src/sound/audio_mixer_user.cpp index d6098e6a9..0b66886f5 100644 --- a/nel/src/sound/audio_mixer_user.cpp +++ b/nel/src/sound/audio_mixer_user.cpp @@ -131,6 +131,39 @@ CAudioMixerUser::CAudioMixerUser() : _AutoLoadSample(false), } } +// ****************************************************************** +std::vector UAudioMixer::getDrivers() +{ + std::vector drivers; + std::vector drv = ISoundDriver::getAvailableDrivers(); + for(uint i = 0; i < drv.size(); ++i) + { + switch(drv[i]) + { + case ISoundDriver::DriverAuto: + drivers.push_back(TDriverInfo(DriverAuto, ISoundDriver::getDriverName(drv[i]))); + break; + case ISoundDriver::DriverFMod: + drivers.push_back(TDriverInfo(DriverFMod, ISoundDriver::getDriverName(drv[i]))); + break; + case ISoundDriver::DriverDSound: + drivers.push_back(TDriverInfo(DriverDSound, ISoundDriver::getDriverName(drv[i]))); + break; + case ISoundDriver::DriverOpenAl: + drivers.push_back(TDriverInfo(DriverOpenAl, ISoundDriver::getDriverName(drv[i]))); + break; + case ISoundDriver::DriverXAudio2: + drivers.push_back(TDriverInfo(DriverXAudio2, ISoundDriver::getDriverName(drv[i]))); + break; + default: + nlwarning("Unknown driver id %d, name '%s'", drv[i], ISoundDriver::getDriverName(drv[i])); + break; + } + } + + return drivers; +} + // ****************************************************************** @@ -374,16 +407,42 @@ void CAudioMixerUser::initDriver(const std::string &driverName) std::string dn = NLMISC::toLowerAscii(driverName); nldebug("AM: Init Driver '%s' ('%s')...", driverName.c_str(), dn.c_str()); - ISoundDriver::TDriver driverType; - if (dn == "auto") driverType = ISoundDriver::DriverAuto; - else if (dn == "fmod") driverType = ISoundDriver::DriverFMod; - else if (dn == "dsound") driverType = ISoundDriver::DriverDSound; - else if (dn == "openal") driverType = ISoundDriver::DriverOpenAl; - else if (dn == "xaudio2") driverType = ISoundDriver::DriverXAudio2; - else + TDriver driverId = dn == "auto" ? DriverAuto : NumDrivers; + if (driverId == NumDrivers) { - driverType = ISoundDriver::DriverAuto; - nlwarning("AM: driverName value '%s' ('%s') is invalid.", driverName.c_str(), dn.c_str()); + std::vector drivers = UAudioMixer::getDrivers(); + for(uint i = 0; i < drivers.size(); ++i) + { + if (nlstricmp(drivers[i].Name, dn.c_str()) == 0) + { + driverId = drivers[i].ID; + break; + } + } + } + + ISoundDriver::TDriver driverType; + switch(driverId) + { + case DriverAuto: + driverType = ISoundDriver::DriverAuto; + break; + case DriverFMod: + driverType = ISoundDriver::DriverFMod; + break; + case DriverDSound: + driverType = ISoundDriver::DriverDSound; + break; + case DriverOpenAl: + driverType = ISoundDriver::DriverOpenAl; + break; + case DriverXAudio2: + driverType = ISoundDriver::DriverXAudio2; + break; + case NumDrivers: + driverType = ISoundDriver::DriverAuto; + nlwarning("AM: driverName value '%s' ('%s') is not available.", driverName.c_str(), dn.c_str()); + break; } try diff --git a/nel/src/sound/driver/sound_driver.cpp b/nel/src/sound/driver/sound_driver.cpp index 378bc7ac7..35a1006b1 100644 --- a/nel/src/sound/driver/sound_driver.cpp +++ b/nel/src/sound/driver/sound_driver.cpp @@ -57,7 +57,7 @@ namespace NLSOUND /// Interface version, increase when any part of sound_lowlevel is changed. /// Put your name in comment to make sure you don't commit with /// the same interface version number as someone else. -const uint32 ISoundDriver::InterfaceVersion = 0x16; // Kaetemi +const uint32 ISoundDriver::InterfaceVersion = 0x17; // Nimetu #ifdef NL_STATIC @@ -104,6 +104,138 @@ const char *ISoundDriver::getDriverName(TDriver driverType) } } +/// Return driver filename from type. +std::string ISoundDriver::getDriverFileName(TDriver driverType) +{ + switch(driverType) + { + case DriverFMod: +#if defined (NL_COMP_MINGW) + return "libnel_drv_fmod_win"; +#elif defined (NL_OS_WINDOWS) + return "nel_drv_fmod_win"; +#elif defined (NL_OS_UNIX) + return "nel_drv_fmod"; +#else +# error "Driver name not define for this platform" +#endif // NL_OS_UNIX / NL_OS_WINDOWS + break; + case DriverOpenAl: +#if defined (NL_COMP_MINGW) + return "libnel_drv_openal_win"; +#elif defined (NL_OS_WINDOWS) + return "nel_drv_openal_win"; +#elif defined (NL_OS_UNIX) + return "nel_drv_openal"; +#else +# error "Driver name not define for this platform" +#endif + break; + case DriverDSound: +#if defined (NL_COMP_MINGW) + return "libnel_drv_dsound_win"; +#elif defined (NL_OS_WINDOWS) + return "nel_drv_dsound_win"; +#elif defined (NL_OS_UNIX) + return ""; +#else +# error "Driver name not define for this platform" +#endif + break; + case DriverXAudio2: +#if defined (NL_COMP_MINGW) + return "libnel_drv_xaudio2_win"; +#elif defined (NL_OS_WINDOWS) + return "nel_drv_xaudio2_win"; +#elif defined (NL_OS_UNIX) + return ""; +#else +# error "Driver name not define for this platform" +#endif + break; + case DriverAuto: +#if defined (NL_COMP_MINGW) + return "libnel_drv_xaudio2_win"; +#elif defined (NL_OS_WINDOWS) + return "nel_drv_xaudio2_win"; +#elif defined (NL_OS_UNIX) + return "nel_drv_openal"; +#else +# error "Driver name not define for this platform" +#endif + break; + default: + break; + } + + return ""; +} + +/// +std::vector ISoundDriver::getAvailableDrivers() +{ + static std::vector m_AvailableDrivers; + + if (!m_AvailableDrivers.empty()) + return m_AvailableDrivers; + +#ifdef NL_STATIC +# ifdef NL_FMOD_AVAILABLE + m_AvailableDrivers.push_back(DriverFMod); +# endif +# ifdef NL_OPENAL_AVAILABLE + m_AvailableDrivers.push_back(DriverOpenAl); +# endif +# ifdef NL_DSOUND_AVAILABLE + m_AvailableDrivers.push_back(DriverDSound); +# endif +# ifdef NL_XAUDIO2_AVAILABLE + m_AvailableDrivers.push_back(DriverXAudio2); +# endif + +#else // NL_STATIC + + const std::vector vec = { + DriverFMod, + DriverOpenAl, + DriverDSound, + DriverXAudio2, + }; + +#if 0 + // if platform has dynamic driver name set, consider it as available + for(uint i = 0; i < vec.size(); i++) + { + std::string dllName = getDriverFileName(vec[i]); + if(!dllName.empty()) + m_AvailableDrivers.push_back(vec[i]); + } +#else + CLibrary driverLib; +#if defined(NL_OS_UNIX) && defined(NL_DRIVER_PREFIX) + driverLib.addLibPath(NL_DRIVER_PREFIX); +#endif + nlinfo("Detecting available sound drivers"); + for(uint i = 0; i < vec.size(); i++) + { + std::string dllName = getDriverFileName(vec[i]); + if(!dllName.empty()) + { + // Load it (adding standard nel pre/suffix, looking in library path and taking ownership) + if (driverLib.loadLibrary(dllName, true, true, true)) + { + m_AvailableDrivers.push_back(vec[i]); + driverLib.freeLibrary(); + } + } + } +#endif + +#endif + + return m_AvailableDrivers; +} + /* * The static method which builds the sound driver instance */ @@ -151,67 +283,9 @@ ISoundDriver *ISoundDriver::createDriver(IStringMapperProvider *stringMapper, TD ISDRV_VERSION_PROC versionDriver = NULL; // dll selected - std::string dllName; - - // Choose the DLL - switch(driverType) - { - case DriverFMod: -#if defined (NL_COMP_MINGW) - dllName = "libnel_drv_fmod_win"; -#elif defined (NL_OS_WINDOWS) - dllName = "nel_drv_fmod_win"; -#elif defined (NL_OS_UNIX) - dllName = "nel_drv_fmod"; -#else -# error "Driver name not define for this platform" -#endif // NL_OS_UNIX / NL_OS_WINDOWS - break; - case DriverOpenAl: -#if defined (NL_COMP_MINGW) - dllName = "libnel_drv_openal_win"; -#elif defined (NL_OS_WINDOWS) - dllName = "nel_drv_openal_win"; -#elif defined (NL_OS_UNIX) - dllName = "nel_drv_openal"; -#else -# error "Driver name not define for this platform" -#endif - break; - case DriverDSound: -#if defined (NL_COMP_MINGW) - dllName = "libnel_drv_dsound_win"; -#elif defined (NL_OS_WINDOWS) - dllName = "nel_drv_dsound_win"; -#elif defined (NL_OS_UNIX) - nlerror("DriverDSound doesn't exist on Unix because it requires DirectX"); -#else -# error "Driver name not define for this platform" -#endif - break; - case DriverXAudio2: -#if defined (NL_COMP_MINGW) - dllName = "libnel_drv_xaudio2_win"; -#elif defined (NL_OS_WINDOWS) - dllName = "nel_drv_xaudio2_win"; -#elif defined (NL_OS_UNIX) - nlerror("DriverXAudio2 doesn't exist on Unix because it requires DirectX"); -#else -# error "Driver name not define for this platform" -#endif - break; - default: -#if defined (NL_COMP_MINGW) - dllName = "libnel_drv_xaudio2_win"; -#elif defined (NL_OS_WINDOWS) - dllName = "nel_drv_xaudio2_win"; -#elif defined (NL_OS_UNIX) - dllName = "nel_drv_openal"; -#else -# error "Driver name not define for this platform" -#endif - break; - } + std::string dllName = getDriverFileName(driverType); + if (dllName.empty()) + throw ESoundDriverCantCreateDriver(("Driver '%s' not available for this platform", ISoundDriver::getDriverName(driverType))); CLibrary driverLib; From f36450d81559ceb1b792bbace979a10b3898119b Mon Sep 17 00:00:00 2001 From: Nimetu Date: Mon, 20 Dec 2021 12:35:03 +0200 Subject: [PATCH 2/3] Sound driver selection ui --- .../client/data/gamedev/interfaces_v3/game_config.xml | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/ryzom/client/data/gamedev/interfaces_v3/game_config.xml b/ryzom/client/data/gamedev/interfaces_v3/game_config.xml index 0ca7ad5b4..f09e32389 100644 --- a/ryzom/client/data/gamedev/interfaces_v3/game_config.xml +++ b/ryzom/client/data/gamedev/interfaces_v3/game_config.xml @@ -138,6 +138,7 @@ + @@ -683,7 +684,14 @@ - + + + + + + + + From fd4d3e0c3498e2a4f0a1a52c5ad16b1dd70b0652 Mon Sep 17 00:00:00 2001 From: Nimetu Date: Tue, 2 Nov 2021 13:13:03 +0200 Subject: [PATCH 3/3] Allow to change sound driver from ingame (ryzom/ryzomcore#63) --- .../src/interface_v3/action_handler_game.cpp | 116 ++++++++++++++++++ ryzom/client/src/main_loop_utilities.cpp | 13 +- 2 files changed, 128 insertions(+), 1 deletion(-) diff --git a/ryzom/client/src/interface_v3/action_handler_game.cpp b/ryzom/client/src/interface_v3/action_handler_game.cpp index 75c9ef0e3..2b55f2c78 100644 --- a/ryzom/client/src/interface_v3/action_handler_game.cpp +++ b/ryzom/client/src/interface_v3/action_handler_game.cpp @@ -95,6 +95,8 @@ #include "nel/gui/ctrl_button.h" #include "../global.h" +#include "nel/sound/u_audio_mixer.h" + using namespace std; using namespace NL3D; using namespace NLMISC; @@ -2984,6 +2986,10 @@ static vector VideoModes; #define GAME_CONFIG_ANISOTROPIC_COMBO "ui:interface:game_config:content:fx:anisotropic_gr:anisotropic" #define GAME_CONFIG_ANISOTROPIC_DB "UI:TEMP:ANISOTROPIC" +// Sound driver +#define GAME_CONFIG_SOUND_DRIVER_COMBO "ui:interface:game_config:content:sound:driver_gr:driver" +#define GAME_CONFIG_SOUND_DRIVER_DB "UI:TEMP:SOUND_DRIVER" + // The 3 possible modes editable (NB: do not allow client.cfg HDEntityTexture==1 and DivideTextureSizeBy2=2 enum TTextureMode {LowTextureMode= 0, NormalTextureMode= 1, HighTextureMode= 2}; @@ -3031,6 +3037,77 @@ void updateVRDevicesComboUI(bool enable) } } +// *************************************************************************** +void updateSoundDriverComboUI() +{ + CDBGroupComboBox *pCB = dynamic_cast(CWidgetManager::getInstance()->getElementFromId(GAME_CONFIG_SOUND_DRIVER_COMBO)); + if (!pCB) + { + nlwarning("Sound driver UI element '%s' not found", GAME_CONFIG_SOUND_DRIVER_COMBO); + return; + } + + pCB->resetTexts(); + + uint32 selected = 0; + + NLSOUND::UAudioMixer::TDriver cfgDriverId = NLSOUND::UAudioMixer::DriverAuto; + if(ClientCfg.DriverSound==CClientConfig::SoundDrvFMod) + cfgDriverId = NLSOUND::UAudioMixer::DriverFMod; + else if(ClientCfg.DriverSound==CClientConfig::SoundDrvOpenAL) + cfgDriverId = NLSOUND::UAudioMixer::DriverOpenAl; + else if(ClientCfg.DriverSound==CClientConfig::SoundDrvDirectSound) + cfgDriverId = NLSOUND::UAudioMixer::DriverDSound; + else if(ClientCfg.DriverSound==CClientConfig::SoundDrvXAudio2) + cfgDriverId = NLSOUND::UAudioMixer::DriverXAudio2; + + std::vector drivers = NLSOUND::UAudioMixer::getDrivers(); + + // add AUTO for ingame selection, if one is not already in list + bool found = false; + for(uint i = 0; i < drivers.size(); ++i) + { + if (drivers[i].ID == NLSOUND::UAudioMixer::DriverAuto) + { + found = true; + break; + } + } + if (!found) + drivers.insert(drivers.begin(), 1, NLSOUND::UAudioMixer::TDriverInfo(NLSOUND::UAudioMixer::DriverAuto, "Auto")); + + for(uint i = 0; i < drivers.size(); ++i) + { + switch(drivers[i].ID) + { + case NLSOUND::UAudioMixer::DriverAuto: + pCB->addText("Auto"); + break; + case NLSOUND::UAudioMixer::DriverFMod: + pCB->addText("FMod"); + break; + case NLSOUND::UAudioMixer::DriverDSound: + pCB->addText("DirectSound"); + break; + case NLSOUND::UAudioMixer::DriverOpenAl: + pCB->addText("OpenAL"); + break; + case NLSOUND::UAudioMixer::DriverXAudio2: + pCB->addText("XAudio2"); + break; + default: + pCB->addText(drivers[i].Name); + break; + } + + if (cfgDriverId == drivers[i].ID) + selected = i; + } + + NLGUI::CDBManager::getInstance()->getDbProp(GAME_CONFIG_SOUND_DRIVER_DB)->setValue32(-1); + NLGUI::CDBManager::getInstance()->getDbProp(GAME_CONFIG_SOUND_DRIVER_DB)->setValue32(selected); +} + // *************************************************************************** class CHandlerGameConfigInit : public IActionHandler { @@ -3083,6 +3160,8 @@ public: } CAHManager::getInstance()->runActionHandler("game_config_change_vid_fullscreen",NULL); + updateSoundDriverComboUI(); + // **** Init Texture Size Modes // init the combo box, according to Texture Installed or not pCB = dynamic_cast(CWidgetManager::getInstance()->getElementFromId( GAME_CONFIG_TEXTURE_MODE_COMBO )); @@ -3439,6 +3518,32 @@ class CHandlerGameConfigVRDevice : public IActionHandler }; REGISTER_ACTION_HANDLER (CHandlerGameConfigVRDevice, "game_config_change_vr_device"); +// *************************************************************************** +class CHandlerGameConfigSoundDriver : public IActionHandler +{ + virtual void execute (CCtrlBase * pCaller, const string &/* Params */) + { + sint oldDriver = NLGUI::CDBManager::getInstance()->getDbProp(GAME_CONFIG_SOUND_DRIVER_DB)->getOldValue32(); + sint newDriver = NLGUI::CDBManager::getInstance()->getDbProp(GAME_CONFIG_SOUND_DRIVER_DB)->getValue32(); + + if (oldDriver != -1 && newDriver != oldDriver) + { + CDBGroupComboBox *pCB = dynamic_cast(CWidgetManager::getInstance()->getElementFromId(GAME_CONFIG_SOUND_DRIVER_COMBO)); + if (!pCB) + { + nlwarning("Unable to change sound driver. UI '%s' not found.", GAME_CONFIG_SOUND_DRIVER_COMBO); + return; + } + + CDDXManager *pDM = CDDXManager::getInstance(); + CInterfaceDDX *pDDX = pDM->get(GAME_CONFIG_DDX); + if(pDDX) + pDDX->validateApplyButton(); + } + } +}; +REGISTER_ACTION_HANDLER (CHandlerGameConfigSoundDriver, "game_config_change_sound_driver"); + // *************************************************************************** class CHandlerGameConfigApply : public IActionHandler { @@ -3545,6 +3650,17 @@ class CHandlerGameConfigApply : public IActionHandler ClientCfg.writeString("VRDisplayDeviceId", VRDeviceCache[deviceIdx].second); } + sint sndDriver = NLGUI::CDBManager::getInstance()->getDbProp(GAME_CONFIG_SOUND_DRIVER_DB)->getValue32(); + if (sndDriver != -1) + { + CDBGroupComboBox *pCB = dynamic_cast(CWidgetManager::getInstance()->getElementFromId(GAME_CONFIG_SOUND_DRIVER_COMBO)); + if (pCB) + { + std::string drv = pCB->getText(sndDriver); + ClientCfg.writeString("DriverSound", drv); + } + } + bool requestReboot = false; // **** Apply the texture mode diff --git a/ryzom/client/src/main_loop_utilities.cpp b/ryzom/client/src/main_loop_utilities.cpp index 95dcf82c8..ceccc80af 100644 --- a/ryzom/client/src/main_loop_utilities.cpp +++ b/ryzom/client/src/main_loop_utilities.cpp @@ -324,8 +324,19 @@ void updateFromClientCfg() bool mustReloadSoundMngrContinent= false; // disable/enable sound? - if (ClientCfg.SoundOn != LastClientCfg.SoundOn) + if (ClientCfg.SoundOn != LastClientCfg.SoundOn || ClientCfg.DriverSound != LastClientCfg.DriverSound) { + // changing sound driver + if (ClientCfg.DriverSound != LastClientCfg.DriverSound) + { + if (SoundMngr) + { + nlwarning("Changing sound driver..."); + delete SoundMngr; + SoundMngr = NULL; + } + } + if (SoundMngr && !ClientCfg.SoundOn) { nlwarning("Deleting sound manager...");