sfxFMODDevice.cpp 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578
  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 "platform/platform.h"
  23. #include "platform/threads/mutex.h"
  24. #include "sfx/fmod/sfxFMODDevice.h"
  25. #include "sfx/fmod/sfxFMODBuffer.h"
  26. #include "sfx/sfxSystem.h"
  27. #include "platform/async/asyncUpdate.h"
  28. #include "console/consoleTypes.h"
  29. #include "core/volume.h"
  30. bool SFXFMODDevice::smPrefDisableSoftware = false;
  31. bool SFXFMODDevice::smPrefUseSoftwareOcclusion = true;
  32. bool SFXFMODDevice::smPrefUseSoftwareHRTF = true;
  33. bool SFXFMODDevice::smPrefEnableProfile = false;
  34. bool SFXFMODDevice::smPrefGeometryUseClosest = false;
  35. const char* SFXFMODDevice::smPrefDSoundHRTF = "full";
  36. const char* SFXFMODDevice::smPrefPluginPath = "";
  37. U32 SFXFMODDevice::smStatMemUsageCore;
  38. U32 SFXFMODDevice::smStatMemUsageEvents;
  39. U32 SFXFMODDevice::smStatNumEventSources;
  40. SFXFMODDevice* SFXFMODDevice::smInstance;
  41. FMOD_SYSTEM* SFXFMODDevice::smSystem;
  42. FMOD_EVENTSYSTEM* SFXFMODDevice::smEventSystem;
  43. FModFNTable* SFXFMODDevice::smFunc;
  44. Mutex* FModFNTable::mutex;
  45. //-----------------------------------------------------------------------------
  46. String FMODResultToString( FMOD_RESULT result )
  47. {
  48. switch( result )
  49. {
  50. #define FMOD_ERROR( n ) case n: return #n;
  51. #include "fmodErrors.h"
  52. #undef FMOD_ERROR
  53. default:
  54. break;
  55. }
  56. return String();
  57. }
  58. //------------------------------------------------------------------------------
  59. // FMOD filesystem wrappers.
  60. //FIXME: these are not thread-safe and cannot be used as such
  61. FMOD_RESULT F_CALLBACK fmodFileOpenCallback( const char* name, int unicode, unsigned int* filesize, void** handle, void** userdata )
  62. {
  63. String fileName;
  64. if( unicode )
  65. fileName = String( ( UTF16* ) name );
  66. else
  67. fileName = String( name );
  68. Torque::FS::FileRef file = Torque::FS::OpenFile( fileName, Torque::FS::File::Read );
  69. if( !file )
  70. return FMOD_ERR_FILE_NOTFOUND;
  71. else if( file->getStatus() != Torque::FS::File::Open )
  72. return FMOD_ERR_FILE_BAD;
  73. // Add a reference so we can pass it into FMOD.
  74. file->incRefCount();
  75. *filesize = U32( file->getSize() );
  76. *handle = file.getPointer();
  77. return FMOD_OK;
  78. }
  79. FMOD_RESULT F_CALLBACK fmodFileCloseCallback( void* handle, void* userdata )
  80. {
  81. Torque::FS::File* file = reinterpret_cast< Torque::FS::File* >( handle );
  82. file->decRefCount();
  83. return FMOD_OK;
  84. }
  85. FMOD_RESULT F_CALLBACK fmodFileReadCallback( void* handle, void* buffer, unsigned int sizebytes, unsigned int* bytesread, void* userdata )
  86. {
  87. Torque::FS::File* file = reinterpret_cast< Torque::FS::File* >( handle );
  88. U32 numRead = file->read( buffer, sizebytes );
  89. *bytesread = numRead;
  90. if( file->getStatus() == Torque::FS::File::EndOfFile )
  91. return FMOD_ERR_FILE_EOF;
  92. else if( file->getStatus() != Torque::FS::File::Open )
  93. return FMOD_ERR_FILE_BAD;
  94. return FMOD_OK;
  95. }
  96. FMOD_RESULT F_CALLBACK fmodFileSeekCallback( void* handle, unsigned int pos, void* userdata )
  97. {
  98. Torque::FS::File* file = reinterpret_cast< Torque::FS::File* >( handle );
  99. if( file->setPosition( pos, Torque::FS::File::Begin ) != pos )
  100. return FMOD_ERR_FILE_COULDNOTSEEK;
  101. return FMOD_OK;
  102. }
  103. //-----------------------------------------------------------------------------
  104. SFXFMODDevice::SFXFMODDevice( SFXProvider* provider,
  105. FModFNTable *fmodFnTbl,
  106. int deviceIdx,
  107. String name )
  108. : SFXDevice( name, provider, false, 32 ),
  109. m3drolloffmode( FMOD_3D_INVERSEROLLOFF ),
  110. mDeviceIndex( deviceIdx )
  111. {
  112. // Store off the function pointers for later use.
  113. smFunc = fmodFnTbl;
  114. smStatMemUsageCore = 0;
  115. smStatMemUsageEvents = 0;
  116. smStatNumEventSources = 0;
  117. // Register our SFXSystem plugin.
  118. SFX->addPlugin( &mPlugin );
  119. smInstance = this;
  120. }
  121. //-----------------------------------------------------------------------------
  122. SFXFMODDevice::~SFXFMODDevice()
  123. {
  124. _releaseAllResources();
  125. SFX->removePlugin( &mPlugin );
  126. if( smEventSystem )
  127. {
  128. smFunc->FMOD_EventSystem_Release( smEventSystem );
  129. smEventSystem = NULL;
  130. smSystem = NULL;
  131. }
  132. else
  133. smFunc->FMOD_System_Close( smSystem );
  134. smInstance = NULL;
  135. }
  136. //-----------------------------------------------------------------------------
  137. bool SFXFMODDevice::_init()
  138. {
  139. #define FMOD_CHECK( message ) \
  140. if( result != FMOD_OK ) \
  141. { \
  142. Con::errorf( "SFXFMODDevice::_init() - %s (%s)", \
  143. message, \
  144. FMOD_ErrorString( result ) ); \
  145. return false; \
  146. }
  147. AssertISV(smSystem,
  148. "SFXFMODDevice::_init() - can't init w/o an existing FMOD system handle!");
  149. FMOD_RESULT result;
  150. // Get some prefs.
  151. if( smPrefPluginPath && smPrefPluginPath[ 0 ] )
  152. {
  153. char fullPath[ 4096 ];
  154. Platform::makeFullPathName( smPrefPluginPath, fullPath, sizeof( fullPath ) );
  155. smFunc->FMOD_System_SetPluginPath( smSystem, fullPath );
  156. }
  157. else
  158. {
  159. smFunc->FMOD_System_SetPluginPath( smSystem, Platform::getExecutablePath() );
  160. }
  161. // Initialize everything from fmod.
  162. FMOD_SPEAKERMODE speakermode;
  163. FMOD_CAPS caps;
  164. result = smFunc->FMOD_System_GetDriverCaps(smSystem, 0, &caps, ( int* ) 0, &speakermode);
  165. FMOD_CHECK( "SFXFMODDevice::init - Failed to get driver caps" );
  166. result = smFunc->FMOD_System_SetDriver(smSystem, mDeviceIndex);
  167. FMOD_CHECK( "SFXFMODDevice::init - Failed to set driver" );
  168. result = smFunc->FMOD_System_SetSpeakerMode(smSystem, speakermode);
  169. FMOD_CHECK( "SFXFMODDevice::init - Failed to set the user selected speaker mode" );
  170. if (caps & FMOD_CAPS_HARDWARE_EMULATED) /* The user has the 'Acceleration' slider set to off! This is really bad for latency!. */
  171. { /* You might want to warn the user about this. */
  172. result = smFunc->FMOD_System_SetDSPBufferSize(smSystem, 1024, 10);
  173. FMOD_CHECK( "SFXFMODDevice::init - Failed to set DSP buffer size" );
  174. }
  175. Con::printf( "\nFMOD Device caps:" );
  176. #define PRINT_CAP( name ) \
  177. if( caps & FMOD_CAPS_ ## name ) \
  178. Con::printf( #name );
  179. PRINT_CAP( HARDWARE );
  180. PRINT_CAP( HARDWARE_EMULATED );
  181. PRINT_CAP( OUTPUT_MULTICHANNEL );
  182. PRINT_CAP( OUTPUT_FORMAT_PCM8 );
  183. PRINT_CAP( OUTPUT_FORMAT_PCM16 );
  184. PRINT_CAP( OUTPUT_FORMAT_PCM24 );
  185. PRINT_CAP( OUTPUT_FORMAT_PCM32 );
  186. PRINT_CAP( OUTPUT_FORMAT_PCMFLOAT );
  187. PRINT_CAP( REVERB_LIMITED );
  188. Con::printf( "" );
  189. bool tryAgain;
  190. do
  191. {
  192. tryAgain = false;
  193. FMOD_INITFLAGS flags = FMOD_INIT_NORMAL | FMOD_INIT_VOL0_BECOMES_VIRTUAL;
  194. if( smPrefDisableSoftware )
  195. flags |= FMOD_INIT_SOFTWARE_DISABLE;
  196. if( smPrefUseSoftwareOcclusion )
  197. flags |= FMOD_INIT_OCCLUSION_LOWPASS;
  198. if( smPrefUseSoftwareHRTF )
  199. flags |= FMOD_INIT_HRTF_LOWPASS;
  200. if( smPrefEnableProfile )
  201. flags |= FMOD_INIT_ENABLE_PROFILE;
  202. if( smPrefGeometryUseClosest )
  203. flags |= FMOD_INIT_GEOMETRY_USECLOSEST;
  204. if( smEventSystem )
  205. result = smFunc->FMOD_EventSystem_Init( smEventSystem, 100, flags, ( void* ) 0, FMOD_EVENT_INIT_NORMAL );
  206. else
  207. result = smFunc->FMOD_System_Init( smSystem, 100, flags, ( void* ) 0 );
  208. if( result == FMOD_ERR_OUTPUT_CREATEBUFFER ) /* Ok, the speaker mode selected isn't supported by this soundcard. Switch it back to stereo... */
  209. {
  210. result = smFunc->FMOD_System_SetSpeakerMode( smSystem, FMOD_SPEAKERMODE_STEREO );
  211. FMOD_CHECK( "SFXFMODDevice::init - failed on fallback speaker mode setup" );
  212. tryAgain = true;
  213. }
  214. } while( tryAgain );
  215. FMOD_CHECK( "SFXFMODDevice::init - failed to init system" );
  216. // Print hardware channel info.
  217. if( caps & FMOD_CAPS_HARDWARE )
  218. {
  219. int num3D, num2D, numTotal;
  220. if( smFunc->FMOD_System_GetHardwareChannels( smSystem, &num2D, &num3D, &numTotal ) == FMOD_OK )
  221. Con::printf( "FMOD Hardware channels: 2d=%i, 3d=%i, total=%i", num2D, num3D, numTotal );
  222. }
  223. // Set up filesystem.
  224. //FIXME: Don't do this for now. Crashes on Windows.
  225. #if 0
  226. smFunc->FMOD_System_SetFileSystem( smSystem, fmodFileOpenCallback, fmodFileCloseCallback, fmodFileReadCallback, fmodFileSeekCallback, -1 );
  227. #endif
  228. // Set capabilities.
  229. mCaps = CAPS_Reverb | CAPS_VoiceManagement;
  230. if( smEventSystem )
  231. mCaps |= CAPS_FMODDesigner;
  232. // Start the update thread.
  233. #ifndef TORQUE_DEDICATED // Avoid dependency on platform/async for Linx dedicated.
  234. if( !Con::getBoolVariable( "$_forceAllMainThread" ) )
  235. {
  236. SFXInternal::gUpdateThread = new AsyncPeriodicUpdateThread
  237. ( "FMOD Update Thread", SFXInternal::gBufferUpdateList,
  238. Con::getIntVariable( "$pref::SFX::updateInterval", SFXInternal::DEFAULT_UPDATE_INTERVAL ) );
  239. SFXInternal::gUpdateThread->start();
  240. }
  241. #endif
  242. return true;
  243. }
  244. //-----------------------------------------------------------------------------
  245. SFXBuffer* SFXFMODDevice::createBuffer( const ThreadSafeRef< SFXStream >& stream, SFXDescription* description )
  246. {
  247. AssertFatal( stream, "SFXFMODDevice::createBuffer() - Got a null stream!" );
  248. AssertFatal( description, "SFXFMODDevice::createBuffer() - Got null description!" );
  249. SFXFMODBuffer *buffer = SFXFMODBuffer::create( stream, description );
  250. if ( buffer )
  251. _addBuffer( buffer );
  252. return buffer;
  253. }
  254. //-----------------------------------------------------------------------------
  255. SFXBuffer* SFXFMODDevice::createBuffer( const String& filename, SFXDescription* description )
  256. {
  257. AssertFatal( filename.isNotEmpty(), "SFXFMODDevice::createBuffer() - Got an empty filename!" );
  258. AssertFatal( description, "SFXFMODDevice::createBuffer() - Got null description!" );
  259. SFXFMODBuffer* buffer = SFXFMODBuffer::create( filename, description );
  260. if( buffer )
  261. _addBuffer( buffer );
  262. return buffer;
  263. }
  264. //-----------------------------------------------------------------------------
  265. SFXVoice* SFXFMODDevice::createVoice( bool is3D, SFXBuffer* buffer )
  266. {
  267. AssertFatal( buffer, "SFXFMODDevice::createVoice() - Got null buffer!" );
  268. SFXFMODBuffer* fmodBuffer = dynamic_cast<SFXFMODBuffer*>( buffer );
  269. AssertFatal( fmodBuffer, "SFXFMODDevice::createVoice() - Got bad buffer!" );
  270. SFXFMODVoice* voice = SFXFMODVoice::create( this, fmodBuffer );
  271. if ( !voice )
  272. return NULL;
  273. _addVoice( voice );
  274. return voice;
  275. }
  276. //-----------------------------------------------------------------------------
  277. void SFXFMODDevice::update()
  278. {
  279. Parent::update();
  280. if( smEventSystem )
  281. {
  282. FModAssert( smFunc->FMOD_EventSystem_Update( smEventSystem ), "Failed to update event system!" );
  283. }
  284. else
  285. {
  286. FModAssert(smFunc->FMOD_System_Update(smSystem), "Failed to update system!");
  287. }
  288. }
  289. //-----------------------------------------------------------------------------
  290. void SFXFMODDevice::setNumListeners( U32 num )
  291. {
  292. smFunc->FMOD_System_Set3DNumListeners( smSystem, num );
  293. }
  294. //-----------------------------------------------------------------------------
  295. void SFXFMODDevice::setListener( U32 index, const SFXListenerProperties& listener )
  296. {
  297. FMOD_VECTOR position, forward, up, velocity;
  298. TorqueTransformToFMODVectors( listener.getTransform(), position, forward, up );
  299. TorqueVectorToFMODVector( listener.getVelocity(), velocity );
  300. // Do the listener state update, then update!
  301. smFunc->FMOD_System_Set3DListenerAttributes( smSystem, index, &position, &velocity, &forward, &up );
  302. }
  303. //-----------------------------------------------------------------------------
  304. void SFXFMODDevice::setDistanceModel( SFXDistanceModel model )
  305. {
  306. switch( model )
  307. {
  308. case SFXDistanceModelLinear:
  309. m3drolloffmode = FMOD_3D_LINEARROLLOFF;
  310. break;
  311. case SFXDistanceModelLogarithmic:
  312. m3drolloffmode = FMOD_3D_INVERSEROLLOFF;
  313. break;
  314. default:
  315. AssertWarn( false, "SFXFMODDevice::setDistanceModel - model not implemented" );
  316. }
  317. }
  318. //-----------------------------------------------------------------------------
  319. void SFXFMODDevice::setDopplerFactor( F32 factor )
  320. {
  321. F32 dopplerFactor;
  322. F32 distanceFactor;
  323. F32 rolloffFactor;
  324. smFunc->FMOD_System_Get3DSettings( smSystem, &dopplerFactor, &distanceFactor, &rolloffFactor );
  325. dopplerFactor = factor;
  326. smFunc->FMOD_System_Set3DSettings( smSystem, dopplerFactor, distanceFactor, rolloffFactor );
  327. }
  328. //-----------------------------------------------------------------------------
  329. void SFXFMODDevice::setRolloffFactor( F32 factor )
  330. {
  331. F32 dopplerFactor;
  332. F32 distanceFactor;
  333. F32 rolloffFactor;
  334. smFunc->FMOD_System_Get3DSettings( smSystem, &dopplerFactor, &distanceFactor, &rolloffFactor );
  335. rolloffFactor = factor;
  336. smFunc->FMOD_System_Set3DSettings( smSystem, dopplerFactor, distanceFactor, rolloffFactor );
  337. }
  338. //-----------------------------------------------------------------------------
  339. void SFXFMODDevice::setReverb( const SFXReverbProperties& reverb )
  340. {
  341. FMOD_REVERB_PROPERTIES prop = FMOD_PRESET_GENERIC;
  342. prop.Environment = 0;
  343. prop.EnvDiffusion = reverb.mEnvDiffusion;
  344. prop.Room = reverb.mRoom;
  345. prop.RoomHF = reverb.mRoomHF;
  346. prop.RoomLF = reverb.mRoomLF;
  347. prop.DecayTime = reverb.mDecayTime;
  348. prop.DecayLFRatio = reverb.mDecayLFRatio;
  349. prop.DecayHFRatio = reverb.mDecayHFRatio;
  350. prop.Reflections = reverb.mReflections;
  351. prop.ReflectionsDelay = reverb.mReflectionsDelay;
  352. prop.Reverb = reverb.mReverb;
  353. prop.ReverbDelay = reverb.mReverbDelay;
  354. prop.ModulationTime = reverb.mModulationTime;
  355. prop.ModulationDepth = reverb.mModulationDepth;
  356. prop.HFReference = reverb.mHFReference;
  357. prop.LFReference = reverb.mLFReference;
  358. prop.Diffusion = reverb.mDiffusion;
  359. prop.Density = reverb.mDensity;
  360. prop.Flags = reverb.mFlags;
  361. // Here we only want to affect 3D sounds. While not quite obvious from the docs,
  362. // SetReverbProperties sets the global reverb environment for 2D sounds whereas
  363. // SetAmbientReverbProperties sets the global reverb environment for 3D sounds.
  364. FMOD_RESULT result = smFunc->FMOD_System_SetReverbAmbientProperties( smSystem, &prop );
  365. if( result != FMOD_OK )
  366. Con::errorf( "SFXFMODDevice::setReverb - Failed to set reverb (%s)", FMODResultToString( result ).c_str() );
  367. }
  368. //-----------------------------------------------------------------------------
  369. void SFXFMODDevice::resetReverb()
  370. {
  371. FMOD_REVERB_PROPERTIES prop = FMOD_PRESET_OFF;
  372. smFunc->FMOD_System_SetReverbProperties( smSystem, &prop );
  373. }
  374. //-----------------------------------------------------------------------------
  375. void SFXFMODDevice::updateMemUsageStats()
  376. {
  377. smFunc->FMOD_System_GetMemoryInfo( smSystem, ( unsigned int ) FMOD_MEMBITS_ALL,
  378. ( unsigned int ) 0, ( unsigned int* ) &smStatMemUsageCore, ( unsigned int* ) 0 );
  379. if( smEventSystem )
  380. smFunc->FMOD_EventSystem_GetMemoryInfo( smEventSystem, ( unsigned int ) 0,
  381. ( unsigned int ) FMOD_EVENT_MEMBITS_ALL, ( unsigned int* ) &smStatMemUsageEvents, ( unsigned int* ) 0 );
  382. }
  383. //=============================================================================
  384. // Console Functions.
  385. //=============================================================================
  386. // MARK: ---- Console Functions ----
  387. //------------------------------------------------------------------------------
  388. ConsoleFunction( fmodDumpDSPInfo, void, 1, 1, "()"
  389. "@brief Dump information about the standard DSP effects.\n\n"
  390. "@ingroup SFXFMOD")
  391. {
  392. if( !SFXFMODDevice::smFunc )
  393. return;
  394. const U32 firstDSPType = FMOD_DSP_TYPE_MIXER;
  395. const U32 lastDSPType = FMOD_DSP_TYPE_TREMOLO;
  396. for( U32 i = firstDSPType; i <= lastDSPType; ++ i )
  397. {
  398. FMOD_DSP* dsp;
  399. if( SFXFMODDevice::smFunc->FMOD_System_CreateDSPByType( SFXFMODDevice::smSystem, ( FMOD_DSP_TYPE ) i, &dsp ) == FMOD_OK )
  400. {
  401. // Print general info.
  402. char name[ 33 ];
  403. unsigned int version;
  404. int channels;
  405. int numParameters;
  406. dMemset( name, 0, sizeof( name ) );
  407. SFXFMODDevice::smFunc->FMOD_DSP_GetInfo( dsp, name, &version, &channels, ( int* ) NULL, ( int* ) NULL );
  408. SFXFMODDevice::smFunc->FMOD_DSP_GetNumParameters( dsp, &numParameters );
  409. Con::printf( "----------------------------------------------------------------" );
  410. Con::printf( "DSP: %s", name );
  411. Con::printf( "Version: %i.%i", ( version & 0xffff0000 ) >> 16, version & 0xffff );
  412. Con::printf( "Channels: %i", channels );
  413. Con::printf( "Parameters: %i", numParameters );
  414. Con::printf( "" );
  415. // Print parameter info.
  416. for( U32 n = 0; n < numParameters; ++ n )
  417. {
  418. char name[ 17 ];
  419. char label[ 17 ];
  420. char description[ 1024 ];
  421. float minValue, maxValue;
  422. float value;
  423. char valueString[ 256 ];
  424. dMemset( name, 0, sizeof( name ) );
  425. dMemset( label, 0, sizeof( label ) );
  426. dMemset( description, 0, sizeof( description ) );
  427. dMemset( valueString, 0, sizeof( valueString ) );
  428. SFXFMODDevice::smFunc->FMOD_DSP_GetParameterInfo( dsp, n, name, label, description, sizeof( description ) - 1, &minValue, &maxValue );
  429. SFXFMODDevice::smFunc->FMOD_DSP_GetParameter( dsp, n, &value, valueString, sizeof( valueString ) - 1 );
  430. Con::printf( "* Parameter %i", n );
  431. Con::printf( "Name: %s", name );
  432. Con::printf( "Label: %s", label );
  433. Con::printf( "Description: %s", description );
  434. Con::printf( "Min: %f", minValue );
  435. Con::printf( "Max: %f", maxValue );
  436. Con::printf( "Value: %f (%s)", value, valueString );
  437. Con::printf( "" );
  438. }
  439. // Release the DSP.
  440. SFXFMODDevice::smFunc->FMOD_DSP_Release( dsp );
  441. }
  442. }
  443. }
  444. //-----------------------------------------------------------------------------
  445. ConsoleFunction( fmodDumpMemoryStats, void, 1, 1, "()"
  446. "@return Prints the current memory consumption of the FMOD module\n\n"
  447. "@ingroup SFXFMOD")
  448. {
  449. int current = 0;
  450. int max = 0;
  451. if (SFXFMODDevice::smFunc && SFXFMODDevice::smFunc->FMOD_Memory_GetStats.fn)
  452. SFXFMODDevice::smFunc->FMOD_Memory_GetStats(&current, &max);
  453. Con::printf("Fmod current: %d, max: %d", current, max);
  454. }