Skip to content
Snippets Groups Projects
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
impl.cpp 146.76 KiB
/*
 *  --------------------------------------------------------------------------------------------
 *
 *    VVV        VVV A           Virtual Acoustics (VA) | http://www.virtualacoustics.org
 *     VVV      VVV AAA          Licensed under the Apache License, Version 2.0
 *      VVV    VVV   AAA
 *       VVV  VVV     AAA        Copyright 2015-2018
 *        VVVVVV       AAA       Institute of Technical Acoustics (ITA)
 *         VVVV         AAA      RWTH Aachen University
 *
 *  --------------------------------------------------------------------------------------------
 */

#include "impl.h"

IVAInterface* VACore::CreateCoreInstance( const CVAStruct& oArgs, std::ostream* pOutputStream )
{
	VA_TRACE( "Config", oArgs );
	return new CVACoreImpl( oArgs, pOutputStream );
}

void VACore::StoreCoreConfigToFile( const CVAStruct& oConfig, const std::string& sConfigFilePath )
{
	StoreStructToINIFile( sConfigFilePath, oConfig );
}

CVAStruct VACore::LoadCoreConfigFromFile( const std::string& sConfigFilePath )
{
	CVAStruct oFinalCoreConfigStruct, oCurrentConfig;

	VistaFileSystemFile oConfigFile( sConfigFilePath );
	std::list< VistaFileSystemFile > voConfigFiles;

	std::vector< VistaFileSystemDirectory > voIncludePaths;
	if( oConfigFile.Exists() && oConfigFile.GetParentDirectory().empty() == false )
		voIncludePaths.push_back( oConfigFile.GetParentDirectory() );

	voConfigFiles.push_back( VistaFileSystemFile( sConfigFilePath ) );

	VA_INFO( "Core", "Working directory: '" << VistaFileSystemDirectory::GetCurrentWorkingDirectory() << "'" );

	while( voConfigFiles.empty() == false )
	{
		VistaFileSystemFile oCurrentConfigFile( voConfigFiles.front() );
		voConfigFiles.pop_front();

		if( oCurrentConfigFile.Exists() == false )
		{
			for( size_t n = 0; n < voIncludePaths.size(); n++ )
			{
				std::string sCombinedFilePath = voIncludePaths[ n ].GetName() + PATH_SEPARATOR + oCurrentConfigFile.GetLocalName();
				oCurrentConfigFile.SetName( sCombinedFilePath );
				if( oCurrentConfigFile.Exists() && oCurrentConfigFile.IsFile() )
				{
					VA_INFO( "Config", "Including further configuration file '" + oCurrentConfigFile.GetLocalName() +
						"' from include path '" + voIncludePaths[ n ].GetName() + "'" );
					break;
				}
			}

			if( !oCurrentConfigFile.Exists() )
			{
				VA_EXCEPT2( FILE_NOT_FOUND, "Configuration file '" + oCurrentConfigFile.GetLocalName() + "' not found, aborting." );
			}
		}

		VA_VERBOSE( "Config", std::string( "Reading INI file '" ) + oCurrentConfigFile.GetLocalName() + "'" );
		LoadStructFromINIFIle( oCurrentConfigFile.GetName(), oCurrentConfig );

		if( oCurrentConfig.HasKey( "paths" ) )
		{
			const CVAStruct& oPaths( oCurrentConfig[ "paths" ] );
			CVAStruct::const_iterator it = oPaths.Begin();
			while( it != oPaths.End() )
			{
				const CVAStructValue& oIncludePath( ( it++ )->second );
				VistaFileSystemDirectory oNewPathDir( oIncludePath );
				if( oNewPathDir.Exists() && oNewPathDir.IsDirectory() )
					voIncludePaths.push_back( oNewPathDir );
			}
		}

		if( oCurrentConfig.HasKey( "files" ) )
		{
			const CVAStruct& oPaths( oCurrentConfig[ "files" ] );
			CVAStruct::const_iterator it = oPaths.Begin();
			while( it != oPaths.End() )
			{
				const CVAStructValue& oIncludeFile( ( it++ )->second );

				voConfigFiles.push_back( VistaFileSystemFile( oIncludeFile ) );
			}
		}

		oCurrentConfig.RemoveKey( "files" );

		// Merge structs (check for uniqueness)
		oFinalCoreConfigStruct.Merge( oCurrentConfig, true );
	}

	return oFinalCoreConfigStruct;
}

#ifdef WIN32
// Trick um DLL-Pfad zu ermitteln
EXTERN_C IMAGE_DOS_HEADER __ImageBase;
#endif

std::string VACore::GetCoreLibFilePath()
{
#ifdef WIN32
	CHAR pszPath[ MAX_PATH + 1 ] = { 0 };
	GetModuleFileNameA( ( HINSTANCE ) &__ImageBase, pszPath, _countof( pszPath ) );
	return std::string( pszPath );
#else
	VA_EXCEPT2( NOT_IMPLEMENTED, "This function is not implemented for your platform. Sorry." );
	return "";
#endif // WIN32
}

CVACoreImpl::CVACoreImpl( const CVAStruct& oArgs, std::ostream* pOutputStream )
	: m_pAudioDriverBackend( nullptr )
	, m_pGlobalSamplePool( nullptr )
	, m_pGlobalSampler( nullptr )
	, m_pSignalSourceManager( nullptr )
	, m_pDirectivityManager( nullptr )
	, m_pSceneManager( nullptr )
	, m_pNewSceneState( nullptr )
	, m_iCurActiveSoundReceiver( -1 )
	, m_iNewActiveSoundReceiver( -1 )
	, m_iUpdActiveSoundReceiver( -1 )
	, m_pEventManager( nullptr )
	, m_pCoreThread( nullptr )
	, m_pInputAmp( nullptr )
	, m_pR2RPatchbay( nullptr )
	, m_pOutputPatchbay( nullptr )
	, m_pInputStreamDetector( nullptr )
	, m_pOutputStreamDetector( nullptr )
	, m_pOutputTracker( nullptr )
	, m_pStreamProbeDeviceInput( nullptr )
	, m_pStreamProbeDeviceOutput( nullptr )
	, m_pCurSceneState( nullptr )
	, m_pClock( ITAClock::getDefaultClock() )
	, m_pTicker( NULL )
	, m_lSyncModOwner( -1 )
	, m_lSyncModSpinCount( 0 )
	, m_iState( VA_CORESTATE_CREATED )
	, m_iGlobalAuralizationMode( IVAInterface::VA_AURAMODE_ALL )
	, m_dOutputGain( 1 )
	, m_dInputGain( 1 )
	, m_bOutputMuted( false )
	, m_bInputMuted( false )
	, m_dStreamClockOffset( 0 )
	, m_fCoreClockOffset( 0 )
	, m_oCoreThreadLoopTotalDuration( "Core thread loop" )
{
	VA_NO_REENTRANCE;

	if( pOutputStream )
		SetOutputStream( pOutputStream );

	VA_TRY
	{
		// read configuration
		m_oCoreConfig.Init( oArgs );

		// register core itself as a module
		SetObjectName( "VACore" );
		m_oModules.RegisterObject( this );
		VA_VERBOSE( "Core", "Registered core module with name '" << GetObjectName() << "'" );

		// Der Event-Manager muss immer verfgbar sein,
		// unabhnging davon ob der Core initialisiert wurde oder nicht.
		m_pEventManager = new CVACoreEventManager;

		m_iState = VA_CORESTATE_CREATED;

		VA_TRACE( "Core", "CVACoreImpl instance created [" << this << "]" );

	}
	VA_RETHROW;
}

CVACoreImpl::~CVACoreImpl()
{
	VA_NO_REENTRANCE;

	// Implizit finalisieren, falls dies nicht durch den Benutzer geschah
	if( m_iState == VA_CORESTATE_READY )
	{
		VA_TRY
		{
			Finalize();
		}
			VA_FINALLY
		{
			// Fehler beim Finalisieren ignorieren
		};
	}

	// Nachricht senden [blocking], das die Kerninstanz gelscht wird.
	CVAEvent ev;
	ev.iEventType = CVAEvent::DESTROY;
	ev.pSender = this;
	m_pEventManager->BroadcastEvent( ev );

	// Module deregistrieren
	m_oModules.Clear();

	// Nachrichten-Manager freigeben
	VA_TRY
	{
		delete m_pEventManager;
	}
	VA_RETHROW;

	VA_TRACE( "Core", "CVACoreImpl instance deleted [" << this << "]" );

	// Profiling ausgeben
	VA_VERBOSE( "Core", m_oCoreThreadLoopTotalDuration.ToString() );
}

void CVACoreImpl::SetOutputStream( std::ostream* posDebug )
{
	VALog_setOutputStream( posDebug );
	VALog_setErrorStream( posDebug );
}

void CVACoreImpl::GetVersionInfo( CVAVersionInfo* pVersionInfo ) const
{
	if( !pVersionInfo )
		return;

	std::stringstream ss;
	ss << VACORE_VERSION_MAJOR << "." << VACORE_VERSION_MINOR;
	pVersionInfo->sVersion = ss.str();
	ss.clear();
#ifdef VACORE_CMAKE_DATE
	ss << VACORE_CMAKE_DATE;
#else
	ss << "Unkown date";
#endif
	pVersionInfo->sDate = ss.str();
	pVersionInfo->sFlags = "";

#ifdef DEBUG
	pVersionInfo->sComments = "debug";
#else
	pVersionInfo->sComments = "release";
#endif
}

void CVACoreImpl::AttachEventHandler( IVAEventHandler* pCoreEventHandler )
{
	VA_TRY
	{
		// Immer mglich. Unabhngig vom Zustand. Thread-safety wird im Manager geregelt.
		m_pEventManager->AttachHandler( pCoreEventHandler );
	}
	VA_RETHROW;
}

void CVACoreImpl::DetachEventHandler( IVAEventHandler* pCoreEventHandler )
{
	VA_TRY
	{
		// Immer mglich. Unabhngig vom Zustand. Thread-safety wird im Manager geregelt.
		m_pEventManager->DetachHandler( pCoreEventHandler );
	}
	VA_RETHROW;
}

int CVACoreImpl::GetState() const
{
	VA_VERBOSE( "Core", "Core state requested, current state is " << m_iState );
	return m_iState;
}

void CVACoreImpl::Reset()
{
	VA_CHECK_INITIALIZED;

	// Wait for core thread
	while( !m_pCoreThread->TryBreak() )
		VASleep( 20 );

	VA_NO_REENTRANCE;

	if( GetUpdateLocked() )
	{
		VA_WARN( "Core", "Encountered locked scene during reset. Please unlock before resetting, skipping." );
		m_pCoreThread->Continue();
	}

	VA_TRY
	{
		VA_INFO( "Core", "Resetting core" );

		// Reset audio renderers
		std::vector< CVAAudioRendererDesc >::iterator it = m_voRenderers.begin();
		while( it != m_voRenderers.end() )
		{
			CVAAudioRendererDesc& oRend( *it++ );
			oRend.pInstance->Reset();
		}

		if( m_pCurSceneState )
		{
			// Referenz entfernen welche in CoreThreadLoop hinzugefgt wurde
			m_pCurSceneState->RemoveReference();
			m_pCurSceneState = nullptr;
		}

		// Alle Szenenobjekte lschen
		m_pSceneManager->Reset();
		m_pSignalSourceManager->Reset();
		m_pDirectivityManager->Reset();

		// TODO: Check if the pool and sampler must really be recreated
		/*
		delete m_pGlobalSamplePool;
		m_pGlobalSamplePool = nullptr;
		m_pGlobalSamplePool = ITASoundSamplePool::Create(1, m_oCoreConfig.oAudioDriverConfig.dSamplerate);

		// This causes a crash in patch bay
		delete m_pGlobalSampler;
		m_pGlobalSampler = nullptr;
		m_pGlobalSampler = ITASoundSampler::Create(1, m_oCoreConfig.oAudioDriverConfig.dSamplerate, m_oCoreConfig.oAudioDriverConfig.iBuffersize, m_pGlobalSamplePool);
		m_pGlobalSampler->AddMonoTrack();
		*/
		//m_pGlobalSampler->RemoveAllPlaybacks();

		// Werte neusetzen
		m_pCurSceneState = m_pSceneManager->GetHeadSceneState();
		m_iCurActiveSoundReceiver = -1;
		m_iNewActiveSoundReceiver = -1;

		m_pCoreThread;

		// Core-Thread fortsetzen
		m_pCoreThread->Continue();

		// Ereignis generieren, wenn Operation erfolgreich
		CVAEvent ev;
		ev.iEventType = CVAEvent::RESET;
		ev.pSender = this;
		m_pEventManager->BroadcastEvent( ev );

	}
		VA_FINALLY
	{
		Tidyup();
		throw;
	}
}

void CVACoreImpl::Tidyup() {
	/*
	 *  Hinweis: Diese Hilfsmethode wird nur innerhalb des Reentrance-Locks
	 *           aufgerufen - daher keine weiter Absicherung ntig.
	 */

	VA_TRY
	{
		if( m_pTicker )
		{
			m_pTicker->StopTicker();
			m_pTicker->SetAfterPulseFunctor( NULL );
		}

		FinalizeAudioDriver();
		FinalizeRenderingModules();
		FinalizeReproductionModules();

		delete m_pTicker;
		m_pTicker = nullptr;

		delete m_pCoreThread;
		m_pCoreThread = nullptr;

		delete m_pInputAmp;
		m_pInputAmp = nullptr;

		delete m_pInputStreamDetector;
		m_pInputStreamDetector = nullptr;

		delete m_pR2RPatchbay;
		m_pR2RPatchbay = nullptr;

		delete m_pOutputPatchbay;
		m_pOutputPatchbay = nullptr;

		delete m_pOutputStreamDetector;
		m_pOutputStreamDetector = nullptr;

		delete m_pOutputTracker;
		m_pOutputTracker = nullptr;

		delete m_pStreamProbeDeviceInput;
		m_pStreamProbeDeviceInput = nullptr;

		delete m_pStreamProbeDeviceOutput;
		m_pStreamProbeDeviceOutput = nullptr;

		delete m_pSignalSourceManager;
		m_pSignalSourceManager = nullptr;

		delete m_pGlobalSampler;
		m_pGlobalSampler = nullptr;

		delete m_pGlobalSamplePool;
		m_pGlobalSamplePool = nullptr;

		if( m_pDirectivityManager )
			m_pDirectivityManager->Finalize();
		delete m_pDirectivityManager;
		m_pDirectivityManager = nullptr;


		if( m_pSceneManager )
			m_pSceneManager->Finalize();
		delete m_pSceneManager;
		m_pSceneManager = nullptr;

		m_iState = VA_CORESTATE_CREATED;

	}
		VA_FINALLY
	{
		m_iState = VA_CORESTATE_FAIL;
	}
}

void CVACoreImpl::Finalize()
{
	VA_NO_REENTRANCE;

	//VA_TRACE("Core", __FUNCTION__ << " entry");
	VA_INFO( "Core", "Finalizing core" );

	VA_TRY
	{
		// Mehrfaches Finialisieren fhrt nicht zu Fehlern
		if( m_iState == VA_CORESTATE_CREATED )
		return;

		if( m_iState == VA_CORESTATE_FAIL )
			VA_EXCEPT2( MODAL_ERROR, "Core corrupted, finalization impossible" );

		// Core-Thread anhalten (wenn frei ist)
		while( !m_pCoreThread->TryBreak() )
			VASleep( 10 );
		//m_pCoreThread->Break(); << deadlock

		// Alle Filterketten lschen und warten bis Zustand sicher bernommen
		// Wichtig: Dies muss vor dem Beenden des Streamings geschehen

		// Reset audio renderers
		for( std::vector<CVAAudioRendererDesc>::iterator it = m_voRenderers.begin(); it != m_voRenderers.end(); ++it )
			it->pInstance->Reset();

		// Peak-Nachrichten stoppen
		m_pTicker->StopTicker();

		// Audio-Streaming beenden
		m_pAudioDriverBackend->stopStreaming();

		InitProgress( "Stopping auralization threads", "", 2 );

		// Stop and delete ticker
		m_pTicker->SetAfterPulseFunctor( NULL );
		delete m_pTicker;
		m_pTicker = NULL;

		// Hauptthread beenden und freigeben
		delete m_pCoreThread;
		m_pCoreThread = nullptr;

		SetProgress( "Releasing audio hardware", "", 1 );
		FinalizeAudioDriver();
		FinalizeRenderingModules();
		FinalizeReproductionModules();

		SetProgress( "Cleaning up resources", "", 2 );
		delete m_pInputAmp;
		m_pInputAmp = nullptr;

		if( m_pInputStreamDetector )
			if( m_pInputStreamDetector->GetProfilerEnabled() )
				VA_VERBOSE( "Core", "Input stream detector profiler: " << m_pInputStreamDetector->GetProfilerResult() );
		delete m_pInputStreamDetector;
		m_pInputStreamDetector = nullptr;

		m_voReproductionModules.clear();

		delete m_pR2RPatchbay;
		m_pR2RPatchbay = nullptr;

		delete m_pOutputPatchbay;
		m_pOutputPatchbay = nullptr;

		if( m_pOutputStreamDetector->GetProfilerEnabled() )
			VA_VERBOSE( "Core", "Output stream detector profiler: " << m_pOutputStreamDetector->GetProfilerResult() );
		delete m_pOutputStreamDetector;
		m_pOutputStreamDetector = nullptr;

		delete m_pOutputTracker;
		m_pOutputTracker = nullptr;

		delete m_pStreamProbeDeviceInput;
		m_pStreamProbeDeviceInput = nullptr;

		delete m_pStreamProbeDeviceOutput;
		m_pStreamProbeDeviceOutput = nullptr;

		delete m_pSignalSourceManager;
		m_pSignalSourceManager = nullptr;

		delete m_pGlobalSampler;
		m_pGlobalSampler = nullptr;

		delete m_pGlobalSamplePool;
		m_pGlobalSamplePool = nullptr;

		m_pDirectivityManager->Finalize();
		delete m_pDirectivityManager;
		m_pDirectivityManager = nullptr;

		m_pSceneManager->Finalize();
		delete m_pSceneManager;
		m_pSceneManager = nullptr;

		// Finalisierung erfolgreich. Nun wieder im Grundzustand!
		m_iState = VA_CORESTATE_CREATED;

		FinishProgress();

	}
		VA_FINALLY
	{
		// Nochmals versuchen aufzurumen
		Tidyup();

		// Allgemein: Fehler beim Finalisieren? => Core im Sack
		m_iState = VA_CORESTATE_FAIL;

		// VAExceptions unverndert nach aussen leiten
		throw;
	}
}


void CVACoreImpl::RegisterModule( CVAObject* pModule )
{
	m_oModules.RegisterObject( pModule );
}

void CVACoreImpl::GetModules( std::vector< CVAModuleInfo >& viModuleInfos ) const
{
	VA_NO_REENTRANCE;
	VA_CHECK_INITIALIZED;

#ifdef VACORE_MODULE_INTERFACE_ENABLED
	VA_TRY
	{
		std::vector<CVAObjectInfo> v;
		m_oModules.GetObjectInfos( v );

		VA_PRINT( "Available modules (" << v.size() << ")" );

		viModuleInfos.clear();
		viModuleInfos.resize( v.size() );
		for( size_t i = 0; i < v.size(); i++ )
		{
			VA_PRINT( "'" << v[ i ].sName << "'\t\t\t" << v[ i ].sDesc );
			viModuleInfos[ i ].sName = v[ i ].sName;
			viModuleInfos[ i ].sDesc = v[ i ].sDesc;
	}
	}
	VA_RETHROW;

#else // VACORE_MODULE_INTERFACE_ENABLED

	VA_EXCEPT1( "This VACore version does not provide modules" );

#endif // VACORE_MODULE_INTERFACE_ENABLED

}

CVAStruct CVACoreImpl::CallModule( const std::string& sModuleName, const CVAStruct& oArgs )
{
	VA_NO_REENTRANCE;
	VA_CHECK_INITIALIZED;

#ifdef VACORE_MODULE_INTERFACE_ENABLED

	VA_TRY
	{
		CVAObject* pModule = m_oModules.FindObjectByName( sModuleName );
		if( !pModule )
		{
			VA_EXCEPT2( INVALID_PARAMETER, "Module '" + sModuleName + "' not found" );
		}

#ifdef VACORE_MODULE_INTERFACE_MECHANISM_EVENT_BASED

		CVAEvent ev;
		ev.iEventType = CVAEvent::SIGNALSOURCE_STATE_CHANGED;
		ev.pSender = this;
		ev.sObjectID = sModuleName;
		ev;
		m_pEventManager->BroadcastEvent( ev );
		m_pEventManager->

#else // not VACORE_MODULE_INTERFACE_MECHANISM_EVENT_BASED

		return pModule->CallObject( oArgs );

#endif // VACORE_MODULE_INTERFACE_MECHANISM_EVENT_BASED

	}
	VA_RETHROW;

#else // VACORE_MODULE_INTERFACE_ENABLED

#ifdef VACORE_NO_MODULE_INTERFACE_THROW_EXCEPTION
	VA_EXCEPT1( "This VACore version does not provide modules" );
#endif // VACORE_NO_MODULE_INTERFACE_THROW_EXCEPTION

#endif // VACORE_MODULE_INTERFACE_ENABLED
}

CVAStruct CVACoreImpl::GetSearchPaths() const
{
	VA_NO_REENTRANCE;
	VA_CHECK_INITIALIZED;

	CVAStruct oSearchPaths;
	for( size_t i = 0; i < m_oCoreConfig.vsSearchPaths.size(); i++ )
		oSearchPaths[ "path_" + std::to_string( long( i ) ) ] = m_oCoreConfig.vsSearchPaths[ i ];

	return oSearchPaths;
}

CVAStruct CVACoreImpl::GetCoreConfiguration( const bool bFilterEnabled ) const
{
	VA_NO_REENTRANCE;
	VA_CHECK_INITIALIZED;

	CVAStruct oCoreConfig;

	if( bFilterEnabled )
	{
		CVAStruct::const_iterator cit = m_oCoreConfig.GetStruct().Begin();
		while( cit != m_oCoreConfig.GetStruct().End() )
		{
			const std::string sKey( cit->first );
			const CVAStructValue& oVal( cit->second );
			++cit;

			if( oVal.IsStruct() )
			{
				const CVAStruct& oSection( oVal.GetStruct() );
				if( oSection.HasKey( "enabled" ) )
					if( bool( oSection[ "enabled" ] ) == false )
						continue; // Only skip if explicitly not enabled
				oCoreConfig[ sKey ] = oVal;
			}
		}

	}
	else
	{
		oCoreConfig = m_oCoreConfig.GetStruct();
	}

	return oCoreConfig;
}

CVAStruct CVACoreImpl::GetHardwareConfiguration() const
{
	VA_NO_REENTRANCE;
	VA_CHECK_INITIALIZED;
	return m_oCoreConfig.oHardwareSetup.GetStruct();
}

CVAStruct CVACoreImpl::GetFileList( const bool bRecursive, const std::string& sFileSuffixFilter ) const
{
	VA_NO_REENTRANCE;
	VA_CHECK_INITIALIZED;

	CVAStruct oFileList;
	for( size_t i = 0; i < m_oCoreConfig.vsSearchPaths.size(); i++ )
	{
		if( bRecursive )
		{
			RecursiveFileList( m_oCoreConfig.vsSearchPaths[ i ], oFileList, sFileSuffixFilter );
		}
		else
		{
			std::vector< std::string > vsFileList;
			FileList( m_oCoreConfig.vsSearchPaths[ i ], vsFileList, sFileSuffixFilter );

			CVAStruct oMoreFiles;
			for( size_t j = 0; j < vsFileList.size(); j++ )
				oMoreFiles[ std::to_string( long( j ) ) ] = vsFileList[ j ];

			oFileList[ m_oCoreConfig.vsSearchPaths[ i ] ] = oMoreFiles;
		}
	}
	return oFileList;
}

int CVACoreImpl::CreateDirectivityFromParameters( const CVAStruct& oParams, const std::string& sName )
{
	VA_NO_REENTRANCE;
	VA_CHECK_INITIALIZED;

	VA_TRY
	{
		int iDirID = m_pDirectivityManager->CreateDirectivity( oParams, sName );

		assert( iDirID != -1 );

		CVAEvent ev;
		ev.iEventType = CVAEvent::DIRECTIVITY_LOADED;
		ev.pSender = this;
		ev.iObjectID = iDirID;
		m_pEventManager->BroadcastEvent( ev );

		VA_INFO( "Core", "Directivity successfully created, assigned identifier " << iDirID );

		return iDirID;

	}
	VA_RETHROW;
}

