123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398 |
- //-----------------------------------------------------------------------------
- // Copyright (c) 2012 GarageGames, LLC
- //
- // Permission is hereby granted, free of charge, to any person obtaining a copy
- // of this software and associated documentation files (the "Software"), to
- // deal in the Software without restriction, including without limitation the
- // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- // sell copies of the Software, and to permit persons to whom the Software is
- // furnished to do so, subject to the following conditions:
- //
- // The above copyright notice and this permission notice shall be included in
- // all copies or substantial portions of the Software.
- //
- // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
- // IN THE SOFTWARE.
- //-----------------------------------------------------------------------------
- #include "sfx/sfxProvider.h"
- #include "sfx/fmod/sfxFMODDevice.h"
- #include "core/util/safeRelease.h"
- #include "console/console.h"
- #include "core/util/safeDelete.h"
- #include "core/module.h"
- #include "console/consoleTypes.h"
- class SFXFMODProvider : public SFXProvider
- {
- public:
- SFXFMODProvider()
- : SFXProvider( "FMOD" )
- {
- Con::addVariable( "$SFX::Device::fmodNumEventSources", TypeS32, &SFXFMODDevice::smStatNumEventSources,
- "The current number of SFXFMODEventSource instances in the system.\n"
- "This tells the number of sounds in the system that are currently playing FMOD Designer events.\n\n"
- "@note Only relevant if an %FMOD sound device is used.\n\n"
- "@ingroup SFXFMOD" );
- Con::addVariable( "$SFX::Device::fmodCoreMem", TypeS32, &SFXFMODDevice::smStatMemUsageCore,
- "Current number of bytes allocated by the core %FMOD sound system.\n\n"
- "@note Only relevant if an %FMOD sound device is used.\n\n"
- "@ingroup SFXFMOD" );
- Con::addVariable( "$SFX::Device::fmodEventMem", TypeS32, &SFXFMODDevice::smStatMemUsageEvents,
- "Current number of bytes allocated by the %FMOD Designer event system.\n\n"
- "@note Only relevant if an %FMOD sound device is used and the FMOD event DLL is loaded.\n\n"
- "@ingroup SFXFMOD" );
-
- Con::addVariable( "$pref::SFX::FMOD::disableSoftware", TypeBool, &SFXFMODDevice::smPrefDisableSoftware,
- "Whether to disable the %FMOD software mixer to conserve memory.\n"
- "All sounds not created with SFXDescription::useHardware or using DSP effects will fail to load.\n\n"
- "@note Only applies when using an %FMOD sound device.\n\n"
- "@ingroup SFXFMOD" );
- Con::addVariable( "$pref::SFX::FMOD::useSoftwareHRTF", TypeBool, &SFXFMODDevice::smPrefUseSoftwareHRTF,
- "Whether to enable HRTF in %FMOD's software mixer.\n"
- "This will add a lowpass filter effect to the DSP effect chain of all sounds mixed in software.\n\n"
- "@note Only applies when using an %FMOD sound device.\n\n"
- "@ingroup SFXFMOD" );
- Con::addVariable( "$pref::SFX::FMOD::enableProfile", TypeBool, &SFXFMODDevice::smPrefEnableProfile,
- "Whether to enable support for %FMOD's profiler.\n\n"
- "@note Only applies when using an %FMOD sound device.\n\n"
- "@ref FMOD_profiler\n\n"
- "@ingroup SFXFMOD" );
- Con::addVariable( "$pref::SFX::FMOD::DSoundHRTF", TypeString, &SFXFMODDevice::smPrefDSoundHRTF,
- "The type of HRTF to use for hardware-mixed 3D sounds when %FMOD is using DirectSound for sound output "
- "and hardware-acceleration is not available.\n\n"
- "Options are\n"
- "- \"none\": simple stereo panning/doppler/attenuation\n"
- "- \"light\": slightly higher quality than \"none\"\n"
- "- \"full\": full quality 3D playback\n\n"
- "@note Only applies when using an %FMOD sound device.\n\n"
- "@ingroup SFXFMOD" );
- Con::addVariable( "$pref::SFX::FMOD::pluginPath", TypeString, &SFXFMODDevice::smPrefPluginPath,
- "%Path to additional %FMOD plugins.\n\n"
- "@note Only applies when using an %FMOD sound device.\n\n"
- "@ingroup SFXFMOD" );
- }
- virtual ~SFXFMODProvider();
- protected:
- FModFNTable mFMod;
- struct FModDeviceInfo : SFXDeviceInfo
- {
- FMOD_CAPS mCaps;
- FMOD_SPEAKERMODE mSpeakerMode;
- };
- void init();
-
- bool _createSystem();
- public:
- SFXDevice* createDevice( const String& deviceName, bool useHardware, S32 maxBuffers );
- };
- MODULE_BEGIN( FMOD )
- MODULE_INIT_BEFORE( SFX )
- MODULE_SHUTDOWN_AFTER( SFX )
-
- SFXFMODProvider* mProvider;
-
- MODULE_INIT
- {
- mProvider = new SFXFMODProvider;
- }
-
- MODULE_SHUTDOWN
- {
- delete mProvider;
- }
-
- MODULE_END;
- //------------------------------------------------------------------------------
- // Helper
- bool fmodBindFunction( DLibrary *dll, void *&fnAddress, const char* name )
- {
- if( !dll )
- return false;
-
- fnAddress = dll->bind( name );
- if (!fnAddress)
- Con::warnf( "FMOD Loader: DLL bind failed for %s", name );
- return fnAddress != 0;
- }
- //------------------------------------------------------------------------------
- void SFXFMODProvider::init()
- {
- #ifdef TORQUE_FMOD_STATIC
- // FMOD statically linked.
-
- mFMod.isLoaded = true;
- #define FMOD_FUNCTION(fn_name, fn_args) \
- (*(void**)&mFMod.fn_name.fn) = &fn_name;
-
- #ifndef TORQUE_FMOD_NO_EVENTS
- mFMod.eventIsLoaded = true;
- #define FMOD_EVENT_FUNCTION(fn_name, fn_args) \
- (*(void**)&mFMod.fn_name.fn) = &fn_name;
- #else
- #define FMOD_EVENT_FUNCTION( fn_name, fn_args )
- #endif
- #include FMOD_FN_FILE
-
- #undef FMOD_FUNCTION
- #undef FMOD_EVENT_FUNCTION
-
- #else
- // FMOD dynamically linked.
-
- const char* dllName;
- const char* pDllName; // plugin-based DLL
- const char* eventDllName;
-
- #ifdef _WIN64
- dllName = "fmodex64.dll";
- pDllName = "fmodexp64.dll";
- eventDllName = "fmod_event64.dll";
- #elif defined(TORQUE_OS_WIN)
- dllName = "fmodex.dll";
- pDllName = "fmodexp.dll";
- eventDllName = "fmod_event.dll";
- #elif defined( TORQUE_OS_MAC )
- dllName = "libfmodex.dylib";
- pDllName = "libfmodexp.dylib";
- eventDllName = "libfmodevent.dylib";
- #else
- # warning Need to set FMOD DLL filename for platform.
- return;
- #endif
- // Grab the functions we'll want from the fmod DLL.
- mFMod.dllRef = OsLoadLibrary( dllName );
- // Try the plugin-based version.
- if( !mFMod.dllRef )
- mFMod.dllRef = OsLoadLibrary( pDllName );
- if(!mFMod.dllRef)
- {
- Con::warnf( "SFXFMODProvider - Could not locate '%s' or '%s' - FMOD not available.", dllName, pDllName );
- return;
- }
-
- mFMod.eventDllRef = OsLoadLibrary( eventDllName );
- if(!mFMod.eventDllRef)
- Con::warnf( "SFXFMODProvider - Could not locate %s - FMOD Designer integration not available.", eventDllName );
- mFMod.isLoaded = true;
- mFMod.eventIsLoaded = true;
- #define FMOD_FUNCTION(fn_name, fn_args) \
- mFMod.isLoaded &= fmodBindFunction(mFMod.dllRef, *(void**)&mFMod.fn_name.fn, #fn_name);
- #define FMOD_EVENT_FUNCTION(fn_name, fn_args) \
- mFMod.eventIsLoaded &= fmodBindFunction(mFMod.eventDllRef, *(void**)&mFMod.fn_name.fn, #fn_name);
-
- #include FMOD_FN_FILE
-
- #undef FMOD_FUNCTION
- #undef FMOD_EVENT_FUNCTION
- if(mFMod.isLoaded == false)
- {
- Con::warnf("SFXFMODProvider - Could not load %s - FMOD not available.", dllName);
- return;
- }
- if( !mFMod.eventIsLoaded && mFMod.eventDllRef )
- Con::warnf("SFXFMODProvider - Could not load %s - FMOD Designer integration not available.", eventDllName);
- #endif
- FMOD_RESULT res;
- // Create the FMOD system object.
-
- if( !_createSystem() )
- return;
-
- // Check that the Ex API version is OK.
-
- unsigned int version;
- res = mFMod.FMOD_System_GetVersion(SFXFMODDevice::smSystem, &version);
- FModAssert(res, "SFXFMODProvider - Failed to get FMOD version!");
- Con::printf( "SFXFMODProvider - FMOD Ex API version: %x.%x.%x",
- ( version & 0xffff0000 ) >> 16,
- ( version & 0x0000ff00 ) >> 8,
- ( version & 0x000000ff )
- );
- if(version < FMOD_VERSION)
- {
- Con::warnf("SFXFMODProvider - FMOD Ex API version in DLL is too old - FMOD not available.");
- return;
- }
-
- // Check that the Designer API version is ok.
-
- if( mFMod.eventIsLoaded )
- {
- res = mFMod.FMOD_EventSystem_GetVersion( SFXFMODDevice::smEventSystem, &version );
- FModAssert(res, "SFXFMODProvider - Failed to get FMOD version!");
-
- Con::printf( "SFXFMODProvider - FMOD Designer API version: %x.%x.%x",
- ( version & 0xffff0000 ) >> 16,
- ( version & 0x0000ff00 ) >> 8,
- ( version & 0x000000ff )
- );
- if( version < FMOD_EVENT_VERSION )
- {
- Con::errorf( "SFXFMODProvider - FMOD Designer API version in DLL is too old!" );
- return;
- }
- }
- // Now, enumerate our devices.
- int numDrivers;
- res = mFMod.FMOD_System_GetNumDrivers(SFXFMODDevice::smSystem, &numDrivers);
- FModAssert(res, "SFXFMODProvider - Failed to get driver count - FMOD not available.");
- char nameBuff[256];
- for(S32 i=0; i<numDrivers; i++)
- {
- res = mFMod.FMOD_System_GetDriverInfo(SFXFMODDevice::smSystem, i, nameBuff, 256, ( FMOD_GUID* ) NULL);
- if( res != FMOD_OK )
- {
- Con::errorf( "SFXFMODProvider - Failed to get driver name (%s)", FMODResultToString( res ).c_str() );
- continue;
- }
- nameBuff[ 255 ] = '\0';
-
- FMOD_CAPS caps;
- FMOD_SPEAKERMODE speakerMode;
- res = mFMod.FMOD_System_GetDriverCaps( SFXFMODDevice::smSystem, i, &caps, ( int* ) 0, &speakerMode );
- if( res != FMOD_OK )
- {
- Con::errorf( "SFXFMODProvider - Failed to get driver caps (%s)", FMODResultToString( res ).c_str() );
- continue;
- }
- // Great - got something - so add it to the list of options.
- FModDeviceInfo *fmodInfo = new FModDeviceInfo();
- fmodInfo->name = String( nameBuff );
- fmodInfo->hasHardware = caps & FMOD_CAPS_HARDWARE;
- fmodInfo->maxBuffers = 32;
- fmodInfo->driver = String();
- fmodInfo->mCaps = caps;
- fmodInfo->mSpeakerMode = speakerMode;
- mDeviceInfo.push_back(fmodInfo);
- }
- // Did we get any devices?
- if ( mDeviceInfo.empty() )
- {
- Con::warnf( "SFXFMODProvider - No valid devices found - FMOD not available." );
- return;
- }
- // TODO: FMOD_Memory_Initialize
- #ifdef TORQUE_OS_XENON
- const dsize_t memSz = 5 * 1024 * 1024;
- void *memBuffer = XPhysicalAlloc( memSz, MAXULONG_PTR, 0, PAGE_READWRITE );
- mFMod.FMOD_Memory_Initialize( memBuffer, memSz, FMOD_MEMORY_ALLOCCALLBACK(NULL), FMOD_MEMORY_REALLOCCALLBACK(NULL), FMOD_MEMORY_FREECALLBACK(NULL) );
- #endif
- // Wow, we made it - register the provider.
- regProvider( this );
- }
- SFXFMODProvider::~SFXFMODProvider()
- {
- if( SFXFMODDevice::smEventSystem )
- {
- mFMod.FMOD_EventSystem_Release( SFXFMODDevice::smEventSystem );
- SFXFMODDevice::smEventSystem = NULL;
- SFXFMODDevice::smSystem = NULL;
- }
- else if( SFXFMODDevice::smSystem )
- {
- mFMod.FMOD_System_Release( SFXFMODDevice::smSystem );
- SFXFMODDevice::smSystem = NULL;
- }
- }
- SFXDevice* SFXFMODProvider::createDevice( const String& deviceName, bool useHardware, S32 maxBuffers )
- {
- FModDeviceInfo* info = dynamic_cast< FModDeviceInfo* >
- ( _findDeviceInfo( deviceName ) );
- if( !info )
- return NULL;
-
- if( !SFXFMODDevice::smSystem && !_createSystem() )
- return false;
- SFXFMODDevice* device = new SFXFMODDevice(this, &mFMod, 0, info->name );
- if( !device->_init() )
- SAFE_DELETE( device );
- return device;
- }
- bool SFXFMODProvider::_createSystem()
- {
- AssertFatal( !SFXFMODDevice::smEventSystem, "SFXFMODProvider::_createSystem() - event system already created!" );
- AssertFatal( !SFXFMODDevice::smSystem, "SFXFMODProvider::_createSystem() - system already created!" );
-
- if( mFMod.eventIsLoaded )
- {
- FMOD_RESULT res = mFMod.FMOD_EventSystem_Create( &SFXFMODDevice::smEventSystem );
- if( res != FMOD_OK )
- {
- Con::errorf( "SFXFMODProvider - could not create the FMOD event system." );
- return false;
- }
-
- res = mFMod.FMOD_EventSystem_GetSystemObject( SFXFMODDevice::smEventSystem, &SFXFMODDevice::smSystem );
- if( res != FMOD_OK )
- {
- Con::errorf( "SFXFMODProvider - could not retrieve the FMOD system object." );
- return false;
- }
- }
- else
- {
- // Allocate the FMod system.
-
- FMOD_RESULT res = mFMod.FMOD_System_Create( &SFXFMODDevice::smSystem );
- if( res != FMOD_OK )
- {
- // Failed - deal with it!
- Con::errorf("SFXFMODProvider - could not create the FMOD system.");
- return false;
- }
- }
-
- return true;
- }
|