/* * -------------------------------------------------------------------------------------------- * * 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-2017 * VVVVVV AAA Institute of Technical Acoustics (ITA) * VVVV AAA RWTH Aachen University * * -------------------------------------------------------------------------------------------- */ #include "VACoreImpl.h" // VA base #include // VA includes #include "Audiosignals/VAAudioSignalSourceManager.h" #include "Audiosignals/VAAudiofileSignalSource.h" #include "Audiosignals/VAAudiofileSignalSource.h" #include "Audiosignals/VAEngineSignalSource.h" #include "Audiosignals/VAMachineSignalSource.h" #include "Audiosignals/VASequencerSignalSource.h" #include "directivities/VADirectivityManager.h" #include "Rendering/VAAudioRenderer.h" #include "Rendering/VAAudioRendererRegistry.h" #include "Reproduction/VAAudioReproductionModule.h" #include "Reproduction/VAAudioReproductionModuleRegistry.h" #include "Scene/VAScene.h" #include "Scene/VASoundSourceDesc.h" #include "Scene/VAListenerDesc.h" #include "Utils/VADebug.h" #include "Utils/VAUtils.h" #include "VAAudiostreamTracker.h" #include "VALog.h" #include "VACoreEventManager.h" #include "VACoreFactory.h" #include "VACoreThread.h" #include "VASourceListenerMetrics.h" #include "Drivers/Audio/VAAudioDriverBackend.h" #include "Drivers/Audio/VAAudioDriverConfig.h" #ifdef VACORE_WITH_AUDIO_BACKEND_ASIO #include "Drivers/Audio/VAASIOBackend.h" #endif #ifdef VACORE_WITH_AUDIO_BACKEND_PORTAUDIO #include "Drivers/Audio/VAPortaudioBackend.h" #endif // ITA includes #include #include #include #include #include #include #include #include #include #include #include #include #include // Vista includes #include #include // 3rdParty includes #include // STL includes #include #include #include /* Informationen =-=-=-=-=-=-= Thread-safety & locking Alle durch die Schnittstelle nach aussen angebotenen Funktionen, werden gegen Reentrance grob-granular mittels eines kritischen Bereiches gesperrt. Damit sind auch parallele Calls auf unterschiedliche Methoden der Klasse unterbunden. Sollte dies zu Performance-Problemen führen, kann ein verfeinerter Locking-Mechanismus entwickelt werden. Zunächst mal aber so. TODO: Überall sicherstellen, das ITAExceptions zu VAExceptions umgebaut werden!!! */ // --= Hilfsmakros =-- // Überprüfung ob Initialisiert #define VA_CHECK_INITIALIZED \ { if (m_iState != VA_CORESTATE_READY) VA_EXCEPT2(MODAL_ERROR, "Core not initialized"); } // Mutex-Lock welches parallelen Methoden-Mehrfracheintritt (reentrance) im Methoden-Scope verhindert #define VA_NO_REENTRANCE \ ITACriticalSectionLock oReentranceLock(m_csReentrance) // Manuelles das Lock gegen parallelen Methoden-Mehrfracheintritt (reentrance) holen #define VA_LOCK_REENTRANCE \ m_csReentrance.enter() // Manuelle das Lock gegen parallelen Methoden-Mehrfracheintritt (reentrance) freigeben #define VA_UNLOCK_REENTRANCE \ m_csReentrance.leave() /* Sichere Ausnahmebehandlung Problem: Intern können auch andere Typen von Ausnahmen als CVAException geworfen werden. Nach aussen hin dürfen aber NUR CVAExceptions geworfen werden (Konsistent) Lösung: TRY-/CATCH-Makros für abgesicherte Bereiche in allen Methoden der externen Schnittstelle. Zweistufiger Aufbau. 1. (innen) Fange alle Exception-Typen und konvertiere sie in CVAExceptions 2. (aussen) Fange die einzig mögl. CVAExceptions und biete gemeinsamen Catch-Weg zur Problemlösung (Aufräumen) an try { try { // Code ... } catch (ITAException& e) { // Konvertiere zu CVAException } catch (VistaExceptionBase& e) { // Konvertiere zu CVAException } catch (...) // Generiere unerwartete CVAException } } catch (CVAException& e) { // Gemeinsames Aufräumen } Beispiel: VA_TRY { // Code .. } VA_CATCH { // Mach was ... } Hinweis: Initiale/finale Geschweifte Klammer fehlen, da diese hinter die Makros geschrieben werden */ #define VA_TRY \ try { try #define VA_CATCH(EXPR) \ catch( CVAException& e ) { throw e; } \ catch( ITAException& e ) { throw convert2VAException( e ); } \ catch( VistaExceptionBase& e ) { throw convert2VAException( e ); } \ catch( ... ) { throw getDefaultUnexpectedVAException(); } \ } catch( CVAException& EXPR ) #define VA_FINALLY \ catch( CVAException& e ) { throw e; } \ catch( ITAException& e ) { throw convert2VAException( e ); } \ catch( VistaExceptionBase& e ) { throw convert2VAException(e); } \ catch( ... ) { throw getDefaultUnexpectedVAException(); } \ } catch( ... ) #define VA_RETHROW \ catch( CVAException& e ) { throw e; } \ catch( ITAException& e ) { throw convert2VAException( e ); } \ catch( VistaExceptionBase& e ) { throw convert2VAException( e ); } \ catch( ... ) { throw getDefaultUnexpectedVAException(); } \ } catch( ... ) { throw; } IVAInterface* VACore::CreateCoreInstance( const CVAStruct& oArgs ) { VA_TRACE( "Config", oArgs ); return new CVACoreImpl( oArgs ); } IVAInterface* VACore::CreateCoreInstance( const std::string& sConfigFile ) { CVAStruct oFinalCoreConfigStruct, oCurrentConfig; std::list< VistaFileSystemFile > voConfigFiles; std::vector< VistaFileSystemDirectory > voIncludePaths; voConfigFiles.push_back( VistaFileSystemFile( sConfigFile ) ); VA_PRINT( "VA 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() + "'" ); readINIFileAsStruct( 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 CreateCoreInstance( 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 ) : 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_pStreamProbeFinal( nullptr ), m_pCurSceneState( nullptr ), m_pClock( ITAClock::getDefaultClock() ), m_pTicker( NULL ), m_lSyncModOwner( -1 ), m_lSyncModSpinCount( 0 ), m_iState( VA_CORESTATE_CREATED ), // TODO: Welche Default-Wert müssen erst in Initialize gesetzt werden? m_iGlobalAuralizationMode( IVAInterface::VA_AURAMODE_ALL ), m_dOutputGain( 1 ), m_dInputGain( 1 ), m_bOutputMuted( false ), m_bInputMuted( false ), m_dStreamClockOffset( 0 ), m_fCoreClockOffset( 0 ), // --= Profiling =-- m_pmCoreThreadLoopTotalDuration( "Core thread loop" ) { VA_NO_REENTRANCE; 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 verfügbar sein, // unabhänging 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 gelöscht wird. CVAEvent ev; ev.iEventType = CVAEvent::VA_EVENT_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_pmCoreThreadLoopTotalDuration.ToString() ); } void CVACoreImpl::SetDebugStream( 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 möglich. Unabhängig vom Zustand. Thread-safety wird im Manager geregelt. m_pEventManager->AttachHandler( pCoreEventHandler ); } VA_RETHROW; } void CVACoreImpl::DetachEventHandler( IVAEventHandler* pCoreEventHandler ) { VA_TRY { // Immer möglich. Unabhängig 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::Initialize() { VA_NO_REENTRANCE; // TODO: Prüfen ob im Fehlerfall zurück in den sauberen Grundzustand [WICHTIG!] VA_VERBOSE( "Core", "Initializing core" ); VA_TRY { if( m_iState == VA_CORESTATE_READY ) VA_EXCEPT2( MODAL_ERROR, "Core already initialized." ); if( m_iState == VA_CORESTATE_FAIL ) VA_EXCEPT2( MODAL_ERROR, "Core corrupted, reinitialization impossible" ); m_pCoreThread = new CVACoreThread( this ); SetProgress( "Setting up audio hardware", "", 1 ); InitializeAudioDriver(); m_pR2RPatchbay = new ITAStreamPatchbay( m_oCoreConfig.oAudioDriverConfig.dSampleRate, m_oCoreConfig.oAudioDriverConfig.iBuffersize ); // Create output patch bay with a single output that uses all available physical audio outputs from sound card m_pOutputPatchbay = new ITAStreamPatchbay( m_oCoreConfig.oAudioDriverConfig.dSampleRate, m_oCoreConfig.oAudioDriverConfig.iBuffersize ); int iPhysicalHardwareOutput = m_pOutputPatchbay->AddOutput( m_oCoreConfig.oAudioDriverConfig.iOutputChannels ); m_pOutputPatchbay->SetOutputGain( iPhysicalHardwareOutput, m_dOutputGain ); m_iGlobalAuralizationMode = VA_AURAMODE_ALL; // Set up input stream network ITADatasource* pInputTail = nullptr; if( m_oCoreConfig.oAudioDriverConfig.iInputChannels > 0 ) { pInputTail = m_pAudioDriverBackend->getInputStreamDatasource(); if( pInputTail ) { m_pInputAmp = new ITAStreamAmplifier( pInputTail, ( float ) m_dInputGain ); m_pInputStreamDetector = new ITAStreamDetector( m_pInputAmp ); pInputTail = m_pInputStreamDetector; if( m_oCoreConfig.bRecordDeviceInputEnabled ) { m_pStreamProbeDeviceInput = new ITAStreamProbe( pInputTail, m_oCoreConfig.sRecordDeviceInputFilePath ); pInputTail = m_pStreamProbeDeviceInput; } } } SetProgress( "Setting up resource managers", "", 2 ); m_pSignalSourceManager = new CVAAudioSignalSourceManager( this, m_oCoreConfig.oAudioDriverConfig, pInputTail ); m_pGlobalSamplePool = ITASoundSamplePool::Create( 1, m_oCoreConfig.oAudioDriverConfig.dSampleRate ); m_pGlobalSampler = ITASoundSampler::Create( 1, m_oCoreConfig.oAudioDriverConfig.dSampleRate, m_oCoreConfig.oAudioDriverConfig.iBuffersize, m_pGlobalSamplePool ); m_pGlobalSampler->AddMonoTrack(); m_pDirectivityManager = new CVADirectivityManager( this, m_oCoreConfig.oAudioDriverConfig.dSampleRate ); m_pDirectivityManager->Initialize(); SetProgress( "Setting up scene management", "", 3 ); m_pSceneManager = new CVASceneManager( m_pClock ); m_pSceneManager->Initialize(); m_pCurSceneState = m_pSceneManager->GetHeadSceneState(); // Register all renderers and initialize CVAAudioRendererRegistry::GetInstance()->RegisterInternalCoreFactoryMethods(); InitializeAudioRenderers(); if( m_voRenderers.empty() ) VA_EXCEPT1( "No audio renderers created" ); SetProgress( "Initializing reproduction modules", "", 6 ); // Register all reproductions and initialize CVAAudioReproductionModuleRegistry::GetInstance()->RegisterInternalCoreFactoryMethods(); InitializeReproductionModules(); if( m_voReproductionModules.empty() ) VA_EXCEPT1( "No audio reproduction modules created" ); // Patch renderer and reproduction modules PatchRendererToReproductionModules(); // Patch audio reproduction to output // TODO: //SetProgress( "Patching audio modules", "", 7 ); PatchReproductionModulesToOutput(); /* Wire the global sampler (1:N) int iGlobalSamplerInput = m_pOutputPatchbay->AddInput( m_pGlobalSampler ); int iNumPhysicalOutputChannels = m_pOutputPatchbay->GetOutputNumChannels( iPhysicalHardwareOutput ); for( int i=0; iConnectChannels( iGlobalSamplerInput, 0, iPhysicalHardwareOutput, i ); */ // Create output peak detector that uses patch bay output stream m_pOutputStreamDetector = new ITAStreamDetector( m_pOutputPatchbay->GetOutputDatasource( iPhysicalHardwareOutput ) ); // Setup output dump (if set) ITADatasource* pOutputTail = m_pOutputStreamDetector; if( m_oCoreConfig.bRecordDeviceOutputEnabled ) { m_pStreamProbeFinal = new ITAStreamProbe( pOutputTail, m_oCoreConfig.sRecordFinalOutputFilePath ); pOutputTail = m_pStreamProbeFinal; } // Attach the stream tracker m_pOutputTracker = new CVAAudiostreamTracker( pOutputTail, m_pClock, &m_fCoreClockOffset, &m_lSyncModOwner, m_pSignalSourceManager ); pOutputTail = m_pOutputTracker; // Give output stream datasource to audio driver m_pAudioDriverBackend->setOutputStreamDatasource( pOutputTail ); // Core-Clock auf 0 initialisieren double dNow = m_pClock->getTime(); m_fCoreClockOffset = ( float ) dNow; m_dStreamClockOffset = -1; // Timer erzeugen und konfigurieren (wird für Peak-Events benutzt) m_pTicker = new VistaTicker(); m_pTicker->AddTrigger( new VistaTicker::TriggerContext( m_oCoreConfig.iTriggerUpdateMilliseconds, true ) ); m_pTicker->SetAfterPulseFunctor( this ); // Audio-Streaming starten SetProgress( "Starting audio streaming", "", 7 ); m_pAudioDriverBackend->startStreaming(); // Timer für Peak-Events starten m_pTicker->StartTicker(); // Initialisierung erfolgreich! m_iState = VA_CORESTATE_READY; SetProgress( "Initialization finished", "", 8 ); FinishProgress(); } VA_FINALLY { // Aufräumen und Exception weiterwerfen Tidyup(); throw; } } 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 hinzugefügt wurde m_pCurSceneState->RemoveReference(); m_pCurSceneState = nullptr; } // Alle Szenenobjekte löschen 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::VA_EVENT_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 nötig. */ 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_pStreamProbeFinal; m_pStreamProbeFinal = 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 führt 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 löschen und warten bis Zustand sicher übernommen // Wichtig: Dies muss vor dem Beenden des Streamings geschehen // Reset audio renderers for( std::vector::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; delete m_pInputStreamDetector; m_pInputStreamDetector = nullptr; m_voReproductionModules.clear(); 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_pStreamProbeFinal; m_pStreamProbeFinal = 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 aufzuräumen Tidyup(); // Allgemein: Fehler beim Finalisieren? => Core im Sack m_iState = VA_CORESTATE_FAIL; // VAExceptions unverändert 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; #if ( VACORE_MODULE_INTERFACE_ENABLED == 1 ) VA_TRY { std::vector 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; #if ( VACORE_MODULE_INTERFACE_ENABLED == 1 ) 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::VA_EVENT_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 #if ( VACORE_NO_MODULE_INTERFACE_THROW_EXCEPTION == 1 ) 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::VA_EVENT_DIRECTIVITY_LOADED; ev.pSender = this; ev.iObjectID = iDirID; m_pEventManager->BroadcastEvent( ev ); VA_INFO( "Core", "Directivity successfully loaded, assigned directivity ID " << 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::VA_EVENT_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& 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::VA_EVENT_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::VA_EVENT_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::VA_EVENT_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::VA_EVENT_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::VA_EVENT_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::VA_EVENT_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::VA_EVENT_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::VA_EVENT_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& 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::VA_EVENT_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::VA_EVENT_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 überprüfen if( dPlaybackPosition < 0 ) VA_EXCEPT2( INVALID_PARAMETER, "Invalid playback position" ); // Quelle anfordern (prüft auf gültige 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::VA_EVENT_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 (prüft auf gültige 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 unverändert 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->fSoundPowerLevelDB; 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: Zunächst 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::VA_EVENT_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::VA_EVENT_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 ); int iResult = 0; if( iResult == 0 ) { // Ereignis generieren, wenn erfolgreich CVAEvent ev; ev.iEventType = CVAEvent::VA_EVENT_SOUND_SOURCE_DELETED; ev.pSender = this; ev.iObjectID = iSoundSourceID; m_pEventManager->EnqueueEvent( ev ); } if( !bSync ) UnlockUpdate(); VA_INFO( "Core", "Deleted sound source " << iSoundSourceID ); return iResult; } 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::VA_EVENT_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::VA_EVENT_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 zusätzlich ... const ITASampleBuffer* pNewBuf( m_pSignalSourceManager->GetSilenceBuffer() ); VA_TRY { CVASoundSourceDesc* pDesc = m_pSceneManager->GetSoundSourceDesc( iSoundSourceID ); // Sicherstellen, das die Signalquellen ID gültig ist .. dann ID und Qu if( !sSignalSourceID.empty() ) pNewSrc = m_pSignalSourceManager->RequestSignalSource( sSignalSourceID, &pNewBuf ); // Vorherige Bindung auflösen 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::VA_EVENT_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 überprüfen 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::VA_EVENT_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::VA_EVENT_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 veränderten State? } } pSourceState->SetDirectivityID( iDirectivityID ); pSourceState->SetDirectivityData( pNewDirectivity ); // Ereignis generieren, falls erfolgreich CVAEvent ev; ev.iEventType = CVAEvent::VA_EVENT_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->GetVolume(); } VA_RETHROW; } void CVACoreImpl::SetSoundSourceSoundPower( const int iSoundSourceID, const double dSoundPower ) { VA_NO_REENTRANCE; VA_CHECK_INITIALIZED; VA_TRY { // Parameter überprüfen 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->SetVolume( dSoundPower ); // Ereignis generieren, falls erfolgreich CVAEvent ev; ev.iEventType = CVAEvent::VA_EVENT_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::VA_EVENT_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::VA_EVENT_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::VA_EVENT_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::VA_EVENT_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::VA_EVENT_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(); // Hörer anlegen const int iID = m_pNewSceneState->AddListener(); assert( iID != -1 ); // HINWEIS: Zunächst hier die statische Beschreibung der Quelle anlegen m_pSceneManager->CreateListenerDesc( iID ); // Initiale Werte setzen m_pSceneManager->SetListenerName( iID, sName ); CVAListenerState* 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::VA_EVENT_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::VA_EVENT_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 ); CVAListenerState* pListenerState = m_pNewSceneState->AlterListenerState( iListenerID ); assert( pListenerState ); CVAEvent ev; ev.iEventType = CVAEvent::VA_EVENT_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::VA_EVENT_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::VA_EVENT_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 CVAListenerState* pListenerState = pHeadState->GetListenerState( iID ); if( !pListenerState ) // Hörer 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 überprüfen if( !GetAuralizationModeValid( iAuralizationMode ) ) VA_EXCEPT2( INVALID_PARAMETER, "Invalid auralization mode" ); bool bSync = GetUpdateLocked(); if( !bSync ) LockUpdate(); CVAListenerState* pListenerState = m_pNewSceneState->AlterListenerState( iID ); if( !pListenerState ) { // Hörer 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::VA_EVENT_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(); CVAListenerState* 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::VA_EVENT_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 CVAListenerState* pListenerState = pHeadState->GetListenerState( 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 CVAListenerState* pListenerState = pHeadState->GetListenerState( 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 überprüfen 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(); CVAListenerState* 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::VA_EVENT_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 HRIR 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 CVAListenerState* pListenerState = pHeadState->GetListenerState( 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(); CVAListenerState* 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::VA_EVENT_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 CVAListenerState* pSoundReceiverState = pHeadState->GetListenerState( 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(); CVAListenerState* 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::VA_EVENT_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(); CVAListenerState* 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::VA_EVENT_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 CVAListenerState* pSoundReceiverState = pHeadState->GetListenerState( 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(); CVAListenerState* 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::VA_EVENT_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_EXCEPT_NOT_IMPLEMENTED_NEXT_VERSION; } void CVACoreImpl::SetSoundReceiverHeadAboveTorsoOrientation( const int iID, const VAQuat& qOrient ) { VA_EXCEPT_NOT_IMPLEMENTED_NEXT_VERSION; } 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 CVAListenerState* pListenerState = pHeadState->GetListenerState( iID ); if( !pListenerState ) // Hörer existiert nicht 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->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(); CVAListenerState* 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.vPos = v3View; oNewPose.vPos = v3Up; pNewMotionState->SetRealWorldPose( oNewPose ); /* Ereignis generieren CVAEvent ev; ev.iEventType = CVAEvent::VA_EVENT_REAL_WORLD_SOUND_RECEIVER_CHANGED_POSE; ev.pSender = this; ev.iObjectID = iID; SetCoreEventParams( ev, pNewMotionState ); m_pCoreEventMan->EnqueueEvent( ev ); */ if( !bSync ) UnlockUpdate(); } VA_RETHROW; } void CVACoreImpl::GetSoundReceiverRealWorldPose( const int iID, VAVec3& v3Pos, VAQuat& qOrient ) const { VA_EXCEPT_NOT_IMPLEMENTED; } void CVACoreImpl::SetSoundReceiverRealWorldPose( const int iID, const VAVec3& v3Pos, const VAQuat& qOrient ) { VA_EXCEPT_NOT_IMPLEMENTED; } VAQuat CVACoreImpl::GetSoundReceiverRealWorldHeadAboveTorsoOrientation( const int iID ) const { VA_EXCEPT_NOT_IMPLEMENTED; } void CVACoreImpl::SetSoundReceiverRealWorldHeadAboveTorsoOrientation( const int iID, const VAQuat& qOrient ) { VA_EXCEPT_NOT_IMPLEMENTED; } void CVACoreImpl::SetHomogeneousMediumSoundSpeed( const double dSoundSpeed ) { VA_EXCEPT_NOT_IMPLEMENTED; } double CVACoreImpl::GetHomogeneousMediumSoundSpeed() const { VA_EXCEPT_NOT_IMPLEMENTED; } void CVACoreImpl::SetHomogeneousMediumTemperature( const double dDegreesCentigrade ) { VA_EXCEPT_NOT_IMPLEMENTED; } double CVACoreImpl::GetHomogeneousMediumTemperature() const { VA_EXCEPT_NOT_IMPLEMENTED; } void CVACoreImpl::SetHomogeneousMediumStaticPressure( const double dPressurePascal ) { VA_EXCEPT_NOT_IMPLEMENTED; } double CVACoreImpl::GetHomogeneousMediumStaticPressure() const { VA_EXCEPT_NOT_IMPLEMENTED; } void CVACoreImpl::SetHomogeneousMediumRelativeHumidity( const double dRelativeHumidityPercent ) { VA_EXCEPT_NOT_IMPLEMENTED; } double CVACoreImpl::GetHomogeneousMediumRelativeHumidity() { VA_EXCEPT_NOT_IMPLEMENTED; } void CVACoreImpl::SetHomogeneousMediumShiftSpeed( const VAVec3& v3TranslationSpeed ) { VA_EXCEPT_NOT_IMPLEMENTED; } VAVec3 CVACoreImpl::GetHomogeneousMediumShiftSpeed() const { VA_EXCEPT_NOT_IMPLEMENTED; } void CVACoreImpl::SetHomogeneousMediumParameters( const CVAStruct& oParams ) { VA_EXCEPT_NOT_IMPLEMENTED; } CVAStruct CVACoreImpl::GetHomogeneousMediumParameters( const CVAStruct& oArgs ) { VA_EXCEPT_NOT_IMPLEMENTED; } 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::iterator it = m_voRenderers.begin(); it != m_voRenderers.end(); ++it ) it->pInstance->LoadScene( sDestFilename ); return "not_implemented"; } else { VA_EXCEPT2( INVALID_PARAMETER, "Could not interpret scene parameters" ); } } VA_RETHROW; } CVASceneInfo CVACoreImpl::GetSceneInfo( const std::string& sSceneID ) const { VA_NO_REENTRANCE; VA_CHECK_INITIALIZED; VA_TRY { VA_EXCEPT_NOT_IMPLEMENTED; } VA_RETHROW; } bool CVACoreImpl::GetSceneEnabled( const std::string& sID ) const { VA_NO_REENTRANCE; VA_CHECK_INITIALIZED; VA_TRY { VA_EXCEPT_NOT_IMPLEMENTED; } VA_RETHROW; } int CVACoreImpl::CreateSoundPortal( const std::string& sName /*= "" */ ) { VA_EXCEPT_NOT_IMPLEMENTED; } void CVACoreImpl::GetSceneIDs( std::vector< std::string >& vsIDs ) const { VA_EXCEPT_NOT_IMPLEMENTED; } std::string CVACoreImpl::GetSceneName( const std::string& sID ) const { VA_EXCEPT_NOT_IMPLEMENTED; } void CVACoreImpl::SetSceneName( const std::string& sID, const std::string& sName ) { VA_EXCEPT_NOT_IMPLEMENTED; } void CVACoreImpl::SetSceneEnabled( const std::string& sID, const bool bEnabled /*= true */ ) { VA_EXCEPT_NOT_IMPLEMENTED; } 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; } std::string CVACoreImpl::GetSoundPortalName( const int iPortalID ) const { VA_NO_REENTRANCE; VA_CHECK_INITIALIZED; VA_TRY { // TODO: Was wenn ID ungültig? 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 ); // Ereignis generieren CVAEvent ev; ev.iEventType = CVAEvent::VA_EVENT_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; } int CVACoreImpl::GetSoundPortalMaterial( const int iSoundPortalID ) const { VA_EXCEPT_NOT_IMPLEMENTED; } void CVACoreImpl::SetSoundPortalNextPortal( const int iSoundPortalID, const int iNextSoundPortalID ) { VA_EXCEPT_NOT_IMPLEMENTED; } int CVACoreImpl::GetSoundPortalNextPortal( const int iSoundPortalID ) const { VA_EXCEPT_NOT_IMPLEMENTED; } void CVACoreImpl::SetSoundPortalSoundReceiver( const int iSoundPortalID, const int iSoundReceiverID ) { VA_EXCEPT_NOT_IMPLEMENTED; } int CVACoreImpl::GetSoundPortalSoundReceiver( const int iSoundPortalID ) const { VA_EXCEPT_NOT_IMPLEMENTED; } void CVACoreImpl::SetSoundPortalSoundSource( const int iSoundPortalID, const int iSoundSourceID ) { VA_EXCEPT_NOT_IMPLEMENTED; } int CVACoreImpl::GetSoundPortalSoundSource( const int iSoundPortalID ) const { VA_EXCEPT_NOT_IMPLEMENTED; } bool CVACoreImpl::GetSoundPortalEnabled( const int iPortalID ) const { VA_NO_REENTRANCE; VA_CHECK_INITIALIZED; VA_TRY { VA_EXCEPT_NOT_IMPLEMENTED; } VA_RETHROW; } CVAStruct CVACoreImpl::GetSoundPortalParameters( const int iID, const CVAStruct& oArgs ) const { VA_EXCEPT_NOT_IMPLEMENTED; } void CVACoreImpl::SetSoundPortalParameters( const int iID, const CVAStruct& oParams ) { VA_EXCEPT_NOT_IMPLEMENTED; } void CVACoreImpl::SetSoundPortalPosition( const int iSoundPortalID, const VAVec3& vPos ) { VA_EXCEPT_NOT_IMPLEMENTED; } VAVec3 CVACoreImpl::GetSoundPortalPosition( const int iSoundPortalID ) const { VA_EXCEPT_NOT_IMPLEMENTED; } void CVACoreImpl::SetSoundPortalOrientation( const int iSoundPortalID, const VAQuat& qOrient ) { VA_EXCEPT_NOT_IMPLEMENTED; } VAQuat CVACoreImpl::GetSoundPortalOrientation( const int iSoundPortalID ) const { VA_EXCEPT_NOT_IMPLEMENTED; } 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; // TODO: Implement return false; } 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 ); else m_pInputAmp->SetGain( ( float ) m_dInputGain ); } // Ereignis generieren CVAEvent ev; ev.iEventType = CVAEvent::VA_EVENT_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::VA_EVENT_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; VA_TRY { return m_dOutputGain; } VA_RETHROW; } 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 ); else m_pOutputPatchbay->SetOutputGain( 0, dGain ); } // Ereignis generieren CVAEvent ev; ev.iEventType = CVAEvent::VA_EVENT_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; // TODO: Implement return false; } void CVACoreImpl::SetOutputMuted( const bool bMuted ) { VA_NO_REENTRANCE; VA_CHECK_INITIALIZED; VA_TRY { if( m_bOutputMuted == bMuted ) return; m_bOutputMuted = bMuted; if( m_pOutputPatchbay ) m_pOutputPatchbay->SetOutputMuted( 0, bMuted ); // Ereignis generieren CVAEvent ev; ev.iEventType = CVAEvent::VA_EVENT_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::VA_EVENT_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; // Prüfen, ob Hörer in der aktuellen Konfig existiert. if( !m_pNewSceneState->GetListenerState( iListenerID ) ) VA_EXCEPT2( INVALID_PARAMETER, "Listener does not existing in head configuration" ); /* TODO: Auch -1 erlauben um Hörer 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::VA_EVENT_ACTIVE_SOUND_RECEIVER_CHANGED; ev.pSender = this; ev.iObjectID = iListenerID; m_pEventManager->EnqueueEvent( ev ); VA_VERBOSE( "Core", "Set sound receiver " << iListenerID << " the active listener" ); } 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_DUMMY if( m_oCoreConfig.oAudioDriverConfig.sDriver == "Dummy" ) m_pAudioDriverBackend = new CVADummyBackend( &m_oCoreConfig.oAudioDriverConfig ); #endif if( m_pAudioDriverBackend == nullptr ) VA_ERROR( "Core", "Unkown 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(); conf.ReqStringListRegex( "Outputs", oParams.vsOutputs, "\\s*,\\s*" ); std::unique( oParams.vsOutputs.begin(), oParams.vsOutputs.end() ); conf.OptBool( "OutputDetectorEnabled", oParams.bOutputLevelMeterEnabled, false ); conf.OptBool( "RecordOutputEnabled", oParams.bRecordOutputEnabled, false ); if( oParams.bRecordOutputEnabled ) { std::string sFilePathRAW; conf.ReqString( "RecordOutputFilePath", sFilePathRAW ); oParams.sRecordOutputFilePath = m_oCoreConfig.mMacros.SubstituteMacros( sFilePathRAW ); } // 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 ) { oRendererDesc.pOutputRecorder = new ITAStreamProbe( pRendererOutputTail, oParams.sRecordOutputFilePath ); pRendererOutputTail = oRendererDesc.pOutputRecorder; } 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.vsOutputs.size(); i++ ) { const std::string& sOutputID( oParams.vsOutputs[ 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.vsOutputs; 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() { CVAAudioReproductionModuleRegistry* pRegistry( CVAAudioReproductionModuleRegistry::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 CVAAudioReproductionModuleInitParams 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 ); conf.OptBool( "RecordInputEnabled", oParams.bRecordInputEnabled, false ); if( oParams.bRecordInputEnabled ) { std::string sFilePathRAW; conf.ReqString( "RecordInputFilePath", sFilePathRAW ); oParams.sRecordInputInputFilePath = m_oCoreConfig.mMacros.SubstituteMacros( sFilePathRAW ); } conf.OptBool( "RecordOutputEnabled", oParams.bRecordOutputEnabled, false ); if( oParams.bRecordOutputEnabled ) { std::string sFilePathRAW; conf.ReqString( "RecordOutputFilePath", sFilePathRAW ); oParams.sRecordOutputInputFilePath = m_oCoreConfig.mMacros.SubstituteMacros( sFilePathRAW ); } // 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 IVAAudioReproductionModuleFactory* 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 ) { oDesc.pInputRecorder = new ITAStreamProbe( pInputTail, oParams.sRecordInputInputFilePath ); pInputTail = oDesc.pInputRecorder; } // 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 ) { oDesc.pOutputRecorder = new ITAStreamProbe( pOutputTail, oParams.sRecordOutputInputFilePath ); pOutputTail = oDesc.pOutputRecorder; } // 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::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::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::VA_EVENT_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::VA_EVENT_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::VA_EVENT_PROGRESS_UPDATE; ev.pSender = this; ev.oProgress = m_Progress; m_pEventManager->BroadcastEvent( ev ); m_csProgress.leave(); } /* +----------------------------------------------------------+ * * | | * * | Core-Thread | * * | | * * +----------------------------------------------------------+ */ void CVACoreImpl::CoreThreadLoop() { m_pmCoreThreadLoopTotalDuration.start(); assert( m_pCurSceneState != nullptr ); assert( m_pCurSceneState->GetNumReferences() >= 1 ); // Auf Änderungen der Szene überprüfen CVASceneState* pNewSceneState = m_pSceneManager->GetHeadSceneState(); assert( pNewSceneState != nullptr ); assert( pNewSceneState->GetNumReferences() >= 1 ); pNewSceneState->AddReference(); // TODO: Aktiver Hörer 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 berücksichtigen /** * 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 benötigt if( m_pCurSceneState != pNewSceneState ) { // Alter Zustand wird nicht mehr benötigt 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_pmCoreThreadLoopTotalDuration.stop(); // @todo: signal event to process object calls (in-sync exec with internal core) return; } void CVACoreImpl::SendAudioDeviceDetectorUpdateEvent() { CVAEvent ev; ev.iEventType = CVAEvent::VA_EVENT_MEASURES_UPDATE; ev.pSender = this; if( m_pInputStreamDetector ) { ev.vfInputPeaks.resize( m_oCoreConfig.oAudioDriverConfig.iInputChannels ); m_pInputStreamDetector->GetPeaks( ev.vfInputPeaks, true ); } if( m_pOutputStreamDetector ) { ev.vfOutputPeaks.resize( m_oCoreConfig.oAudioDriverConfig.iOutputChannels ); m_pOutputStreamDetector->GetPeaks( ev.vfOutputPeaks, 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::VA_EVENT_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.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::VA_EVENT_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.vfInputPeaks.resize( oReproduction.pInputDetector->GetNumberOfChannels() ); oReproduction.pInputDetector->GetPeaks( ev.vfInputPeaks, true ); } if( oReproduction.pOutputDetector ) { 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( "getloglevel" ) ) { oReturn[ "loglevel" ] = VALog_GetLogLevel(); } if( oArgs.HasKey( "setloglevel" ) ) { int iLogLevel = oArgs[ "setloglevel" ]; VALog_SetLogLevel( iLogLevel ); } if( oArgs.HasKey( "structrebound" ) ) { oReturn = oArgs[ "structrebound" ]; } 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.sOutputRecordingFilePath; 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 ) { 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.sInputRecordingFilePath; oRepInfo.bOutputDetectorEnabled = oRepro.bOutputDetectorEnabled; oRepInfo.sOutputRecordingFilePath = oRepro.sOutputRecordingFilePath; 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 ) { 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(); }