VACoreImpl.cpp 141 KB
Newer Older
Jonas Stienen's avatar
Jonas Stienen committed
1
/*
2
 *  --------------------------------------------------------------------------------------------
Jonas Stienen's avatar
Jonas Stienen committed
3
 *
4
5
6
7
8
9
10
11
 *    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
 *
 *  --------------------------------------------------------------------------------------------
Jonas Stienen's avatar
Jonas Stienen committed
12
 */
13

Jonas Stienen's avatar
Jonas Stienen committed
14
15
16
#include "VACoreImpl.h"

// VA base
17
#include <VA.h>
Jonas Stienen's avatar
Jonas Stienen committed
18
19
20
21
22
23
24
25

// 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"
26
#include "directivities/VADirectivityManager.h"
Jonas Stienen's avatar
Jonas Stienen committed
27
28
#include "Rendering/VAAudioRenderer.h"
#include "Rendering/VAAudioRendererRegistry.h"
29
30
#include "Reproduction/VAAudioReproduction.h"
#include "Reproduction/VAAudioReproductionRegistry.h"
Jonas Stienen's avatar
Jonas Stienen committed
31
32
33
34
35
36
37
38
39
40
41
42
#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"

43
#include "Drivers/Audio/VAAudioDriverBackend.h"
44
#include "Drivers/Audio/VAAudioDriverConfig.h"
45
46
47
48
49
50
51
52

#ifdef VACORE_WITH_AUDIO_BACKEND_ASIO
#include "Drivers/Audio/VAASIOBackend.h"
#endif
#ifdef VACORE_WITH_AUDIO_BACKEND_PORTAUDIO
#include "Drivers/Audio/VAPortaudioBackend.h"
#endif

Jonas Stienen's avatar
Jonas Stienen committed
53
54
55
56
// ITA includes
#include <ITAASCIITable.h>
#include <ITAClock.h>
#include <ITAException.h>
57
#include <ITAFileSystemUtils.h>
Jonas Stienen's avatar
Jonas Stienen committed
58
#include <ITAFunctors.h>
59
#include <ITAStreamDetector.h>
Jonas Stienen's avatar
Jonas Stienen committed
60
61
62
63
#include <ITASoundSample.h>
#include <ITASoundSampler.h>
#include <ITASoundSamplePool.h>
#include <ITAStreamAmplifier.h>
64
#include <ITAStreamPatchBay.h>
Jonas Stienen's avatar
Jonas Stienen committed
65
66
67
68
69
70
71
72
73
74
75
76
#include <ITAStreamProbe.h>
#include <ITAStringUtils.h>

// Vista includes
#include <VistaTools/VistaFileSystemFile.h>
#include <VistaTools/VistaFileSystemDirectory.h>

// 3rdParty includes
#include <DAFF.h>

// STL includes
#include <algorithm>
77
#include <iomanip>
Jonas Stienen's avatar
Jonas Stienen committed
78
79
80
81
82
83
84
85
86
87
88
89
#include <iostream>

/*

	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
90
	unterbunden. Sollte dies zu Performance-Problemen fhren, kann ein
Jonas Stienen's avatar
Jonas Stienen committed
91
92
93
94
95
	verfeinerter Locking-Mechanismus entwickelt werden. Zunchst mal aber so.


	TODO: berall sicherstellen, das ITAExceptions zu VAExceptions umgebaut werden!!!

96
	*/
Jonas Stienen's avatar
Jonas Stienen committed
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121


// --= Hilfsmakros =--

// berprfung 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 knnen auch andere Typen von Ausnahmen als
122
123
	CVAException geworfen werden. Nach aussen hin drfen
	aber NUR CVAExceptions geworfen werden (Konsistent)
Jonas Stienen's avatar
Jonas Stienen committed
124
125

	Lsung: TRY-/CATCH-Makros fr abgesicherte Bereiche in allen Methoden
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
	der externen Schnittstelle. Zweistufiger Aufbau.
	1. (innen) Fange alle Exception-Typen und konvertiere sie in CVAExceptions
	2. (aussen) Fange die einzig mgl. CVAExceptions und biete
	gemeinsamen Catch-Weg zur Problemlsung (Aufrumen) an

	try {
	try {
	// Code ...
	} catch (ITAException& e) {
	// Konvertiere zu CVAException
	} catch (VistaExceptionBase& e) {
	// Konvertiere zu CVAException
	} catch (...)
	// Generiere unerwartete CVAException
	}
	} catch (CVAException& e) {
	// Gemeinsames Aufrumen
	}
Jonas Stienen's avatar
Jonas Stienen committed
144
145

	Beispiel:
146
147
148
149
150
151

	VA_TRY {
	// Code ..
	} VA_CATCH {
	// Mach was ...
	}
Jonas Stienen's avatar
Jonas Stienen committed
152
153
154

	Hinweis: Initiale/finale Geschweifte Klammer fehlen, da diese hinter die Makros geschrieben werden

155
	*/
Jonas Stienen's avatar
Jonas Stienen committed
156
157

#define VA_TRY \
158
try { try
Jonas Stienen's avatar
Jonas Stienen committed
159
160

#define VA_CATCH(EXPR) \
161
162
163
164
165
catch( CVAException& e ) { throw e; } \
catch( ITAException& e ) { throw convert2VAException( e ); } \
catch( VistaExceptionBase& e ) { throw convert2VAException( e ); } \
catch( ... ) { throw getDefaultUnexpectedVAException(); } \
} catch( CVAException& EXPR )
Jonas Stienen's avatar
Jonas Stienen committed
166
167