bool CVACoreImpl::DeleteDirectivity( const int iDirID )
{
	VA_NO_REENTRANCE;
	VA_CHECK_INITIALIZED;

	VA_TRY
	{
		bool bSuccess = m_pDirectivityManager->DeleteDirectivity( iDirID );
		//assert( bSuccess );

		// Ereignis generieren, wenn Operation erfolgreich
		CVAEvent ev;
		ev.iEventType = CVAEvent::DIRECTIVITY_DELETED;
		ev.pSender = this;
		ev.iObjectID = iDirID;
		m_pEventManager->BroadcastEvent( ev );

		VA_INFO( "Core", "FreeDirectivity successful, freed directivity " << iDirID );

		return bSuccess;

	} VA_RETHROW;
}

CVADirectivityInfo CVACoreImpl::GetDirectivityInfo( int iDirID ) const {
	VA_NO_REENTRANCE;
	VA_CHECK_INITIALIZED;

	VA_TRY{
		return m_pDirectivityManager->GetDirectivityInfo( iDirID );
	} VA_RETHROW;
}

void CVACoreImpl::GetDirectivityInfos( std::vector<CVADirectivityInfo>& vdiDest ) const
{
	VA_NO_REENTRANCE;
	VA_CHECK_INITIALIZED;

	VA_TRY
	{
		m_pDirectivityManager->GetDirectivityInfos( vdiDest );
	}
	VA_RETHROW;
}

void CVACoreImpl::SetDirectivityName( const int iID, const std::string& sName )
{
	VA_NO_REENTRANCE;
	VA_CHECK_INITIALIZED;

	VA_TRY
	{
		VA_EXCEPT_NOT_IMPLEMENTED_NEXT_VERSION;
		//m_pDirectivityManager->SetName( iID, sName );
	}
	VA_RETHROW;
}

std::string CVACoreImpl::GetDirectivityName( const int iID ) const
{
	VA_NO_REENTRANCE;
	VA_CHECK_INITIALIZED;

	VA_TRY
	{
		CVADirectivityInfo oInfo = m_pDirectivityManager->GetDirectivityInfo( iID );
		return oInfo.sName;
	}
	VA_RETHROW;
}

void CVACoreImpl::SetDirectivityParameters( const int iID, const CVAStruct& oParams )
{
	VA_NO_REENTRANCE;
	VA_CHECK_INITIALIZED;

	VA_TRY
	{
		VA_EXCEPT_NOT_IMPLEMENTED_NEXT_VERSION;
		//m_pDirectivityManager->SetParameters( iID, oParams );
	}
	VA_RETHROW;
}

CVAStruct CVACoreImpl::GetDirectivityParameters( const int iID, const CVAStruct& ) const
{
	VA_NO_REENTRANCE;
	VA_CHECK_INITIALIZED;

	VA_TRY
	{
		CVADirectivityInfo oInfo = m_pDirectivityManager->GetDirectivityInfo( iID );
		return oInfo.oParams;

		// @todo
		//return m_pDirectivityManager->GetDirectivityParameters( iID, oParams );
	}
	VA_RETHROW;
}

int CVACoreImpl::CreateAcousticMaterial( const CVAAcousticMaterial& oMaterial, const std::string& sName )
{
	VA_EXCEPT_NOT_IMPLEMENTED_FUTURE_VERSION;
}

int CVACoreImpl::CreateAcousticMaterialFromParameters( const CVAStruct& oParams, const std::string& sName )
{
	VA_EXCEPT_NOT_IMPLEMENTED_FUTURE_VERSION;
}

bool CVACoreImpl::DeleteAcousticMaterial( const int iID )
{
	VA_EXCEPT_NOT_IMPLEMENTED_FUTURE_VERSION;
}

CVAAcousticMaterial CVACoreImpl::GetAcousticMaterialInfo( const int iID ) const
{
	VA_EXCEPT_NOT_IMPLEMENTED_FUTURE_VERSION;
}

void CVACoreImpl::GetAcousticMaterialInfos( std::vector< CVAAcousticMaterial >& voDest ) const
{
	VA_EXCEPT_NOT_IMPLEMENTED_FUTURE_VERSION;
}

void CVACoreImpl::SetAcousticMaterialName( const int iID, const std::string& sName )
{
	VA_EXCEPT_NOT_IMPLEMENTED_FUTURE_VERSION;
}

std::string CVACoreImpl::GetAcousticMaterialName( const int iID ) const
{
	VA_EXCEPT_NOT_IMPLEMENTED_FUTURE_VERSION;
}

void CVACoreImpl::SetAcousticMaterialParameters( const int iID, const CVAStruct& oParams )
{
	VA_EXCEPT_NOT_IMPLEMENTED_FUTURE_VERSION;
}

CVAStruct CVACoreImpl::GetAcousticMaterialParameters( const int iID, const CVAStruct& oParams ) const
{
	VA_EXCEPT_NOT_IMPLEMENTED_FUTURE_VERSION;
}

int CVACoreImpl::CreateGeometryMesh( const CVAGeometryMesh& oMesh, const std::string& sName )
{
	VA_EXCEPT_NOT_IMPLEMENTED_FUTURE_VERSION;
}

int CVACoreImpl::CreateGeometryMeshFromParameters( const CVAStruct& oParams, const std::string& sName )
{
	VA_EXCEPT_NOT_IMPLEMENTED_FUTURE_VERSION;
}

bool CVACoreImpl::DeleteGeometryMesh( const int iID )
{
	VA_EXCEPT_NOT_IMPLEMENTED_FUTURE_VERSION;
}

CVAGeometryMesh CVACoreImpl::GetGeometryMesh( const int iID ) const
{
	VA_EXCEPT_NOT_IMPLEMENTED_FUTURE_VERSION;
}

void CVACoreImpl::GetGeometryMeshIDs( std::vector< int >& viIDs ) const
{
	VA_EXCEPT_NOT_IMPLEMENTED_FUTURE_VERSION;
}

void CVACoreImpl::SetGeometryMeshName( const int iID, const std::string& sName )
{
	VA_EXCEPT_NOT_IMPLEMENTED_FUTURE_VERSION;
}

std::string CVACoreImpl::GetGeometryMeshName( const int iID ) const
{
	VA_EXCEPT_NOT_IMPLEMENTED_FUTURE_VERSION;
}

void CVACoreImpl::SetGeometryMeshParameters( const int iID, const CVAStruct& oParams )
{
	VA_EXCEPT_NOT_IMPLEMENTED_FUTURE_VERSION;
}

CVAStruct CVACoreImpl::GetGeometryMeshParameters( const int iID, const CVAStruct& oParams ) const
{
	VA_EXCEPT_NOT_IMPLEMENTED_FUTURE_VERSION;
}

void CVACoreImpl::SetGeometryMeshEnabled( const int iID, const bool bEnabled )
{
	VA_EXCEPT_NOT_IMPLEMENTED_FUTURE_VERSION;
}

bool CVACoreImpl::GetGeometryMeshEnabled( const int iID ) const
{
	VA_EXCEPT_NOT_IMPLEMENTED_FUTURE_VERSION;
}

std::string CVACoreImpl::CreateSignalSourceBufferFromParameters( const CVAStruct& oParams, const std::string& sName )
{
	VA_NO_REENTRANCE;
	VA_CHECK_INITIALIZED;

	VA_TRY
	{
		if( oParams.HasKey( "filepath" ) )
		{
			const std::string sFilePath = oParams[ "filepath" ];
			const std::string sDestFilePath = FindFilePath( sFilePath );
			if( sDestFilePath.empty() )
				VA_EXCEPT2( INVALID_PARAMETER, "Looked everywhere, but could not find file '" + sFilePath + "'" );

			std::string sID = m_pSignalSourceManager->CreateAudiofileSignalSource( sDestFilePath, sName );
			assert( !sID.empty() );

			CVAEvent ev;
			ev.iEventType = CVAEvent::SIGNALSOURCE_CREATED;
			ev.pSender = this;
			ev.sObjectID = sID;
			m_pEventManager->BroadcastEvent( ev );

			VA_INFO( "Core", "Created audiofile signal source (ID=" << sID << ", Name=\"" << sName << "\", Filename=\"" << sDestFilePath << "\")" );

			return sID;
		}
		else
		{
			VA_EXCEPT2( INVALID_PARAMETER, "Could not interpret parameter arguments to create a buffer signal source" );
		}
	}
	VA_RETHROW;
}

std::string CVACoreImpl::CreateSignalSourceTextToSpeech( const std::string& sName /*= "" */ )
{
	VA_NO_REENTRANCE;
	VA_CHECK_INITIALIZED;

	VA_TRY
	{
		std::string sID = m_pSignalSourceManager->CreateTextToSpeechSignalSource( sName );
		assert( !sID.empty() );

		CVAEvent ev;
		ev.iEventType = CVAEvent::SIGNALSOURCE_CREATED;
		ev.pSender = this;
		ev.sObjectID = sID;
		m_pEventManager->BroadcastEvent( ev );

		VA_INFO( "Core", "Created text-to-speech signal source ( ID=" << sID << ", Name=\"" << sName << "\" )" );

		return sID;
	}
	VA_RETHROW;
}

std::string CVACoreImpl::CreateSignalSourceSequencer( const std::string& sName )
{
	VA_NO_REENTRANCE;
	VA_CHECK_INITIALIZED;

	VA_TRY
	{
		std::string sID = m_pSignalSourceManager->CreateSequencerSignalSource( sName );

		// Ereignis generieren, wenn Operation erfolgreich
		CVAEvent ev;
		ev.iEventType = CVAEvent::SIGNALSOURCE_CREATED;
		ev.pSender = this;
		ev.sObjectID = sID;
		m_pEventManager->BroadcastEvent( ev );

		VA_INFO( "Core", "Created sequencer signal source (ID=" << sID << ", Name=\"" << sName << "\")" );

		return sID;
	}
	VA_RETHROW;
}

std::string CVACoreImpl::CreateSignalSourceNetworkStream( const std::string& sInterface, const int iPort, const std::string& sName )
{
	VA_NO_REENTRANCE;
	VA_CHECK_INITIALIZED;

	VA_TRY
	{
		VA_TRACE( "Core", "Attempting to connect to a netstream signal source on " << sInterface << " with port " << iPort );
		std::string sID = m_pSignalSourceManager->CreateNetstreamSignalSource( sInterface, iPort, sName );
		assert( !sID.empty() );

		// Ereignis generieren, wenn Operation erfolgreich
		CVAEvent ev;
		ev.iEventType = CVAEvent::SIGNALSOURCE_CREATED;
		ev.pSender = this;
		ev.sObjectID = sID;
		m_pEventManager->BroadcastEvent( ev );

		VA_INFO( "Core", "Created network stream signal source (ID=" << sID << ", Name='" << sName << "', Interface=" << sInterface << ":" << iPort << ")" );

		return sID;
	}
	VA_RETHROW;
}

std::string CVACoreImpl::CreateSignalSourceEngine( const CVAStruct&, const std::string& sName )
{
	VA_NO_REENTRANCE;
	VA_CHECK_INITIALIZED;

	VA_TRY
	{
		std::string sID = m_pSignalSourceManager->CreateEngineSignalSource( sName );

		// Ereignis generieren, wenn Operation erfolgreich
		CVAEvent ev;
		ev.iEventType = CVAEvent::SIGNALSOURCE_CREATED;
		ev.pSender = this;
		ev.sObjectID = sID;
		m_pEventManager->BroadcastEvent( ev );

		VA_INFO( "Core", "Created engine signal source (ID=" << sID << ", Name=\"" << sName << "\")" );

		return sID;
	}
	VA_RETHROW;
}


std::string CVACoreImpl::CreateSignalSourceMachine( const CVAStruct&, const std::string& sName/*="" */ )
{
	VA_NO_REENTRANCE;
	VA_CHECK_INITIALIZED;

	VA_TRY
	{
		std::string sID = m_pSignalSourceManager->CreateMachineSignalSource( sName );
		return sID;
	}
	VA_RETHROW;
}


bool CVACoreImpl::DeleteSignalSource( const std::string& sID )
{
	VA_NO_REENTRANCE;
	VA_CHECK_INITIALIZED;

	VA_TRY
	{
		m_pSignalSourceManager->DeleteSignalSource( sID );

		// Ereignis generieren, wenn Operation erfolgreich
		CVAEvent ev;
		ev.iEventType = CVAEvent::SIGNALSOURCE_DELETED;
		ev.pSender = this;
		ev.sObjectID = sID;
		m_pEventManager->BroadcastEvent( ev );

		VA_INFO( "Core", "Deleted signal source " << sID );
		return true;
	}
	VA_RETHROW;
}

std::string CVACoreImpl::RegisterSignalSource( IVAAudioSignalSource* pSignalSource, const std::string& sName )
{
	VA_NO_REENTRANCE;
	VA_CHECK_INITIALIZED;

	VA_TRY
	{
		std::string sID = m_pSignalSourceManager->RegisterSignalSource( pSignalSource, sName, false, false );
		assert( !sID.empty() );

		// Ereignis generieren, wenn Operation erfolgreich
		CVAEvent ev;
		ev.iEventType = CVAEvent::SIGNALSOURCE_REGISTERED;
		ev.pSender = this;
		ev.sObjectID = sID;
		m_pEventManager->BroadcastEvent( ev );

		return sID;
	}
	VA_RETHROW;
}

bool CVACoreImpl::UnregisterSignalSource( IVAAudioSignalSource* pSignalSource )
{
	VA_NO_REENTRANCE;
	VA_CHECK_INITIALIZED;

	VA_TRY
	{
		// ID der Quelle suchen
		std::string sID = m_pSignalSourceManager->GetSignalSourceID( pSignalSource );
		if( sID.empty() )
			VA_EXCEPT2( INVALID_ID, "Invalid signal source ID" );

		m_pSignalSourceManager->UnregisterSignalSource( sID );

		// Ereignis generieren, wenn Operation erfolgreich
		CVAEvent ev;
		ev.iEventType = CVAEvent::SIGNALSOURCE_UNREGISTERED;
		ev.pSender = this;
		ev.sObjectID = sID;
		m_pEventManager->BroadcastEvent( ev );
	}
	VA_RETHROW;

	return true;
}

CVASignalSourceInfo CVACoreImpl::GetSignalSourceInfo( const std::string& sSignalSourceID ) const
{
	VA_NO_REENTRANCE;
	VA_CHECK_INITIALIZED;

	VA_TRY
	{
		CVASignalSourceInfo ssi = m_pSignalSourceManager->GetSignalSourceInfo( sSignalSourceID );
		return ssi;
	}
	VA_RETHROW;
}

void CVACoreImpl::GetSignalSourceInfos( std::vector<CVASignalSourceInfo>& vssiDest ) const
{
	VA_NO_REENTRANCE;
	VA_CHECK_INITIALIZED;

	VA_TRY
	{
		m_pSignalSourceManager->GetSignalSourceInfos( vssiDest );
	}
	VA_RETHROW;
}

int CVACoreImpl::GetSignalSourceBufferPlaybackState( const std::string& sSignalSourceID ) const
{
	VA_NO_REENTRANCE;
	VA_CHECK_INITIALIZED;

	VA_TRY
	{
		IVAAudioSignalSource* pSource = m_pSignalSourceManager->RequestSignalSource( sSignalSourceID );
		CVAAudiofileSignalSource* pAudiofileSource = dynamic_cast< CVAAudiofileSignalSource* >( pSource );

		int iState = pAudiofileSource->GetPlaybackState();
		m_pSignalSourceManager->ReleaseSignalSource( pSource );
		return iState;
	} VA_RETHROW;
}

CVAStruct CVACoreImpl::GetSignalSourceParameters( const std::string& sSignalSourceID, const CVAStruct& oParams ) const
{
	VA_NO_REENTRANCE;
	VA_CHECK_INITIALIZED;

	VA_TRY
	{
		IVAAudioSignalSource* pSource = m_pSignalSourceManager->RequestSignalSource( sSignalSourceID );
		CVAStruct oRet = pSource->GetParameters( oParams );
		m_pSignalSourceManager->ReleaseSignalSource( pSource );
		return oRet;
	} VA_RETHROW;

}

int CVACoreImpl::AddSignalSourceSequencerSample( const std::string& sSignalSourceID, const CVAStruct& oArgs )
{
	VA_EXCEPT_NOT_IMPLEMENTED;
}

void CVACoreImpl::SetSignalSourceParameters( const std::string& sSignalSourceID, const CVAStruct& oParams )
{
	VA_NO_REENTRANCE;
	VA_CHECK_INITIALIZED;

	VA_TRY
	{
		IVAAudioSignalSource* pSource = m_pSignalSourceManager->RequestSignalSource( sSignalSourceID );
		pSource->SetParameters( oParams );

		CVAEvent ev;
		ev.iEventType = CVAEvent::SIGNALSOURCE_STATE_CHANGED;
		ev.pSender = this;
		ev.sObjectID = sSignalSourceID;
		m_pEventManager->BroadcastEvent( ev );

		m_pSignalSourceManager->ReleaseSignalSource( pSource );

		VA_VERBOSE( "Core", "Changed parameters of signal source " << sSignalSourceID );

	} VA_RETHROW;

}

void CVACoreImpl::SetSignalSourceBufferPlaybackAction( const std::string& sSignalSourceID, const int iPlaybackAction )
{
	VA_NO_REENTRANCE;
	VA_CHECK_INITIALIZED;

	VA_TRY
	{
		if( !GetSignalSourceBufferPlaybackActionValid( iPlaybackAction ) )
		VA_EXCEPT2( INVALID_PARAMETER, "Invalid playback action" );

		IVAAudioSignalSource* pSource = m_pSignalSourceManager->RequestSignalSource( sSignalSourceID );

		if( pSource->GetType() != IVAAudioSignalSource::VA_SS_AUDIOFILE )
		{
			m_pSignalSourceManager->ReleaseSignalSource( pSource );
			VA_EXCEPT2( INVALID_PARAMETER, "Cannot set playback action for this type of signal source" );
		}

		CVAAudiofileSignalSource* pAudiofileSource = dynamic_cast< CVAAudiofileSignalSource* >( pSource );
		pAudiofileSource->SetPlaybackAction( iPlaybackAction );

		CVAEvent ev;
		ev.iEventType = CVAEvent::SIGNALSOURCE_STATE_CHANGED;
		ev.pSender = this;
		ev.sObjectID = sSignalSourceID;
		m_pEventManager->BroadcastEvent( ev );

		m_pSignalSourceManager->ReleaseSignalSource( pSource );

		VA_INFO( "Core", "Set audio file signal source '" << sSignalSourceID << "'"
			<< " playstate action to " << IVAInterface::GetPlaybackActionStr( iPlaybackAction ) );

	} VA_RETHROW;
}

void CVACoreImpl::SetSignalSourceBufferPlaybackPosition( const std::string& sSignalSourceID, const double dPlaybackPosition )
{
	VA_NO_REENTRANCE;
	VA_CHECK_INITIALIZED;

	VA_TRY
	{
		// Parameter berprfen
		if( dPlaybackPosition < 0 )
		VA_EXCEPT2( INVALID_PARAMETER, "Invalid playback position" );

		// Quelle anfordern (prft auf gltige ID)
		IVAAudioSignalSource* pSource = m_pSignalSourceManager->RequestSignalSource( sSignalSourceID );

		// Playstate kann man nur bei Dateiquellen setzen
		if( pSource->GetType() != IVAAudioSignalSource::VA_SS_AUDIOFILE )
		{
			m_pSignalSourceManager->ReleaseSignalSource( pSource );
			VA_EXCEPT2( INVALID_PARAMETER, "Cannot set playstate for this type of signal source" );
		}

		/* TODO:
		// Sicherstellen das es eine Dateiquelle ist
		if (pSource->GetTypeMnemonic() != "af") {
		m_pSignalSourceMan->ReleaseSignalSource(pSource);
		VA_EXCEPT2(INVALID_PARAMETER, "Invalid auralization mode");
		}
		*/

		// Zustand setzen
		CVAAudiofileSignalSource* pAudiofileSource = dynamic_cast< CVAAudiofileSignalSource* >( pSource );
		try
		{
			pAudiofileSource->SetCursorSeconds( dPlaybackPosition );
		}
		catch( ... )
		{
			m_pSignalSourceManager->ReleaseSignalSource( pSource );
			throw;
		}

		m_pSignalSourceManager->ReleaseSignalSource( pSource );

		VA_INFO( "Core", "Set audiofile signal source " << sSignalSourceID << " playback position to " << dPlaybackPosition );

	} VA_RETHROW;
}

void CVACoreImpl::SetSignalSourceBufferLooping( const std::string& sSignalSourceID, const bool bLooping )
{
	VA_NO_REENTRANCE;
	VA_CHECK_INITIALIZED;

	VA_TRY
	{
		IVAAudioSignalSource* pSource = m_pSignalSourceManager->RequestSignalSource( sSignalSourceID );
		if( pSource->GetType() != IVAAudioSignalSource::VA_SS_AUDIOFILE )
		{
			m_pSignalSourceManager->ReleaseSignalSource( pSource );
			VA_EXCEPT2( INVALID_PARAMETER, "Cannot set looping mode for this type of signal source" );
		}

		CVAAudiofileSignalSource* pAudiofileSource = dynamic_cast< CVAAudiofileSignalSource* >( pSource );
		pAudiofileSource->SetIsLooping( bLooping );

		CVAEvent ev;
		ev.iEventType = CVAEvent::SIGNALSOURCE_STATE_CHANGED;
		ev.pSender = this;
		ev.sObjectID = sSignalSourceID;
		m_pEventManager->BroadcastEvent( ev );

		m_pSignalSourceManager->ReleaseSignalSource( pSource );

		VA_INFO( "Core", "Changed audiofile signal source '" << sSignalSourceID << "'"
			<< " playstate looping mode to " << ( bLooping ? "looping" : "not looping" ) );

	} VA_RETHROW;
}

bool CVACoreImpl::GetSignalSourceBufferLooping( const std::string& sSignalSourceID ) const
{
	VA_NO_REENTRANCE;
	VA_CHECK_INITIALIZED;

	VA_TRY
	{
		IVAAudioSignalSource* pSource = m_pSignalSourceManager->RequestSignalSource( sSignalSourceID );

		if( pSource->GetType() != IVAAudioSignalSource::VA_SS_AUDIOFILE )
		{
			m_pSignalSourceManager->ReleaseSignalSource( pSource );
			VA_EXCEPT2( INVALID_PARAMETER, "Cannot set looping mode for this type of signal source" );
		}

		CVAAudiofileSignalSource* pAudiofileSource = dynamic_cast< CVAAudiofileSignalSource* >( pSource );
		bool bLooping = pAudiofileSource->GetIsLooping();
		m_pSignalSourceManager->ReleaseSignalSource( pSource );

		return bLooping;

	} VA_RETHROW;
}

int CVACoreImpl::AddSignalSourceSequencerPlayback( const std::string& sSignalSourceID, const int iSoundID, const int iFlags, const double dTimecode )
{
	VA_NO_REENTRANCE;
	VA_CHECK_INITIALIZED;

	IVAAudioSignalSource* pSource = nullptr;

	VA_TRY
	{
		// Quelle anfordern (prft auf gltige ID)
		pSource = m_pSignalSourceManager->RequestSignalSource( sSignalSourceID );

		// Playbacks kann man nur bei Sequencer-Quellen modifizieren
		if( pSource->GetType() != IVAAudioSignalSource::VA_SS_SEQUENCER )
		{
			m_pSignalSourceManager->ReleaseSignalSource( pSource );
			VA_EXCEPT2( INVALID_PARAMETER, "Playbacks can only be added to sequencer signal sources" );
		}

		/* TODO:
		// Sicherstellen das es eine Sampler ist
		if (pSource->GetTypeMnemonic() != "af") {
		m_pSignalSourceMan->ReleaseSignalSource(pSource);
		VA_EXCEPT2(INVALID_PARAMETER, "Invalid auralization mode");
		}
		*/

		// Zustand setzen
		int iPlaybackID;
		try
		{
			CVASequencerSignalSource* pSamplerSource = dynamic_cast< CVASequencerSignalSource* >( pSource );
			iPlaybackID = pSamplerSource->AddSoundPlayback( iSoundID, iFlags, dTimecode );
		}
		catch( ... )
		{
			m_pSignalSourceManager->ReleaseSignalSource( pSource );
			throw;
		}

		// Signalquelle freigeben
		m_pSignalSourceManager->ReleaseSignalSource( pSource );

		VA_INFO( "Core", "Added sound playback (Signal source=" << sSignalSourceID << ", Sound=" << iSoundID << ", Flags=" << iFlags << ", Timecode=" << dTimecode << ")" );

		return iPlaybackID;

	}
		VA_FINALLY
	{
		// Signalquelle freigeben
		if( pSource ) m_pSignalSourceManager->ReleaseSignalSource( pSource );

		// VAExceptions unverndert nach aussen leiten
		throw;
	}
}

