// -------------------------------------------------------------------------- // // Overridden functions // -------------------------------------------------------------------------- // BOOL VFmodSoundResource::Reload() { VFmodManager &manager = VFmodManager::GlobalManager(); if (!manager.IsInitialized()) return FALSE; VASSERT(!m_pSound); int iFMODFlags = FMOD_SOFTWARE; // software must be used when geometry is used iFMODFlags |= Is3D() ? FMOD_3D:FMOD_2D; iFMODFlags |= IsStreaming() ? FMOD_CREATESTREAM : FMOD_CREATESAMPLE; if (!LogAttenuation()) iFMODFlags |= FMOD_3D_LINEARROLLOFF; if(IsCompressedData()) iFMODFlags |= FMOD_CREATECOMPRESSEDSAMPLE; iFMODFlags |= LoadsAsyncronous() ? FMOD_NONBLOCKING : FMOD_DEFAULT; FMOD_WARNINGCHECK(manager.m_pSystem->createSound(GetFilename(), iFMODFlags, NULL, &m_pSound)); if (!m_pSound) return FALSE; // get the size in memory unsigned int iSize = 0; FMOD_WARNINGCHECK(m_pSound->getMemoryInfo(FMOD_MEMBITS_ALL, 0, &iSize, NULL)); SetNewMemSize(VRESOURCEMEMORY_SYSTEM,iSize); m_iSysMem = (int)iSize; return TRUE; }
VFmodManager::VFmodSoundInit_e VFmodManager::InitDevice() { bool bOutputPresent = ResetDriver(); if(!bOutputPresent || m_bOutputDevicePresent) //no further actions needed return VFMODSOUNDINIT_NO_SPEAKERS; #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 de-initialize 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(); return VFMODSOUNDINIT_NO_HARDWARE; } m_bOutputDevicePresent = true; VisionFM_System(NULL, FMOD_SYSTEM_CALLBACKTYPE_DEVICELISTCHANGED, NULL, NULL); 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); return VFMODSOUNDINIT_OK; }
// -------------------------------------------------------------------------- // // Overridden functions // -------------------------------------------------------------------------- // BOOL VFmodEventGroup::Reload() { VFmodManager &manager = VFmodManager::GlobalManager(); if (!manager.IsInitialized()) return TRUE; VASSERT(!m_pEventGroup); FMOD::EventSystem *pEventSystem = manager.GetFmodEventSystem(); VASSERT(pEventSystem!=NULL); // the resource filename is concatenated from the corresponding project-path and group-name, // which are separated by '|' const char *szResourceName = GetFilename(); // split resource name into project-path and group-name char szResourceNameCopy[2*FS_MAX_PATH]; strcpy(szResourceNameCopy, szResourceName); VStringTokenizerInPlace tokenizer(szResourceNameCopy, '|'); const char *szEventProjectPath = tokenizer.Next(); const char *szEventGroupName = tokenizer.Next(); VASSERT(szEventProjectPath!=NULL && szEventGroupName!=NULL); m_sEventProjectPath = szEventProjectPath; m_sEventGroupName = szEventGroupName; FMOD::EventProject *pEventProject = NULL; pEventProject = manager.LoadEventProject(m_sEventProjectPath.GetChar()); if (!pEventProject) return FALSE; // retrieve event group from event project FMOD_WARNINGCHECK(pEventProject->getGroup(m_sEventGroupName, true, &m_pEventGroup)); if (!m_pEventGroup) return FALSE; // load wave data and allocate event instances for all events within an event group FMOD_EVENT_MODE mode = manager.m_config.bLoadEventDataAsyncronous ? FMOD_EVENT_NONBLOCKING : FMOD_EVENT_DEFAULT; FMOD_RESULT result = m_pEventGroup->loadEventData(FMOD_EVENT_RESOURCE_STREAMS_AND_SAMPLES, mode); FMOD_WARNINGCHECK(result); if(result!=FMOD_OK) return FALSE; // get the size in memory unsigned int iSize = 0; FMOD_WARNINGCHECK(m_pEventGroup->getMemoryInfo(0, FMOD_EVENT_MEMBITS_EVENTINSTANCE_GROUP|FMOD_EVENT_MEMBITS_SOUNDDEF_GROUP, &iSize, 0)); SetNewMemSize(VRESOURCEMEMORY_SYSTEM, iSize); m_iSysMem = (int)iSize; return TRUE; }
int VFmodSoundObject::GetChannelIndex() const { int idx = 0; if (m_pChannel) FMOD_WARNINGCHECK(m_pChannel->getIndex(&idx)); return idx; }
bool VFmodEventGroup::IsReady() const { if (!VFmodManager::GlobalManager().IsInitialized()) return true; VASSERT(m_pEventGroup!=NULL); FMOD_EVENT_STATE eventState; FMOD_WARNINGCHECK(m_pEventGroup->getState(&eventState)); return (eventState & FMOD_EVENT_STATE_READY); }
float VFmodSoundObject::GetCurrentPosition(bool bAbsolute) const { if (m_pChannel) { unsigned int iPos = 0; FMOD_WARNINGCHECK(m_pChannel->getPosition(&iPos,FMOD_TIMEUNIT_MS)); float fSecs = ((float)iPos*(1.0f/1000.0f)); return bAbsolute ? fSecs : fSecs - GetStartTime(); } return 0.0f; }
BOOL VFmodEventGroup::Unload() { if (!VFmodManager::GlobalManager().IsInitialized()) return TRUE; VASSERT(m_pEventGroup!=NULL); FMOD_WARNINGCHECK(m_pEventGroup->freeEventData()); m_pEventGroup = NULL; m_iSysMem = 0; SetNewMemSize(VRESOURCEMEMORY_ALLTYPES, m_iSysMem); return TRUE; }
FMOD::EventProject* VFmodManager::LoadEventProject(const char *szEventProjectPath) { VASSERT(szEventProjectPath!=NULL && m_pEventSystem!=NULL); // make absolute filenames comparable if (szEventProjectPath[0]=='\\' || szEventProjectPath[0]=='/') szEventProjectPath++; VStaticString<FS_MAX_PATH> sEventProjectPathNoExt(szEventProjectPath); VFileHelper::GetFilenameNoExt(sEventProjectPathNoExt, szEventProjectPath); // ensure, that project-path has no .fdp extension // First check, whether event project has been loaded. Please note: Fmod does not support loading // multiple projects with the same name in different directories! FMOD::EventProject *pEventProject = NULL; const char *szEventProjectName = VPathHelper::GetFilename(sEventProjectPathNoExt); m_pEventSystem->getProject(szEventProjectName, &pEventProject); // If event project has not been loaded, then try to load it now. First try to load the // platform-specific exported event-project. When that fails, then try to load the // platform-nonspecific version. if (!pEventProject) { // create path to the platform-specific exported event project (.fev) VStaticString<FS_MAX_PATH> sEventProjectPath(sEventProjectPathNoExt); VPathHelper::GetFileDir(sEventProjectPathNoExt, sEventProjectPath); if(!sEventProjectPath.IsEmpty()) sEventProjectPath += "/"; sEventProjectPath += VFMOD_PLATFORM_STR; sEventProjectPath += "/"; sEventProjectPath += szEventProjectName; sEventProjectPath += ".fev"; // add .fev file-extension m_pEventSystem->load(sEventProjectPath, 0, &pEventProject); if (!pEventProject) { sEventProjectPath = sEventProjectPathNoExt; sEventProjectPath += ".fev"; // add .fev file-extension FMOD_WARNINGCHECK(m_pEventSystem->load(sEventProjectPath, 0, &pEventProject)); if (!pEventProject) return NULL; Vision::Error.Warning("Fmod Warning: platform-specific %s.fev could not be loaded, fall back to platform-nonspecific version", sEventProjectPath.AsChar()); } } return pEventProject; }
void VFmodSoundObject::Stop() { if (!IsPlaying()) return; VFmodManager &manager = VFmodManager::GlobalManager(); manager.m_bAnyStopped = true; // notify manager if (manager.IsInitialized()) { FMOD_WARNINGCHECK(m_pChannel->stop()); m_pChannel = NULL; } m_bUnpause = false; m_bIsPlaying = false; m_fStartTime = 0.0f; }
// -------------------------------------------------------------------------- // // Sound property functions // -------------------------------------------------------------------------- // void VFmodSoundObject::Play(float fStartTime, bool bAlsoInEditor) { if (m_spResource == NULL || IsPlaying()) return; if (!bAlsoInEditor && !Vision::Editor.IsAnimatingOrPlaying()) return; m_fStartTime = fStartTime; VFmodManager &manager = VFmodManager::GlobalManager(); if (manager.IsInitialized()) { const hkvVec3 &vPos = GetPosition(); // stop old playing if (m_pChannel) m_pChannel->stop(); VFmodSoundResource* pResource = (VFmodSoundResource*)GetResource(); if (pResource->m_pSound == NULL) // sound resource not loaded successfully return; FMOD_WARNINGCHECK(manager.m_pSystem->playSound(FMOD_CHANNEL_FREE, pResource->m_pSound, true, &m_pChannel)); if (!m_pChannel) return; FMOD_WARNINGCHECK(m_pChannel->getFrequency(&m_fInitialFreq)); // if this a music sound object assign it to the music channel group if (IsMusic()) m_pChannel->setChannelGroup(manager.m_pMusicGroup); // set everything m_pChannel->setUserData(this); // ...so that we can get from channel to VSoundObject m_pChannel->setCallback(ChannelCallback); m_pChannel->setMode(IsLooped() ? FMOD_LOOP_NORMAL : FMOD_LOOP_OFF); m_pChannel->setPriority(GetPriority()); m_pChannel->set3DMinMaxDistance(Get3DFadeMinDistance(), Get3DFadeMaxDistance()); m_pChannel->set3DAttributes((FMOD_VECTOR *)&vPos, NULL); // no speed (yet) m_pChannel->setVolume(GetVolume()); m_pChannel->setPan(GetPan()); SetPitch(GetPitch()); SetConeAngles(GetConeAngleInside(), GetConeAngleOutside()); // Initially the sound is left paused, then within the first RunTick it is unpaused. This is required since // the 3D listener attributes has to be set prior to playing a sound. Otherwise Fmod would perform // occlusion-raycasts without having initialized listener-attributes, which potentially results in a // wrong occlusion-behavior. m_bUnpause = true; m_bIsPlaying = true; m_bPlayedOnce = true; unsigned int ims = (int)(fStartTime*1000.f); // milliseconds m_pChannel->setPosition(ims,FMOD_TIMEUNIT_MS); m_pChannel->setMute(IsMuted()); } Helper_SetFlag(VFMOD_FLAG_PAUSED, !IsPlaying()); }
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); }
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) hkvLog::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)); //listen to system events (eg. new device - headphones) FMOD_ERRORCHECK(m_pSystem->setCallback(VisionFM_System)); #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; hkvLog::Warning("Fmod DSP buffer size increased from %i to %i, in order to get correct sound output", iBufferSize, iBufferSize*2); #endif } #endif VFmodSoundInit_e initResult = InitDevice(); switch(initResult) { case VFMODSOUNDINIT_NO_HARDWARE: hkvLog::Warning("No sound card present!"); break; case VFMODSOUNDINIT_NO_SPEAKERS: hkvLog::Warning("No speakers or headphones connected."); break; default: //case VSOUNDINIT_OK: hkvLog::Info("Sound successfully initialized."); break; } }