#define VA_FINALLY \
168
169
170
171
172
catch( CVAException& e ) { throw e; } \
catch( ITAException& e ) { throw convert2VAException( e ); } \
catch( VistaExceptionBase& e ) { throw convert2VAException(e); } \
catch( ... ) { throw getDefaultUnexpectedVAException(); } \
} catch( ... )
Jonas Stienen's avatar
Jonas Stienen committed
173
174

#define VA_RETHROW \
175
176
177
178
179
catch( CVAException& e ) { throw e; } \
catch( ITAException& e ) { throw convert2VAException( e ); } \
catch( VistaExceptionBase& e ) { throw convert2VAException( e ); } \
catch( ... ) { throw getDefaultUnexpectedVAException(); } \
} catch( ... ) { throw; }
Jonas Stienen's avatar
Jonas Stienen committed
180
181


182
IVAInterface* VACore::CreateCoreInstance( const CVAStruct& oArgs )
Jonas Stienen's avatar
Jonas Stienen committed
183
{
184
	VA_TRACE( "Config", oArgs );
Jonas Stienen's avatar
Jonas Stienen committed
185
186
187
	return new CVACoreImpl( oArgs );
}

188
189
190
191
192
193
void VACore::StoreCoreConfigToFile( const CVAStruct& oConfig, const std::string& sConfigFilePath )
{
	StoreStructToINIFile( sConfigFilePath, oConfig );
}