void CVACoreImpl::RemoveSignalSourceSequencerSample( const std::string& sSignalSourceID, const int iSoundID )
{
	VA_EXCEPT_NOT_IMPLEMENTED;
}


bool CVACoreImpl::GetUpdateLocked() const
{
	VA_CHECK_INITIALIZED;
	return ( m_lSyncModOwner != -1 );
}

void CVACoreImpl::LockUpdate()
{
	m_dSyncEntryTime = m_pClock->getTime();

	VA_CHECK_INITIALIZED;
	VA_LOCK_REENTRANCE;

	if( m_lSyncModOwner != -1 )
	{
		// Thread already owner, increment spin counter
		if( getCurrentThreadID() == m_lSyncModOwner )
		{
			++m_lSyncModSpinCount;
			VA_UNLOCK_REENTRANCE;
			VA_VERBOSE( "Core", "Attempt to enter synchronized scene modification ignored - already in a synchronized scene modification" );
			return;
		}
	}

	VA_UNLOCK_REENTRANCE;

	VA_TRACE( "Core", "Beginning synchronized scene modification" );
	/*
	 *  Blocking wait des aufrufenden Thread.
	 *  Wichtig: Dies muss ausserhalb des Reentrance-Lock geschehen,
	 *           da sonst kein anderer Thread mehr auf der Schnittstelle aufrufen kann.
	 */
	m_mxSyncModLock.Lock();

	VA_LOCK_REENTRANCE;

	m_lSyncModOwner = getCurrentThreadID();
	++m_lSyncModSpinCount;

	VA_TRY
	{
		m_pNewSceneState = m_pSceneManager->CreateDerivedSceneState( m_pSceneManager->GetHeadSceneStateID(), m_dSyncEntryTime );
		VA_UNLOCK_REENTRANCE;

	}
		VA_FINALLY
	{
		m_mxSyncModLock.Unlock();
		m_lSyncModOwner = -1;
		VA_UNLOCK_REENTRANCE;
		throw;
	}
}

int CVACoreImpl::UnlockUpdate()
{
	VA_CHECK_INITIALIZED;
	VA_LOCK_REENTRANCE;

	int iNewSceneID = -1;

	VA_TRACE( "Core", "Unlocking scene" );

	// Sicherheitscheck: Gar nicht innerhalb Synchronisation => Fehler
	if( m_lSyncModOwner == -1 )
	{
		VA_UNLOCK_REENTRANCE;
		VA_EXCEPT2( MODAL_ERROR, "Not within a synchronized modification phase" );
	}

	if( m_lSyncModOwner != getCurrentThreadID() )
	{
		VA_UNLOCK_REENTRANCE;
		VA_EXCEPT2( MODAL_ERROR, "Synchronized modification may only be ended by the same thread that begun it" );
	}

	if( --m_lSyncModSpinCount > 0 )
	{
		// Nicht die letzte Freigabe des Token.
		VA_UNLOCK_REENTRANCE;
		return -1;
	}

	VA_TRY
	{
		m_pNewSceneState->Fix();

		iNewSceneID = m_pNewSceneState->GetID();
		m_pSceneManager->SetHeadSceneState( iNewSceneID );

		m_iNewActiveSoundReceiver = m_iUpdActiveSoundReceiver;

		m_lSyncModOwner = -1;
		m_mxSyncModLock.Unlock();

		VA_UNLOCK_REENTRANCE;
	}
		VA_FINALLY
	{
		VA_UNLOCK_REENTRANCE;
		throw;
	}
		VA_TRY
	{
		m_pCoreThread->Trigger();
		m_pEventManager->BroadcastEvents();
		return iNewSceneID;
	}
	VA_RETHROW;
}

void CVACoreImpl::GetSoundSourceIDs( std::vector< int >& vSoundSourceIDs )
{
	VA_NO_REENTRANCE;
	VA_CHECK_INITIALIZED;

	VA_TRY
	{
		m_pSceneManager->GetHeadSceneState()->GetSoundSourceIDs( &vSoundSourceIDs );
	}
	VA_RETHROW;
}

CVASoundSourceInfo CVACoreImpl::GetSoundSourceInfo( const int iID ) const
{
	VA_NO_REENTRANCE;
	VA_CHECK_INITIALIZED;

	VA_TRY
	{
		const CVASoundSourceDesc* oDesc = m_pSceneManager->GetSoundSourceDesc( iID );
		CVASoundSourceInfo oInfo;
		oInfo.iID = oDesc->iID;
		oInfo.bMuted = oDesc->bMuted;
		oInfo.dSpoundPower = oDesc->fSoundPower;
		oInfo.sName = oDesc->sName;
		return oInfo;
	}
	VA_RETHROW;
}

int CVACoreImpl::CreateSoundSource( const std::string& sName )
{
	VA_NO_REENTRANCE;
	VA_CHECK_INITIALIZED;

	const bool bInSyncMode = GetUpdateLocked();
	if( !bInSyncMode )
		LockUpdate();

	VA_TRY
	{
		if( ( VACORE_MAX_NUM_SOUND_SOURCES != 0 ) && m_pNewSceneState )
		{
			int iSourcesRemain = VACORE_MAX_NUM_SOUND_SOURCES - m_pNewSceneState->GetNumSoundSources();
			if( iSourcesRemain <= 0 )
			{
				std::stringstream ss;
				ss << "Maximum number of sound sources reached. This version of VA only supports up to " << VACORE_MAX_NUM_SOUND_SOURCES << " sound sources.";
				VA_EXCEPT2( INVALID_PARAMETER, ss.str() );
			}
		}

		// Schallquelle anlegen
		int iSourceID = m_pNewSceneState->AddSoundSource();
		assert( iSourceID != -1 );
		// HINWEIS: Zunchst hier die statische Beschreibung der Quelle anlegen
		CVASoundSourceDesc* pDesc = m_pSceneManager->CreateSoundSourceDesc( iSourceID );

		// Keine Signalquelle zugewiesen. Wichtig: Stillepuffer einsetzen!
		pDesc->pSignalSourceInputBuf = m_pSignalSourceManager->GetSilenceBuffer();

		// Initiale Werte setzen
		m_pSceneManager->SetSoundSourceName( iSourceID, sName );
		CVASoundSourceState* pSourceState = m_pNewSceneState->AlterSoundSourceState( iSourceID );
		assert( pSourceState );

		// Ereignis generieren
		CVAEvent ev;
		ev.iEventType = CVAEvent::SOUND_SOURCE_CREATED;
		ev.pSender = this;
		ev.iObjectID = iSourceID;
		ev.sName = sName;

		m_pEventManager->EnqueueEvent( ev );

		if( !bInSyncMode )
			UnlockUpdate();

		VA_INFO( "Core", "Created sound source '" << sName << "' and assigned ID " << iSourceID );

		return iSourceID;
	}
		VA_FINALLY
	{
		if( bInSyncMode )
		UnlockUpdate();

		throw;
	}
}

int CVACoreImpl::CreateSoundSourceExplicitRenderer( const std::string& sRendererID, const std::string& sName )
{
	VA_NO_REENTRANCE;
	VA_CHECK_INITIALIZED;

	bool bSync = GetUpdateLocked();
	if( !bSync )
		LockUpdate();

	VA_TRY
	{
		if( ( VACORE_MAX_NUM_SOUND_SOURCES != 0 ) && m_pNewSceneState )
		{
			int iSourcesRemain = VACORE_MAX_NUM_SOUND_SOURCES - m_pNewSceneState->GetNumSoundSources();
			if( iSourcesRemain <= 0 )
			{
				std::stringstream ss;
				ss << "Maximum number of sound sources reached. This version of VA only supports up to " << VACORE_MAX_NUM_SOUND_SOURCES << " sound sources.";
				VA_EXCEPT2( INVALID_PARAMETER, ss.str() );
			}
		}

		int iSourceID = m_pNewSceneState->AddSoundSource();
		assert( iSourceID != -1 );

		CVASoundSourceDesc* pDesc = m_pSceneManager->CreateSoundSourceDesc( iSourceID );
		pDesc->sExplicitRendererID = sRendererID;
		pDesc->pSignalSourceInputBuf = m_pSignalSourceManager->GetSilenceBuffer();

		m_pSceneManager->SetSoundSourceName( iSourceID, sName );
		CVASoundSourceState* pSourceState = m_pNewSceneState->AlterSoundSourceState( iSourceID );
		assert( pSourceState );

		CVAEvent ev;
		ev.iEventType = CVAEvent::SOUND_SOURCE_CREATED;
		ev.pSender = this;
		ev.iObjectID = iSourceID;
		ev.sName = sName;
		ev.iAuralizationMode = VA_AURAMODE_ALL;
		ev.dVolume = 1.0f;
		m_pEventManager->EnqueueEvent( ev );

		if( !bSync )
			UnlockUpdate();

		VA_INFO( "Core", "Created sound receiver '" << sName << "' and assigned ID " << iSourceID << " explicitly for renderer '" << sRendererID << "' only" );

		return iSourceID;
	}
		VA_FINALLY
	{
		if( bSync )
		UnlockUpdate();
		throw;
	}
}

int CVACoreImpl::DeleteSoundSource( const  int iSoundSourceID )
{
	VA_NO_REENTRANCE;
	VA_CHECK_INITIALIZED;

	bool bSync = GetUpdateLocked();
	if( !bSync )
		LockUpdate();

	VA_TRY
	{
		m_pNewSceneState->RemoveSoundSource( iSoundSourceID );

		// Ereignis generieren, wenn erfolgreich
		CVAEvent ev;
		ev.iEventType = CVAEvent::SOUND_SOURCE_DELETED;
		ev.pSender = this;
		ev.iObjectID = iSoundSourceID;
		m_pEventManager->EnqueueEvent( ev );

		if( !bSync )
			UnlockUpdate();

		VA_INFO( "Core", "Deleted sound source " << iSoundSourceID );

		return 0;
	}
		VA_FINALLY
	{
		if( !bSync )
		UnlockUpdate();
		throw;
	}
}

void CVACoreImpl::SetSoundSourceEnabled( const int iSoundSourceID, const bool bEnabled )
{
	VA_NO_REENTRANCE;
	VA_CHECK_INITIALIZED;

	VA_TRY
	{
		CVASoundSourceDesc* pDesc = m_pSceneManager->GetSoundSourceDesc( iSoundSourceID );

		if( pDesc->bEnabled != bEnabled )
		{
			pDesc->bEnabled = bEnabled;

			CVAEvent ev;
			ev.iEventType = CVAEvent::SOUND_SOURCE_CHANGED_MUTING; // @todo JST new event type
			ev.pSender = this;
			ev.iObjectID = iSoundSourceID;
			//ev.bEnabled = bEnabled; // @todo JST
			m_pEventManager->EnqueueEvent( ev );

			// Trigger core thread
			m_pCoreThread->Trigger();
		}
	}
	VA_RETHROW;
}

bool CVACoreImpl::GetSoundSourceEnabled( const int iSoundSourceID ) const
{
	VA_NO_REENTRANCE;
	VA_CHECK_INITIALIZED;

	VA_TRY
	{
		const CVASoundSourceDesc* pDesc = m_pSceneManager->GetSoundSourceDesc( iSoundSourceID );
		return pDesc->bEnabled;
	}
	VA_RETHROW;
}

std::string CVACoreImpl::GetSoundSourceName( const int iSoundSourceID ) const
{
	VA_NO_REENTRANCE;
	VA_CHECK_INITIALIZED;

	VA_TRY
	{
		return m_pSceneManager->GetSoundSourceName( iSoundSourceID );
	}
	VA_RETHROW;
}

void CVACoreImpl::SetSoundSourceName( const int iSoundSourceID, const std::string& sName )
{
	VA_NO_REENTRANCE;
	VA_CHECK_INITIALIZED;

	VA_TRY
	{
		m_pSceneManager->SetSoundSourceName( iSoundSourceID, sName );

		// Ereignis generieren, falls erfolgreich
		CVAEvent ev;
		ev.iEventType = CVAEvent::SOUND_SOURCE_CHANGED_NAME;
		ev.pSender = this;
		ev.iObjectID = iSoundSourceID;
		ev.sName = sName;
		m_pEventManager->BroadcastEvent( ev );
	}
	VA_RETHROW;
}

std::string CVACoreImpl::GetSoundSourceSignalSource( int iSoundSourceID ) const
{
	VA_NO_REENTRANCE;
	VA_CHECK_INITIALIZED;

	VA_TRY
	{
		CVASoundSourceDesc* pDesc = m_pSceneManager->GetSoundSourceDesc( iSoundSourceID );
		if( pDesc->pSignalSource.get() != nullptr )
			return m_pSignalSourceManager->GetSignalSourceID( pDesc->pSignalSource );
		else
			return "";
	}
	VA_RETHROW;
}

int CVACoreImpl::GetSoundSourceGeometryMesh( const int iID ) const
{
	VA_EXCEPT_NOT_IMPLEMENTED_FUTURE_VERSION;
}

void CVACoreImpl::SetSoundSourceGeometryMesh( const int iSoundSourceID, const int iGeometryMeshID )
{
	VA_EXCEPT_NOT_IMPLEMENTED_FUTURE_VERSION;
}

void CVACoreImpl::SetSoundSourceSignalSource( int iSoundSourceID, const std::string& sSignalSourceID )
{
	VA_NO_REENTRANCE;
	VA_CHECK_INITIALIZED;

	// Keine Signalquelle zugewiesen. Wichtig: Stillepuffer einsetzen!
	IVAAudioSignalSource* pNewSrc( nullptr ); // Neu oder zustzlich ...
	const ITASampleBuffer* pNewBuf( m_pSignalSourceManager->GetSilenceBuffer() );

	VA_TRY
	{
		CVASoundSourceDesc* pDesc = m_pSceneManager->GetSoundSourceDesc( iSoundSourceID );

		// Sicherstellen, das die Signalquellen ID gltig ist .. dann ID und Qu
		if( !sSignalSourceID.empty() )
			pNewSrc = m_pSignalSourceManager->RequestSignalSource( sSignalSourceID, &pNewBuf );

		// Vorherige Bindung auflsen und Signalquelle freigeben
		if( pDesc->pSignalSource.get() != nullptr )
			m_pSignalSourceManager->ReleaseSignalSource( pDesc->pSignalSource );

		// Vorhandene Signalquelle zu dieser SoundSource zuordnen (atomare Ops)
		pDesc->pSignalSource.set( pNewSrc );
		pDesc->pSignalSourceInputBuf.set( pNewBuf );

		// Ereignis generieren
		CVAEvent ev;
		ev.iEventType = CVAEvent::SOUND_SOURCE_CHANGED_SIGNALSOURCE;
		ev.pSender = this;
		ev.iObjectID = iSoundSourceID;
		ev.sParam = sSignalSourceID;
		m_pEventManager->EnqueueEvent( ev );

		if( pNewSrc == nullptr )
		{
			VA_INFO( "Core", "Removed signal source from sound source " << iSoundSourceID << " (now uses silence buffer samples)" );
		}
		else
		{
			VA_INFO( "Core", "Set sound source " << iSoundSourceID << " signal source '" << sSignalSourceID << "'" );
		}

		return;
	}
		VA_CATCH( ex )
	{
		// Referenz auf die neue Signalquelle wieder entfernen
		if( pNewSrc )
			m_pSignalSourceManager->ReleaseSignalSource( pNewSrc );
		throw ex;
	}
}

int CVACoreImpl::GetSoundSourceAuralizationMode( int iSoundSourceID ) const
{
	VA_NO_REENTRANCE;
	VA_CHECK_INITIALIZED;

	VA_TRY
	{
		CVASceneState* pHeadState = m_pSceneManager->GetHeadSceneState();
		const CVASoundSourceState* pSourceState = pHeadState->GetSoundSourceState( iSoundSourceID );

		if( !pSourceState )
			VA_EXCEPT2( INVALID_PARAMETER, "Invalid sound source ID" );

		return pSourceState->GetAuralizationMode();
	}
	VA_RETHROW;
}

void CVACoreImpl::SetSoundSourceAuralizationMode( int iSoundSourceID, int iAuralizationMode )
{
	VA_NO_REENTRANCE;
	VA_CHECK_INITIALIZED;

	VA_TRY
	{
		// Parameter berprfen
		if( !GetAuralizationModeValid( iAuralizationMode ) )
		VA_EXCEPT2( INVALID_PARAMETER, "Invalid auralization mode" );

		bool bSync = GetUpdateLocked();
		if( !bSync ) LockUpdate();

		CVASoundSourceState* pSourceState = m_pNewSceneState->AlterSoundSourceState( iSoundSourceID );

		if( !pSourceState )
		{
			// Quelle existiert nicht
			if( !bSync )
				UnlockUpdate();
			VA_EXCEPT2( INVALID_PARAMETER, "Invalid sound source ID" );
		}

		pSourceState->SetAuralizationMode( iAuralizationMode );

		// Ereignis generieren, falls erfolgreich
		CVAEvent ev;
		ev.iEventType = CVAEvent::SOUND_SOURCE_CHANGED_AURALIZATIONMODE;
		ev.pSender = this;
		ev.iObjectID = iSoundSourceID;
		ev.iAuralizationMode = iAuralizationMode;
		m_pEventManager->EnqueueEvent( ev );

		if( !bSync )
			UnlockUpdate();

	}
	VA_RETHROW;
}

void CVACoreImpl::SetSoundSourceParameters( int iID, const CVAStruct& oParams )
{
	VA_NO_REENTRANCE;
	VA_CHECK_INITIALIZED;

	VA_TRY
	{

		bool bSync = GetUpdateLocked();
		if( !bSync )
			LockUpdate();
		CVASoundSourceState* pSoundSourceState = m_pNewSceneState->AlterSoundSourceState( iID );

		if( !pSoundSourceState )
		{
			if( !bSync )
				UnlockUpdate();

			VA_EXCEPT2( INVALID_PARAMETER, "Invalid sound receiver ID" );
		}

		pSoundSourceState->SetParameters( oParams );

		CVAEvent ev;
		ev.iEventType = CVAEvent::SOUND_SOURCE_CHANGED_NAME; // @todo create own core event "parameter changed"
		ev.pSender = this;
		ev.iObjectID = iID;
		// ev.oStruct @todo: add a struct to the event
		m_pEventManager->EnqueueEvent( ev );

		if( !bSync )
			UnlockUpdate();
	}
	VA_RETHROW;
}

CVAStruct CVACoreImpl::GetSoundSourceParameters( int iID, const CVAStruct& oArgs ) const
{
	VA_NO_REENTRANCE;
	VA_CHECK_INITIALIZED;

	VA_TRY
	{
		CVASceneState* pHeadState = m_pSceneManager->GetHeadSceneState();
		const CVASoundSourceState* pSoundSourceState = pHeadState->GetSoundSourceState( iID );

		if( !pSoundSourceState )
			VA_EXCEPT2( INVALID_PARAMETER, "Invalid sound receiver ID" );

		return pSoundSourceState->GetParameters( oArgs );

	}
	VA_RETHROW;
}

int CVACoreImpl::GetSoundSourceDirectivity( int iSoundSourceID ) const {
	VA_NO_REENTRANCE;
	VA_CHECK_INITIALIZED;

	VA_TRY{
		CVASceneState* pHeadState = m_pSceneManager->GetHeadSceneState();
		const CVASoundSourceState* pSourceState = pHeadState->GetSoundSourceState( iSoundSourceID );

		if( !pSourceState )
			// Quelle existiert nicht
			VA_EXCEPT2( INVALID_PARAMETER, "Invalid sound source ID" );

		return pSourceState->GetDirectivityID();
	} VA_RETHROW;
}

void CVACoreImpl::SetSoundSourceDirectivity( const int iSoundSourceID, const int iDirectivityID )
{
	VA_NO_REENTRANCE;
	VA_CHECK_INITIALIZED;

	VA_TRY
	{
		bool bSync = GetUpdateLocked();
		if( !bSync )
			LockUpdate();

		CVASoundSourceState* pSourceState = m_pNewSceneState->AlterSoundSourceState( iSoundSourceID );

		if( !pSourceState )
		{
			if( !bSync )
				UnlockUpdate();
			VA_EXCEPT2( INVALID_PARAMETER, "Invalid sound source ID" );
		}

		const IVADirectivity* pNewDirectivity = nullptr;
		if( iDirectivityID != -1 )
		{
			pNewDirectivity = m_pDirectivityManager->RequestDirectivity( iDirectivityID );
			if( !pNewDirectivity )
			{
				VA_EXCEPT2( INVALID_PARAMETER, "Invalid directivity ID" );
				// TODO: Release des vernderten State?
			}
		}

		pSourceState->SetDirectivityID( iDirectivityID );
		pSourceState->SetDirectivityData( pNewDirectivity );

		// Ereignis generieren, falls erfolgreich
		CVAEvent ev;
		ev.iEventType = CVAEvent::SOUND_SOURCE_CHANGED_DIRECTIVITY;
		ev.pSender = this;
		ev.iObjectID = iSoundSourceID;
		ev.iParamID = iDirectivityID;
		m_pEventManager->EnqueueEvent( ev );

		if( !bSync ) UnlockUpdate();

	} VA_RETHROW;
}

double CVACoreImpl::GetSoundSourceSoundPower( const int iSoundSourceID ) const
{
	VA_NO_REENTRANCE;
	VA_CHECK_INITIALIZED;

	VA_TRY
	{
		CVASceneState* pHeadState = m_pSceneManager->GetHeadSceneState();
		const CVASoundSourceState* pSourceState = pHeadState->GetSoundSourceState( iSoundSourceID );

		if( !pSourceState )
			VA_EXCEPT2( INVALID_PARAMETER, "Invalid sound source ID" );

		return pSourceState->GetSoundPower();
	}
	VA_RETHROW;
}

void CVACoreImpl::SetSoundSourceSoundPower( const int iSoundSourceID, const double dSoundPower )
{
	VA_NO_REENTRANCE;
	VA_CHECK_INITIALIZED;

	VA_TRY
	{
		// Parameter berprfen
		if( !GetVolumeValid( dSoundPower ) )
		{
			VA_EXCEPT2( INVALID_PARAMETER, "Invalid volume" );
		}

		bool bSync = GetUpdateLocked();
		if( !bSync )
			LockUpdate();

		CVASoundSourceState* pSourceState = m_pNewSceneState->AlterSoundSourceState( iSoundSourceID );

		if( !pSourceState )
		{
			// Quelle existiert nicht
			if( !bSync )
				UnlockUpdate();
			VA_EXCEPT2( INVALID_PARAMETER, "Invalid sound source ID" );
		}

		pSourceState->SetSoundPower( dSoundPower );

		// Ereignis generieren, falls erfolgreich
		CVAEvent ev;
		ev.iEventType = CVAEvent::SOUND_SOURCE_CHANGED_SOUND_POWER;
		ev.pSender = this;
		ev.iObjectID = iSoundSourceID;
		ev.dVolume = dSoundPower;
		m_pEventManager->EnqueueEvent( ev );

		if( !bSync ) UnlockUpdate();

	} VA_RETHROW;
}

bool CVACoreImpl::GetSoundSourceMuted( const int iSoundSourceID ) const
{
	VA_NO_REENTRANCE;
	VA_CHECK_INITIALIZED;

	VA_TRY
	{
		const CVASoundSourceDesc* pDesc = m_pSceneManager->GetSoundSourceDesc( iSoundSourceID );
		return pDesc->bMuted;
	}
	VA_RETHROW;
}

void CVACoreImpl::SetSoundSourceMuted( const int iSoundSourceID, const bool bMuted )
{
	VA_NO_REENTRANCE;
	VA_CHECK_INITIALIZED;

	VA_TRY
	{
		CVASoundSourceDesc* pDesc = m_pSceneManager->GetSoundSourceDesc( iSoundSourceID );

		if( pDesc->bMuted != bMuted )
		{
			pDesc->bMuted = bMuted;

			CVAEvent ev;
			ev.iEventType = CVAEvent::SOUND_SOURCE_CHANGED_MUTING;
			ev.pSender = this;
			ev.iObjectID = iSoundSourceID;
			ev.bMuted = bMuted;
			m_pEventManager->EnqueueEvent( ev );

			// Trigger core thread
			m_pCoreThread->Trigger();
		}
	} VA_RETHROW;
}


