sfxFMODProvider.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398
  1. //-----------------------------------------------------------------------------
  2. // Copyright (c) 2012 GarageGames, LLC
  3. //
  4. // Permission is hereby granted, free of charge, to any person obtaining a copy
  5. // of this software and associated documentation files (the "Software"), to
  6. // deal in the Software without restriction, including without limitation the
  7. // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  8. // sell copies of the Software, and to permit persons to whom the Software is
  9. // furnished to do so, subject to the following conditions:
  10. //
  11. // The above copyright notice and this permission notice shall be included in
  12. // all copies or substantial portions of the Software.
  13. //
  14. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  19. // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
  20. // IN THE SOFTWARE.
  21. //-----------------------------------------------------------------------------
  22. #include "sfx/sfxProvider.h"
  23. #include "sfx/fmod/sfxFMODDevice.h"
  24. #include "core/util/safeRelease.h"
  25. #include "console/console.h"
  26. #include "core/util/safeDelete.h"
  27. #include "core/module.h"
  28. #include "console/consoleTypes.h"
  29. class SFXFMODProvider : public SFXProvider
  30. {
  31. public:
  32. SFXFMODProvider()
  33. : SFXProvider( "FMOD" )
  34. {
  35. Con::addVariable( "$SFX::Device::fmodNumEventSources", TypeS32, &SFXFMODDevice::smStatNumEventSources,
  36. "The current number of SFXFMODEventSource instances in the system.\n"
  37. "This tells the number of sounds in the system that are currently playing FMOD Designer events.\n\n"
  38. "@note Only relevant if an %FMOD sound device is used.\n\n"
  39. "@ingroup SFXFMOD" );
  40. Con::addVariable( "$SFX::Device::fmodCoreMem", TypeS32, &SFXFMODDevice::smStatMemUsageCore,
  41. "Current number of bytes allocated by the core %FMOD sound system.\n\n"
  42. "@note Only relevant if an %FMOD sound device is used.\n\n"
  43. "@ingroup SFXFMOD" );
  44. Con::addVariable( "$SFX::Device::fmodEventMem", TypeS32, &SFXFMODDevice::smStatMemUsageEvents,
  45. "Current number of bytes allocated by the %FMOD Designer event system.\n\n"
  46. "@note Only relevant if an %FMOD sound device is used and the FMOD event DLL is loaded.\n\n"
  47. "@ingroup SFXFMOD" );
  48. Con::addVariable( "$pref::SFX::FMOD::disableSoftware", TypeBool, &SFXFMODDevice::smPrefDisableSoftware,
  49. "Whether to disable the %FMOD software mixer to conserve memory.\n"
  50. "All sounds not created with SFXDescription::useHardware or using DSP effects will fail to load.\n\n"
  51. "@note Only applies when using an %FMOD sound device.\n\n"
  52. "@ingroup SFXFMOD" );
  53. Con::addVariable( "$pref::SFX::FMOD::useSoftwareHRTF", TypeBool, &SFXFMODDevice::smPrefUseSoftwareHRTF,
  54. "Whether to enable HRTF in %FMOD's software mixer.\n"
  55. "This will add a lowpass filter effect to the DSP effect chain of all sounds mixed in software.\n\n"
  56. "@note Only applies when using an %FMOD sound device.\n\n"
  57. "@ingroup SFXFMOD" );
  58. Con::addVariable( "$pref::SFX::FMOD::enableProfile", TypeBool, &SFXFMODDevice::smPrefEnableProfile,
  59. "Whether to enable support for %FMOD's profiler.\n\n"
  60. "@note Only applies when using an %FMOD sound device.\n\n"
  61. "@ref FMOD_profiler\n\n"
  62. "@ingroup SFXFMOD" );
  63. Con::addVariable( "$pref::SFX::FMOD::DSoundHRTF", TypeString, &SFXFMODDevice::smPrefDSoundHRTF,
  64. "The type of HRTF to use for hardware-mixed 3D sounds when %FMOD is using DirectSound for sound output "
  65. "and hardware-acceleration is not available.\n\n"
  66. "Options are\n"
  67. "- \"none\": simple stereo panning/doppler/attenuation\n"
  68. "- \"light\": slightly higher quality than \"none\"\n"
  69. "- \"full\": full quality 3D playback\n\n"
  70. "@note Only applies when using an %FMOD sound device.\n\n"
  71. "@ingroup SFXFMOD" );
  72. Con::addVariable( "$pref::SFX::FMOD::pluginPath", TypeString, &SFXFMODDevice::smPrefPluginPath,
  73. "%Path to additional %FMOD plugins.\n\n"
  74. "@note Only applies when using an %FMOD sound device.\n\n"
  75. "@ingroup SFXFMOD" );
  76. }
  77. virtual ~SFXFMODProvider();
  78. protected:
  79. FModFNTable mFMod;
  80. struct FModDeviceInfo : SFXDeviceInfo
  81. {
  82. FMOD_CAPS mCaps;
  83. FMOD_SPEAKERMODE mSpeakerMode;
  84. };
  85. void init();
  86. bool _createSystem();
  87. public:
  88. SFXDevice* createDevice( const String& deviceName, bool useHardware, S32 maxBuffers );
  89. };
  90. MODULE_BEGIN( FMOD )
  91. MODULE_INIT_BEFORE( SFX )
  92. MODULE_SHUTDOWN_AFTER( SFX )
  93. SFXFMODProvider* mProvider;
  94. MODULE_INIT
  95. {
  96. mProvider = new SFXFMODProvider;
  97. }
  98. MODULE_SHUTDOWN
  99. {
  100. delete mProvider;
  101. }
  102. MODULE_END;
  103. //------------------------------------------------------------------------------
  104. // Helper
  105. bool fmodBindFunction( DLibrary *dll, void *&fnAddress, const char* name )
  106. {
  107. if( !dll )
  108. return false;
  109. fnAddress = dll->bind( name );
  110. if (!fnAddress)
  111. Con::warnf( "FMOD Loader: DLL bind failed for %s", name );
  112. return fnAddress != 0;
  113. }
  114. //------------------------------------------------------------------------------
  115. void SFXFMODProvider::init()
  116. {
  117. #ifdef TORQUE_FMOD_STATIC
  118. // FMOD statically linked.
  119. mFMod.isLoaded = true;
  120. #define FMOD_FUNCTION(fn_name, fn_args) \
  121. (*(void**)&mFMod.fn_name.fn) = &fn_name;
  122. #ifndef TORQUE_FMOD_NO_EVENTS
  123. mFMod.eventIsLoaded = true;
  124. #define FMOD_EVENT_FUNCTION(fn_name, fn_args) \
  125. (*(void**)&mFMod.fn_name.fn) = &fn_name;
  126. #else
  127. #define FMOD_EVENT_FUNCTION( fn_name, fn_args )
  128. #endif
  129. #include FMOD_FN_FILE
  130. #undef FMOD_FUNCTION
  131. #undef FMOD_EVENT_FUNCTION
  132. #else
  133. // FMOD dynamically linked.
  134. const char* dllName;
  135. const char* pDllName; // plugin-based DLL
  136. const char* eventDllName;
  137. #ifdef _WIN64
  138. dllName = "fmodex64.dll";
  139. pDllName = "fmodexp64.dll";
  140. eventDllName = "fmod_event64.dll";
  141. #elif defined(TORQUE_OS_WIN)
  142. dllName = "fmodex.dll";
  143. pDllName = "fmodexp.dll";
  144. eventDllName = "fmod_event.dll";
  145. #elif defined( TORQUE_OS_MAC )
  146. dllName = "libfmodex.dylib";
  147. pDllName = "libfmodexp.dylib";
  148. eventDllName = "libfmodevent.dylib";
  149. #else
  150. # warning Need to set FMOD DLL filename for platform.
  151. return;
  152. #endif
  153. // Grab the functions we'll want from the fmod DLL.
  154. mFMod.dllRef = OsLoadLibrary( dllName );
  155. // Try the plugin-based version.
  156. if( !mFMod.dllRef )
  157. mFMod.dllRef = OsLoadLibrary( pDllName );
  158. if(!mFMod.dllRef)
  159. {
  160. Con::warnf( "SFXFMODProvider - Could not locate '%s' or '%s' - FMOD not available.", dllName, pDllName );
  161. return;
  162. }
  163. mFMod.eventDllRef = OsLoadLibrary( eventDllName );
  164. if(!mFMod.eventDllRef)
  165. Con::warnf( "SFXFMODProvider - Could not locate %s - FMOD Designer integration not available.", eventDllName );
  166. mFMod.isLoaded = true;
  167. mFMod.eventIsLoaded = true;
  168. #define FMOD_FUNCTION(fn_name, fn_args) \
  169. mFMod.isLoaded &= fmodBindFunction(mFMod.dllRef, *(void**)&mFMod.fn_name.fn, #fn_name);
  170. #define FMOD_EVENT_FUNCTION(fn_name, fn_args) \
  171. mFMod.eventIsLoaded &= fmodBindFunction(mFMod.eventDllRef, *(void**)&mFMod.fn_name.fn, #fn_name);
  172. #include FMOD_FN_FILE
  173. #undef FMOD_FUNCTION
  174. #undef FMOD_EVENT_FUNCTION
  175. if(mFMod.isLoaded == false)
  176. {
  177. Con::warnf("SFXFMODProvider - Could not load %s - FMOD not available.", dllName);
  178. return;
  179. }
  180. if( !mFMod.eventIsLoaded && mFMod.eventDllRef )
  181. Con::warnf("SFXFMODProvider - Could not load %s - FMOD Designer integration not available.", eventDllName);
  182. #endif
  183. FMOD_RESULT res;
  184. // Create the FMOD system object.
  185. if( !_createSystem() )
  186. return;
  187. // Check that the Ex API version is OK.
  188. unsigned int version;
  189. res = mFMod.FMOD_System_GetVersion(SFXFMODDevice::smSystem, &version);
  190. FModAssert(res, "SFXFMODProvider - Failed to get FMOD version!");
  191. Con::printf( "SFXFMODProvider - FMOD Ex API version: %x.%x.%x",
  192. ( version & 0xffff0000 ) >> 16,
  193. ( version & 0x0000ff00 ) >> 8,
  194. ( version & 0x000000ff )
  195. );
  196. if(version < FMOD_VERSION)
  197. {
  198. Con::warnf("SFXFMODProvider - FMOD Ex API version in DLL is too old - FMOD not available.");
  199. return;
  200. }
  201. // Check that the Designer API version is ok.
  202. if( mFMod.eventIsLoaded )
  203. {
  204. res = mFMod.FMOD_EventSystem_GetVersion( SFXFMODDevice::smEventSystem, &version );
  205. FModAssert(res, "SFXFMODProvider - Failed to get FMOD version!");
  206. Con::printf( "SFXFMODProvider - FMOD Designer API version: %x.%x.%x",
  207. ( version & 0xffff0000 ) >> 16,
  208. ( version & 0x0000ff00 ) >> 8,
  209. ( version & 0x000000ff )
  210. );
  211. if( version < FMOD_EVENT_VERSION )
  212. {
  213. Con::errorf( "SFXFMODProvider - FMOD Designer API version in DLL is too old!" );
  214. return;
  215. }
  216. }
  217. // Now, enumerate our devices.
  218. int numDrivers;
  219. res = mFMod.FMOD_System_GetNumDrivers(SFXFMODDevice::smSystem, &numDrivers);
  220. FModAssert(res, "SFXFMODProvider - Failed to get driver count - FMOD not available.");
  221. char nameBuff[256];
  222. for(S32 i=0; i<numDrivers; i++)
  223. {
  224. res = mFMod.FMOD_System_GetDriverInfo(SFXFMODDevice::smSystem, i, nameBuff, 256, ( FMOD_GUID* ) NULL);
  225. if( res != FMOD_OK )
  226. {
  227. Con::errorf( "SFXFMODProvider - Failed to get driver name (%s)", FMODResultToString( res ).c_str() );
  228. continue;
  229. }
  230. nameBuff[ 255 ] = '\0';
  231. FMOD_CAPS caps;
  232. FMOD_SPEAKERMODE speakerMode;
  233. res = mFMod.FMOD_System_GetDriverCaps( SFXFMODDevice::smSystem, i, &caps, ( int* ) 0, &speakerMode );
  234. if( res != FMOD_OK )
  235. {
  236. Con::errorf( "SFXFMODProvider - Failed to get driver caps (%s)", FMODResultToString( res ).c_str() );
  237. continue;
  238. }
  239. // Great - got something - so add it to the list of options.
  240. FModDeviceInfo *fmodInfo = new FModDeviceInfo();
  241. fmodInfo->name = String( nameBuff );
  242. fmodInfo->hasHardware = caps & FMOD_CAPS_HARDWARE;
  243. fmodInfo->maxBuffers = 32;
  244. fmodInfo->driver = String();
  245. fmodInfo->mCaps = caps;
  246. fmodInfo->mSpeakerMode = speakerMode;
  247. mDeviceInfo.push_back(fmodInfo);
  248. }
  249. // Did we get any devices?
  250. if ( mDeviceInfo.empty() )
  251. {
  252. Con::warnf( "SFXFMODProvider - No valid devices found - FMOD not available." );
  253. return;
  254. }
  255. // TODO: FMOD_Memory_Initialize
  256. #ifdef TORQUE_OS_XENON
  257. const dsize_t memSz = 5 * 1024 * 1024;
  258. void *memBuffer = XPhysicalAlloc( memSz, MAXULONG_PTR, 0, PAGE_READWRITE );
  259. mFMod.FMOD_Memory_Initialize( memBuffer, memSz, FMOD_MEMORY_ALLOCCALLBACK(NULL), FMOD_MEMORY_REALLOCCALLBACK(NULL), FMOD_MEMORY_FREECALLBACK(NULL) );
  260. #endif
  261. // Wow, we made it - register the provider.
  262. regProvider( this );
  263. }
  264. SFXFMODProvider::~SFXFMODProvider()
  265. {
  266. if( SFXFMODDevice::smEventSystem )
  267. {
  268. mFMod.FMOD_EventSystem_Release( SFXFMODDevice::smEventSystem );
  269. SFXFMODDevice::smEventSystem = NULL;
  270. SFXFMODDevice::smSystem = NULL;
  271. }
  272. else if( SFXFMODDevice::smSystem )
  273. {
  274. mFMod.FMOD_System_Release( SFXFMODDevice::smSystem );
  275. SFXFMODDevice::smSystem = NULL;
  276. }
  277. }
  278. SFXDevice* SFXFMODProvider::createDevice( const String& deviceName, bool useHardware, S32 maxBuffers )
  279. {
  280. FModDeviceInfo* info = dynamic_cast< FModDeviceInfo* >
  281. ( _findDeviceInfo( deviceName ) );
  282. if( !info )
  283. return NULL;
  284. if( !SFXFMODDevice::smSystem && !_createSystem() )
  285. return false;
  286. SFXFMODDevice* device = new SFXFMODDevice(this, &mFMod, 0, info->name );
  287. if( !device->_init() )
  288. SAFE_DELETE( device );
  289. return device;
  290. }
  291. bool SFXFMODProvider::_createSystem()
  292. {
  293. AssertFatal( !SFXFMODDevice::smEventSystem, "SFXFMODProvider::_createSystem() - event system already created!" );
  294. AssertFatal( !SFXFMODDevice::smSystem, "SFXFMODProvider::_createSystem() - system already created!" );
  295. if( mFMod.eventIsLoaded )
  296. {
  297. FMOD_RESULT res = mFMod.FMOD_EventSystem_Create( &SFXFMODDevice::smEventSystem );
  298. if( res != FMOD_OK )
  299. {
  300. Con::errorf( "SFXFMODProvider - could not create the FMOD event system." );
  301. return false;
  302. }
  303. res = mFMod.FMOD_EventSystem_GetSystemObject( SFXFMODDevice::smEventSystem, &SFXFMODDevice::smSystem );
  304. if( res != FMOD_OK )
  305. {
  306. Con::errorf( "SFXFMODProvider - could not retrieve the FMOD system object." );
  307. return false;
  308. }
  309. }
  310. else
  311. {
  312. // Allocate the FMod system.
  313. FMOD_RESULT res = mFMod.FMOD_System_Create( &SFXFMODDevice::smSystem );
  314. if( res != FMOD_OK )
  315. {
  316. // Failed - deal with it!
  317. Con::errorf("SFXFMODProvider - could not create the FMOD system.");
  318. return false;
  319. }
  320. }
  321. return true;
  322. }