CVAStruct VACore::LoadCoreConfigFromFile( const std::string& sConfigFilePath )
194
{
Jonas Stienen's avatar
Jonas Stienen committed
195
196
197
	CVAStruct oFinalCoreConfigStruct, oCurrentConfig;
	std::list< VistaFileSystemFile > voConfigFiles;
	std::vector< VistaFileSystemDirectory > voIncludePaths;
198
	voConfigFiles.push_back( VistaFileSystemFile( sConfigFilePath ) );
Jonas Stienen's avatar
Jonas Stienen committed
199

200
201
	VA_PRINT( "VA working directory: '" << VistaFileSystemDirectory::GetCurrentWorkingDirectory() << "'" );

Jonas Stienen's avatar
Jonas Stienen committed
202
203
204
205
206
207
208
	while( voConfigFiles.empty() == false )
	{
		VistaFileSystemFile oCurrentConfigFile( voConfigFiles.front() );
		voConfigFiles.pop_front();

		if( oCurrentConfigFile.Exists() == false )
		{
209
			for( size_t n = 0; n < voIncludePaths.size(); n++ )
Jonas Stienen's avatar
Jonas Stienen committed
210
			{
211
				std::string sCombinedFilePath = voIncludePaths[ n ].GetName() + PATH_SEPARATOR + oCurrentConfigFile.GetLocalName();
Jonas Stienen's avatar
Jonas Stienen committed
212
213
214
				oCurrentConfigFile.SetName( sCombinedFilePath );
				if( oCurrentConfigFile.Exists() && oCurrentConfigFile.IsFile() )
				{
215
					VA_INFO( "Config", "Including further configuration file '" + oCurrentConfigFile.GetLocalName() +
216
						"' from include path '" + voIncludePaths[ n ].GetName() + "'" );
Jonas Stienen's avatar
Jonas Stienen committed
217
218
219
220
221
222
223
224
225
					break;
				}
			}

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

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

Jonas Stienen's avatar
Jonas Stienen committed
230
231
232
233
234
235
		if( oCurrentConfig.HasKey( "paths" ) )
		{
			const CVAStruct& oPaths( oCurrentConfig[ "paths" ] );
			CVAStruct::const_iterator it = oPaths.Begin();
			while( it != oPaths.End() )
			{
236
				const CVAStructValue& oIncludePath( ( it++ )->second );
Jonas Stienen's avatar
Jonas Stienen committed
237
238
239
240
241
242
243
244
245
246
247
248
				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() )
			{
249
250
				const CVAStructValue& oIncludeFile( ( it++ )->second );

Jonas Stienen's avatar
Jonas Stienen committed
251
252
253
254
255
256
257
258
259
260
				voConfigFiles.push_back( VistaFileSystemFile( oIncludeFile ) );
			}
		}

		oCurrentConfig.RemoveKey( "files" );

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

261
	return oFinalCoreConfigStruct;
Jonas Stienen's avatar
Jonas Stienen committed
262
263
}

264
#ifdef WIN32
Jonas Stienen's avatar
Jonas Stienen committed
265
266
// Trick um DLL-Pfad zu ermitteln
EXTERN_C IMAGE_DOS_HEADER __ImageBase;
267
#endif
Jonas Stienen's avatar
Jonas Stienen committed
268

269
std::string VACore::GetCoreLibFilePath()
Jonas Stienen's avatar
Jonas Stienen committed
270
{
271
#ifdef WIN32
Jonas Stienen's avatar
Jonas Stienen committed
272
	CHAR pszPath[ MAX_PATH + 1 ] = { 0 };
273
	GetModuleFileNameA( ( HINSTANCE ) &__ImageBase, pszPath, _countof( pszPath ) );
Jonas Stienen's avatar
Jonas Stienen committed
274
	return std::string( pszPath );
275
276
#else
	VA_EXCEPT2( NOT_IMPLEMENTED, "This function is not implemented for your platform. Sorry." );
Jonas Stienen's avatar
Jonas Stienen committed
277
	return "";
278
#endif // WIN32
Jonas Stienen's avatar
Jonas Stienen committed
279
280
}

281
282
283
284
CVACoreImpl::CVACoreImpl( const CVAStruct& oArgs )
	: m_pAudioDriverBackend( nullptr ),
	m_pGlobalSamplePool( nullptr ),
	m_pGlobalSampler( nullptr ),
285
286
287
	m_pSignalSourceManager( nullptr ),
	m_pDirectivityManager( nullptr ),
	m_pSceneManager( nullptr ),
288
	m_pNewSceneState( nullptr ),
Dipl.-Ing. Jonas Stienen's avatar
Dipl.-Ing. Jonas Stienen committed
289
290
291
	m_iCurActiveSoundReceiver( -1 ),
	m_iNewActiveSoundReceiver( -1 ),
	m_iUpdActiveSoundReceiver( -1 ),
292
	m_pEventManager( nullptr ),
293
294
295
296
	m_pCoreThread( nullptr ),
	m_pInputAmp( nullptr ),
	m_pR2RPatchbay( nullptr ),
	m_pOutputPatchbay( nullptr ),
297
298
	m_pInputStreamDetector( nullptr ),
	m_pOutputStreamDetector( nullptr ),
299
300
301
302
303
304
305
306
307
308
309
	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 mssen erst in Initialize gesetzt werden?
310
	m_iGlobalAuralizationMode( IVAInterface::VA_AURAMODE_ALL ),
311
312
313
314
315
316
	m_dOutputGain( 1 ), m_dInputGain( 1 ),
	m_bOutputMuted( false ), m_bInputMuted( false ),
	m_dStreamClockOffset( 0 ), m_fCoreClockOffset( 0 ),

	// --= Profiling =--
	m_pmCoreThreadLoopTotalDuration( "Core thread loop" )
Jonas Stienen's avatar
Jonas Stienen committed
317
318
319
{
	VA_NO_REENTRANCE;

320
321
322
323
	VA_TRY
	{
		// read configuration
		m_oCoreConfig.Init( oArgs );
Jonas Stienen's avatar
Jonas Stienen committed
324

325
		// register core itself as a module
Jonas Stienen's avatar
Jonas Stienen committed
326
327
		SetObjectName( "VACore" );
		m_oModules.RegisterObject( this );
328
		VA_VERBOSE( "Core", "Registered core module with name '" << GetObjectName() << "'" );
Jonas Stienen's avatar
Jonas Stienen committed
329
330
331

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

Jonas Stienen's avatar
Jonas Stienen committed
334
335
		m_iState = VA_CORESTATE_CREATED;

336
		VA_TRACE( "Core", "CVACoreImpl instance created [" << this << "]" );
Jonas Stienen's avatar
Jonas Stienen committed
337

338
339
	}
	VA_RETHROW;
Jonas Stienen's avatar
Jonas Stienen committed
340
341
}

342
343
CVACoreImpl::~CVACoreImpl()
{
Jonas Stienen's avatar
Jonas Stienen committed
344
345
346
	VA_NO_REENTRANCE;

	// Implizit finalisieren, falls dies nicht durch den Benutzer geschah
347
348
349
350
	if( m_iState == VA_CORESTATE_READY )
	{
		VA_TRY
		{
Jonas Stienen's avatar
Jonas Stienen committed
351
			Finalize();
352
		}
353
			VA_FINALLY
354
		{
Jonas Stienen's avatar
Jonas Stienen committed
355
356
357
358
359
			// Fehler beim Finalisieren ignorieren
		};
	}

	// Nachricht senden [blocking], das die Kerninstanz gelscht wird.
360
	CVAEvent ev;
361
	ev.iEventType = CVAEvent::DESTROY;
Jonas Stienen's avatar
Jonas Stienen committed
362
	ev.pSender = this;
363
	m_pEventManager->BroadcastEvent( ev );
Jonas Stienen's avatar
Jonas Stienen committed
364
365
366
367
368

	// Module deregistrieren
	m_oModules.Clear();

	// Nachrichten-Manager freigeben
369
370
	VA_TRY
	{
371
		delete m_pEventManager;
372
373
	}
	VA_RETHROW;
Jonas Stienen's avatar
Jonas Stienen committed
374

375
	VA_TRACE( "Core", "CVACoreImpl instance deleted [" << this << "]" );
Jonas Stienen's avatar
Jonas Stienen committed
376
377

	// Profiling ausgeben
378
	VA_VERBOSE( "Core", m_pmCoreThreadLoopTotalDuration.ToString() );
Jonas Stienen's avatar
Jonas Stienen committed
379
380
}

381
void CVACoreImpl::SetOutputStream( std::ostream* posDebug )
382
{
383
384
	VALog_setOutputStream( posDebug );
	VALog_setErrorStream( posDebug );
Jonas Stienen's avatar
Jonas Stienen committed
385
386
}

387
void CVACoreImpl::GetVersionInfo( CVAVersionInfo* pVersionInfo ) const
Jonas Stienen's avatar
Jonas Stienen committed
388
389
390
391
392
{
	if( !pVersionInfo )
		return;

	std::stringstream ss;
393
	ss << VACORE_VERSION_MAJOR << "." << VACORE_VERSION_MINOR;
Jonas Stienen's avatar
Jonas Stienen committed
394
	pVersionInfo->sVersion = ss.str();
395
396
397
398
	ss.clear();
#ifdef VACORE_CMAKE_DATE
	ss << VACORE_CMAKE_DATE;
#else
399
	ss << "Unkown date";
400
401
#endif
	pVersionInfo->sDate = ss.str();
Jonas Stienen's avatar
Jonas Stienen committed
402
	pVersionInfo->sFlags = "";
403

Jonas Stienen's avatar
Jonas Stienen committed
404
#ifdef DEBUG
405
	pVersionInfo->sComments = "debug";
Jonas Stienen's avatar
Jonas Stienen committed
406
#else
407
	pVersionInfo->sComments = "release";
Jonas Stienen's avatar
Jonas Stienen committed
408
409
410
#endif
}

411
412
void CVACoreImpl::AttachEventHandler( IVAEventHandler* pCoreEventHandler )
{
Jonas Stienen's avatar
Jonas Stienen committed
413
414
415
	VA_TRY
	{
		// Immer mglich. Unabhngig vom Zustand. Thread-safety wird im Manager geregelt.
416
		m_pEventManager->AttachHandler( pCoreEventHandler );
417
418
	}
	VA_RETHROW;
Jonas Stienen's avatar
Jonas Stienen committed
419
420
}

421
422
423
424
void CVACoreImpl::DetachEventHandler( IVAEventHandler* pCoreEventHandler )
{
	VA_TRY
	{
Jonas Stienen's avatar
Jonas Stienen committed
425
		// Immer mglich. Unabhngig vom Zustand. Thread-safety wird im Manager geregelt.
426
		m_pEventManager->DetachHandler( pCoreEventHandler );
427
428
	}
	VA_RETHROW;
Jonas Stienen's avatar
Jonas Stienen committed
429
430
}

431
432
433
int CVACoreImpl::GetState() const
{
	VA_VERBOSE( "Core", "Core state requested, current state is " << m_iState );
Jonas Stienen's avatar
Jonas Stienen committed
434
435
436
437
438
439
440
441
	return m_iState;
}

void CVACoreImpl::Initialize() {
	VA_NO_REENTRANCE;

	// TODO: Prfen ob im Fehlerfall zurck in den sauberen Grundzustand [WICHTIG!]

442
	VA_VERBOSE( "Core", "Initializing core" );
Jonas Stienen's avatar
Jonas Stienen committed
443

444
445
	VA_TRY
	{
446
447
		if( m_iState == VA_CORESTATE_READY )
		VA_EXCEPT2( MODAL_ERROR, "Core already initialized." );
Jonas Stienen's avatar
Jonas Stienen committed
448

449
450
		if( m_iState == VA_CORESTATE_FAIL )
			VA_EXCEPT2( MODAL_ERROR, "Core corrupted, reinitialization impossible" );
Jonas Stienen's avatar
Jonas Stienen committed
451

452
		m_pCoreThread = new CVACoreThread( this );
Jonas Stienen's avatar
Jonas Stienen committed
453

454
		SetProgress( "Setting up audio hardware", "", 1 );
Jonas Stienen's avatar
Jonas Stienen committed
455
456
		InitializeAudioDriver();

457
		m_pR2RPatchbay = new ITAStreamPatchbay( m_oCoreConfig.oAudioDriverConfig.dSampleRate, m_oCoreConfig.oAudioDriverConfig.iBuffersize );
Jonas Stienen's avatar
Jonas Stienen committed
458
459

		// Create output patch bay with a single output that uses all available physical audio outputs from sound card
460
		m_pOutputPatchbay = new ITAStreamPatchbay( m_oCoreConfig.oAudioDriverConfig.dSampleRate, m_oCoreConfig.oAudioDriverConfig.iBuffersize );
Jonas Stienen's avatar
Jonas Stienen committed
461
462
463
464
465
		int iPhysicalHardwareOutput = m_pOutputPatchbay->AddOutput( m_oCoreConfig.oAudioDriverConfig.iOutputChannels );
		m_pOutputPatchbay->SetOutputGain( iPhysicalHardwareOutput, m_dOutputGain );

		m_iGlobalAuralizationMode = VA_AURAMODE_ALL;

466
		// Set up input stream network
Jonas Stienen's avatar
Jonas Stienen committed
467
		ITADatasource* pInputTail = nullptr;
468
469
		if( m_oCoreConfig.oAudioDriverConfig.iInputChannels > 0 )
		{
Jonas Stienen's avatar
Jonas Stienen committed
470
			pInputTail = m_pAudioDriverBackend->getInputStreamDatasource();
471
472
			if( pInputTail )
			{
473
				m_pInputAmp = new ITAStreamAmplifier( pInputTail, ( float ) m_dInputGain );
474
				m_pInputStreamDetector = new ITAStreamDetector( m_pInputAmp );
475
				m_pInputStreamDetector->SetProfilerEnabled( true );
476
				pInputTail = m_pInputStreamDetector;
Jonas Stienen's avatar
Jonas Stienen committed
477

478
479
480
481
482
				if( m_oCoreConfig.bRecordDeviceInputEnabled )
				{
					m_pStreamProbeDeviceInput = new ITAStreamProbe( pInputTail, m_oCoreConfig.sRecordDeviceInputFilePath );
					pInputTail = m_pStreamProbeDeviceInput;
				}
Jonas Stienen's avatar
Jonas Stienen committed
483
484
485
			}
		}

486
		SetProgress( "Setting up resource managers", "", 2 );
Jonas Stienen's avatar
Jonas Stienen committed
487

488
		m_pSignalSourceManager = new CVAAudioSignalSourceManager( this, m_oCoreConfig.oAudioDriverConfig, pInputTail );
489
490
		m_pGlobalSamplePool = ITASoundSamplePool::Create( 1, m_oCoreConfig.oAudioDriverConfig.dSampleRate );
		m_pGlobalSampler = ITASoundSampler::Create( 1, m_oCoreConfig.oAudioDriverConfig.dSampleRate, m_oCoreConfig.oAudioDriverConfig.iBuffersize, m_pGlobalSamplePool );
Jonas Stienen's avatar
Jonas Stienen committed
491
		m_pGlobalSampler->AddMonoTrack();
492

493
494
		m_pDirectivityManager = new CVADirectivityManager( this, m_oCoreConfig.oAudioDriverConfig.dSampleRate );
		m_pDirectivityManager->Initialize();
Jonas Stienen's avatar
Jonas Stienen committed
495
496


497
		SetProgress( "Setting up scene management", "", 3 );
Jonas Stienen's avatar
Jonas Stienen committed
498

499
500
501
		m_pSceneManager = new CVASceneManager( m_pClock );
		m_pSceneManager->Initialize();
		m_pCurSceneState = m_pSceneManager->GetHeadSceneState();
502

503
504
505
506
507
508
		SetProgress( "Setting up medium environment", "", 4 );

		oHomogeneousMedium = m_oCoreConfig.oInitialHomogeneousMedium;


		SetProgress( "Initializing rendering modules", "", 5 );
Jonas Stienen's avatar
Jonas Stienen committed
509

510
		// Register all renderers and initialize
511
		CVAAudioRendererRegistry::GetInstance()->RegisterInternalCoreFactoryMethods();
Jonas Stienen's avatar
Jonas Stienen committed
512
513
		InitializeAudioRenderers();

514
		if( m_voRenderers.empty() )
Jonas Stienen's avatar
Jonas Stienen committed
515
516
			VA_EXCEPT1( "No audio renderers created" );

517

518
		SetProgress( "Initializing reproduction modules", "", 6 );
519

520
		// Register all reproductions and initialize
521
		CVAAudioReproductionRegistry::GetInstance()->RegisterInternalCoreFactoryMethods();
Jonas Stienen's avatar
Jonas Stienen committed
522
523
		InitializeReproductionModules();

524
		if( m_voReproductionModules.empty() )
Jonas Stienen's avatar
Jonas Stienen committed
525
			VA_EXCEPT1( "No audio reproduction modules created" );
526

527
528
529

		SetProgress( "Patching audio i/o of rendering and reproduction modules", "", 7 );

Jonas Stienen's avatar
Jonas Stienen committed
530
531
532
533
534
535
536
537
		// Patch renderer and reproduction modules
		PatchRendererToReproductionModules();

		// Patch audio reproduction to output
		PatchReproductionModulesToOutput();


		// Create output peak detector that uses patch bay output stream
Michael Kohnen's avatar
merging    
Michael Kohnen committed
538

539
		m_pOutputStreamDetector = new ITAStreamDetector( m_pOutputPatchbay->GetOutputDatasource( iPhysicalHardwareOutput ) );
540
		m_pOutputStreamDetector->SetProfilerEnabled( true );
541
542


Jonas Stienen's avatar
Jonas Stienen committed
543
		// Setup output dump (if set)
544
		ITADatasource* pOutputTail = m_pOutputStreamDetector;
545
		if( m_oCoreConfig.bRecordDeviceOutputEnabled )
Jonas Stienen's avatar
Jonas Stienen committed
546
		{
547
			m_pStreamProbeFinal = new ITAStreamProbe( pOutputTail, m_oCoreConfig.sRecordFinalOutputFilePath );
Jonas Stienen's avatar
Jonas Stienen committed
548
549
550
551
			pOutputTail = m_pStreamProbeFinal;
		}

		// Attach the stream tracker
552
		m_pOutputTracker = new CVAAudiostreamTracker( pOutputTail, m_pClock, &m_fCoreClockOffset, &m_lSyncModOwner, m_pSignalSourceManager );
Jonas Stienen's avatar
Jonas Stienen committed
553
554
555
556
557
558
559
		pOutputTail = m_pOutputTracker;

		// Give output stream datasource to audio driver
		m_pAudioDriverBackend->setOutputStreamDatasource( pOutputTail );

		// Core-Clock auf 0 initialisieren
		double dNow = m_pClock->getTime();
560
		m_fCoreClockOffset = ( float ) dNow;
Jonas Stienen's avatar
Jonas Stienen committed
561
562
563
		m_dStreamClockOffset = -1;

		// Timer erzeugen und konfigurieren (wird fr Peak-Events benutzt)
564
		m_pTicker = new VistaTicker();
565
		m_pTicker->AddTrigger( new VistaTicker::TriggerContext( m_oCoreConfig.iTriggerUpdateMilliseconds, true ) );
566
		m_pTicker->SetAfterPulseFunctor( this );
Jonas Stienen's avatar
Jonas Stienen committed
567
568

		// Audio-Streaming starten
569
		SetProgress( "Starting audio streaming", "", 8 );
Jonas Stienen's avatar
Jonas Stienen committed
570
571
572
		m_pAudioDriverBackend->startStreaming();

		// Timer fr Peak-Events starten
573
		m_pTicker->StartTicker();
Jonas Stienen's avatar
Jonas Stienen committed
574
575
576
577

		// Initialisierung erfolgreich!
		m_iState = VA_CORESTATE_READY;

578
		SetProgress( "Initialization finished", "", 9 );
Jonas Stienen's avatar
Jonas Stienen committed
579
580
		FinishProgress();

Dipl.-Ing. Jonas Stienen's avatar
Dipl.-Ing. Jonas Stienen committed
581
	}
582
		VA_FINALLY
Dipl.-Ing. Jonas Stienen's avatar
Dipl.-Ing. Jonas Stienen committed
583
	{
Jonas Stienen's avatar
Jonas Stienen committed
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
		// Aufrumen und Exception weiterwerfen
		Tidyup();
		throw;
	}
}

void CVACoreImpl::Reset()
{
	VA_CHECK_INITIALIZED;

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

	VA_NO_REENTRANCE;

600
	if( GetUpdateLocked() )
Jonas Stienen's avatar
Jonas Stienen committed
601
	{
602
		VA_WARN( "Core", "Encountered locked scene during reset. Please unlock before resetting, skipping." );
Jonas Stienen's avatar
Jonas Stienen committed
603
604
605
606
607
		m_pCoreThread->Continue();
	}

	VA_TRY
	{
608
		VA_INFO( "Core", "Resetting core" );
Jonas Stienen's avatar
Jonas Stienen committed
609
610

		// Reset audio renderers
611
612
		std::vector< CVAAudioRendererDesc >::iterator it = m_voRenderers.begin();
		while( it != m_voRenderers.end() )
Jonas Stienen's avatar
Jonas Stienen committed
613
614
615
616
		{
			CVAAudioRendererDesc& oRend( *it++ );
			oRend.pInstance->Reset();
		}
617

Jonas Stienen's avatar
Jonas Stienen committed
618
619
620
		if( m_pCurSceneState )
		{
			// Referenz entfernen welche in CoreThreadLoop hinzugefgt wurde
621
			m_pCurSceneState->RemoveReference();
Jonas Stienen's avatar
Jonas Stienen committed
622
623
624
625
			m_pCurSceneState = nullptr;
		}

		// Alle Szenenobjekte lschen
626
627
628
		m_pSceneManager->Reset();
		m_pSignalSourceManager->Reset();
		m_pDirectivityManager->Reset();
Jonas Stienen's avatar
Jonas Stienen committed
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644

		// 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
645
		m_pCurSceneState = m_pSceneManager->GetHeadSceneState();
Dipl.-Ing. Jonas Stienen's avatar
Dipl.-Ing. Jonas Stienen committed
646
647
		m_iCurActiveSoundReceiver = -1;
		m_iNewActiveSoundReceiver = -1;
Jonas Stienen's avatar
Jonas Stienen committed
648
649
650
651
652
653
654

		m_pCoreThread;

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

		// Ereignis generieren, wenn Operation erfolgreich
655
		CVAEvent ev;
656
		ev.iEventType = CVAEvent::RESET;
Jonas Stienen's avatar
Jonas Stienen committed
657
		ev.pSender = this;
658
		m_pEventManager->BroadcastEvent( ev );
Jonas Stienen's avatar
Jonas Stienen committed
659
660

	}
661
		VA_FINALLY
Jonas Stienen's avatar
Jonas Stienen committed
662
663
664
665
666
667
668
669
	{
		Tidyup();
		throw;
	}
}

void CVACoreImpl::Tidyup() {
	/*
670
	 *  Hinweis: Diese Hilfsmethode wird nur innerhalb des Reentrance-Locks
Jonas Stienen's avatar
Jonas Stienen committed
671
672
	 *           aufgerufen - daher keine weiter Absicherung ntig.
	 */
673

Jonas Stienen's avatar
Jonas Stienen committed
674
675
	VA_TRY
	{
676
677
678
679
680
		if( m_pTicker )
		{
			m_pTicker->StopTicker();
			m_pTicker->SetAfterPulseFunctor( NULL );
		}
Jonas Stienen's avatar
Jonas Stienen committed
681
682

		FinalizeAudioDriver();
683
684
		FinalizeRenderingModules();
		FinalizeReproductionModules();
Jonas Stienen's avatar
Jonas Stienen committed
685

686
687
		delete m_pTicker;
		m_pTicker = nullptr;
Jonas Stienen's avatar
Jonas Stienen committed
688
689
690
691
692
693
694

		delete m_pCoreThread;
		m_pCoreThread = nullptr;

		delete m_pInputAmp;
		m_pInputAmp = nullptr;

695
696
		delete m_pInputStreamDetector;
		m_pInputStreamDetector = nullptr;
Jonas Stienen's avatar
Jonas Stienen committed
697
698
699
700
701
702
703

		delete m_pR2RPatchbay;
		m_pR2RPatchbay = nullptr;

		delete m_pOutputPatchbay;
		m_pOutputPatchbay = nullptr;

704
705
		delete m_pOutputStreamDetector;
		m_pOutputStreamDetector = nullptr;
Jonas Stienen's avatar
Jonas Stienen committed
706
707
708

		delete m_pOutputTracker;
		m_pOutputTracker = nullptr;
709

Jonas Stienen's avatar
Jonas Stienen committed
710
711
712
713
714
715
		delete m_pStreamProbeDeviceInput;
		m_pStreamProbeDeviceInput = nullptr;

		delete m_pStreamProbeFinal;
		m_pStreamProbeFinal = nullptr;

716
717
		delete m_pSignalSourceManager;
		m_pSignalSourceManager = nullptr;
Jonas Stienen's avatar
Jonas Stienen committed
718
719
720
721
722
723
724

		delete m_pGlobalSampler;
		m_pGlobalSampler = nullptr;

		delete m_pGlobalSamplePool;
		m_pGlobalSamplePool = nullptr;

725
726
727
728
		if( m_pDirectivityManager )
			m_pDirectivityManager->Finalize();
		delete m_pDirectivityManager;
		m_pDirectivityManager = nullptr;
Jonas Stienen's avatar
Jonas Stienen committed
729
730


731
732
733
734
		if( m_pSceneManager )
			m_pSceneManager->Finalize();
		delete m_pSceneManager;
		m_pSceneManager = nullptr;
Jonas Stienen's avatar
Jonas Stienen committed
735
736
737
738

		m_iState = VA_CORESTATE_CREATED;

	}
739
		VA_FINALLY
Jonas Stienen's avatar
Jonas Stienen committed
740
741
742
743
744
	{
		m_iState = VA_CORESTATE_FAIL;
	}
}

745
746
void CVACoreImpl::Finalize()
{
Jonas Stienen's avatar
Jonas Stienen committed
747
748
749
	VA_NO_REENTRANCE;

	//VA_TRACE("Core", __FUNCTION__ << " entry");
750
	VA_INFO( "Core", "Finalizing core" );
Jonas Stienen's avatar
Jonas Stienen committed
751

752
753
	VA_TRY
	{
Jonas Stienen's avatar
Jonas Stienen committed
754
		// Mehrfaches Finialisieren fhrt nicht zu Fehlern
755
756
757
758
		if( m_iState == VA_CORESTATE_CREATED ) return;

		if( m_iState == VA_CORESTATE_FAIL )
			VA_EXCEPT2( MODAL_ERROR, "Core corrupted, finalization impossible" );
Jonas Stienen's avatar
Jonas Stienen committed
759
760
761
762
763
764
765
766

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

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

Jonas Stienen's avatar
Jonas Stienen committed
768
		// Reset audio renderers
769
		for( std::vector<CVAAudioRendererDesc>::iterator it = m_voRenderers.begin(); it != m_voRenderers.end(); ++it )
Jonas Stienen's avatar
Jonas Stienen committed
770
771
772
			it->pInstance->Reset();

		// Peak-Nachrichten stoppen
773
		m_pTicker->StopTicker();
Jonas Stienen's avatar
Jonas Stienen committed
774
775
776
777

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

778
		InitProgress( "Stopping auralization threads", "", 2 );
Jonas Stienen's avatar
Jonas Stienen committed
779

780
781
782
783
		// Stop and delete ticker
		m_pTicker->SetAfterPulseFunctor( NULL );
		delete m_pTicker;
		m_pTicker = NULL;
Jonas Stienen's avatar
Jonas Stienen committed
784
785
786
787
788

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

789
		SetProgress( "Releasing audio hardware", "", 1 );
Jonas Stienen's avatar
Jonas Stienen committed
790
		FinalizeAudioDriver();
791
792
		FinalizeRenderingModules();
		FinalizeReproductionModules();
Jonas Stienen's avatar
Jonas Stienen committed
793

794
		SetProgress( "Cleaning up resources", "", 2 );
Jonas Stienen's avatar
Jonas Stienen committed
795
796
797
		delete m_pInputAmp;
		m_pInputAmp = nullptr;

798
799
800
		if( m_pInputStreamDetector )
			if( m_pInputStreamDetector->GetProfilerEnabled() )
				VA_VERBOSE( "Core", "Input stream detector profiler: " << m_pInputStreamDetector->GetProfilerResult() );
801
802
		delete m_pInputStreamDetector;
		m_pInputStreamDetector = nullptr;
Jonas Stienen's avatar
Jonas Stienen committed
803

804
		m_voReproductionModules.clear();
Jonas Stienen's avatar
Jonas Stienen committed
805
806
807
808
809
810
811

		delete m_pR2RPatchbay;
		m_pR2RPatchbay = nullptr;

		delete m_pOutputPatchbay;
		m_pOutputPatchbay = nullptr;

812
813
		if( m_pOutputStreamDetector->GetProfilerEnabled() )
			VA_VERBOSE( "Core", "Output stream detector profiler: " << m_pOutputStreamDetector->GetProfilerResult() );
814
815
		delete m_pOutputStreamDetector;
		m_pOutputStreamDetector = nullptr;
Jonas Stienen's avatar
Jonas Stienen committed
816
817
818
819
820
821
822
823
824
825

		delete m_pOutputTracker;
		m_pOutputTracker = nullptr;

		delete m_pStreamProbeDeviceInput;
		m_pStreamProbeDeviceInput = nullptr;

		delete m_pStreamProbeFinal;
		m_pStreamProbeFinal = nullptr;

826
827
		delete m_pSignalSourceManager;
		m_pSignalSourceManager = nullptr;
Jonas Stienen's avatar
Jonas Stienen committed
828
829
830
831
832
833
834

		delete m_pGlobalSampler;
		m_pGlobalSampler = nullptr;

		delete m_pGlobalSamplePool;
		m_pGlobalSamplePool = nullptr;

835
836
837
		m_pDirectivityManager->Finalize();
		delete m_pDirectivityManager;
		m_pDirectivityManager = nullptr;
Jonas Stienen's avatar
Jonas Stienen committed
838

839
840
841
		m_pSceneManager->Finalize();
		delete m_pSceneManager;
		m_pSceneManager = nullptr;
Jonas Stienen's avatar
Jonas Stienen committed
842
843
844
845
846
847

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

		FinishProgress();

848
849
850
	}
		VA_FINALLY
	{
Jonas Stienen's avatar
Jonas Stienen committed
851
852
853
854
855
856
857
858
859
860
861
862
		// Nochmals versuchen aufzurumen
		Tidyup();

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

		// VAExceptions unverndert nach aussen leiten
		throw;
	}
}


863
void CVACoreImpl::RegisterModule( CVAObject* pModule )
Jonas Stienen's avatar
Jonas Stienen committed
864
{
865
	m_oModules.RegisterObject( pModule );
Jonas Stienen's avatar
Jonas Stienen committed
866
867
}

868
void CVACoreImpl::GetModules( std::vector< CVAModuleInfo >& viModuleInfos ) const
869
{
Jonas Stienen's avatar
Jonas Stienen committed
870
871
872
	VA_NO_REENTRANCE;
	VA_CHECK_INITIALIZED;

873
#ifdef VACORE_MODULE_INTERFACE_ENABLED
874
875
	VA_TRY
	{
Jonas Stienen's avatar
Jonas Stienen committed
876
		std::vector<CVAObjectInfo> v;
877
		m_oModules.GetObjectInfos( v );
Jonas Stienen's avatar
Jonas Stienen committed
878

879
		VA_PRINT( "Available modules (" << v.size() << ")" );
Jonas Stienen's avatar
Jonas Stienen committed
880
881
882

		viModuleInfos.clear();
		viModuleInfos.resize( v.size() );
883
884
885
886
887
		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;
Jonas Stienen's avatar
Jonas Stienen committed
888
		}
889
		}
890
891
	VA_RETHROW;

892
#else // VACORE_MODULE_INTERFACE_ENABLED
893

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

896
#endif // VACORE_MODULE_INTERFACE_ENABLED
897

898
	}
Jonas Stienen's avatar
Jonas Stienen committed
899

900
CVAStruct CVACoreImpl::CallModule( const std::string& sModuleName, const CVAStruct& oArgs )
901
{
Jonas Stienen's avatar
Jonas Stienen committed
902
903
904
	VA_NO_REENTRANCE;
	VA_CHECK_INITIALIZED;

905
#ifdef VACORE_MODULE_INTERFACE_ENABLED
906
907
908

	VA_TRY
	{
909
		CVAObject* pModule = m_oModules.FindObjectByName( sModuleName );
910
		if( !pModule )
911
		{
912
			VA_EXCEPT2( INVALID_PARAMETER, "Module '" + sModuleName + "' not found" );
913
		}
914
915
916

#ifdef VACORE_MODULE_INTERFACE_MECHANISM_EVENT_BASED

917
		CVAEvent ev;
918
		ev.iEventType = CVAEvent::SIGNALSOURCE_STATE_CHANGED;
919
920
921
		ev.pSender = this;
		ev.sObjectID = sModuleName;
		ev;
922
923
		m_pEventManager->BroadcastEvent( ev );
		m_pEventManager->
924
925
926

#else // not VACORE_MODULE_INTERFACE_MECHANISM_EVENT_BASED

927
		return pModule->CallObject( oArgs );
928
929

#endif // VACORE_MODULE_INTERFACE_MECHANISM_EVENT_BASED
Jonas Stienen's avatar
Jonas Stienen committed
930

931
932
	}
	VA_RETHROW;
933

934
#else // VACORE_MODULE_INTERFACE_ENABLED
935

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

940
#endif // VACORE_MODULE_INTERFACE_ENABLED
Jonas Stienen's avatar
Jonas Stienen committed
941
942
}

943
944
945
946
CVAStruct CVACoreImpl::GetSearchPaths() const
{
	VA_NO_REENTRANCE;
	VA_CHECK_INITIALIZED;
Jonas Stienen's avatar
Jonas Stienen committed
947

948
949
950
951
952
953
954
	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;
}

955
CVAStruct CVACoreImpl::GetCoreConfiguration( const bool bFilterEnabled ) const
Jonas Stienen's avatar
Jonas Stienen committed
956
957
958
959
{
	VA_NO_REENTRANCE;
	VA_CHECK_INITIALIZED;

960
961
	CVAStruct oCoreConfig;

962
963
964
965
966
	if( bFilterEnabled )
	{
		CVAStruct::const_iterator cit = m_oCoreConfig.GetStruct().Begin();
		while( cit != m_oCoreConfig.GetStruct().End() )
		{
967
968
969
970
			const std::string sKey( cit->first );
			const CVAStructValue& oVal( cit->second );
			++cit;

971
972
973
974
975
976
			if( oVal.IsStruct() )
			{
				const CVAStruct& oSection( oVal.GetStruct() );
				if( oSection.HasKey( "enabled" ) )
					if( bool( oSection[ "enabled" ] ) == false )
						continue; // Only skip if explicitly not enabled
977
				oCoreConfig[ sKey ] = oVal;
978
979
			}
		}
980

981
982
983
	}
	else
	{
984
		oCoreConfig = m_oCoreConfig.GetStruct();
985
	}
986
987

	return oCoreConfig;
988
989
990
991
992
993
994
995
996
997
998
999
1000
}

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;
For faster browsing, not all history is shown. View entire blame