void CVACoreImpl::GetSoundSourcePose( const int iSoundSourceID, VAVec3& v3Pos, VAQuat& qOrient ) const
{
	VA_NO_REENTRANCE;
	VA_CHECK_INITIALIZED;

	VA_TRY
	{
		const CVASceneState* pHeadState = m_pSceneManager->GetHeadSceneState();
		const CVASoundSourceState* pSourceState = pHeadState->GetSoundSourceState( iSoundSourceID );

		if( !pSourceState )
			VA_EXCEPT2( INVALID_PARAMETER, "Invalid sound source ID" );

		const CVAMotionState* pMotionState = pSourceState->GetMotionState();
		if( !pMotionState )
			VA_EXCEPT2( INVALID_PARAMETER, "Sound source has invalid motion state, probably it has not been positioned, yet?" );

		v3Pos = pMotionState->GetPosition();
		qOrient = pMotionState->GetOrientation();
	}
	VA_RETHROW;
}

void CVACoreImpl::SetSoundSourcePose( const int iID, const VAVec3& v3Pos, const VAQuat& qOrient )
{
	VA_NO_REENTRANCE;
	VA_CHECK_INITIALIZED;

	VA_TRY
	{
		bool bSync = GetUpdateLocked();
		if( !bSync )
			LockUpdate();

		CVASoundSourceState* pSourceState = m_pNewSceneState->AlterSoundSourceState( iID );

		if( !pSourceState )
		{
			// Quelle existiert nicht
			if( !bSync )
				UnlockUpdate();
			VA_EXCEPT2( INVALID_PARAMETER, "Invalid sound source ID" );
		}

		CVAMotionState* pNewMotionState = pSourceState->AlterMotionState();
		pNewMotionState->SetPosition( v3Pos );
		pNewMotionState->SetOrientation( qOrient );

		m_pSceneManager->GetSoundSourceDesc( iID )->bInitPositionOrientation = true;

		// Ereignis generieren, falls erfolgreich
		CVAEvent ev;
		ev.iEventType = CVAEvent::SOUND_SOURCE_CHANGED_POSE;
		ev.pSender = this;
		ev.iObjectID = iID;
		ev.vPos = v3Pos;
		SetCoreEventParams( ev, pNewMotionState );

		m_pEventManager->EnqueueEvent( ev );

		if( !bSync )
			UnlockUpdate();

	}
	VA_RETHROW;
}

VAVec3 CVACoreImpl::GetSoundSourcePosition( const int iID ) const
{
	VA_NO_REENTRANCE;
	VA_CHECK_INITIALIZED;

	VA_TRY
	{
		const CVASceneState* pHeadState = m_pSceneManager->GetHeadSceneState();
		const CVASoundSourceState* pSourceState = pHeadState->GetSoundSourceState( iID );

		if( !pSourceState )
			VA_EXCEPT2( INVALID_PARAMETER, "Invalid sound source ID" );

		const CVAMotionState* pMotionState = pSourceState->GetMotionState();
		if( !pMotionState )
			VA_EXCEPT2( INVALID_PARAMETER, "Sound source has invalid motion state, probably it has not been positioned, yet?" );

		return pMotionState->GetPosition();
	}
	VA_RETHROW;
}

void CVACoreImpl::SetSoundSourcePosition( const int iID, const VAVec3& v3Pos )
{
	VA_NO_REENTRANCE;
	VA_CHECK_INITIALIZED;

	VA_TRY
	{
		bool bSync = GetUpdateLocked();
		if( !bSync )
			LockUpdate();

		CVASoundSourceState* pSourceState = m_pNewSceneState->AlterSoundSourceState( iID );

		if( !pSourceState )
		{
			// Quelle existiert nicht
			if( !bSync )
				UnlockUpdate();
			VA_EXCEPT2( INVALID_PARAMETER, "Invalid sound source ID" );
		}

		CVAMotionState* pNewMotionState = pSourceState->AlterMotionState();
		pNewMotionState->SetPosition( v3Pos );

		m_pSceneManager->GetSoundSourceDesc( iID )->bInitPositionOrientation = true;

		// Ereignis generieren, falls erfolgreich
		CVAEvent ev;
		ev.iEventType = CVAEvent::SOUND_SOURCE_CHANGED_POSE;
		ev.pSender = this;
		ev.iObjectID = iID;
		ev.vPos = v3Pos;
		SetCoreEventParams( ev, pNewMotionState );

		m_pEventManager->EnqueueEvent( ev );

		if( !bSync )
			UnlockUpdate();

	} VA_RETHROW;
}

VAQuat CVACoreImpl::GetSoundSourceOrientation( const int iID ) const
{
	VA_NO_REENTRANCE;
	VA_CHECK_INITIALIZED;

	VA_TRY
	{
		const CVASceneState* pHeadState = m_pSceneManager->GetHeadSceneState();
		const CVASoundSourceState* pSourceState = pHeadState->GetSoundSourceState( iID );

		if( !pSourceState )
			VA_EXCEPT2( INVALID_PARAMETER, "Invalid sound source ID" );

		const CVAMotionState* pMotionState = pSourceState->GetMotionState();
		if( !pMotionState )
			VA_EXCEPT2( INVALID_PARAMETER, "Sound source has invalid motion state, probably it has not been positioned, yet?" );

		return pMotionState->GetOrientation();
	}
	VA_RETHROW;
}

void CVACoreImpl::SetSoundSourceOrientation( const int iID, const VAQuat& qOrient )
{
	VA_NO_REENTRANCE;
	VA_CHECK_INITIALIZED;

	VA_TRY
	{
		bool bSync = GetUpdateLocked();
		if( !bSync )
			LockUpdate();

		CVASoundSourceState* pSourceState = m_pNewSceneState->AlterSoundSourceState( iID );

		if( !pSourceState )
		{
			// Quelle existiert nicht
			if( !bSync )
				UnlockUpdate();
			VA_EXCEPT2( INVALID_PARAMETER, "Invalid sound source ID" );
		}

		CVAMotionState* pNewMotionState = pSourceState->AlterMotionState();
		pNewMotionState->SetOrientation( qOrient );

		m_pSceneManager->GetSoundSourceDesc( iID )->bInitPositionOrientation = true;

		// Ereignis generieren
		CVAEvent ev;
		ev.iEventType = CVAEvent::SOUND_SOURCE_CHANGED_POSE;
		ev.pSender = this;
		ev.iObjectID = iID;
		//ev.qOrient = qOrient; // @todo
		ConvertQuaternionToViewUp( qOrient, ev.vView, ev.vUp );
		SetCoreEventParams( ev, pNewMotionState );

		m_pEventManager->EnqueueEvent( ev );

		if( !bSync )
			UnlockUpdate();
	}
	VA_RETHROW;
}

void CVACoreImpl::GetSoundSourceOrientationVU( const int iID, VAVec3& v3View, VAVec3& v3Up ) const
{
	ConvertQuaternionToViewUp( GetSoundSourceOrientation( iID ), v3View, v3Up );
}

void CVACoreImpl::SetSoundSourceOrientationVU( const int iSoundSourceID, const VAVec3& v3View, const VAVec3& v3Up )
{
	VA_NO_REENTRANCE;
	VA_CHECK_INITIALIZED;

	VA_TRY
	{
		bool bSync = GetUpdateLocked();
		if( !bSync )
			LockUpdate();

		CVASoundSourceState* pSourceState = m_pNewSceneState->AlterSoundSourceState( iSoundSourceID );

		if( !pSourceState )
		{
			// Quelle existiert nicht
			if( !bSync )
				UnlockUpdate();
			VA_EXCEPT2( INVALID_PARAMETER, "Invalid sound source ID" );
		}

		CVAMotionState* pNewMotionState = pSourceState->AlterMotionState();
		pNewMotionState->SetOrientationVU( v3View, v3Up );

		m_pSceneManager->GetSoundSourceDesc( iSoundSourceID )->bInitPositionOrientation = true;

		// Ereignis generieren
		CVAEvent ev;
		ev.iEventType = CVAEvent::SOUND_SOURCE_CHANGED_POSE;
		ev.pSender = this;
		ev.iObjectID = iSoundSourceID;
		ev.vView = v3View;
		ev.vUp = v3Up;
		SetCoreEventParams( ev, pNewMotionState );

		m_pEventManager->EnqueueEvent( ev );

		if( !bSync )
			UnlockUpdate();
	}
	VA_RETHROW;
}

void CVACoreImpl::GetSoundReceiverIDs( std::vector< int >& vSoundReceiverIDs ) const
{
	VA_NO_REENTRANCE;
	VA_CHECK_INITIALIZED;

	VA_TRY
	{
		m_pSceneManager->GetHeadSceneState()->GetListenerIDs( &vSoundReceiverIDs );
	}
	VA_RETHROW;
}

int CVACoreImpl::CreateSoundReceiver( const std::string& sName )
{
	VA_NO_REENTRANCE;
	VA_CHECK_INITIALIZED;

	VA_TRY
	{
		if( ( VACORE_MAX_NUM_SOUND_RECEIVERS != 0 ) && m_pNewSceneState )
		{
			const int iListenersRemain = VACORE_MAX_NUM_SOUND_RECEIVERS - m_pNewSceneState->GetNumListeners();
			if( iListenersRemain <= 0 )
			{
				std::stringstream ss;
				ss << "Maximum number of listeners reached. This version of VA only supports up to " << VACORE_MAX_NUM_SOUND_RECEIVERS << " listeners.";
				VA_EXCEPT2( INVALID_PARAMETER, ss.str() );
			}
		}

		const bool bSync = GetUpdateLocked();
		if( !bSync )
			LockUpdate();

		// Hrer anlegen
		const int iID = m_pNewSceneState->AddListener();
		assert( iID != -1 );

		// HINWEIS: Zunchst hier die statische Beschreibung der Quelle anlegen
		m_pSceneManager->CreateListenerDesc( iID );

		// Initiale Werte setzen
		m_pSceneManager->SetListenerName( iID, sName );
		CVAReceiverState* pListenerState = m_pNewSceneState->AlterListenerState( iID );
		assert( pListenerState );

		// INFO: Set the default position/orientation of the new listener
		CVAMotionState* pMotionState = pListenerState->AlterMotionState();
		pMotionState->SetPosition( VAVec3( 0, 0, 0 ) ); // Really?

		// Ereignis generieren
		CVAEvent ev;
		ev.iEventType = CVAEvent::SOUND_RECEIVER_CREATED;
		ev.pSender = this;
		ev.iObjectID = iID;
		ev.sName = sName;
		SetCoreEventParams( ev, pMotionState );

		m_pEventManager->EnqueueEvent( ev );

		if( !bSync )
			UnlockUpdate();

		VA_INFO( "Core", "Created sound receiver '" << sName << "' and assigned ID " << iID );

		return iID;

	} VA_RETHROW;
}

int CVACoreImpl::DeleteSoundReceiver( const int iID )
{
	VA_NO_REENTRANCE;
	VA_CHECK_INITIALIZED;

	bool bSync = GetUpdateLocked();
	if( !bSync )
		LockUpdate();

	VA_TRY
	{
		if( iID == m_iCurActiveSoundReceiver )
		{
			UnlockUpdate();
			VA_EXCEPT2( INVALID_PARAMETER, "Cannot delete a sound receiver that is set as active sound receiver" );
		}

		m_pNewSceneState->RemoveListener( iID );
		// Ereignis generieren, falls erfolgreich
		CVAEvent ev;
		ev.iEventType = CVAEvent::SOUND_RECEIVER_DELETED;
		ev.pSender = this;
		ev.iObjectID = iID;
		m_pEventManager->EnqueueEvent( ev );

		if( !bSync )
			UnlockUpdate();

		VA_INFO( "Core", "Deleted sound receiver " << iID );

		return 0;
	}
	VA_RETHROW;
}

CVASoundReceiverInfo CVACoreImpl::GetSoundReceiverInfo( const int iID ) const
{
	VA_NO_REENTRANCE;
	VA_CHECK_INITIALIZED;

	VA_TRY
	{
		const CVAListenerDesc* oDesc = m_pSceneManager->GetListenerDesc( iID );
		CVASoundReceiverInfo oInfo;
		oInfo.iID = oDesc->iID;
		oInfo.sName = oDesc->sName;
		return oInfo;
		// @todo improve
	}
	VA_RETHROW;
}

int CVACoreImpl::CreateSoundReceiverExplicitRenderer( const std::string& sRendererID, const std::string& sName )
{
	VA_NO_REENTRANCE;
	VA_CHECK_INITIALIZED;

	bool bSync = GetUpdateLocked();
	if( !bSync )
		LockUpdate();

	VA_TRY
	{
		if( ( VACORE_MAX_NUM_SOUND_RECEIVERS != 0 ) && m_pNewSceneState )
		{
			int iListenersRemain = VACORE_MAX_NUM_SOUND_RECEIVERS - m_pNewSceneState->GetNumListeners();
			if( iListenersRemain <= 0 )
			{
				std::stringstream ss;
				ss << "Maximum number of listeners reached. This version of VA only supports up to " << VACORE_MAX_NUM_SOUND_RECEIVERS << " listeners.";
				VA_EXCEPT2( INVALID_PARAMETER, ss.str() );
			}
		}

		int iListenerID = m_pNewSceneState->AddListener();
		assert( iListenerID != -1 );

		CVAListenerDesc* pDesc = m_pSceneManager->CreateListenerDesc( iListenerID );
		pDesc->sExplicitRendererID = sRendererID;

		m_pSceneManager->SetListenerName( iListenerID, sName );
		CVAReceiverState* pListenerState = m_pNewSceneState->AlterListenerState( iListenerID );
		assert( pListenerState );

		CVAEvent ev;
		ev.iEventType = CVAEvent::SOUND_RECEIVER_CREATED;
		ev.pSender = this;
		ev.iObjectID = iListenerID;
		ev.sName = sName;
		ev.iAuralizationMode = VA_AURAMODE_ALL;
		ev.dVolume = 1.0f;
		m_pEventManager->EnqueueEvent( ev );

		if( !bSync )
			UnlockUpdate();

		VA_INFO( "Core", "Created sound receiver (ID=" << iListenerID << ", Name=\"" << sName << "\") explicitly for renderer '" << sRendererID << "' only" );

		return iListenerID;
	}
		VA_FINALLY
	{
		if( bSync )
		UnlockUpdate();
		throw;
	}
}

void CVACoreImpl::SetSoundReceiverEnabled( const int iID, const bool bEnabled )
{
	VA_NO_REENTRANCE;
	VA_CHECK_INITIALIZED;

	VA_TRY
	{
		CVAListenerDesc* pDesc = m_pSceneManager->GetListenerDesc( iID );

		if( pDesc->bEnabled != bEnabled )
		{
			pDesc->bEnabled = bEnabled;

			CVAEvent ev;
			ev.iEventType = CVAEvent::SOUND_RECEIVER_CHANGED_NAME; // @todo JST new event type
			ev.pSender = this;
			ev.iObjectID = iID;
			//ev.bEnabled = bEnabled; // @todo JST
			m_pEventManager->EnqueueEvent( ev );

			// Trigger core thread
			m_pCoreThread->Trigger();
		}
	} VA_RETHROW;
}

bool CVACoreImpl::GetSoundReceiverEnabled( const int iSoundReceiverID ) const
{
	VA_NO_REENTRANCE;
	VA_CHECK_INITIALIZED;

	VA_TRY
	{
		const CVAListenerDesc* pDesc = m_pSceneManager->GetListenerDesc( iSoundReceiverID );
		return pDesc->bEnabled;
	}
	VA_RETHROW;
}

void CVACoreImpl::SetActiveSoundReceiverExplicitRenderer( const int iID, const std::string& sRendererID )
{
	// @todo JST call renderer and set active listener
	VA_EXCEPT2( NOT_IMPLEMENTED, "This method is currently not available (not implented)." );
}

int CVACoreImpl::GetActiveSoundReceiverExplicitRenderer( const std::string& sRendererID ) const
{
	// @todo JST call renderer and return active listener
	VA_EXCEPT2( NOT_IMPLEMENTED, "This method is currently not available (not implented)." );
}

std::string CVACoreImpl::GetSoundReceiverName( const int iID ) const
{
	VA_NO_REENTRANCE;
	VA_CHECK_INITIALIZED;

	VA_TRY
	{
		return m_pSceneManager->GetListenerName( iID );
	}
	VA_RETHROW;
}

void CVACoreImpl::SetSoundReceiverName( const int iID, const std::string& sName )
{
	VA_NO_REENTRANCE;
	VA_CHECK_INITIALIZED;

	VA_TRY
	{
		m_pSceneManager->SetListenerName( iID, sName );

		// Ereignis generieren, falls erfolgreich
		CVAEvent ev;
		ev.iEventType = CVAEvent::SOUND_RECEIVER_CHANGED_NAME;
		ev.pSender = this;
		ev.iObjectID = iID;
		ev.sName = sName;
		m_pEventManager->BroadcastEvent( ev );

	} VA_RETHROW;
}

int CVACoreImpl::GetSoundReceiverAuralizationMode( const int iID ) const
{
	VA_NO_REENTRANCE;
	VA_CHECK_INITIALIZED;

	VA_TRY{
		CVASceneState* pHeadState = m_pSceneManager->GetHeadSceneState();
		const CVAReceiverState* pListenerState = pHeadState->GetReceiverState( iID );

		if( !pListenerState )
			// Hrer existiert nicht
			VA_EXCEPT2( INVALID_PARAMETER, "Invalid sound receiver ID" );

		return pListenerState->GetAuralizationMode();

	} VA_RETHROW;
}

void CVACoreImpl::SetSoundReceiverAuralizationMode( const int iID, const int iAuralizationMode )
{
	VA_NO_REENTRANCE;
	VA_CHECK_INITIALIZED;

	VA_TRY
	{
		// Parameter berprfen
		if( !GetAuralizationModeValid( iAuralizationMode ) )
		VA_EXCEPT2( INVALID_PARAMETER, "Invalid auralization mode" );

		bool bSync = GetUpdateLocked();
		if( !bSync ) LockUpdate();

		CVAReceiverState* pListenerState = m_pNewSceneState->AlterListenerState( iID );

		if( !pListenerState ) {
			// Hrer existiert nicht
			if( !bSync ) UnlockUpdate();
			VA_EXCEPT2( INVALID_PARAMETER, "Invalid sound receiver ID" );
		}

		pListenerState->SetAuralizationMode( iAuralizationMode );

		// Ereignis generieren, falls erfolgreich
		CVAEvent ev;
		ev.iEventType = CVAEvent::SOUND_RECEIVER_CHANGED_AURALIZATIONMODE;
		ev.pSender = this;
		ev.iObjectID = iID;
		ev.iAuralizationMode = iAuralizationMode;
		m_pEventManager->EnqueueEvent( ev );

		if( !bSync ) UnlockUpdate();

	} VA_RETHROW;
}

void CVACoreImpl::SetSoundReceiverParameters( const int iID, const CVAStruct& oParams )
{
	VA_NO_REENTRANCE;
	VA_CHECK_INITIALIZED;

	VA_TRY
	{
		bool bSync = GetUpdateLocked();
		if( !bSync )
			LockUpdate();

		CVAReceiverState* pListenerState = m_pNewSceneState->AlterListenerState( iID );

		if( !pListenerState )
		{
			if( !bSync )
				UnlockUpdate();

			VA_EXCEPT2( INVALID_PARAMETER, "Invalid sound receiver ID " + std::to_string( long( iID ) ) );
		}

		pListenerState->SetParameters( oParams );

		// Ereignis generieren, falls erfolgreich
		CVAEvent ev;
		ev.iEventType = CVAEvent::SOUND_RECEIVER_CHANGED_NAME; // @todo create own core event "parameter changed"
		ev.pSender = this;
		ev.iObjectID = iID;
		// ev.oStruct @todo: add a struct to the event
		m_pEventManager->EnqueueEvent( ev );

		if( !bSync )
			UnlockUpdate();
	}
	VA_RETHROW;
}

CVAStruct CVACoreImpl::GetSoundReceiverParameters( const int iID, const CVAStruct& oArgs ) const
{
	VA_NO_REENTRANCE;
	VA_CHECK_INITIALIZED;

	VA_TRY
	{
		CVASceneState* pHeadState = m_pSceneManager->GetHeadSceneState();
		const CVAReceiverState* pListenerState = pHeadState->GetReceiverState( iID );

		if( !pListenerState )
			VA_EXCEPT2( INVALID_PARAMETER, "Invalid sound receiver ID" );

		return pListenerState->GetParameters( oArgs );

	}
	VA_RETHROW;
}

int CVACoreImpl::GetSoundReceiverDirectivity( const int iID ) const
{
	VA_NO_REENTRANCE;
	VA_CHECK_INITIALIZED;

	VA_TRY
	{
		CVASceneState* pHeadState = m_pSceneManager->GetHeadSceneState();
		const CVAReceiverState* pListenerState = pHeadState->GetReceiverState( iID );

		if( !pListenerState )
			VA_EXCEPT2( INVALID_PARAMETER, "Invalid sound receiver ID" );

		return pListenerState->GetDirectivityID();

	}
	VA_RETHROW;
}

void CVACoreImpl::SetSoundReceiverDirectivity( const int iID, const int iDirectivityID )
{
	VA_NO_REENTRANCE;
	VA_CHECK_INITIALIZED;

	VA_TRY
	{
		// Parameter berprfen
		const IVADirectivity* pDirectivity = nullptr;
		if( iDirectivityID != -1 )
		{
			pDirectivity = m_pDirectivityManager->RequestDirectivity( iDirectivityID );
			if( !pDirectivity )
				VA_EXCEPT2( INVALID_ID, "Invalid directivity dataset for ID " + std::to_string( iID ) );
		}

		bool bSync = GetUpdateLocked();
		if( !bSync )
			LockUpdate();

		CVAReceiverState* pListenerState = m_pNewSceneState->AlterListenerState( iID );

		if( !pListenerState )
		{
			// Quelle existiert nicht
			if( !bSync )
				UnlockUpdate();

			if( pDirectivity )
				m_pDirectivityManager->DeleteDirectivity( iDirectivityID );

			VA_EXCEPT2( INVALID_PARAMETER, "Invalid sound receiver ID " + std::to_string( iID ) );
		}

		pListenerState->SetDirectivityID( iDirectivityID );
		pListenerState->SetDirectivity( pDirectivity );

		// Ereignis generieren, falls erfolgreich
		CVAEvent ev;
		ev.iEventType = CVAEvent::SOUND_RECEIVER_CHANGED_DIRECTIVITY;
		ev.pSender = this;
		ev.iObjectID = iID;
		ev.iParamID = iDirectivityID;
		m_pEventManager->EnqueueEvent( ev );

		if( !bSync )
			UnlockUpdate();

		VA_INFO( "Core", "Linked sound receiver " + std::to_string( long( iID ) ) + " with receiver directivity dataset " + std::to_string( long( iDirectivityID ) ) );

	}
	VA_RETHROW;
}

int CVACoreImpl::GetSoundReceiverGeometryMesh( const int iID ) const
{
	VA_EXCEPT_NOT_IMPLEMENTED_FUTURE_VERSION;
}

void CVACoreImpl::SetSoundReceiverGeometryMesh( const int iSoundReceiverID, const int iGeometryMeshID )
{
	VA_EXCEPT_NOT_IMPLEMENTED_FUTURE_VERSION;
}

void CVACoreImpl::GetSoundReceiverPose( const int iID, VAVec3& v3Pos, VAQuat& qOrient ) const
{
	VA_NO_REENTRANCE;
	VA_CHECK_INITIALIZED;

	VA_TRY
	{
		CVASceneState* pHeadState = m_pSceneManager->GetHeadSceneState();
		const CVAReceiverState* pListenerState = pHeadState->GetReceiverState( iID );

		if( !pListenerState )
			VA_EXCEPT2( INVALID_PARAMETER, "Invalid sound receiver ID" );

		const CVAMotionState* pMotionState = pListenerState->GetMotionState();
		if( !pMotionState )
			VA_EXCEPT2( INVALID_PARAMETER, "SoundReceiver has invalid motion state, probably it has not been positioned, yet?" );

		v3Pos = pMotionState->GetPosition();
		qOrient = pMotionState->GetOrientation();
	}
	VA_RETHROW;
}

