void VFmodManager::InitFmodSystem() { // Give the application a chance to modify the m_config. VFmodConfigCallbackData config(&OnBeforeInitializeFmod, m_config); OnBeforeInitializeFmod.TriggerCallbacks(&config); // Set debug output level. Has only effect when using Fmod logging libs, otherwise will return FMOD_ERR_UNSUPPORTED. #ifdef HK_DEBUG_SLOW FMOD_WARNINGCHECK(FMOD::Debug_SetLevel(m_config.iDebugLevel)); #endif // initialize memory { FMOD_RESULT result = FMOD_OK; if (!m_config.bUseMemoryPool) result = FMOD::Memory_Initialize(NULL, 0, VisionFM_Alloc, VisionFM_Realloc, VisionFM_Free, 0); else { #ifndef _VISION_XENON pMemoryPool = vMemAlloc(m_config.iMemoryPoolSize); #else pMemoryPool = VFmodXenonAlloc(m_config.iMemoryPoolSize, true); #endif VASSERT(pMemoryPool != NULL); result = FMOD::Memory_Initialize(pMemoryPool,m_config.iMemoryPoolSize, NULL, NULL, NULL); } // In case the old Sound Plugin and the new Fmod Plugin are both loaded inside vForge (required for converting scenes), // it can happen that the Fmod system is already initialized by the old Sound Plugin. Then Memory_Initialize() will be // called after Fmod system is already initialized, which is illegal. Therefore inside vForge failing to call Memory_Initialize() // in such a case is not treated as fatal error. Fmod will simply not use Vision De-/ Allocators or a preallocated memory block, // instead it will use it own de-/ allocators. This should be fine in case of converting scenes. Otherwise it should be anyway // avoided to load both plugins simultaneously. if (!Vision::Editor.IsInEditor()) FMOD_ERRORCHECK(result); else { if(result == FMOD_ERR_INITIALIZED) Vision::Error.Warning("Failed to initialize Fmod memory system, this is most probably because the old Sound Plugin is loaded, too. This should only be done for converting scenes."); else FMOD_ERRORCHECK(result); } } FMOD_ERRORCHECK(FMOD::EventSystem_Create(&m_pEventSystem)); #ifdef VFMOD_SUPPORTS_NETWORK if (m_config.bUseNetworkSystem) { #ifdef _VISION_PS3 bool bNetworkInitialized = VInitializeNetworkPS3(); VASSERT(bNetworkInitialized == true); #endif FMOD_ERRORCHECK(FMOD::NetEventSystem_Init(m_pEventSystem)); } #endif FMOD_ERRORCHECK(m_pEventSystem->getSystemObject(&m_pSystem)); unsigned int iVersion = 0; FMOD_ERRORCHECK(m_pEventSystem->getVersion(&iVersion)); VASSERT(iVersion >= FMOD_VERSION) FMOD_ERRORCHECK(m_pSystem->setSoftwareFormat(m_config.iSampleRate, m_config.iFormat, 0,m_config.iMaxInputChannels, m_config.iResampleMethod)); // install file manager callbacks FMOD_ERRORCHECK(m_pSystem->setFileSystem(VisionFM_Open, VisionFM_Close, VisionFM_Read, VisionFM_Seek, NULL, NULL, 4096)); #ifdef _VISION_ANDROID // Increase DSP buffer size on Android { unsigned int iBlocksize = 0; int iNumblocks = 0; m_pSystem->getDSPBufferSize(&iBlocksize, &iNumblocks); m_pSystem->setDSPBufferSize(iBlocksize*2, iNumblocks); #ifdef HK_DEBUG_SLOW int iBufferSize = iNumblocks*iBlocksize; Vision::Error.Warning("Fmod DSP buffer size increased from %i to %i, in order to get correct sound output", iBufferSize, iBufferSize*2); #endif } #endif #ifndef _VISION_PS3 FMOD_RESULT result = m_pEventSystem->init(m_config.iMaxChannels, FMOD_INIT_NORMAL, NULL, FMOD_EVENT_INIT_NORMAL); FMOD_WARNINGCHECK(result); #else VSpursHandler *spursHandler = Vision::GetSpursHandler(); VASSERT(spursHandler != NULL); CellSpurs *spurs = spursHandler->GetSpurs(); FMOD_PS3_EXTRADRIVERDATA extradriverdata; memset(&extradriverdata, 0, sizeof(FMOD_PS3_EXTRADRIVERDATA)); extradriverdata.spurs = spurs; /* Using SPURS */ extradriverdata.spu_thread_priority = 16; /* Default, THIS WILL BE IGNORED */ FMOD_RESULT result = m_pEventSystem->init(m_config.iMaxChannels, FMOD_INIT_NORMAL, (void *)&extradriverdata, FMOD_EVENT_INIT_NORMAL); FMOD_WARNINGCHECK(result); #endif // In case of missing sound card, we need to deinitialize the Fmod Event System. // However it is still ensured, that the application can be run, by preventing calls to native Fmod functions. if(result != FMOD_OK) { DeInitFmodSystem(); Vision::Error.Warning("The application will run without sound output!"); return; } FMOD_ERRORCHECK(m_pSystem->set3DSettings(1.0, m_config.fFmodToVisionScale, 1.0f)); // get the master channel group where all sound instances go to initially FMOD_ERRORCHECK(m_pSystem->getMasterChannelGroup(&m_pMasterGroup)); VASSERT(m_pMasterGroup!=NULL); // create a special channel group for background music FMOD_ERRORCHECK(m_pSystem->createChannelGroup("music", &m_pMusicGroup)); VASSERT(m_pMusicGroup!=NULL); IVisCallbackDataObject_cl data(&OnAfterInitializeFmod); OnAfterInitializeFmod.TriggerCallbacks(&data); }
// -------------------------------------------------------------------------- // // Misc // -------------------------------------------------------------------------- // void VFmodManager::OnHandleCallback(IVisCallbackDataObject_cl *pData) { if (pData->m_pSender==&Vision::Callbacks.OnEngineInit) { InitFmodSystem(); return; } if(pData->m_pSender == &Vision::Callbacks.OnEngineDeInit) { // release all resources before the engine deinitializes m_soundInstances.Clear(); m_events.Clear(); m_collisionMeshes.Clear(); m_reverbs.Clear(); m_bAnyStopped = false; DeInitFmodSystem(); return; } if (pData->m_pSender==&Vision::Callbacks.OnUpdateSceneFinished) { RunTick(Vision::GetTimer()->GetTimeDifference()); #ifdef _DEBUG_OUTPUT SoundInstances().DebugOutput(); Events().DebugOutput(); #endif return; } if (pData->m_pSender==&Vision::Callbacks.OnWorldInit) { if (!IsInitialized()) return; VASSERT(m_pSystem!=NULL); // notify the sound engine about the world extents float fRadius = 32000.0f; hkvAlignedBBox bbox; Vision::GetSceneManager()->GetSceneExtents(bbox); if (bbox.isValid()) fRadius = bbox.getBoundingSphere().m_fRadius; FMOD_ERRORCHECK(m_pSystem->setGeometrySettings(fRadius)); return; } if (pData->m_pSender==&Vision::Callbacks.OnWorldDeInit) { // stop all instances and dispose them if possible (i.e VFMOD_FLAG_NODISPOSE flag not set) SoundInstances().StopAll(true); Events().StopAll(true); // remove all collision meshes CollisionMeshes().Clear(); // remove all reverbs Reverbs().Clear(); m_bAnyStopped = false; return; } if (pData->m_pSender==&IVScriptManager::OnScriptProxyCreation) { VScriptCreateStackProxyObject * pScriptData = (VScriptCreateStackProxyObject *)pData; //process data only as far as not handled until now if (!pScriptData->m_bProcessed) { int iRetParams = 0; if (pScriptData->m_pInstance->IsOfType(V_RUNTIME_CLASS(VFmodSoundObject))) iRetParams = LUA_CallStaticFunction(pScriptData->m_pLuaState,"FireLight","VFmodSoundObject","Cast","O>O",pScriptData->m_pInstance); else if (pScriptData->m_pInstance->IsOfType(V_RUNTIME_CLASS(VFmodEvent))) iRetParams = LUA_CallStaticFunction(pScriptData->m_pLuaState,"FireLight","VFmodEvent","Cast","O>O",pScriptData->m_pInstance); if (iRetParams>0) { if(lua_isnil(pScriptData->m_pLuaState, -1)) lua_pop(pScriptData->m_pLuaState, iRetParams); else pScriptData->m_bProcessed = true; } } return; } if(pData->m_pSender==&IVScriptManager::OnRegisterScriptFunctions) { IVScriptManager* pSM = Vision::GetScriptManager(); if (pSM) { lua_State* pLuaState = ((VScriptResourceManager*)pSM)->GetMasterState(); if(pLuaState) { lua_getglobal(pLuaState, "Fmod"); int iType = lua_type(pLuaState, -1); lua_pop(pLuaState, 1); if(iType!=LUA_TUSERDATA) { luaopen_FireLight(pLuaState); int iRetParams = LUA_CallStaticFunction(pLuaState,"FireLight","VFmodManager","Cast","v>v", &VFmodManager::GlobalManager()); if (iRetParams==1) { if(lua_isnil(pLuaState, -1)) { lua_pop(pLuaState, iRetParams); } else { lua_setglobal(pLuaState, "Fmod"); return; } } } else { return; //already loaded } } Vision::Error.Warning("Unable to create Lua Fmod Module, lua_State is NULL or cast failed!"); } return; } #if defined(_VISION_MOBILE) // Pause Sound when in background if (pData->m_pSender == &Vision::Callbacks.OnLeaveForeground) { if (IsInitialized()) { // From the FMOD Ex documentation: // "Channels will not have their per channel pause state overwritten, // so that when a channelgroup is unpaused, the paused state of the channels will // correct as they were set on a per channel basis." m_pMasterGroup->getPaused(&m_bMasterGroupPausedInForeground); m_pMusicGroup->getPaused(&m_bMusicGroupPausedInForeground); m_pMasterGroup->setPaused(true); m_pMusicGroup->setPaused(true); // Get master event category and pause it as well FMOD::EventCategory *pEventCategory = NULL; FMOD_ERRORCHECK(m_pEventSystem->getCategoryByIndex(-1, &pEventCategory)); pEventCategory->getPaused(&m_bMasterEventCategoryPausedInForeground); pEventCategory->setPaused(true); } return; } if (pData->m_pSender == &Vision::Callbacks.OnEnterForeground) { if (IsInitialized()) { m_pMasterGroup->setPaused(m_bMasterGroupPausedInForeground); m_pMusicGroup->setPaused(m_bMusicGroupPausedInForeground); FMOD::EventCategory *pEventCategory = NULL; FMOD_ERRORCHECK(m_pEventSystem->getCategoryByIndex(-1, &pEventCategory)); pEventCategory->setPaused(m_bMasterEventCategoryPausedInForeground); } return; } #endif }