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;