void CVACoreImpl::SetSoundReceiverPose( const int iID, const VAVec3& v3Pos, const VAQuat& qOrient )
{
	VA_NO_REENTRANCE;
	VA_CHECK_INITIALIZED;

	VA_TRY
	{
		bool bSync = GetUpdateLocked();
		if( !bSync )
			LockUpdate();

		CVAReceiverState* pState = m_pNewSceneState->AlterListenerState( iID );

		if( !pState )
		{
			if( !bSync )
				UnlockUpdate();
			VA_EXCEPT2( INVALID_PARAMETER, "Invalid sound receiver ID, not found in scene" );
		}

		CVAMotionState* pNewMotionState = pState->AlterMotionState();
		pNewMotionState->SetPosition( v3Pos );
		pNewMotionState->SetOrientation( qOrient );

		//m_pSceneManager->GetListenerDesc( iID )->bInitPositionOrientation = true; // @todo

		// Ereignis generieren, falls erfolgreich
		CVAEvent ev;
		ev.iEventType = CVAEvent::SOUND_RECEIVER_CHANGED_POSE;
		ev.pSender = this;
		ev.iObjectID = iID;
		ev.vPos = v3Pos;
		//ev.qOrient = qOrient; // @todo
		ConvertQuaternionToViewUp( qOrient, ev.vView, ev.vUp );
		SetCoreEventParams( ev, pNewMotionState );

		m_pEventManager->EnqueueEvent( ev );

		if( !bSync )
			UnlockUpdate();

	}
	VA_RETHROW;
}

VAVec3 CVACoreImpl::GetSoundReceiverPosition( const int iID ) const
{
	VA_NO_REENTRANCE;
	VA_CHECK_INITIALIZED;

	VA_TRY
	{
		CVASceneState* pHeadState = m_pSceneManager->GetHeadSceneState();
		const CVAReceiverState* pSoundReceiverState = pHeadState->GetReceiverState( iID );

		if( !pSoundReceiverState )
			VA_EXCEPT2( INVALID_PARAMETER, "Invalid sound receiver ID" );

		const CVAMotionState* pMotionState = pSoundReceiverState->GetMotionState();
		if( !pMotionState )
			VA_EXCEPT2( INVALID_PARAMETER, "SoundReceiver has invalid motion state, probably it has not been positioned, yet?" );

		return pMotionState->GetPosition();
	}
	VA_RETHROW;
}

void CVACoreImpl::SetSoundReceiverPosition( const int iID, const VAVec3& v3Pos )
{
	VA_NO_REENTRANCE;
	VA_CHECK_INITIALIZED;

	VA_TRY
	{
		bool bSync = GetUpdateLocked();
		if( !bSync )
			LockUpdate();

		CVAReceiverState* pListenerState = m_pNewSceneState->AlterListenerState( iID );

		if( !pListenerState )
		{
			if( !bSync ) UnlockUpdate();
			VA_EXCEPT2( INVALID_PARAMETER, "Invalid sound receiver ID" );
		}

		CVAMotionState* pNewMotionState = pListenerState->AlterMotionState();
		pNewMotionState->SetPosition( v3Pos );

		// Ereignis generieren
		CVAEvent ev;
		ev.iEventType = CVAEvent::SOUND_RECEIVER_CHANGED_POSE;
		ev.pSender = this;
		ev.iObjectID = iID;
		SetCoreEventParams( ev, pNewMotionState );

		m_pEventManager->EnqueueEvent( ev );

		if( !bSync )
			UnlockUpdate();

	} VA_RETHROW;
}

void CVACoreImpl::GetSoundReceiverOrientationVU( const int iID, VAVec3& vView, VAVec3& vUp ) const
{
	ConvertQuaternionToViewUp( GetSoundReceiverOrientation( iID ), vView, vUp );
}

void CVACoreImpl::SetSoundReceiverOrientationVU( const int iID, const VAVec3& v3View, const VAVec3& v3Up )
{
	VA_NO_REENTRANCE;
	VA_CHECK_INITIALIZED;

	VA_TRY
	{
		const bool bSync = GetUpdateLocked();
		if( !bSync )
			LockUpdate();

		CVAReceiverState* pListenerState = m_pNewSceneState->AlterListenerState( iID );

		if( !pListenerState )
		{
			if( !bSync )
				UnlockUpdate();
			VA_EXCEPT2( INVALID_PARAMETER, "Invalid sound receiver ID" );
		}

		CVAMotionState* pNewMotionState = pListenerState->AlterMotionState();
		pNewMotionState->SetOrientationVU( v3View, v3Up );

		// Ereignis generieren
		CVAEvent ev;
		ev.iEventType = CVAEvent::SOUND_RECEIVER_CHANGED_POSE;
		ev.pSender = this;
		ev.iObjectID = iID;
		SetCoreEventParams( ev, pNewMotionState );

		m_pEventManager->EnqueueEvent( ev );

		if( !bSync )
			UnlockUpdate();

	}
	VA_RETHROW;
}

VAQuat CVACoreImpl::GetSoundReceiverOrientation( const int iID ) const
{
	VA_NO_REENTRANCE;
	VA_CHECK_INITIALIZED;

	VA_TRY
	{
		CVASceneState* pHeadState = m_pSceneManager->GetHeadSceneState();
		const CVAReceiverState* pSoundReceiverState = pHeadState->GetReceiverState( iID );

		if( !pSoundReceiverState )
			VA_EXCEPT2( INVALID_PARAMETER, "Invalid sound receiver ID" );

		const CVAMotionState* pMotionState = pSoundReceiverState->GetMotionState();
		if( !pMotionState )
			VA_EXCEPT2( INVALID_PARAMETER, "Sound receiver has invalid motion state, probably it has not been positioned, yet?" );

		return pMotionState->GetOrientation();
	}
	VA_RETHROW;
}

void CVACoreImpl::SetSoundReceiverOrientation( const int iID, const VAQuat& qOrient )
{
	VA_NO_REENTRANCE;
	VA_CHECK_INITIALIZED;

	VA_TRY
	{
		const bool bSync = GetUpdateLocked();
		if( !bSync )
			LockUpdate();

		CVAReceiverState* pListenerState = m_pNewSceneState->AlterListenerState( iID );

		if( !pListenerState )
		{
			if( !bSync )
				UnlockUpdate();
			VA_EXCEPT2( INVALID_PARAMETER, "Invalid sound receiver ID" );
		}

		CVAMotionState* pNewMotionState = pListenerState->AlterMotionState();
		pNewMotionState->SetOrientation( qOrient );

		// Ereignis generieren
		CVAEvent ev;
		ev.iEventType = CVAEvent::SOUND_RECEIVER_CHANGED_POSE;
		ev.pSender = this;
		ev.iObjectID = iID;
		SetCoreEventParams( ev, pNewMotionState );

		m_pEventManager->EnqueueEvent( ev );

		if( !bSync )
			UnlockUpdate();

	}
	VA_RETHROW;
}

VAQuat CVACoreImpl::GetSoundReceiverHeadAboveTorsoOrientation( const int iID ) const
{
	VA_NO_REENTRANCE;
	VA_CHECK_INITIALIZED;

	VA_TRY
	{
		CVASceneState* pHeadState = m_pSceneManager->GetHeadSceneState();
		const CVAReceiverState* pListenerState = pHeadState->GetReceiverState( iID );

		if( !pListenerState )
			VA_EXCEPT2( INVALID_PARAMETER, "Invalid sound receiver ID" );

		const CVAMotionState* pMotionState = pListenerState->GetMotionState();
		if( !pMotionState )
			VA_EXCEPT2( INVALID_PARAMETER, "Sound receiver has invalid motion state, probably it has not been positioned, yet?" );

		return pMotionState->GetHeadAboveTorsoOrientation();
	}
	VA_RETHROW;
}

void CVACoreImpl::SetSoundReceiverHeadAboveTorsoOrientation( const int iID, const VAQuat& qOrient )
{
	VA_NO_REENTRANCE;
	VA_CHECK_INITIALIZED;

	VA_TRY
	{
		const bool bSync = GetUpdateLocked();
		if( !bSync )
			LockUpdate();

		CVAReceiverState* pListenerState = m_pNewSceneState->AlterListenerState( iID );

		if( !pListenerState )
		{
			if( !bSync )
				UnlockUpdate();
			VA_EXCEPT2( INVALID_PARAMETER, "Invalid sound receiver ID" );
		}

		CVAMotionState* pNewMotionState = pListenerState->AlterMotionState();
		pNewMotionState->SetHeadAboveTorsoOrientation( qOrient );

		CVAEvent ev;
		ev.iEventType = CVAEvent::SOUND_RECEIVER_CHANGED_POSE;
		ev.pSender = this;
		ev.iObjectID = iID;
		SetCoreEventParams( ev, pNewMotionState );
		m_pEventManager->EnqueueEvent( ev );
		if( !bSync )
			UnlockUpdate();

	}
	VA_RETHROW;
}

void CVACoreImpl::GetSoundReceiverRealWorldPositionOrientationVU( const int iID, VAVec3& v3Pos, VAVec3& v3View, VAVec3& v3Up ) const
{
	VA_NO_REENTRANCE;
	VA_CHECK_INITIALIZED;

	VA_TRY
	{
		CVASceneState* pHeadState = m_pSceneManager->GetHeadSceneState();
		const CVAReceiverState* pListenerState = pHeadState->GetReceiverState( iID );

		if( !pListenerState )
			// Hrer existiert nicht
			VA_EXCEPT2( INVALID_PARAMETER, "Invalid sound receiver ID" );

		const CVAMotionState* pMotionState = pListenerState->GetMotionState();
		if( !pMotionState )
			VA_EXCEPT2( INVALID_PARAMETER, "Sound receiver has invalid motion state, probably it has not been positioned, yet?" );

		v3Pos = pMotionState->GetRealWorldPose().vPos;
		VAQuat qOrient = pMotionState->GetRealWorldPose().qOrient;
		ConvertQuaternionToViewUp( qOrient, v3View, v3Up );
	}
	VA_RETHROW;
}

void CVACoreImpl::SetSoundReceiverRealWorldPositionOrientationVU( const int iID, const VAVec3& v3Pos, const VAVec3& v3View, const VAVec3& v3Up )
{
	VA_NO_REENTRANCE;
	VA_CHECK_INITIALIZED;

	VA_TRY
	{
		const bool bSync = GetUpdateLocked();
		if( !bSync )
			LockUpdate();

		CVAReceiverState* pListenerState = m_pNewSceneState->AlterListenerState( iID );

		if( !pListenerState )
		{
			if( !bSync )
				UnlockUpdate();
			VA_EXCEPT2( INVALID_PARAMETER, "Invalid sound receiver ID" );
		}

		CVAMotionState* pNewMotionState = pListenerState->AlterMotionState();
		CVAMotionState::CVAPose oNewPose;
		oNewPose.vPos = v3Pos;
		ConvertViewUpToQuaternion( v3View, v3Up, oNewPose.qOrient );
		pNewMotionState->SetRealWorldPose( oNewPose );

		CVAEvent ev;
		ev.iEventType = CVAEvent::SOUND_RECEIVER_REAL_WORLD_POSE_CHANGED;
		ev.pSender = this;
		ev.iObjectID = iID;
		SetCoreEventParams( ev, pNewMotionState );
		m_pEventManager->EnqueueEvent( ev );

		if( !bSync )
			UnlockUpdate();

	}
	VA_RETHROW;
}

void CVACoreImpl::GetSoundReceiverRealWorldPose( const int iID, VAVec3& v3Pos, VAQuat& qOrient ) const
{
	VA_NO_REENTRANCE;
	VA_CHECK_INITIALIZED;

	VA_TRY
	{
		CVASceneState* pHeadState = m_pSceneManager->GetHeadSceneState();
		const CVAReceiverState* pListenerState = pHeadState->GetReceiverState( iID );

		if( !pListenerState )
			// Hrer existiert nicht
			VA_EXCEPT2( INVALID_PARAMETER, "Invalid sound receiver ID" );

		const CVAMotionState* pMotionState = pListenerState->GetMotionState();
		if( !pMotionState )
			VA_EXCEPT2( INVALID_PARAMETER, "Sound receiver has invalid motion state, probably it has not been positioned, yet?" );

		v3Pos = pMotionState->GetRealWorldPose().vPos;
		qOrient = pMotionState->GetRealWorldPose().qOrient;
	}
	VA_RETHROW;
}

void CVACoreImpl::SetSoundReceiverRealWorldPose( const int iID, const VAVec3& v3Pos, const VAQuat& qOrient )
{
	VA_NO_REENTRANCE;
	VA_CHECK_INITIALIZED;

	VA_TRY
	{
		const bool bSync = GetUpdateLocked();
		if( !bSync )
			LockUpdate();

		CVAReceiverState* pListenerState = m_pNewSceneState->AlterListenerState( iID );

		if( !pListenerState )
		{
			if( !bSync )
				UnlockUpdate();
			VA_EXCEPT2( INVALID_PARAMETER, "Invalid sound receiver ID" );
		}

		CVAMotionState* pNewMotionState = pListenerState->AlterMotionState();
		CVAMotionState::CVAPose oNewPose;
		oNewPose.vPos = v3Pos;
		oNewPose.qOrient = qOrient;
		pNewMotionState->SetRealWorldPose( oNewPose );

		CVAEvent ev;
		ev.iEventType = CVAEvent::SOUND_RECEIVER_CHANGED_POSE;
		ev.pSender = this;
		ev.iObjectID = iID;
		SetCoreEventParams( ev, pNewMotionState );
		m_pEventManager->EnqueueEvent( ev );

		if( !bSync )
			UnlockUpdate();

	}
	VA_RETHROW;
}

VAQuat CVACoreImpl::GetSoundReceiverRealWorldHeadAboveTorsoOrientation( const int iID ) const
{
	VA_NO_REENTRANCE;
	VA_CHECK_INITIALIZED;

	VA_TRY
	{
		CVASceneState* pHeadState = m_pSceneManager->GetHeadSceneState();
		const CVAReceiverState* pListenerState = pHeadState->GetReceiverState( iID );

		if( !pListenerState )
			VA_EXCEPT2( INVALID_PARAMETER, "Invalid sound receiver ID" );

		const CVAMotionState* pMotionState = pListenerState->GetMotionState();
		if( !pMotionState )
			VA_EXCEPT2( INVALID_PARAMETER, "Sound receiver has invalid motion state, probably it has not been positioned, yet?" );

		return pMotionState->GetRealWorldHeadAboveTorsoOrientation();
	}
	VA_RETHROW;
}

void CVACoreImpl::SetSoundReceiverRealWorldHeadAboveTorsoOrientation( const int iID, const VAQuat& qOrient )
{
	VA_NO_REENTRANCE;
	VA_CHECK_INITIALIZED;

	VA_TRY
	{
		const bool bSync = GetUpdateLocked();
		if( !bSync )
			LockUpdate();

		CVAReceiverState* pListenerState = m_pNewSceneState->AlterListenerState( iID );

		if( !pListenerState )
		{
			if( !bSync )
				UnlockUpdate();
			VA_EXCEPT2( INVALID_PARAMETER, "Invalid sound receiver ID" );
		}

		CVAMotionState* pNewMotionState = pListenerState->AlterMotionState();
		pNewMotionState->SetRealWorldHeadAboveTorsoOrientation( qOrient );

		CVAEvent ev;
		ev.iEventType = CVAEvent::SOUND_RECEIVER_CHANGED_POSE;
		ev.pSender = this;
		ev.iObjectID = iID;
		SetCoreEventParams( ev, pNewMotionState );
		m_pEventManager->EnqueueEvent( ev );

		if( !bSync )
			UnlockUpdate();
	}
	VA_RETHROW;
}

void CVACoreImpl::SetHomogeneousMediumSoundSpeed( const double dSoundSpeed )
{
	VA_NO_REENTRANCE;
	VA_TRY
	{
		if( dSoundSpeed <= 0.0f )
		VA_EXCEPT2( INVALID_PARAMETER, "Speed of sound can not be zero or negative" );
		oHomogeneousMedium.dSoundSpeed = dSoundSpeed;
	}
	VA_RETHROW;
}

double CVACoreImpl::GetHomogeneousMediumSoundSpeed() const
{
	VA_NO_REENTRANCE;
	return oHomogeneousMedium.dSoundSpeed;
}

void CVACoreImpl::SetHomogeneousMediumTemperature( const double dDegreesCentigrade )
{
	VA_NO_REENTRANCE;
	VA_TRY
	{
		if( dDegreesCentigrade <= -270.0f )
		VA_EXCEPT2( INVALID_PARAMETER, "Temperature can not be below total zero" );
		oHomogeneousMedium.dTemperatureDegreeCentigrade = dDegreesCentigrade;
	}
	VA_RETHROW;
}

double CVACoreImpl::GetHomogeneousMediumTemperature() const
{
	VA_NO_REENTRANCE;
	return oHomogeneousMedium.dTemperatureDegreeCentigrade;
}

void CVACoreImpl::SetHomogeneousMediumStaticPressure( const double dPressurePascal )
{
	VA_NO_REENTRANCE;
	VA_TRY
	{
		if( dPressurePascal <= 0.0f )
		VA_EXCEPT2( INVALID_PARAMETER, "Static pressure can not be zero or negative" );
		oHomogeneousMedium.dStaticPressurePascal = dPressurePascal;
	}
	VA_RETHROW;
}

double CVACoreImpl::GetHomogeneousMediumStaticPressure() const
{
	VA_NO_REENTRANCE;
	return oHomogeneousMedium.dStaticPressurePascal;
}

void CVACoreImpl::SetHomogeneousMediumRelativeHumidity( const double dRelativeHumidityPercent )
{
	VA_NO_REENTRANCE;
	VA_TRY
	{
		if( dRelativeHumidityPercent < 0.0f )
		VA_EXCEPT2( INVALID_PARAMETER, "Relative humidity can not be negative" );
		oHomogeneousMedium.dRelativeHumidityPercent = dRelativeHumidityPercent;
	}
	VA_RETHROW;
}

double CVACoreImpl::GetHomogeneousMediumRelativeHumidity()
{
	VA_NO_REENTRANCE;
	return oHomogeneousMedium.dRelativeHumidityPercent;
}

void CVACoreImpl::SetHomogeneousMediumShiftSpeed( const VAVec3& v3TranslationSpeed )
{
	VA_NO_REENTRANCE;
	VA_TRY
	{
		if( v3TranslationSpeed.Length() >= oHomogeneousMedium.dSoundSpeed )
		VA_EXCEPT2( INVALID_PARAMETER, "Medium shift can not be equal or faster than sound speed" );
		oHomogeneousMedium.v3ShiftSpeed = v3TranslationSpeed;
	}
	VA_RETHROW;
}

VAVec3 CVACoreImpl::GetHomogeneousMediumShiftSpeed() const
{
	VA_NO_REENTRANCE;
	return oHomogeneousMedium.v3ShiftSpeed;
}

void CVACoreImpl::SetHomogeneousMediumParameters( const CVAStruct& oParams )
{
	VA_NO_REENTRANCE;
	oHomogeneousMedium.oParameters = oParams;
}

CVAStruct CVACoreImpl::GetHomogeneousMediumParameters( const CVAStruct& oArgs )
{
	VA_NO_REENTRANCE;
	return oHomogeneousMedium.oParameters;
}

std::string CVACoreImpl::CreateScene( const CVAStruct& oParams, const std::string& sSceneName )
{
	VA_NO_REENTRANCE;
	VA_CHECK_INITIALIZED;

	VA_TRY
	{
		if( oParams.HasKey( "filepath" ) )
		{
			const std::string sFilePath = oParams[ "filepath" ];
			VA_INFO( "Core", "Loading scene from file '" << sFilePath << "'" );
			std::string sDestFilename = correctPath( m_oCoreConfig.mMacros.SubstituteMacros( sFilePath ) );
			for( std::vector<CVAAudioRendererDesc>::iterator it = m_voRenderers.begin(); it != m_voRenderers.end(); ++it )
				it->pInstance->LoadScene( sDestFilename );

			// @todo: create a scene manager and return a proper scene identifier
			return sDestFilename;
		}
		else
		{
			VA_EXCEPT2( INVALID_PARAMETER, "Could not interpret scene parameters, missing key 'filepath'" );
		}
	}
	VA_RETHROW;
}

CVASceneInfo CVACoreImpl::GetSceneInfo( const std::string& sSceneID ) const
{
	VA_NO_REENTRANCE;
	VA_CHECK_INITIALIZED;

	VA_TRY
	{
		VA_EXCEPT_NOT_IMPLEMENTED_FUTURE_VERSION;
	}
	VA_RETHROW;
}

bool CVACoreImpl::GetSceneEnabled( const std::string& sID ) const
{
	VA_NO_REENTRANCE;
	VA_CHECK_INITIALIZED;

	VA_TRY
	{
		VA_EXCEPT_NOT_IMPLEMENTED_FUTURE_VERSION;
	}
	VA_RETHROW;
}


int CVACoreImpl::CreateSoundPortal( const std::string& sName /*= "" */ )
{
	VA_EXCEPT_NOT_IMPLEMENTED_FUTURE_VERSION;
	//m_pSceneManager->CreatePortalDesc()
}

void CVACoreImpl::GetSceneIDs( std::vector< std::string >& vsIDs ) const
{
	VA_EXCEPT_NOT_IMPLEMENTED_FUTURE_VERSION;
}


std::string CVACoreImpl::GetSceneName( const std::string& sID ) const
{
	VA_EXCEPT_NOT_IMPLEMENTED_FUTURE_VERSION;
}

void CVACoreImpl::SetSceneName( const std::string& sID, const std::string& sName )
{
	VA_EXCEPT_NOT_IMPLEMENTED_FUTURE_VERSION;
}

void CVACoreImpl::SetSceneEnabled( const std::string& sID, const bool bEnabled /*= true */ )
{
	VA_EXCEPT_NOT_IMPLEMENTED_FUTURE_VERSION;
}

void CVACoreImpl::GetSoundPortalIDs( std::vector< int >& vPortalIDs )
{
	VA_NO_REENTRANCE;
	VA_CHECK_INITIALIZED;

	VA_TRY
	{
		m_pSceneManager->GetHeadSceneState()->GetPortalIDs( &vPortalIDs );
	}
	VA_RETHROW;
}

CVASoundPortalInfo CVACoreImpl::GetSoundPortalInfo( const int iID ) const
{
	VA_EXCEPT_NOT_IMPLEMENTED_FUTURE_VERSION;
}

std::string CVACoreImpl::GetSoundPortalName( const int iPortalID ) const
{
	VA_NO_REENTRANCE;
	VA_CHECK_INITIALIZED;

	VA_TRY
	{
		return m_pSceneManager->GetPortalName( iPortalID );
	}
	VA_RETHROW;
}

void CVACoreImpl::SetSoundPortalName( const int iPortalID, const std::string& sName )
{
	VA_NO_REENTRANCE;
	VA_CHECK_INITIALIZED;

	VA_TRY
	{
		m_pSceneManager->SetPortalName( iPortalID, sName );

		CVAEvent ev;
		ev.iEventType = CVAEvent::SOUND_PORTAL_CHANGED_NAME;
		ev.pSender = this;
		ev.iObjectID = iPortalID;
		ev.sName = sName;
		m_pEventManager->BroadcastEvent( ev );

	}
	VA_RETHROW;
}

void CVACoreImpl::SetSoundPortalMaterial( const int iSoundPortalID, const int iMaterialID )
{
	VA_EXCEPT_NOT_IMPLEMENTED_FUTURE_VERSION;
}

int CVACoreImpl::GetSoundPortalMaterial( const int iSoundPortalID ) const
{
	VA_EXCEPT_NOT_IMPLEMENTED_FUTURE_VERSION;
}

void CVACoreImpl::SetSoundPortalNextPortal( const int iSoundPortalID, const int iNextSoundPortalID )
{
	VA_EXCEPT_NOT_IMPLEMENTED_FUTURE_VERSION;
}

int CVACoreImpl::GetSoundPortalNextPortal( const int iSoundPortalID ) const
{
	VA_EXCEPT_NOT_IMPLEMENTED_FUTURE_VERSION;
}

void CVACoreImpl::SetSoundPortalSoundReceiver( const int iSoundPortalID, const int iSoundReceiverID )
{
	VA_EXCEPT_NOT_IMPLEMENTED_FUTURE_VERSION;
}

int CVACoreImpl::GetSoundPortalSoundReceiver( const int iSoundPortalID ) const
{
	VA_EXCEPT_NOT_IMPLEMENTED_FUTURE_VERSION;
}

void CVACoreImpl::SetSoundPortalSoundSource( const int iSoundPortalID, const int iSoundSourceID )
{
	VA_EXCEPT_NOT_IMPLEMENTED_FUTURE_VERSION;
}

int CVACoreImpl::GetSoundPortalSoundSource( const int iSoundPortalID ) const
{
	VA_EXCEPT_NOT_IMPLEMENTED_FUTURE_VERSION;
}

