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
}