sfxFMODProvider.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394
  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 TORQUE_OS_WIN
  138. dllName = "fmodex.dll";
  139. pDllName = "fmodexp.dll";
  140. eventDllName = "fmod_event.dll";
  141. #elif defined( TORQUE_OS_MAC )
  142. dllName = "libfmodex.dylib";
  143. pDllName = "libfmodexp.dylib";
  144. eventDllName = "libfmodevent.dylib";
  145. #else
  146. # warning Need to set FMOD DLL filename for platform.
  147. return;
  148. #endif
  149. // Grab the functions we'll want from the fmod DLL.
  150. mFMod.dllRef = OsLoadLibrary( dllName );
  151. // Try the plugin-based version.
  152. if( !mFMod.dllRef )
  153. mFMod.dllRef = OsLoadLibrary( pDllName );
  154. if(!mFMod.dllRef)
  155. {
  156. Con::warnf( "SFXFMODProvider - Could not locate '%s' or '%s' - FMOD not available.", dllName, pDllName );
  157. return;
  158. }
  159. mFMod.eventDllRef = OsLoadLibrary( eventDllName );
  160. if(!mFMod.eventDllRef)
  161. Con::warnf( "SFXFMODProvider - Could not locate %s - FMOD Designer integration not available.", eventDllName );
  162. mFMod.isLoaded = true;
  163. mFMod.eventIsLoaded = true;
  164. #define FMOD_FUNCTION(fn_name, fn_args) \
  165. mFMod.isLoaded &= fmodBindFunction(mFMod.dllRef, *(void**)&mFMod.fn_name.fn, #fn_name);
  166. #define FMOD_EVENT_FUNCTION(fn_name, fn_args) \
  167. mFMod.eventIsLoaded &= fmodBindFunction(mFMod.eventDllRef, *(void**)&mFMod.fn_name.fn, #fn_name);
  168. #include FMOD_FN_FILE
  169. #undef FMOD_FUNCTION
  170. #undef FMOD_EVENT_FUNCTION
  171. if(mFMod.isLoaded == false)
  172. {
  173. Con::warnf("SFXFMODProvider - Could not load %s - FMOD not available.", dllName);
  174. return;
  175. }
  176. if( !mFMod.eventIsLoaded && mFMod.eventDllRef )
  177. Con::warnf("SFXFMODProvider - Could not load %s - FMOD Designer integration not available.", eventDllName);
  178. #endif
  179. FMOD_RESULT res;
  180. // Create the FMOD system object.
  181. if( !_createSystem() )
  182. return;
  183. // Check that the Ex API version is OK.
  184. unsigned int version;
  185. res = mFMod.FMOD_System_GetVersion(SFXFMODDevice::smSystem, &version);
  186. FModAssert(res, "SFXFMODProvider - Failed to get FMOD version!");
  187. Con::printf( "SFXFMODProvider - FMOD Ex API version: %x.%x.%x",
  188. ( version & 0xffff0000 ) >> 16,
  189. ( version & 0x0000ff00 ) >> 8,
  190. ( version & 0x000000ff )
  191. );
  192. if(version < FMOD_VERSION)
  193. {
  194. Con::warnf("SFXFMODProvider - FMOD Ex API version in DLL is too old - FMOD not available.");
  195. return;
  196. }
  197. // Check that the Designer API version is ok.
  198. if( mFMod.eventIsLoaded )
  199. {
  200. res = mFMod.FMOD_EventSystem_GetVersion( SFXFMODDevice::smEventSystem, &version );
  201. FModAssert(res, "SFXFMODProvider - Failed to get FMOD version!");
  202. Con::printf( "SFXFMODProvider - FMOD Designer API version: %x.%x.%x",
  203. ( version & 0xffff0000 ) >> 16,
  204. ( version & 0x0000ff00 ) >> 8,
  205. ( version & 0x000000ff )
  206. );
  207. if( version < FMOD_EVENT_VERSION )
  208. {
  209. Con::errorf( "SFXFMODProvider - FMOD Designer API version in DLL is too old!" );
  210. return;
  211. }
  212. }
  213. // Now, enumerate our devices.
  214. int numDrivers;
  215. res = mFMod.FMOD_System_GetNumDrivers(SFXFMODDevice::smSystem, &numDrivers);
  216. FModAssert(res, "SFXFMODProvider - Failed to get driver count - FMOD not available.");
  217. char nameBuff[256];
  218. for(S32 i=0; i<numDrivers; i++)
  219. {
  220. res = mFMod.FMOD_System_GetDriverInfo(SFXFMODDevice::smSystem, i, nameBuff, 256, ( FMOD_GUID* ) NULL);
  221. if( res != FMOD_OK )
  222. {
  223. Con::errorf( "SFXFMODProvider - Failed to get driver name (%s)", FMODResultToString( res ).c_str() );
  224. continue;
  225. }
  226. nameBuff[ 255 ] = '\0';
  227. FMOD_CAPS caps;
  228. FMOD_SPEAKERMODE speakerMode;
  229. res = mFMod.FMOD_System_GetDriverCaps( SFXFMODDevice::smSystem, i, &caps, ( int* ) 0, &speakerMode );
  230. if( res != FMOD_OK )
  231. {
  232. Con::errorf( "SFXFMODProvider - Failed to get driver caps (%s)", FMODResultToString( res ).c_str() );
  233. continue;
  234. }
  235. // Great - got something - so add it to the list of options.
  236. FModDeviceInfo *fmodInfo = new FModDeviceInfo();
  237. fmodInfo->name = String( nameBuff );
  238. fmodInfo->hasHardware = caps & FMOD_CAPS_HARDWARE;
  239. fmodInfo->maxBuffers = 32;
  240. fmodInfo->driver = String();
  241. fmodInfo->mCaps = caps;
  242. fmodInfo->mSpeakerMode = speakerMode;
  243. mDeviceInfo.push_back(fmodInfo);
  244. }
  245. // Did we get any devices?
  246. if ( mDeviceInfo.empty() )
  247. {
  248. Con::warnf( "SFXFMODProvider - No valid devices found - FMOD not available." );
  249. return;
  250. }
  251. // TODO: FMOD_Memory_Initialize
  252. #ifdef TORQUE_OS_XENON
  253. const dsize_t memSz = 5 * 1024 * 1024;
  254. void *memBuffer = XPhysicalAlloc( memSz, MAXULONG_PTR, 0, PAGE_READWRITE );
  255. mFMod.FMOD_Memory_Initialize( memBuffer, memSz, FMOD_MEMORY_ALLOCCALLBACK(NULL), FMOD_MEMORY_REALLOCCALLBACK(NULL), FMOD_MEMORY_FREECALLBACK(NULL) );
  256. #endif
  257. // Wow, we made it - register the provider.
  258. regProvider( this );
  259. }
  260. SFXFMODProvider::~SFXFMODProvider()
  261. {
  262. if( SFXFMODDevice::smEventSystem )
  263. {
  264. mFMod.FMOD_EventSystem_Release( SFXFMODDevice::smEventSystem );
  265. SFXFMODDevice::smEventSystem = NULL;
  266. SFXFMODDevice::smSystem = NULL;
  267. }
  268. else if( SFXFMODDevice::smSystem )
  269. {
  270. mFMod.FMOD_System_Release( SFXFMODDevice::smSystem );
  271. SFXFMODDevice::smSystem = NULL;
  272. }
  273. }
  274. SFXDevice* SFXFMODProvider::createDevice( const String& deviceName, bool useHardware, S32 maxBuffers )
  275. {
  276. FModDeviceInfo* info = dynamic_cast< FModDeviceInfo* >
  277. ( _findDeviceInfo( deviceName ) );
  278. if( !info )
  279. return NULL;
  280. if( !SFXFMODDevice::smSystem && !_createSystem() )
  281. return false;
  282. SFXFMODDevice* device = new SFXFMODDevice(this, &mFMod, 0, info->name );
  283. if( !device->_init() )
  284. SAFE_DELETE( device );
  285. return device;
  286. }
  287. bool SFXFMODProvider::_createSystem()
  288. {
  289. AssertFatal( !SFXFMODDevice::smEventSystem, "SFXFMODProvider::_createSystem() - event system already created!" );
  290. AssertFatal( !SFXFMODDevice::smSystem, "SFXFMODProvider::_createSystem() - system already created!" );
  291. if( mFMod.eventIsLoaded )
  292. {
  293. FMOD_RESULT res = mFMod.FMOD_EventSystem_Create( &SFXFMODDevice::smEventSystem );
  294. if( res != FMOD_OK )
  295. {
  296. Con::errorf( "SFXFMODProvider - could not create the FMOD event system." );
  297. return false;
  298. }
  299. res = mFMod.FMOD_EventSystem_GetSystemObject( SFXFMODDevice::smEventSystem, &SFXFMODDevice::smSystem );
  300. if( res != FMOD_OK )
  301. {
  302. Con::errorf( "SFXFMODProvider - could not retrieve the FMOD system object." );
  303. return false;
  304. }
  305. }
  306. else
  307. {
  308. // Allocate the FMod system.
  309. FMOD_RESULT res = mFMod.FMOD_System_Create( &SFXFMODDevice::smSystem );
  310. if( res != FMOD_OK )
  311. {
  312. // Failed - deal with it!
  313. Con::errorf("SFXFMODProvider - could not create the FMOD system.");
  314. return false;
  315. }
  316. }
  317. return true;
  318. }