bool CVACoreImpl::GetSoundPortalEnabled( const int iPortalID ) const
{
	VA_NO_REENTRANCE;
	VA_CHECK_INITIALIZED;

	VA_TRY
	{
		VA_EXCEPT_NOT_IMPLEMENTED_FUTURE_VERSION;
	}
	VA_RETHROW;
}

CVAStruct CVACoreImpl::GetSoundPortalParameters( const int iID, const CVAStruct& oArgs ) const
{
	VA_EXCEPT_NOT_IMPLEMENTED_FUTURE_VERSION;
}

void CVACoreImpl::SetSoundPortalParameters( const int iID, const CVAStruct& oParams )
{
	VA_EXCEPT_NOT_IMPLEMENTED_FUTURE_VERSION;
}

void CVACoreImpl::SetSoundPortalPosition( const int iSoundPortalID, const VAVec3& vPos )
{
	VA_EXCEPT_NOT_IMPLEMENTED_FUTURE_VERSION;
}
VAVec3 CVACoreImpl::GetSoundPortalPosition( const int iSoundPortalID ) const
{
	VA_EXCEPT_NOT_IMPLEMENTED_FUTURE_VERSION;
}

void CVACoreImpl::SetSoundPortalOrientation( const int iSoundPortalID, const VAQuat& qOrient )
{
	VA_EXCEPT_NOT_IMPLEMENTED_FUTURE_VERSION;
}

VAQuat CVACoreImpl::GetSoundPortalOrientation( const int iSoundPortalID ) const
{
	VA_EXCEPT_NOT_IMPLEMENTED_FUTURE_VERSION;
}

void CVACoreImpl::SetSoundPortalEnabled( const int iID, const bool bEnabled )
{
	VA_NO_REENTRANCE;
	VA_CHECK_INITIALIZED;

	VA_TRY
	{
		VA_EXCEPT_NOT_IMPLEMENTED_NEXT_VERSION;
		//m_pSceneManager->SetPortalEnabled( iID, bEnabled );
	}
	VA_RETHROW;
}

bool CVACoreImpl::GetInputMuted() const
{
	VA_NO_REENTRANCE;
	VA_CHECK_INITIALIZED;

	return m_bInputMuted;
}

void CVACoreImpl::SetInputMuted( const bool bMuted )
{
	VA_NO_REENTRANCE;
	VA_CHECK_INITIALIZED;

	VA_TRY
	{
		if( m_bInputMuted == bMuted )
		return;

		m_bInputMuted = bMuted;

		if( m_pInputAmp )
		{
			if( m_bInputMuted )
				m_pInputAmp->SetGain( 0.0f );
			else
				m_pInputAmp->SetGain( ( float ) m_dInputGain );
		}

		VA_INFO( "Core", "Input mute toggled" );

		CVAEvent ev;
		ev.iEventType = CVAEvent::INPUT_MUTING_CHANGED;
		ev.pSender = this;
		ev.bMuted = m_bInputMuted;
		m_pEventManager->BroadcastEvent( ev );

	}
	VA_RETHROW;
}

double CVACoreImpl::GetInputGain() const
{
	VA_NO_REENTRANCE;
	VA_CHECK_INITIALIZED;

	return m_dInputGain;
}

void CVACoreImpl::SetInputGain( double dGain )
{
	VA_NO_REENTRANCE;
	VA_CHECK_INITIALIZED;

	VA_TRY
	{
		if( !GetVolumeValid( dGain ) )
		VA_EXCEPT2( INVALID_PARAMETER, "Invalid gain" );

		if( m_dInputGain == dGain )
			return;
		m_dInputGain = dGain;

		if( m_pInputAmp )
		{
			if( m_bInputMuted )
				m_pInputAmp->SetGain( 0 );
			else
				m_pInputAmp->SetGain( ( float ) dGain );
		}

		// Ereignis generieren
		CVAEvent ev;
		ev.iEventType = CVAEvent::INPUT_GAIN_CHANGED;
		ev.pSender = this;
		ev.dVolume = dGain;
		m_pEventManager->BroadcastEvent( ev );

		VA_VERBOSE( "Core", "Set input gain = " << IVAInterface::GetVolumeStrDecibel( dGain ) );
	}
	VA_RETHROW;
}

double CVACoreImpl::GetOutputGain() const
{
	VA_NO_REENTRANCE;
	VA_CHECK_INITIALIZED;

	return m_dOutputGain;
}

void CVACoreImpl::SetOutputGain( const double dGain )
{
	VA_NO_REENTRANCE;
	VA_CHECK_INITIALIZED;

	VA_TRY
	{
		if( !GetVolumeValid( dGain ) )
		VA_EXCEPT2( INVALID_PARAMETER, "Invalid gain" );

		if( m_dOutputGain == dGain )
			return;
		m_dOutputGain = dGain;
		if( m_pOutputPatchbay )
		{
			if( m_bOutputMuted )
				m_pOutputPatchbay->SetOutputGain( 0, 0.0f );
			else
				m_pOutputPatchbay->SetOutputGain( 0, dGain );
		}

		// Ereignis generieren
		CVAEvent ev;
		ev.iEventType = CVAEvent::OUTPUT_GAIN_CHANGED;
		ev.pSender = this;
		ev.dVolume = dGain;
		m_pEventManager->BroadcastEvent( ev );

		VA_VERBOSE( "Core", "Set output gain = " << IVAInterface::GetVolumeStrDecibel( dGain ) );

	}
	VA_RETHROW;
}

bool CVACoreImpl::GetOutputMuted() const
{
	VA_NO_REENTRANCE;
	VA_CHECK_INITIALIZED;

	return m_bOutputMuted;
}

void CVACoreImpl::SetOutputMuted( const bool bMuted )
{
	VA_NO_REENTRANCE;
	VA_CHECK_INITIALIZED;

	VA_TRY
	{
		if( m_bOutputMuted == bMuted )
		return;
		m_bOutputMuted = bMuted;
		VA_INFO( "Core", "Output mute toggled" );

		if( m_pOutputPatchbay )
			m_pOutputPatchbay->SetOutputMuted( 0, bMuted );

		// Ereignis generieren
		CVAEvent ev;
		ev.iEventType = CVAEvent::OUTPUT_MUTING_CHANGED;
		ev.pSender = this;
		ev.bMuted = m_bOutputMuted;
		m_pEventManager->BroadcastEvent( ev );
	}
	VA_RETHROW;
}

int CVACoreImpl::GetGlobalAuralizationMode() const
{
	VA_NO_REENTRANCE;
	VA_CHECK_INITIALIZED;

	return m_iGlobalAuralizationMode;
}

void CVACoreImpl::SetGlobalAuralizationMode( const int iAuralizationMode )
{
	VA_NO_REENTRANCE;
	VA_CHECK_INITIALIZED;

	VA_TRY
	{
		if( !GetAuralizationModeValid( iAuralizationMode ) )
		VA_EXCEPT2( INVALID_PARAMETER, "Invalid auralization mode" );

		if( m_iGlobalAuralizationMode == iAuralizationMode )
		{
			return;
		}

		m_iGlobalAuralizationMode = iAuralizationMode;
		// Neuberechnung der Schallpfade triggern
		m_pCoreThread->Trigger();

		// Ereignis generieren
		CVAEvent ev;
		ev.iEventType = CVAEvent::GLOBAL_AURALIZATION_MODE_CHANGED;
		ev.pSender = this;
		ev.iAuralizationMode = iAuralizationMode;
		m_pEventManager->BroadcastEvent( ev );

		VA_VERBOSE( "Core", "Set global auralization mode = " << IVAInterface::GetAuralizationModeStr( iAuralizationMode, true ) );
	}
	VA_RETHROW;
}

int CVACoreImpl::GetActiveSoundReceiver() const
{
	VA_NO_REENTRANCE;
	VA_CHECK_INITIALIZED;

	return m_iCurActiveSoundReceiver;
}

void CVACoreImpl::SetActiveSoundReceiver( const int iListenerID )
{
	VA_NO_REENTRANCE;
	VA_CHECK_INITIALIZED;

	bool bSync = false;

	VA_TRY
	{
		LockUpdate();
		bSync = true;

		// Prfen, ob Hrer in der aktuellen Konfig existiert.
		if( !m_pNewSceneState->GetReceiverState( iListenerID ) )
			VA_EXCEPT2( INVALID_PARAMETER, "Listener does not existing in head configuration" );
		/* TODO: Auch -1 erlauben um Hrer zu entfernen
		if (iListenerID != -1) {
		if (!m_pNewSceneState->GetListenerState(iListenerID))
		VA_EXCEPT2(INVALID_PARAMETER, "Listener does not existing in head configuration");
		}
		*/

		if( iListenerID != m_iUpdActiveSoundReceiver )
		{
			m_iUpdActiveSoundReceiver = iListenerID;
			m_iCurActiveSoundReceiver = iListenerID;

			// Ereignis generieren
			CVAEvent ev;
			ev.iEventType = CVAEvent::ACTIVE_SOUND_RECEIVER_CHANGED;
			ev.pSender = this;
			ev.iObjectID = iListenerID;
			m_pEventManager->EnqueueEvent( ev );

			VA_VERBOSE( "Core", "Set sound receiver " << iListenerID << " the active receiver" );
		}

		bSync = false;
		UnlockUpdate();

	}
		VA_FINALLY
	{
		if( bSync ) UnlockUpdate();
		throw;
	}
}

double CVACoreImpl::GetCoreClock() const
{
	// Clock ist immer da, reentrance hier erlaubt
	double dNow = m_pClock->getTime();
	double dOffset = ( double ) m_fCoreClockOffset;
	return ( dNow - dOffset );
}

void CVACoreImpl::SetCoreClock( const double dSeconds )
{
	VA_NO_REENTRANCE;
	VA_CHECK_INITIALIZED;

	VA_TRY
	{
		if( dSeconds < 0 )
		VA_EXCEPT2( INVALID_PARAMETER, "Time must not be negative" );

		// Aktuelle Zeit holen
		double dNow = m_pClock->getTime();
		double dOffset = dSeconds - dNow;

		// TODO: Sollte eigentlich ber doubles gehen. Leider noch keine AtomicDoubles...
		m_fCoreClockOffset = ( float ) dOffset;

		VA_VERBOSE( "Core", "Set clock to " << timeToString( dSeconds ) );

	}
	VA_RETHROW;
}

std::string CVACoreImpl::SubstituteMacros( const std::string& sStr ) const
{
	VA_TRY
	{
		return m_oCoreConfig.mMacros.SubstituteMacros( sStr );
	}
	VA_RETHROW;
}

std::string CVACoreImpl::FindFilePath( const std::string& sRelativeFilePath ) const
{
	VA_TRY
	{
		std::string sRelativeFilePathSubstituted = SubstituteMacros( sRelativeFilePath );
		VistaFileSystemFile oFile( sRelativeFilePathSubstituted );
		if( oFile.Exists() && oFile.IsFile() )
			return sRelativeFilePathSubstituted;

		// Search with paths list
		std::string sFinalPathWithSearch;
		for( size_t i = 0; i < m_oCoreConfig.vsSearchPaths.size(); i++ )
		{
			const std::string& sSearchPath( m_oCoreConfig.vsSearchPaths[ i ] );
			std::string sCombinedFilePath = correctPath( sSearchPath + PATH_SEPARATOR + sRelativeFilePathSubstituted );
			VistaFileSystemFile oFile( sCombinedFilePath );
			VA_TRACE( "Core:FindFilePath", "Searching in directory '" + sSearchPath + "' for file '" + sRelativeFilePathSubstituted + "'" );
			if( oFile.Exists() && oFile.IsFile() )
			{
				if( sFinalPathWithSearch.empty() )
				{
					sFinalPathWithSearch = sCombinedFilePath;
				}
				else
				{
					VA_WARN( "Core", "Found ambiguous file path '" + sCombinedFilePath + "' (skipped), using first path '" + sFinalPathWithSearch + "'" );
				}
			}
		}
		return sFinalPathWithSearch;
	}
	VA_RETHROW;
}

void CVACoreImpl::InitializeAudioDriver()
{
#ifdef VACORE_WITH_AUDIO_BACKEND_ASIO
	if( m_oCoreConfig.oAudioDriverConfig.sDriver == "ASIO" )
		m_pAudioDriverBackend = new CVAASIOBackend( &m_oCoreConfig.oAudioDriverConfig );
#endif
#ifdef VACORE_WITH_AUDIO_BACKEND_PORTAUDIO
	if( m_oCoreConfig.oAudioDriverConfig.sDriver == "Portaudio" )
		m_pAudioDriverBackend = new CVAPortaudioBackend( &m_oCoreConfig.oAudioDriverConfig );
#endif
#ifdef VACORE_WITH_AUDIO_BACKEND_VIRTUAL
	if( m_oCoreConfig.oAudioDriverConfig.sDriver == "Virtual" )
	{

		if( m_oCoreConfig.oAudioDriverConfig.iBuffersize == -1 )
			VA_EXCEPT2( INVALID_PARAMETER, "For a virtual audio device, the buffer size has to be set (AUTO detect not possible)" );

		if( m_oCoreConfig.oAudioDriverConfig.iOutputChannels == -1 )
			VA_EXCEPT2( INVALID_PARAMETER, "For a virtual audio device, the output channel number has to be set (AUTO detect not possible)" );

		m_oCoreConfig.oAudioDriverConfig.iInputChannels = 0; // not allowed, override

		CVAVirtualAudioDriverBackend* pAudioDriverBackend = new CVAVirtualAudioDriverBackend( &m_oCoreConfig.oAudioDriverConfig );
		RegisterModule( pAudioDriverBackend );
		m_pAudioDriverBackend = pAudioDriverBackend;

		// Overwride default block pointer by manual clock
		CVAVirtualAudioDriverBackend::ManualClock* pManualClock = new CVAVirtualAudioDriverBackend::ManualClock();
		RegisterModule( pManualClock );
		m_pClock = pManualClock;
	}
#else
#endif

	if( m_pAudioDriverBackend == nullptr )
		VA_EXCEPT2( INVALID_PARAMETER, "Unkown, uninitializable or unsupported audio driver backend '" + m_oCoreConfig.oAudioDriverConfig.sDriver + "'" );

	try
	{
		VA_INFO( "Core", "Initializing audio device '" << m_pAudioDriverBackend->getDeviceName() << "' using '" << m_pAudioDriverBackend->getDriverName() << "' driver" );

		VA_TRACE( "Core", "Desired settings: sampling rate " << m_oCoreConfig.oAudioDriverConfig.dSampleRate << " Hz, " <<
			( m_oCoreConfig.oAudioDriverConfig.iInputChannels == CVAAudioDriverConfig::AUTO ? "all" : std::to_string( m_oCoreConfig.oAudioDriverConfig.iInputChannels ) ) << " inputs, " <<
			( m_oCoreConfig.oAudioDriverConfig.iOutputChannels == CVAAudioDriverConfig::AUTO ? "all" : std::to_string( m_oCoreConfig.oAudioDriverConfig.iOutputChannels ) ) << " outputs, " <<
			"buffer size = " << ( m_oCoreConfig.oAudioDriverConfig.iBuffersize == 0 ? "auto" : std::to_string( m_oCoreConfig.oAudioDriverConfig.iBuffersize ) ) );

		m_pAudioDriverBackend->initialize();

		m_oCoreConfig.oAudioDriverConfig.dSampleRate = m_pAudioDriverBackend->getOutputStreamProperties()->dSamplerate;
		m_oCoreConfig.oAudioDriverConfig.iInputChannels = m_pAudioDriverBackend->getNumberOfInputs();
		m_oCoreConfig.oAudioDriverConfig.iOutputChannels = m_pAudioDriverBackend->getOutputStreamProperties()->uiChannels;
		m_oCoreConfig.oAudioDriverConfig.iBuffersize = m_pAudioDriverBackend->getOutputStreamProperties()->uiBlocklength;

		VA_INFO( "Core", "Streaming at " << std::fixed << std::setw( 3 ) << std::setprecision( 1 ) << ( m_oCoreConfig.oAudioDriverConfig.dSampleRate / 1000.0f ) << " kHz on " <<
			( m_oCoreConfig.oAudioDriverConfig.iInputChannels == 0 ? "no" : std::to_string( m_oCoreConfig.oAudioDriverConfig.iInputChannels ) ) << " inputs and " <<
			( m_oCoreConfig.oAudioDriverConfig.iOutputChannels == 0 ? "no" : std::to_string( m_oCoreConfig.oAudioDriverConfig.iOutputChannels ) ) <<
			" outputs with a buffer size of " << m_oCoreConfig.oAudioDriverConfig.iBuffersize << " samples." );

	}
	catch( ... )
	{
		m_pAudioDriverBackend->finalize();

		delete m_pAudioDriverBackend;
		m_pAudioDriverBackend = nullptr;

		throw;
	}
}

void CVACoreImpl::FinalizeAudioDriver()
{
	if( m_pAudioDriverBackend )
	{
		VA_INFO( "Core", "Finalizing audio device \"" << m_oCoreConfig.oAudioDriverConfig.sDevice <<
			"\" [" << m_oCoreConfig.oAudioDriverConfig.sDriver << "]" );

		m_pAudioDriverBackend->finalize();
		delete m_pAudioDriverBackend;
		m_pAudioDriverBackend = nullptr;
	}
}

void CVACoreImpl::FinalizeRenderingModules()
{
	for( size_t i = 0; i < m_voRenderers.size(); i++ )
	{
		m_voRenderers[ i ].Finalize();
	}
}

void CVACoreImpl::FinalizeReproductionModules()
{
	for( size_t i = 0; i < m_voReproductionModules.size(); i++ )
	{
		m_voReproductionModules[ i ].Finalize();
	}
}

bool CVACoreImpl::IsStreaming() const
{
	return ( m_pAudioDriverBackend ? m_pAudioDriverBackend->isStreaming() : false );
}

void CVACoreImpl::InitializeAudioRenderers()
{
	CVAAudioRendererRegistry* pRegistry( CVAAudioRendererRegistry::GetInstance() );
	const CVAStruct& oConfig( GetCoreConfig()->GetStruct() );

	// Parse config for audio renderers and try to instantiate them
	CVAStruct::const_iterator cit = oConfig.Begin();
	while( cit != oConfig.End() )
	{
		const std::string& sKey( cit->first );
		const CVAStruct& oArgs( cit->second );

		std::vector< std::string > vsKeyParts = splitString( sKey, ':' );
		if( vsKeyParts.size() == 2 && cit->second.GetDatatype() == CVAStructValue::STRUCT )
		{
			std::string sCategory( toUppercase( vsKeyParts[ 0 ] ) );
			std::string sID( vsKeyParts[ 1 ] );

			if( sCategory == "RENDERER" )
			{
				CVAConfigInterpreter conf( oArgs );
				conf.SetErrorPrefix( "Configuration error in section \"" + cit->first + "\"" );
				std::string sClass;
				conf.ReqString( "Class", sClass );

				bool bEnabled;
				conf.OptBool( "Enabled", bEnabled, true );
				if( !bEnabled )
				{
					cit++;
					continue; // Skip
				}

				// Initialization parameters
				CVAAudioRendererInitParams oParams;
				oParams.sID = sID;
				oParams.sClass = sClass;
				oParams.pCore = this;
				oParams.pConfig = &cit->second.GetStruct();
				oParams.bOfflineRendering = ( m_oCoreConfig.oAudioDriverConfig.sDriver == "Virtual" ) ? true : false;

				conf.ReqStringListRegex( "Reproductions", oParams.vsReproductions, "\\s*,\\s*" );
				std::unique( oParams.vsReproductions.begin(), oParams.vsReproductions.end() );

				conf.OptBool( "OutputDetectorEnabled", oParams.bOutputLevelMeterEnabled, false );


				// Set up rendering output recording								
				conf.OptBool( "RecordOutputEnabled", oParams.bRecordOutputEnabled, false );
				if( oParams.bRecordOutputEnabled )
				{
					VistaFileSystemFile oRecordOutputFile( "renderer.wav" );
					VistaFileSystemDirectory oRecordOutputBaseFolder( "./" );

					std::string sFilePathRAWDeprecated;
					conf.OptString( "RecordOutputFilePath", sFilePathRAWDeprecated );
					if( !sFilePathRAWDeprecated.empty() )
					{
						VA_WARN( "Core", "The renderer configuration key 'RecordOutputFilePath' is deprecated. Use 'RecordOutputBaseFolder' (optional) and 'RecordOutputFileName' instead." );

						std::string sDummy;
						if( conf.OptString( "RecordOutputBaseFolder", sDummy ) || conf.OptString( "RecordOutputFileName", sDummy ) )
							VA_EXCEPT2( INVALID_PARAMETER, "You have combined old rendering configuration key 'RecordOutputFilePath' with one of the new keys 'RecordOutputBaseFolder' (optional) or 'RecordOutputFileName'. Please use new key only." );

						std::string sRecordOutputFilePath = m_oCoreConfig.mMacros.SubstituteMacros( sFilePathRAWDeprecated );
						oRecordOutputFile.SetName( sRecordOutputFilePath );
						oRecordOutputBaseFolder.SetName( oRecordOutputFile.GetParentDirectory() );
					}
					else
					{
						std::string sFileNameRAW;
						conf.ReqString( "RecordOutputFileName", sFileNameRAW );
						std::string sFileName = m_oCoreConfig.mMacros.SubstituteMacros( sFileNameRAW );
						oRecordOutputFile.SetName( sFileName );

						std::string sBaseFolderRAW;
						conf.ReqString( "RecordOutputBaseFolder", sBaseFolderRAW );
						std::string sBaseFolder = m_oCoreConfig.mMacros.SubstituteMacros( sBaseFolderRAW );
						oRecordOutputBaseFolder.SetName( sBaseFolder );
					}

					if( !oRecordOutputBaseFolder.Exists() )
					{
						if( oRecordOutputBaseFolder.CreateWithParentDirectories() )
						{
							VA_INFO( "Core", "Created renderer record output base folder " << oRecordOutputBaseFolder.GetName() << " with parent directories" );
						}
						else
						{
							VA_EXCEPT2( INVALID_PARAMETER, "Could not create non-existent renderer record base folder '" + oRecordOutputBaseFolder.GetName() + "'" );
						}
					}

					oParams.sRecordOutputFileName = oRecordOutputFile.GetLocalName();
					oParams.sRecordOutputBaseFolder = oRecordOutputBaseFolder.GetName();
				}


				// Get factory method to create requested rendering module (if available from registry)
				IVAAudioRendererFactory* pFactory = pRegistry->FindFactory( sClass );
				if( !pFactory )
					conf.Error( "Unknown class \"" + sClass + "\"" );

				IVAAudioRenderer* pRenderer = pFactory->Create( oParams );
				// TODO: Active umsetzen

				CVAAudioRendererDesc oRendererDesc( pRenderer );
				oRendererDesc.sID = sID;
				oRendererDesc.sClass = sClass;
				oRendererDesc.bEnabled = bEnabled;

				ITADatasource* pRendererOutputTail = pRenderer->GetOutputDatasource();;
				if( oParams.bRecordOutputEnabled )
				{
					std::string sFilePath = oParams.sRecordOutputBaseFolder + "/" + oParams.sRecordOutputFileName;

					if( VistaFileSystemFile( sFilePath ).Exists() )
						VA_INFO( "Core", "Rendering record file '" << sFilePath << "' exists, will overwrite" );

					VistaFileSystemFile oFile( sFilePath );
					oRendererDesc.pOutputRecorder = new ITAStreamProbe( pRendererOutputTail, oFile.GetName() );
					pRendererOutputTail = oRendererDesc.pOutputRecorder;
					VA_TRACE( "Core", "Rendering module will record output to file '" << oFile.GetName() << "'" );
				}

				if( oParams.bOutputLevelMeterEnabled )
				{
					oRendererDesc.pOutputDetector = new ITAStreamDetector( pRendererOutputTail );
					pRendererOutputTail = oRendererDesc.pOutputDetector;
				}

				// Setup the intermediate patchbay input [temporary]
				int iInput = m_pR2RPatchbay->AddInput( pRendererOutputTail );

				// Create direct output in output patchbay for each output group [todo, not allowed yet]
				for( size_t i = 0; i < oParams.vsReproductions.size(); i++ )
				{
					const std::string& sOutputID( oParams.vsReproductions[ i ] );

					const CVAHardwareOutput* pOutput = m_oCoreConfig.oHardwareSetup.GetOutput( sOutputID );
					if( pOutput )
					{
						// Output found, use direct out (no renderer)
						VA_EXCEPT2( NOT_IMPLEMENTED, "Direct output to an audio hardware group is currently not supported. Use the Talkthrough reproduction module instead." );
					}
				}

				oRendererDesc.iR2RPatchBayInput = iInput;
				oRendererDesc.vsOutputs = oParams.vsReproductions;
				m_voRenderers.push_back( oRendererDesc );
			}
		}
		cit++;
	}

	const size_t nNumRenderingModules = m_voRenderers.size();
	if( nNumRenderingModules == 1 )
	{
		VA_INFO( "Core", "Started one rendering module" );
	}
	else
	{
		VA_INFO( "Core", "Started " << nNumRenderingModules << " rendering modules" );
	}

	for( size_t i = 0; i < nNumRenderingModules; i++ )
	{
		std::string sReproductionFeedStr = ( m_voRenderers[ i ].vsOutputs.size() == 1 ) ? "one reproduction module." : std::to_string( long( m_voRenderers[ i ].vsOutputs.size() ) ) + " reproduction modules.";
		VA_INFO( "Core", "    +    " << m_voRenderers[ i ].sID << " (" << m_voRenderers[ i ].sClass << ") feeding " << sReproductionFeedStr );
	}
}

void CVACoreImpl::InitializeReproductionModules()
{
	CVAAudioReproductionRegistry* pRegistry( CVAAudioReproductionRegistry::GetInstance() );
	const CVAStruct& oConfig( GetCoreConfig()->GetStruct() );

	// Parse config for reproduction modules and try to instantiate them
	CVAStruct::const_iterator cit = oConfig.Begin();
	while( cit != oConfig.End() )
	{
		const std::string& sKey( cit->first );
		const CVAStruct& oArgs( cit->second );

		std::vector< std::string > vsKeyParts = splitString( sKey, ':' );
		if( vsKeyParts.size() == 2 && cit->second.GetDatatype() == CVAStructValue::STRUCT )
		{
			std::string sCategory( toUppercase( vsKeyParts[ 0 ] ) );

			if( sCategory == "REPRODUCTION" )
			{
				CVAConfigInterpreter conf( oArgs );
				conf.SetErrorPrefix( "Configuration error in section \"" + cit->first + "\"" );

				// Initialization parameters
				CVAAudioReproductionInitParams oParams;
				oParams.pCore = this;
				oParams.pConfig = &cit->second.GetStruct();

				oParams.sID = vsKeyParts[ 1 ];
				conf.ReqString( "Class", oParams.sClass );

				bool bEnabled;
				conf.OptBool( "Enabled", bEnabled, true );
				if( !bEnabled )
				{
					cit++;
					continue; // Skip this entry
				}

				conf.OptBool( "InputDetectorEnabled", oParams.bInputDetectorEnabled, false );
				conf.OptBool( "OutputDetectorEnabled", oParams.bOutputDetectorEnabled, false );


				// Set up reproduction output recording			

				conf.OptBool( "RecordInputEnabled", oParams.bRecordInputEnabled, false );
				if( oParams.bRecordInputEnabled )
				{
					VistaFileSystemFile oRecordInputFile( "reproduction.wav" );
					VistaFileSystemDirectory oRecordInputFolder( "./" );

					std::string sFilePathRAWDeprecated;
					conf.OptString( "RecordInputFilePath", sFilePathRAWDeprecated );
					if( !sFilePathRAWDeprecated.empty() )
					{
						VA_WARN( "Core", "The reproduction configuration key 'RecordInputFilePath' is deprecated. Use 'RecordInputBaseFolder' (optional) and 'RecordInputFileName' instead." );

						std::string sDummy;
						if( conf.OptString( "RecordInputBaseFolder", sDummy ) || conf.OptString( "RecordInputFileName", sDummy ) )
							VA_EXCEPT2( INVALID_PARAMETER, "You have combined old reproduction configuration key 'RecordInputFilePath' with one of the new keys 'RecordInputBaseFolder' (optional) or 'RecordInputFileName'. Please use new key only." );

						std::string sRecordInputFilePath = m_oCoreConfig.mMacros.SubstituteMacros( sFilePathRAWDeprecated );
						oRecordInputFile.SetName( sRecordInputFilePath );
						oRecordInputFolder.SetName( oRecordInputFile.GetParentDirectory() );
					}
					else
					{
						std::string sFileNameRAW;
						conf.ReqString( "RecordInputFileName", sFileNameRAW );
						std::string sFileName = m_oCoreConfig.mMacros.SubstituteMacros( sFileNameRAW );
						oRecordInputFile.SetName( sFileName );

						std::string sBaseFolderRAW;
						conf.ReqString( "RecordInputBaseFolder", sBaseFolderRAW );
						std::string sBaseFolder = m_oCoreConfig.mMacros.SubstituteMacros( sBaseFolderRAW );
						oRecordInputFolder.SetName( sBaseFolder );
					}

					if( !oRecordInputFolder.Exists() )
					{
						if( oRecordInputFolder.CreateWithParentDirectories() )
						{
							VA_INFO( "Core", "Created reproduction input record base folder " << oRecordInputFolder.GetName() << " with parent directories" );
						}
						else
						{
							VA_EXCEPT2( INVALID_PARAMETER, "Could not create non-existent reproduction input record base folder '" + oRecordInputFolder.GetName() + "'" );
						}
					}

					oParams.sRecordInputFileName = oRecordInputFile.GetLocalName();
					oParams.sRecordInputBaseFolder = oRecordInputFolder.GetName();
				}


				// Set up reproduction output recording

				conf.OptBool( "RecordOutputEnabled", oParams.bRecordOutputEnabled, false );
				if( oParams.bRecordOutputEnabled )
				{
					VistaFileSystemFile oRecordOutputFile( "reproduction.wav" );
					VistaFileSystemDirectory oRecordOutputBaseFolder( "./" );

					std::string sFilePathRAWDeprecated;
					conf.OptString( "RecordOutputFilePath", sFilePathRAWDeprecated );
					if( !sFilePathRAWDeprecated.empty() )
					{
						VA_WARN( "Core", "The reproduction configuration key 'RecordOutputFilePath' is deprecated. Use 'RecordOutputBaseFolder' (optional) and 'RecordOutputFileName' instead." );

						std::string sDummy;
						if( conf.OptString( "RecordOutputBaseFolder", sDummy ) || conf.OptString( "RecordOutputFileName", sDummy ) )
							VA_EXCEPT2( INVALID_PARAMETER, "You have combined old reproduction configuration key 'RecordOutputFilePath' with one of the new keys 'RecordOutputBaseFolder' (optional) or 'RecordOutputFileName'. Please use new key only." );

						std::string sRecordOutputFilePath = m_oCoreConfig.mMacros.SubstituteMacros( sFilePathRAWDeprecated );
						oRecordOutputFile.SetName( sRecordOutputFilePath );
						oRecordOutputBaseFolder.SetName( oRecordOutputFile.GetParentDirectory() );
					}
					else
					{
						std::string sFileNameRAW;
						conf.ReqString( "RecordOutputFileName", sFileNameRAW );
						std::string sFileName = m_oCoreConfig.mMacros.SubstituteMacros( sFileNameRAW );
						oRecordOutputFile.SetName( sFileName );

						std::string sBaseFolderRAW;
						conf.ReqString( "RecordOutputBaseFolder", sBaseFolderRAW );
						std::string sBaseFolder = m_oCoreConfig.mMacros.SubstituteMacros( sBaseFolderRAW );
						oRecordOutputBaseFolder.SetName( sBaseFolder );
					}

					if( !oRecordOutputBaseFolder.Exists() )
					{
						if( oRecordOutputBaseFolder.CreateWithParentDirectories() )
						{
							VA_INFO( "Core", "Created reproduction output record base folder " << oRecordOutputBaseFolder.GetName() << " with parent directories" );
						}
						else
						{
							VA_EXCEPT2( INVALID_PARAMETER, "Could not create non-existent reproduction output record base folder '" + oRecordOutputBaseFolder.GetName() + "'" );
						}
					}

					oParams.sRecordOutputFileName = oRecordOutputFile.GetLocalName();
					oParams.sRecordOutputBaseFolder = oRecordOutputBaseFolder.GetName();
				}


				// Parse outputs
				std::vector< std::string > vsOutputs;
				conf.ReqStringListRegex( "Outputs", vsOutputs, "\\s*,\\s*" );
				std::unique( vsOutputs.begin(), vsOutputs.end() ); // Uniqueness, baby!

				// Check outputs in hardware setup
				std::vector< std::string >::const_iterator cjt = vsOutputs.begin();
				while( cjt != vsOutputs.end() )
				{
					const std::string& sOutput( *cjt );
					const CVAHardwareOutput* pOutput = m_oCoreConfig.oHardwareSetup.GetOutput( sOutput );
					if( pOutput == nullptr )
						conf.Error( "Referring to unknown output \"" + sOutput + "\"" );
					oParams.vpOutputs.push_back( pOutput );
					cjt++;
				}

				// Register this reproduction module
				IVAAudioReproductionFactory* pFactory = pRegistry->FindFactory( oParams.sClass );
				if( !pFactory )
					conf.Error( "Unknown class \"" + oParams.sClass + "\"" );

				// Create the module
				CVAAudioReproductionModuleDesc oDesc( pFactory->Create( oParams ) );
				oDesc.sID = oParams.sID;
				oDesc.sClass = oParams.sClass;
				oDesc.vpOutputs = oParams.vpOutputs;
				oDesc.bEnabled = bEnabled;

				// Add output in Renderer-to-Reproduction patch bay
				int iReproductionModuleNumInputChannels = oDesc.pInstance->GetNumInputChannels();
				oDesc.iR2RPatchBayOutput = m_pR2RPatchbay->AddOutput( iReproductionModuleNumInputChannels );

				ITADatasource* pInputTail = m_pR2RPatchbay->GetOutputDatasource( oDesc.iR2RPatchBayOutput );
				if( oParams.bInputDetectorEnabled )
				{
					oDesc.pInputDetector = new ITAStreamDetector( pInputTail );
					pInputTail = oDesc.pInputDetector;
				}
				if( oParams.bRecordInputEnabled )
				{
					std::string sFilePath = oParams.sRecordInputBaseFolder + "/" + oParams.sRecordInputFileName;
					VistaFileSystemFile oFile( sFilePath );

					if( oFile.Exists() )
						VA_INFO( "Core", "Reproduction input record file '" << oFile.GetName() << "' exists, will overwrite" );
					
					oDesc.pInputRecorder = new ITAStreamProbe( pInputTail, oFile.GetName() );
					pInputTail = oDesc.pInputRecorder;
					VA_TRACE( "Core", "Reproduction will record input to file '" << oFile.GetName() << "'" );
				}

				// Assign Renderer-to-Reproduction patch bay output datasource as input for reproduction module
				oDesc.pInstance->SetInputDatasource( pInputTail );


				ITADatasource* pOutputTail = oDesc.pInstance->GetOutputDatasource();
				if( oParams.bOutputDetectorEnabled )
				{
					oDesc.pOutputDetector = new ITAStreamDetector( pOutputTail );
					pOutputTail = oDesc.pOutputDetector;
				}
				if( oParams.bRecordOutputEnabled )
				{
					std::string sFilePath = oParams.sRecordOutputBaseFolder + "/" + oParams.sRecordOutputFileName;
					VistaFileSystemFile oFile( sFilePath );

					if( oFile.Exists() )
						VA_INFO( "Core", "Reproduction output record file '" << oFile.GetName() << "' exists, will overwrite" );
					
					oDesc.pOutputRecorder = new ITAStreamProbe( pOutputTail, oFile.GetName() );
					pOutputTail = oDesc.pOutputRecorder;
					VA_TRACE( "Core", "Reproduction will record output to file '" << oFile.GetName() << "'" );
				}

				// Add input in output patch bay and assign reproduction module datasource output to this input
				oDesc.iOutputPatchBayInput = m_pOutputPatchbay->AddInput( pOutputTail );

				// TODO: Active umsetzen ggf. in Params rein
				m_voReproductionModules.push_back( oDesc );
			}
		}
		cit++;
	}

	const size_t nNumReproductionModules = m_voReproductionModules.size();
	if( nNumReproductionModules == 1 )
	{
		VA_INFO( "Core", "Started one reproduction module" );
	}
	else
	{
		VA_INFO( "Core", "Started " << nNumReproductionModules << " reproduction modules" );
	}

	for( size_t i = 0; i < nNumReproductionModules; i++ )
	{
		std::string sOutputGroupFeedStr = ( m_voReproductionModules[ i ].vpOutputs.size() == 1 ) ? "one output group." : std::to_string( long( m_voReproductionModules[ i ].vpOutputs.size() ) ) + " output groups.";
		VA_INFO( "Core", "    +    " << m_voReproductionModules[ i ].sID << " (" << m_voReproductionModules[ i ].sClass << ") feeding " << sOutputGroupFeedStr );
	}

	return;
}

void CVACoreImpl::PatchRendererToReproductionModules()
{
	std::vector<CVAAudioRendererDesc>::iterator rendit = m_voRenderers.begin();
	while( rendit != m_voRenderers.end() )
	{
		const CVAAudioRendererDesc& renddesc( *rendit );
		int iRendererNumOutputChannels = renddesc.pInstance->GetOutputDatasource()->GetNumberOfChannels();
		int iRendererR2RPatchBayInput = renddesc.iR2RPatchBayInput;

		// Iterate over all target reproduction modules
		std::vector< std::string >::const_iterator ocit = renddesc.vsOutputs.begin();
		while( ocit != renddesc.vsOutputs.end() )
		{
			const std::string& sTargetReproductionModule( *ocit );

			std::vector< CVAAudioReproductionModuleDesc >::const_iterator repcit = m_voReproductionModules.begin();
			while( repcit != m_voReproductionModules.end() )
			{
				const CVAAudioReproductionModuleDesc& repdesc( *repcit );
				if( repdesc.sID == sTargetReproductionModule )
				{
					// Get R2R patch bay output of target reproduction module and patch channels from renderer input
					for( int k = 0; k < iRendererNumOutputChannels; k++ )
						m_pR2RPatchbay->ConnectChannels( iRendererR2RPatchBayInput, k, repdesc.iR2RPatchBayOutput, k );

					break; // break after target reproduction module is patched and continue with next
				}
				repcit++;
			}
			ocit++;
		}
		rendit++;
	}

	return;
}

void CVACoreImpl::PatchReproductionModulesToOutput()
{
	int iMaxPhysicalChannelsAvailable = m_pOutputPatchbay->GetOutputNumChannels( 0 );

	std::vector<CVAAudioReproductionModuleDesc>::iterator it = m_voReproductionModules.begin();
	while( it != m_voReproductionModules.end() )
	{
		CVAAudioReproductionModuleDesc& oRepDesc( *it );

		std::vector< const CVAHardwareOutput* >::iterator jt = oRepDesc.vpOutputs.begin();
		while( jt != oRepDesc.vpOutputs.end() )
		{
			const CVAHardwareOutput* pOutput( *jt );

			// Only consider outputs for patching, that are set enabled via configuration
			if( pOutput->IsEnabled() == false )
			{
				jt++;
				continue;
			}

			for( size_t k = 0; k < pOutput->GetPhysicalOutputChannels().size(); k++ )
			{
				int iPhysicalOutputChannel = pOutput->GetPhysicalOutputChannels()[ k ] - 1;
				if( iPhysicalOutputChannel < iMaxPhysicalChannelsAvailable )
					m_pOutputPatchbay->ConnectChannels( oRepDesc.iOutputPatchBayInput, int( k ), 0, iPhysicalOutputChannel );
				else
					VA_EXCEPT2( INVALID_PARAMETER, "VACore/ConnectRendererWithReproductionModules: Group '" +
					pOutput->sIdentifier + "' output channel out of range for this sound card" );
			}
			jt++;
		}
		it++;
	}

	return;
}


void CVACoreImpl::RecursiveFileList( const std::string& sBasePath, CVAStruct& oFileList, const std::string sFileSuffixMask ) const
{
	std::vector< std::string > vsFileList;
	FileList( sBasePath, vsFileList, sFileSuffixMask );

	CVAStruct oMoreFiles;
	for( size_t j = 0; j < vsFileList.size(); j++ )
		oMoreFiles[ std::to_string( long( j ) ) ] = vsFileList[ j ];

	oFileList[ sBasePath ] = oMoreFiles;

	std::vector< std::string > vsFolderList;
	FolderList( sBasePath, vsFolderList );

	for( size_t j = 0; j < vsFolderList.size(); j++ )
		RecursiveFileList( vsFolderList[ j ], oFileList, sFileSuffixMask );
}

void CVACoreImpl::FolderList( const std::string& sBasePath, std::vector< std::string >& vsFolderList ) const
{
	vsFolderList.clear();
	VistaFileSystemDirectory oFolder( sBasePath );
	if( !oFolder.Exists() || !oFolder.IsDirectory() )
		return;

	VistaFileSystemDirectory::const_iterator cit = oFolder.begin();
	while( cit != oFolder.end() )
	{
		VistaFileSystemNode* pNode( *cit++ );
		if( pNode->IsDirectory() && pNode->GetLocalName() != "." && pNode->GetLocalName() != ".." )
			vsFolderList.push_back( pNode->GetName() );
	}
}

void CVACoreImpl::FileList( const std::string& sBasePath, std::vector< std::string >& vsFileList, const std::string& sFileSuffixMask ) const
{
	vsFileList.clear();

	VistaFileSystemDirectory oFolder( sBasePath );
	if( !oFolder.Exists() || !oFolder.IsDirectory() )
		return;

	VistaFileSystemDirectory::const_iterator cit = oFolder.begin();
	while( cit != oFolder.end() )
	{
		VistaFileSystemNode* pNode( *cit++ );
		if( pNode->IsFile() )
		{
			const std::string sFileName = pNode->GetLocalName();
			if( sFileSuffixMask != "*" && !sFileSuffixMask.empty() )
			{
				if( sFileName.substr( sFileName.find_last_of( "." ) + 1 ).compare( sFileSuffixMask ) )
					vsFileList.push_back( pNode->GetName() );
			}
			else
				vsFileList.push_back( pNode->GetName() );
		}
	}
}

// --= Progress =---------------------------------------------------

ITACriticalSection m_csProgress;
CVAProgress m_Progress;

void CVACoreImpl::InitProgress( const std::string& sAction, const std::string& sSubaction, const int iMaxStep )
{
	m_csProgress.enter();

	m_Progress.sAction = sAction;
	m_Progress.sSubaction = sSubaction;
	m_Progress.iCurrentStep = 0;
	m_Progress.iMaxStep = iMaxStep;

	// Fortschritts-Ereignis senden
	CVAEvent ev;
	ev.iEventType = CVAEvent::PROGRESS_UPDATE;
	ev.pSender = this;
	ev.oProgress = m_Progress;
	m_pEventManager->BroadcastEvent( ev );

	m_csProgress.leave();
}

void CVACoreImpl::SetProgress( const std::string& sAction, const std::string& sSubaction, const int iCurrentStep )
{
	m_csProgress.enter();

	m_Progress.sAction = sAction;
	m_Progress.sSubaction = sSubaction;
	m_Progress.iCurrentStep = iCurrentStep;

	// Fortschritts-Ereignis senden
	CVAEvent ev;
	ev.iEventType = CVAEvent::PROGRESS_UPDATE;
	ev.pSender = this;
	ev.oProgress = m_Progress;
	m_pEventManager->BroadcastEvent( ev );

	m_csProgress.leave();
}

void CVACoreImpl::FinishProgress()
{
	m_csProgress.enter();

	// Die Aktionen bleiben, nur die aktuelle Schritt = maximaler Schritt
	m_Progress.iCurrentStep = m_Progress.iMaxStep;

	// Fortschritts-Ereignis senden
	CVAEvent ev;
	ev.iEventType = CVAEvent::PROGRESS_UPDATE;
	ev.pSender = this;
	ev.oProgress = m_Progress;
	m_pEventManager->BroadcastEvent( ev );

	m_csProgress.leave();
}

/* +----------------------------------------------------------+ *
 * |                                                          | *
 * |   Core-Thread                                            | *
 * |                                                          | *
 * +----------------------------------------------------------+ */

void CVACoreImpl::CoreThreadLoop()
{
	m_oCoreThreadLoopTotalDuration.start();

	assert( m_pCurSceneState != nullptr );
	assert( m_pCurSceneState->GetNumReferences() >= 1 );

	// Auf nderungen der Szene berprfen
	CVASceneState* pNewSceneState = m_pSceneManager->GetHeadSceneState();

	assert( pNewSceneState != nullptr );
	assert( pNewSceneState->GetNumReferences() >= 1 );

	pNewSceneState->AddReference();

	// TODO: Aktiver Hrer wird erstmal ignoriert.
	//int iNewActiveListener = m_iNewActiveListener;

	if( pNewSceneState != m_pCurSceneState )
	{
		VA_TRACE( "CoreThread", "Update scene state " << m_pCurSceneState->GetID() << " -> " << pNewSceneState->GetID() );

		// Audio renderer
		std::vector< CVAAudioRendererDesc >::iterator rendit = m_voRenderers.begin();
		while( rendit != m_voRenderers.end() )
		{
			CVAAudioRendererDesc& rendesc( *rendit );
			rendesc.pInstance->UpdateScene( pNewSceneState );
			rendit++;
		}

		// Audio reproduction modules
		std::vector< CVAAudioReproductionModuleDesc >::iterator repit = m_voReproductionModules.begin();
		while( repit != m_voReproductionModules.end() )
		{
			CVAAudioReproductionModuleDesc& repdesc( *repit );
			repdesc.pInstance->UpdateScene( pNewSceneState );
			repit++;
		}
	}


	// nderung des globalen Auralisierungsmodus in den Schallpfaden bercksichtigen
	/**
	  * Da es keine Versionierung des AuraModes gibt, muss der Audio
	  * Renderer selbst entscheiden, was zu tun ist.
	  */
	std::vector< CVAAudioRendererDesc >::iterator rendit = m_voRenderers.begin();
	while( rendit != m_voRenderers.end() )
	{
		CVAAudioRendererDesc& rendesc( *rendit );
		rendesc.pInstance->UpdateGlobalAuralizationMode( m_iGlobalAuralizationMode );

		rendit++;
	}

	// Referenzen verwalten: Alter Szenezustand wird nun nicht mehr bentigt
	if( m_pCurSceneState != pNewSceneState )
	{
		// Alter Zustand wird nicht mehr bentigt
		m_pCurSceneState->RemoveReference();

		// Aktuelle Szene ist nun die neu erzeugte (abgeleitete) Szene
		m_pCurSceneState = pNewSceneState;
	}
	else
	{
		// Remove reference of new/current state again
		pNewSceneState->RemoveReference();
	}

	m_oCoreThreadLoopTotalDuration.stop();

	// @todo: signal event to process object calls (in-sync exec with internal core)

	return;
}

void CVACoreImpl::SendAudioDeviceDetectorUpdateEvent()
{
	CVAEvent ev;
	ev.iEventType = CVAEvent::MEASURES_UPDATE;
	ev.pSender = this;

	if( m_pInputStreamDetector )
	{
		ev.vfInputPeaks.resize( m_oCoreConfig.oAudioDriverConfig.iInputChannels );
		m_pInputStreamDetector->GetPeaks( ev.vfInputPeaks, true );
		ev.vfInputRMSs.resize( m_oCoreConfig.oAudioDriverConfig.iInputChannels );
		m_pInputStreamDetector->GetRMSs( ev.vfInputRMSs, true );
	}

	if( m_pOutputStreamDetector )
	{
		ev.vfOutputPeaks.resize( m_oCoreConfig.oAudioDriverConfig.iOutputChannels );
		m_pOutputStreamDetector->GetPeaks( ev.vfOutputPeaks, true );
		ev.vfOutputRMSs.resize( m_oCoreConfig.oAudioDriverConfig.iOutputChannels );
		m_pOutputStreamDetector->GetRMSs( ev.vfOutputRMSs, true );
	}

	ev.fSysLoad = 0;
	// TODO: Sollte am Ende gemessen werden! => StreamTracker
	ev.fDSPLoad = 0;
	//ev.fDSPLoad = m_pAudiostreamProcessor->GetDSPLoad();

	m_pEventManager->BroadcastEvent( ev );
}

void CVACoreImpl::SendRenderingModuleOutputDetectorsUpdateEvents()
{
	for( size_t i = 0; i < m_voRenderers.size(); i++ )
	{
		CVAAudioRendererDesc& oRenderer( m_voRenderers[ i ] );

		CVAEvent ev;
		ev.iEventType = CVAEvent::MEASURES_UPDATE;
		ev.pSender = this;
		ev.sObjectID = oRenderer.sID;
		ev.sParam = "RenderingModule"; // Use generic parameter slot to mark rendering module source

		if( oRenderer.pOutputDetector )
		{
			ev.vfOutputRMSs.resize( oRenderer.pOutputDetector->GetNumberOfChannels() );
			oRenderer.pOutputDetector->GetRMSs( ev.vfOutputRMSs, true );
			ev.vfOutputPeaks.resize( oRenderer.pOutputDetector->GetNumberOfChannels() );
			oRenderer.pOutputDetector->GetPeaks( ev.vfOutputPeaks, true );
		}

		m_pEventManager->BroadcastEvent( ev );
		}
	}

void CVACoreImpl::SendReproductionModuleOIDetectorsUpdateEvents()
{
	for( size_t i = 0; i < m_voReproductionModules.size(); i++ )
	{
		CVAAudioReproductionModuleDesc& oReproduction( m_voReproductionModules[ i ] );

		CVAEvent ev;
		ev.iEventType = CVAEvent::MEASURES_UPDATE;
		ev.pSender = this;
		ev.sObjectID = oReproduction.sID;
		ev.sParam = "ReproductionModule"; // Use generic parameter slot to mark reproduction module source

		if( oReproduction.pInputDetector )
		{
			ev.vfInputRMSs.resize( oReproduction.pInputDetector->GetNumberOfChannels() );
			oReproduction.pInputDetector->GetRMSs( ev.vfInputRMSs, true );
			ev.vfInputPeaks.resize( oReproduction.pInputDetector->GetNumberOfChannels() );
			oReproduction.pInputDetector->GetPeaks( ev.vfInputPeaks, true );
		}

		if( oReproduction.pOutputDetector )
		{
			ev.vfOutputRMSs.resize( oReproduction.pOutputDetector->GetNumberOfChannels() );
			oReproduction.pOutputDetector->GetRMSs( ev.vfOutputRMSs, true );
			ev.vfOutputPeaks.resize( oReproduction.pOutputDetector->GetNumberOfChannels() );
			oReproduction.pOutputDetector->GetPeaks( ev.vfOutputPeaks, true );
		}

		m_pEventManager->BroadcastEvent( ev );
	}
}

bool CVACoreImpl::operator()()
{
#ifndef DO_NOT_SEND_MEASURE_UPDATE_EVENTS

	// Audio device I/O detectors
	SendAudioDeviceDetectorUpdateEvent();

	// Rendering module output detectors
	SendRenderingModuleOutputDetectorsUpdateEvents();

	// Rerproduction module I/O detectors
	SendReproductionModuleOIDetectorsUpdateEvents();

	return true;
#else
	return false;
#endif
}

CVAObjectInfo CVACoreImpl::GetObjectInfo() const
{
	CVAObjectInfo oCoreModuleInfo;
	oCoreModuleInfo.iID = GetObjectID();
	oCoreModuleInfo.sName = GetObjectName();
	oCoreModuleInfo.sDesc = "VA core module";
	return oCoreModuleInfo;
}

// Handle calls to the kernel from the module interface
CVAStruct CVACoreImpl::CallObject( const CVAStruct& oArgs )
{
	VA_VERBOSE( "Core", "Core module has been called" );
	CVAStruct oReturn;

	if( oArgs.HasKey( "help" ) || oArgs.HasKey( "info" ) || oArgs.IsEmpty() )
	{
		oReturn[ "help" ] = "Get comprehensive help online at http://www.virtualacoustics.org ...";
		oReturn[ "version" ] = "Returns version information";
		oReturn[ "addsearchpath" ] = "Adds a search path";
		oReturn[ "getsearchpaths" ] = "Returns all search paths";
		oReturn[ "getloglevel" ] = "Returns current core log level (integer)";
		oReturn[ "setloglevel" ] = "Sets current core log level (integer)";
		oReturn[ "structrebound" ] = "Rebounds argument of any content to client (for testing VA structs)";
	}

	if( oArgs.HasKey( "version" ) )
	{
		CVAVersionInfo oVersionInfo;
		GetVersionInfo( &oVersionInfo );
		oReturn[ "comments" ] = oVersionInfo.sComments;
		oReturn[ "date" ] = oVersionInfo.sDate;
		oReturn[ "flags" ] = oVersionInfo.sFlags;
		oReturn[ "version" ] = oVersionInfo.sVersion;
		oReturn[ "string" ] = oVersionInfo.ToString();
	}

	if( oArgs.HasKey( "addsearchpath" ) )
	{
		if( oArgs[ "addsearchpath" ].IsString() )
		{
			std::string sPath = oArgs[ "addsearchpath" ];
			VistaFileSystemDirectory oDir( sPath );
			oReturn[ "pathvalid" ] = false;
			if( oDir.Exists() )
			{
				m_oCoreConfig.vsSearchPaths.push_back( sPath );
				oReturn[ "pathvalid" ] = true;
			}
		}
	}

	if( oArgs.HasKey( "getsearchpaths" ) )
	{
		CVAStruct oSearchPaths;
		for( size_t i = 0; i < m_oCoreConfig.vsSearchPaths.size(); i++ )
			oSearchPaths[ "path_" + std::to_string( long( i ) ) ] = m_oCoreConfig.vsSearchPaths[ i ];
		oReturn[ "searchpaths" ] = oSearchPaths;
	}

	if( oArgs.HasKey( "getmacros" ) )
	{
		CVAStruct oMacros;
		for( auto& macro : m_oCoreConfig.mMacros.GetMacroMapCopy() )
			oMacros[ macro.first ] = macro.second;
		oReturn[ "macros" ] = oMacros;
	}

	if( oArgs.HasKey( "getloglevel" ) )
	{
		oReturn[ "loglevel" ] = VALog_GetLogLevel();
	}

	if( oArgs.HasKey( "setloglevel" ) )
	{
		int iLogLevel = oArgs[ "setloglevel" ];
		VALog_SetLogLevel( iLogLevel );
	}
	if( oArgs.HasKey( "structrebound" ) )
	{
		oReturn = oArgs[ "structrebound" ];
	}

	if( oArgs.HasKey( "shutdown" ) || oArgs.HasKey( "finalize" ) || oArgs.HasKey( "stop" ) )
	{
		VA_WARN( "Core", "Received shutdown request" );
		if( GetCoreConfig()->bRemoteShutdownAllowed )
		{
			VA_TRACE( "Core", "Accepting remote shutdown request, will broadcast shutdown event" );

			CVAEvent ev;
			ev.pSender = this;
			ev.iEventType = CVAEvent::SHOTDOWN_REQUEST;
			ev.sParam = "shutdown";
			m_pEventManager->BroadcastEvent( ev );

			VA_TRACE( "Core", "Shutdown performed" );
		}
		else
		{
			VA_WARN( "Core", "Shutdown request denied, the core configuration does not accept a remote shutdown" );
		}
	}

	bool bUpdateRecordInputPath = false;
	if( oArgs.HasKey( "Audio device/RecordInputFileName" ) )
	{
		m_oCoreConfig.sRecordDeviceInputFileName = oArgs[ "Audio device/RecordInputFileName" ];
		bUpdateRecordInputPath = true;
	}
	if( oArgs.HasKey( "Audio device/RecordInputBaseFolder" ) )
	{
		m_oCoreConfig.sRecordDeviceInputBaseFolder = oArgs[ "Audio device/RecordInputBaseFolder" ];
		bUpdateRecordInputPath = true;
	}

	if( bUpdateRecordInputPath )
	{
		VistaFileSystemFile oFile( m_oCoreConfig.sRecordDeviceInputFileName );
		VistaFileSystemDirectory oFolder( m_oCoreConfig.sRecordDeviceInputBaseFolder );
			 
		VistaFileSystemFile oFilePath( oFolder.GetName() + "/" + oFile.GetLocalName() );
		VA_INFO( "Core", "Updating record device input file path to " << oFilePath.GetName() );

		if( oFilePath.Exists() )
			VA_INFO( "Core", "Record device input file path exists, will overwrite" );

		if( !oFolder.Exists() )
			if( !oFolder.CreateWithParentDirectories() )
				VA_EXCEPT2( INVALID_PARAMETER, "Could not create record device output directory " + oFolder.GetName() );

		m_pStreamProbeDeviceInput->SetFilePath( oFilePath.GetName() );
	}


	bool bUpdateRecordOutputPath = false;
	if( oArgs.HasKey( "Audio device/RecordOutputFileName" ) )
	{
		m_oCoreConfig.sRecordDeviceOutputFileName = oArgs[ "Audio device/RecordOutputFileName" ];
		bUpdateRecordOutputPath = true;
	}
	if( oArgs.HasKey( "Audio device/RecordOutputBaseFolder" ) )
	{
		m_oCoreConfig.sRecordDeviceOutputBaseFolder = oArgs[ "Audio device/RecordOutputBaseFolder" ];
		bUpdateRecordOutputPath = true;
	}

	if( bUpdateRecordOutputPath )
	{
		VistaFileSystemFile oFile( m_oCoreConfig.sRecordDeviceOutputFileName );
		VistaFileSystemDirectory oFolder( m_oCoreConfig.sRecordDeviceOutputBaseFolder );

		VistaFileSystemFile oFilePath( oFolder.GetName() + "/" + oFile.GetLocalName() );
		VA_INFO( "Core", "Updating record device output file path to " << oFilePath.GetName() );

		if( oFilePath.Exists() )
			VA_INFO( "Core", "Record device output file path exists, will overwrite" );

		if( !oFolder.Exists() )
			if( !oFolder.CreateWithParentDirectories() )
				VA_EXCEPT2( INVALID_PARAMETER, "Could not create record device output directory " + oFolder.GetName() );

		m_pStreamProbeDeviceOutput->SetFilePath( oFilePath.GetName() );
	}


	VA_VERBOSE( "Core", "Core module will transmit answer now" );
	return oReturn;
}

const CVACoreConfig* CVACoreImpl::GetCoreConfig() const
{
	return &m_oCoreConfig;
}

const CVASceneManager* CVACoreImpl::GetSceneManager() const
{
	return m_pSceneManager;
}

const CVAAudioSignalSourceManager* CVACoreImpl::GetSignalSourceManager() const
{
	return m_pSignalSourceManager;
}

void CVACoreImpl::SetRenderingModuleMuted( const std::string& sModuleID, const bool bMuted )
{
	for( size_t n = 0; n < m_voRenderers.size(); n++ )
	{
		const CVAAudioRendererDesc& oRend( m_voRenderers[ n ] );
		if( oRend.sID == sModuleID )
		{
			m_pR2RPatchbay->SetInputMuted( oRend.iR2RPatchBayInput, bMuted );
			return;
		}
	}

	VA_ERROR( "Core", "Could not find rendering module '" << sModuleID << "'" );
}

void CVACoreImpl::SetRenderingModuleGain( const std::string& sModuleID, const double dGain )
{
	for( size_t n = 0; n < m_voRenderers.size(); n++ )
	{
		const CVAAudioRendererDesc& oRend( m_voRenderers[ n ] );
		if( oRend.sID == sModuleID )
		{
			m_pR2RPatchbay->SetInputGain( oRend.iR2RPatchBayInput, dGain );
			return;
		}
	}

	VA_ERROR( "Core", "Could not find rendering module '" << sModuleID << "'" );
}

double CVACoreImpl::GetRenderingModuleGain( const std::string& sModuleID ) const
{
	for( size_t n = 0; n < m_voRenderers.size(); n++ )
	{
		const CVAAudioRendererDesc& oRend( m_voRenderers[ n ] );
		if( oRend.sID == sModuleID )
			return m_pR2RPatchbay->GetInputGain( oRend.iR2RPatchBayInput );
	}

	VA_ERROR( "Core", "Could not find rendering module '" << sModuleID << "'" );
	return 0.0f;
}

void CVACoreImpl::SetRenderingModuleAuralizationMode( const std::string& sModuleID, const int iAM )
{
	for( size_t n = 0; n < m_voRenderers.size(); n++ )
	{
		const CVAAudioRendererDesc& oRend( m_voRenderers[ n ] );
		if( oRend.sID == sModuleID )
		{
			oRend.pInstance->UpdateGlobalAuralizationMode( iAM );
			return;
		}
	}

	VA_ERROR( "Core", "Could not find rendering module '" << sModuleID << "'" );
}

int CVACoreImpl::GetRenderingModuleAuralizationMode( const std::string& sModuleID ) const
{
	for( size_t n = 0; n < m_voRenderers.size(); n++ )
	{
		const CVAAudioRendererDesc& oRend( m_voRenderers[ n ] );
		if( oRend.sID == sModuleID )
			return oRend.pInstance->GetAuralizationMode();
	}

	VA_EXCEPT2( INVALID_PARAMETER, "Could not find rendering module '" + sModuleID + "'" );
}

bool CVACoreImpl::GetRenderingModuleMuted( const std::string& sModuleID ) const
{
	for( size_t n = 0; n < m_voRenderers.size(); n++ )
	{
		const CVAAudioRendererDesc& oRend( m_voRenderers[ n ] );
		if( oRend.sID == sModuleID )
			return m_pR2RPatchbay->IsInputMuted( oRend.iR2RPatchBayInput );
	}

	VA_ERROR( "Core", "Could not find rendering module '" << sModuleID << "'" );
	return true;
}

void CVACoreImpl::SetReproductionModuleMuted( const std::string& sModuleID, const bool bMuted )
{
	for( size_t n = 0; n < m_voReproductionModules.size(); n++ )
	{
		const CVAAudioReproductionModuleDesc& oRepro( m_voReproductionModules[ n ] );
		if( oRepro.sID == sModuleID )
		{
			m_pOutputPatchbay->SetInputMuted( oRepro.iOutputPatchBayInput, bMuted );
			return;
		}
	}

	VA_ERROR( "Core", "Could not find reproduction module '" << sModuleID << "'" );
}

void CVACoreImpl::SetReproductionModuleGain( const std::string& sModuleID, const double dGain )
{
	for( size_t n = 0; n < m_voReproductionModules.size(); n++ )
	{
		const CVAAudioReproductionModuleDesc& oRepro( m_voReproductionModules[ n ] );
		if( oRepro.sID == sModuleID )
		{
			m_pOutputPatchbay->SetInputGain( oRepro.iOutputPatchBayInput, dGain );
			return;
		}
	}

	VA_ERROR( "Core", "Could not find reproduction module '" << sModuleID << "'" );
}

double CVACoreImpl::GetReproductionModuleGain( const std::string& sModuleID ) const
{
	for( size_t n = 0; n < m_voReproductionModules.size(); n++ )
	{
		const CVAAudioReproductionModuleDesc& oRepro( m_voReproductionModules[ n ] );
		if( oRepro.sID == sModuleID )
			return m_pOutputPatchbay->GetInputGain( oRepro.iOutputPatchBayInput );
	}

	VA_ERROR( "Core", "Could not find reproduction module '" << sModuleID << "'" );
	return 0.0f;
}

bool CVACoreImpl::GetReproductionModuleMuted( const std::string& sModuleID ) const
{
	for( size_t n = 0; n < m_voReproductionModules.size(); n++ )
	{
		const CVAAudioReproductionModuleDesc& oRepro( m_voReproductionModules[ n ] );
		if( oRepro.sID == sModuleID )
			return m_pOutputPatchbay->IsInputMuted( oRepro.iOutputPatchBayInput );
	}

	VA_ERROR( "Core", "Could not find reproduction module '" << sModuleID << "'" );
	return true;
}

void CVACoreImpl::GetRenderingModules( std::vector< CVAAudioRendererInfo >& vRenderers, const bool bFilterEnabled /* = true */ ) const
{
	vRenderers.clear();
	for( size_t i = 0; i < m_voRenderers.size(); i++ )
	{
		const CVAAudioRendererDesc& oRenderer( m_voRenderers[ i ] );
		CVAAudioRendererInfo oRendererInfo;
		oRendererInfo.sID = oRenderer.sID;
		oRendererInfo.sClass = oRenderer.sClass;
		oRendererInfo.sDescription = oRendererInfo.sDescription;
		oRendererInfo.bEnabled = oRenderer.bEnabled;
		oRendererInfo.bOutputDetectorEnabled = oRenderer.bOutputDetectorEnabled;
		oRendererInfo.oParams = oRenderer.oParams;
		oRendererInfo.sOutputRecordingFilePath = oRenderer.pOutputRecorder->GetFilePath();
		if( !bFilterEnabled || oRendererInfo.bEnabled )
			vRenderers.push_back( oRendererInfo );
	}
}

void CVACoreImpl::SetReproductionModuleParameters( const std::string& sModuleID, const CVAStruct& oParams )
{
	for( size_t n = 0; n < m_voReproductionModules.size(); n++ )
	{
		const CVAAudioReproductionModuleDesc& oRep( m_voReproductionModules[ n ] );
		if( oRep.sID == sModuleID )
		{
			// Check for recording parameters and apply if necessary

			if( oParams.HasKey( "RecordInputEnabled" ) )
				VA_EXCEPT2( INVALID_PARAMETER, "Recording has to be enabled before streaming is active" );

			VistaFileSystemFile oFilePath( oRep.pInputRecorder->GetFilePath() );
			std::string sFileName = oFilePath.GetLocalName();
			std::string sBaseFolder = oFilePath.GetParentDirectory();

			bool bUpdateRecordInputPath = false;
			if( oParams.HasKey( "RecordInputFileName" ) )
			{
				sFileName = oParams[ "RecordInputFileName" ];
				bUpdateRecordInputPath = true;
			}
			if( oParams.HasKey( "RecordInputBaseFolder" ) )
			{
				sBaseFolder = oParams[ "RecordInputBaseFolder" ];
				bUpdateRecordInputPath = true;
			}

			if( bUpdateRecordInputPath )
			{
				VistaFileSystemFile oFile( sFileName );
				VistaFileSystemDirectory oFolder( sBaseFolder );

				VistaFileSystemFile oFilePath( oFolder.GetName() + "/" + oFile.GetLocalName() );
				VA_INFO( "Core", "Updating reproduction input recording file path to " << oFilePath.GetName() );

				if( oFilePath.Exists() )
					VA_INFO( "Core", "Record reproduction input recording file path exists, will overwrite" );

				if( !oFolder.Exists() )
					if( !oFolder.CreateWithParentDirectories() )
						VA_EXCEPT2( INVALID_PARAMETER, "Could not create reproduction input recording directory " + oFolder.GetName() );

				oRep.pInputRecorder->SetFilePath( oFilePath.GetName() );
			}


			if( oParams.HasKey( "RecordOutputEnabled" ) )
				VA_EXCEPT2( INVALID_PARAMETER, "Recording has to be enabled before streaming is active" );

			oFilePath.SetName( oRep.pOutputRecorder->GetFilePath() );
			sFileName = oFilePath.GetLocalName();
			sBaseFolder = oFilePath.GetParentDirectory();

			bool bUpdateRecordOutputPath = false;
			if( oParams.HasKey( "RecordOutputFileName" ) )
			{
				sFileName = oParams[ "RecordOutputFileName" ];
				bUpdateRecordOutputPath = true;
			}
			if( oParams.HasKey( "RecordOutputBaseFolder" ) )
			{
				sBaseFolder = oParams[ "RecordOutputBaseFolder" ];
				bUpdateRecordOutputPath = true;
			}

			if( bUpdateRecordOutputPath )
			{
				VistaFileSystemFile oFile( sFileName );
				VistaFileSystemDirectory oFolder( sBaseFolder );

				VistaFileSystemFile oFilePath( oFolder.GetName() + "/" + oFile.GetLocalName() );
				VA_INFO( "Core", "Updating reproduction output recording file path to " << oFilePath.GetName() );

				if( oFilePath.Exists() )
					VA_INFO( "Core", "Record reproduction output recording file path exists, will overwrite" );

				if( !oFolder.Exists() )
					if( !oFolder.CreateWithParentDirectories() )
						VA_EXCEPT2( INVALID_PARAMETER, "Could not create reproduction output recording directory " + oFolder.GetName() );

				oRep.pOutputRecorder->SetFilePath( oFilePath.GetName() );
			}

			// Propagate parameters
			oRep.pInstance->SetParameters( oParams );
			return;
		}
	}

	VA_ERROR( "Core", "Could not find Reproduction module '" << sModuleID << "'" );
}

CVAStruct CVACoreImpl::GetReproductionModuleParameters( const std::string& sModuleID, const CVAStruct& oParams ) const
{
	for( size_t n = 0; n < m_voReproductionModules.size(); n++ )
	{
		const CVAAudioReproductionModuleDesc& oRep( m_voReproductionModules[ n ] );
		if( oRep.sID == sModuleID )
			return oRep.pInstance->GetParameters( oParams );
	}

	VA_ERROR( "Core", "Could not find Reproduction module '" << sModuleID << "'" );
	return CVAStruct();
}

void CVACoreImpl::GetReproductionModules( std::vector< CVAAudioReproductionInfo >& vRepros, const bool bFilterEnabled /* = true */ ) const
{
	vRepros.clear();
	for( size_t i = 0; i < m_voReproductionModules.size(); i++ )
	{
		const CVAAudioReproductionModuleDesc& oRepro( m_voReproductionModules[ i ] );
		CVAAudioReproductionInfo oRepInfo;
		oRepInfo.sID = oRepro.sID;
		oRepInfo.sClass = oRepro.sClass;
		oRepInfo.sDescription = oRepro.sDescription;
		oRepInfo.bEnabled = oRepro.bEnabled;
		oRepInfo.bInputDetectorEnabled = oRepro.bInputDetectorEnabled;
		oRepInfo.sInputRecordingFilePath = oRepro.pInputRecorder->GetFilePath();
		oRepInfo.bOutputDetectorEnabled = oRepro.bOutputDetectorEnabled;
		oRepInfo.sOutputRecordingFilePath = oRepro.pOutputRecorder->GetFilePath();
		oRepInfo.oParams = oRepro.oParams;
		if( !bFilterEnabled || oRepInfo.bEnabled )
			vRepros.push_back( oRepInfo );
	}
}

void CVACoreImpl::SetRenderingModuleParameters( const std::string& sModuleID, const CVAStruct& oParams )
{
	for( size_t n = 0; n < m_voRenderers.size(); n++ )
	{
		const CVAAudioRendererDesc& oRend( m_voRenderers[ n ] );
		if( oRend.sID == sModuleID )
		{
			// Check for recording parameters and apply if necessary

			if( oParams.HasKey( "RecordOutputEnabled" ) )
				VA_EXCEPT2( INVALID_PARAMETER, "Recording has to be enabled before streaming is active" );
			VistaFileSystemFile oFilePath( oRend.pOutputRecorder->GetFilePath() );
			std::string sFileName = oFilePath.GetLocalName();
			std::string sBaseFolder = oFilePath.GetParentDirectory();

			bool bUpdateRecordOutputPath = false;
			if( oParams.HasKey( "RecordOutputFileName" ) )
			{
				sFileName = oParams[ "RecordOutputFileName" ];
				bUpdateRecordOutputPath = true;
			}
			if( oParams.HasKey( "RecordOutputBaseFolder" ) )
			{
				sBaseFolder = oParams[ "RecordOutputBaseFolder" ];
				bUpdateRecordOutputPath = true;
			}

			if( bUpdateRecordOutputPath )
			{
				VistaFileSystemFile oFile( sFileName );
				VistaFileSystemDirectory oFolder( sBaseFolder );

				VistaFileSystemFile oFilePath( oFolder.GetName() + "/" + oFile.GetLocalName() );
				VA_INFO( "Core", "Updating rendering output recording file path to " << oFilePath.GetName() );

				if( oFilePath.Exists() )
					VA_INFO( "Core", "Record rendering output recording file path exists, will overwrite" );

				if( !oFolder.Exists() )
					if( !oFolder.CreateWithParentDirectories() )
						VA_EXCEPT2( INVALID_PARAMETER, "Could not create rendering output recording directory " + oFolder.GetName() );

				oRend.pOutputRecorder->SetFilePath( oFilePath.GetName() );
			}
			
			// Propagate parameters
			oRend.pInstance->SetParameters( oParams );
			
			return;
		}
	}

	VA_ERROR( "Core", "Could not find rendering module '" << sModuleID << "'" );
}

CVAStruct CVACoreImpl::GetRenderingModuleParameters( const std::string& sModuleID, const CVAStruct& oParams ) const
{
	for( size_t n = 0; n < m_voRenderers.size(); n++ )
	{
		const CVAAudioRendererDesc& oRend( m_voRenderers[ n ] );
		if( oRend.sID == sModuleID )
			return oRend.pInstance->GetParameters( oParams );
	}

	VA_ERROR( "Core", "Could not find rendering module '" << sModuleID << "'" );
	return CVAStruct();
}