VACoreImpl.cpp 142 KB
Newer Older
Jonas Stienen's avatar
Jonas Stienen committed
1
/*
2
 *  --------------------------------------------------------------------------------------------
Jonas Stienen's avatar
Jonas Stienen committed
3
 *
4
5
6
 *    VVV        VVV A           Virtual Acoustics (VA) | http://www.virtualacoustics.org
 *     VVV      VVV AAA          Licensed under the Apache License, Version 2.0
 *      VVV    VVV   AAA
7
 *       VVV  VVV     AAA        Copyright 2015-2018
8
9
10
11
 *        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

#ifdef VACORE_WITH_AUDIO_BACKEND_ASIO
#include "Drivers/Audio/VAASIOBackend.h"
#endif
#ifdef VACORE_WITH_AUDIO_BACKEND_PORTAUDIO
#include "Drivers/Audio/VAPortaudioBackend.h"
#endif
52
53
54
#ifdef VACORE_WITH_AUDIO_BACKEND_DUMMY
#include "Drivers/Audio/VADummyAudioDriverBackend.h"
#endif
55

Jonas Stienen's avatar
Jonas Stienen committed
56
57
58
59
// ITA includes
#include <ITAASCIITable.h>
#include <ITAClock.h>
#include <ITAException.h>
60
#include <ITAFileSystemUtils.h>
Jonas Stienen's avatar
Jonas Stienen committed
61
#include <ITAFunctors.h>
62
#include <ITAStreamDetector.h>
Jonas Stienen's avatar
Jonas Stienen committed
63
64
65
66
#include <ITASoundSample.h>
#include <ITASoundSampler.h>
#include <ITASoundSamplePool.h>
#include <ITAStreamAmplifier.h>
67
#include <ITAStreamPatchBay.h>
Jonas Stienen's avatar
Jonas Stienen committed
68
69
70
71
72
73
74
75
76
77
78
79
#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>
80
#include <iomanip>
Jonas Stienen's avatar
Jonas Stienen committed
81
82
#include <iostream>

83
84
85
86

// We know about unreferenced formal parameters. There are a lot of unused methods for future use.
#pragma warning( disable : 4100 )

Jonas Stienen's avatar
Jonas Stienen committed
87
88
89
90
91
92
93
94
95
96
/*

	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
97
	unterbunden. Sollte dies zu Performance-Problemen fhren, kann ein
Jonas Stienen's avatar
Jonas Stienen committed
98
99
100
101
102
	verfeinerter Locking-Mechanismus entwickelt werden. Zunchst mal aber so.


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

103
	*/
Jonas Stienen's avatar
Jonas Stienen committed
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128


// --= 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
129
130
	CVAException geworfen werden. Nach aussen hin drfen
	aber NUR CVAExceptions geworfen werden (Konsistent)
Jonas Stienen's avatar
Jonas Stienen committed
131
132

	Lsung: TRY-/CATCH-Makros fr abgesicherte Bereiche in allen Methoden
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
	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
151
152

	Beispiel:
153
154
155
156
157
158

	VA_TRY {
	// Code ..
	} VA_CATCH {
	// Mach was ...
	}
Jonas Stienen's avatar
Jonas Stienen committed
159
160
161

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

162
	*/
Jonas Stienen's avatar
Jonas Stienen committed
163
164

#define VA_TRY \
165
try { try
Jonas Stienen's avatar
Jonas Stienen committed
166
167

#define VA_CATCH(EXPR) \
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( CVAException& EXPR )
Jonas Stienen's avatar
Jonas Stienen committed
173
174

#define VA_FINALLY \
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( ... )
Jonas Stienen's avatar
Jonas Stienen committed
180
181

#define VA_RETHROW \
182
183
184
185
186
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
187
188


189
IVAInterface* VACore::CreateCoreInstance( const CVAStruct& oArgs, std::ostream* pOutputStream )
Jonas Stienen's avatar
Jonas Stienen committed
190
{
191
	VA_TRACE( "Config", oArgs );
192
	return new CVACoreImpl( oArgs, pOutputStream );
Jonas Stienen's avatar
Jonas Stienen committed
193
194
}

195
196
197
198
199
200
void VACore::StoreCoreConfigToFile( const CVAStruct& oConfig, const std::string& sConfigFilePath )
{
	StoreStructToINIFile( sConfigFilePath, oConfig );
}

CVAStruct VACore::LoadCoreConfigFromFile( const std::string& sConfigFilePath )
201
{
Jonas Stienen's avatar
Jonas Stienen committed
202
203
204
	CVAStruct oFinalCoreConfigStruct, oCurrentConfig;
	std::list< VistaFileSystemFile > voConfigFiles;
	std::vector< VistaFileSystemDirectory > voIncludePaths;
205
	voConfigFiles.push_back( VistaFileSystemFile( sConfigFilePath ) );
Jonas Stienen's avatar
Jonas Stienen committed
206

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

Jonas Stienen's avatar
Jonas Stienen committed
209
210
211
212
213
214
215
	while( voConfigFiles.empty() == false )
	{
		VistaFileSystemFile oCurrentConfigFile( voConfigFiles.front() );
		voConfigFiles.pop_front();

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

			if( !oCurrentConfigFile.Exists() )
229
			{
Jonas Stienen's avatar
Jonas Stienen committed
230
231
232
				VA_EXCEPT2( FILE_NOT_FOUND, "Configuration file '" + oCurrentConfigFile.GetLocalName() + "' not found, aborting." );
			}
		}
233

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

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

Jonas Stienen's avatar
Jonas Stienen committed
258
259
260
261
262
263
264
265
266
267
				voConfigFiles.push_back( VistaFileSystemFile( oIncludeFile ) );
			}
		}

		oCurrentConfig.RemoveKey( "files" );

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

268
	return oFinalCoreConfigStruct;
Jonas Stienen's avatar
Jonas Stienen committed
269
270
}

271
#ifdef WIN32
Jonas Stienen's avatar
Jonas Stienen committed
272
273
// Trick um DLL-Pfad zu ermitteln
EXTERN_C IMAGE_DOS_HEADER __ImageBase;
274
#endif
Jonas Stienen's avatar
Jonas Stienen committed
275

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

288
CVACoreImpl::CVACoreImpl( const CVAStruct& oArgs, std::ostream* pOutputStream )
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
	: 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 )
	, m_iGlobalAuralizationMode( IVAInterface::VA_AURAMODE_ALL )
	, m_dOutputGain( 1 )
	, m_dInputGain( 1 )
	, m_bOutputMuted( false )
	, m_bInputMuted( false )
	, m_dStreamClockOffset( 0 )
	, m_fCoreClockOffset( 0 )
	, m_oCoreThreadLoopTotalDuration( "Core thread loop" )
Jonas Stienen's avatar
Jonas Stienen committed
323
324
325
{
	VA_NO_REENTRANCE;

326
327
328
	if( pOutputStream )
		SetOutputStream( pOutputStream );

329
330
331
332
	VA_TRY
	{
		// read configuration
		m_oCoreConfig.Init( oArgs );
Jonas Stienen's avatar
Jonas Stienen committed
333

334
		// register core itself as a module
Jonas Stienen's avatar
Jonas Stienen committed
335
336
		SetObjectName( "VACore" );
		m_oModules.RegisterObject( this );
337
		VA_VERBOSE( "Core", "Registered core module with name '" << GetObjectName() << "'" );
Jonas Stienen's avatar
Jonas Stienen committed
338
339
340

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

Jonas Stienen's avatar
Jonas Stienen committed
343
344
		m_iState = VA_CORESTATE_CREATED;

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

347
348
	}
	VA_RETHROW;
Jonas Stienen's avatar
Jonas Stienen committed
349
350
}

351
352
CVACoreImpl::~CVACoreImpl()
{
Jonas Stienen's avatar
Jonas Stienen committed
353
354
355
	VA_NO_REENTRANCE;

	// Implizit finalisieren, falls dies nicht durch den Benutzer geschah
356
357
358
359
	if( m_iState == VA_CORESTATE_READY )
	{
		VA_TRY
		{
Jonas Stienen's avatar
Jonas Stienen committed
360
			Finalize();
361
		}
362
			VA_FINALLY
363
		{
Jonas Stienen's avatar
Jonas Stienen committed
364
365
366
367
368
			// Fehler beim Finalisieren ignorieren
		};
	}

	// Nachricht senden [blocking], das die Kerninstanz gelscht wird.
369
	CVAEvent ev;
370
	ev.iEventType = CVAEvent::DESTROY;
Jonas Stienen's avatar
Jonas Stienen committed
371
	ev.pSender = this;
372
	m_pEventManager->BroadcastEvent( ev );
Jonas Stienen's avatar
Jonas Stienen committed
373
374
375
376
377

	// Module deregistrieren
	m_oModules.Clear();

	// Nachrichten-Manager freigeben
378
379
	VA_TRY
	{
380
		delete m_pEventManager;
381
382
	}
	VA_RETHROW;
Jonas Stienen's avatar
Jonas Stienen committed
383

384
	VA_TRACE( "Core", "CVACoreImpl instance deleted [" << this << "]" );
Jonas Stienen's avatar
Jonas Stienen committed
385
386

	// Profiling ausgeben
387
	VA_VERBOSE( "Core", m_oCoreThreadLoopTotalDuration.ToString() );
Jonas Stienen's avatar
Jonas Stienen committed
388
389
}

390
void CVACoreImpl::SetOutputStream( std::ostream* posDebug )
391
{
392
393
	VALog_setOutputStream( posDebug );
	VALog_setErrorStream( posDebug );
Jonas Stienen's avatar
Jonas Stienen committed
394
395
}

396
void CVACoreImpl::GetVersionInfo( CVAVersionInfo* pVersionInfo ) const
Jonas Stienen's avatar
Jonas Stienen committed
397
398
399
400
401
{
	if( !pVersionInfo )
		return;

	std::stringstream ss;
402
	ss << VACORE_VERSION_MAJOR << "." << VACORE_VERSION_MINOR;
Jonas Stienen's avatar
Jonas Stienen committed
403
	pVersionInfo->sVersion = ss.str();
404
405
406
407
	ss.clear();
#ifdef VACORE_CMAKE_DATE
	ss << VACORE_CMAKE_DATE;
#else
408
	ss << "Unkown date";
409
410
#endif
	pVersionInfo->sDate = ss.str();
Jonas Stienen's avatar
Jonas Stienen committed
411
	pVersionInfo->sFlags = "";
412

Jonas Stienen's avatar
Jonas Stienen committed
413
#ifdef DEBUG
414
	pVersionInfo->sComments = "debug";
Jonas Stienen's avatar
Jonas Stienen committed
415
#else
416
	pVersionInfo->sComments = "release";
Jonas Stienen's avatar
Jonas Stienen committed
417
418
419
#endif
}

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

430
431
432
433
void CVACoreImpl::DetachEventHandler( IVAEventHandler* pCoreEventHandler )
{
	VA_TRY
	{
Jonas Stienen's avatar
Jonas Stienen committed
434
		// Immer mglich. Unabhngig vom Zustand. Thread-safety wird im Manager geregelt.
435
		m_pEventManager->DetachHandler( pCoreEventHandler );
436
437
	}
	VA_RETHROW;
Jonas Stienen's avatar
Jonas Stienen committed
438
439
}

440
441
442
int CVACoreImpl::GetState() const
{
	VA_VERBOSE( "Core", "Core state requested, current state is " << m_iState );
Jonas Stienen's avatar
Jonas Stienen committed
443
444
445
446
447
448
449
450
	return m_iState;
}

void CVACoreImpl::Initialize() {
	VA_NO_REENTRANCE;

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

451
	VA_VERBOSE( "Core", "Initializing core" );
Jonas Stienen's avatar
Jonas Stienen committed
452

453
454
	VA_TRY
	{
455
456
		if( m_iState == VA_CORESTATE_READY )
		VA_EXCEPT2( MODAL_ERROR, "Core already initialized." );
Jonas Stienen's avatar
Jonas Stienen committed
457

458
459
		if( m_iState == VA_CORESTATE_FAIL )
			VA_EXCEPT2( MODAL_ERROR, "Core corrupted, reinitialization impossible" );
Jonas Stienen's avatar
Jonas Stienen committed
460

461
		m_pCoreThread = new CVACoreThread( this );
Jonas Stienen's avatar
Jonas Stienen committed
462

463
		SetProgress( "Setting up audio hardware", "", 1 );
Jonas Stienen's avatar
Jonas Stienen committed
464
465
		InitializeAudioDriver();

466
		m_pR2RPatchbay = new ITAStreamPatchbay( m_oCoreConfig.oAudioDriverConfig.dSampleRate, m_oCoreConfig.oAudioDriverConfig.iBuffersize );
Jonas Stienen's avatar
Jonas Stienen committed
467
468

		// Create output patch bay with a single output that uses all available physical audio outputs from sound card
469
		m_pOutputPatchbay = new ITAStreamPatchbay( m_oCoreConfig.oAudioDriverConfig.dSampleRate, m_oCoreConfig.oAudioDriverConfig.iBuffersize );
Jonas Stienen's avatar
Jonas Stienen committed
470
471
472
473
474
		int iPhysicalHardwareOutput = m_pOutputPatchbay->AddOutput( m_oCoreConfig.oAudioDriverConfig.iOutputChannels );
		m_pOutputPatchbay->SetOutputGain( iPhysicalHardwareOutput, m_dOutputGain );

		m_iGlobalAuralizationMode = VA_AURAMODE_ALL;

475
		// Set up input stream network
Jonas Stienen's avatar
Jonas Stienen committed
476
		ITADatasource* pInputTail = nullptr;
477
478
		if( m_oCoreConfig.oAudioDriverConfig.iInputChannels > 0 )
		{
Jonas Stienen's avatar
Jonas Stienen committed
479
			pInputTail = m_pAudioDriverBackend->getInputStreamDatasource();
480
481
			if( pInputTail )
			{
482
				m_pInputAmp = new ITAStreamAmplifier( pInputTail, ( float ) m_dInputGain );
483
				m_pInputStreamDetector = new ITAStreamDetector( m_pInputAmp );
484
				m_pInputStreamDetector->SetProfilerEnabled( true );
485
				pInputTail = m_pInputStreamDetector;
Jonas Stienen's avatar
Jonas Stienen committed
486

487
488
489
490
491
				if( m_oCoreConfig.bRecordDeviceInputEnabled )
				{
					m_pStreamProbeDeviceInput = new ITAStreamProbe( pInputTail, m_oCoreConfig.sRecordDeviceInputFilePath );
					pInputTail = m_pStreamProbeDeviceInput;
				}
Jonas Stienen's avatar
Jonas Stienen committed
492
493
494
			}
		}

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

497
		m_pSignalSourceManager = new CVAAudioSignalSourceManager( this, m_oCoreConfig.oAudioDriverConfig, pInputTail );
498
499
		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
500
		m_pGlobalSampler->AddMonoTrack();
501

502
503
		m_pDirectivityManager = new CVADirectivityManager( this, m_oCoreConfig.oAudioDriverConfig.dSampleRate );
		m_pDirectivityManager->Initialize();
Jonas Stienen's avatar
Jonas Stienen committed
504
505


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

508
509
510
		m_pSceneManager = new CVASceneManager( m_pClock );
		m_pSceneManager->Initialize();
		m_pCurSceneState = m_pSceneManager->GetHeadSceneState();
511

512
513
514
515
516
517
		SetProgress( "Setting up medium environment", "", 4 );

		oHomogeneousMedium = m_oCoreConfig.oInitialHomogeneousMedium;


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

519
		// Register all renderers and initialize
520
		CVAAudioRendererRegistry::GetInstance()->RegisterInternalCoreFactoryMethods();
Jonas Stienen's avatar
Jonas Stienen committed
521
522
		InitializeAudioRenderers();

523
		if( m_voRenderers.empty() )
Jonas Stienen's avatar
Jonas Stienen committed
524
525
			VA_EXCEPT1( "No audio renderers created" );

526

527
		SetProgress( "Initializing reproduction modules", "", 6 );
528

529
		// Register all reproductions and initialize
530
		CVAAudioReproductionRegistry::GetInstance()->RegisterInternalCoreFactoryMethods();
Jonas Stienen's avatar
Jonas Stienen committed
531
532
		InitializeReproductionModules();

533
		if( m_voReproductionModules.empty() )
Jonas Stienen's avatar
Jonas Stienen committed
534
			VA_EXCEPT1( "No audio reproduction modules created" );
535

536
537
538

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

Jonas Stienen's avatar
Jonas Stienen committed
539
540
541
542
543
544
545
546
		// 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
547

548
		m_pOutputStreamDetector = new ITAStreamDetector( m_pOutputPatchbay->GetOutputDatasource( iPhysicalHardwareOutput ) );
549
		m_pOutputStreamDetector->SetProfilerEnabled( true );
550
551


Jonas Stienen's avatar
Jonas Stienen committed
552
		// Setup output dump (if set)
553
		ITADatasource* pOutputTail = m_pOutputStreamDetector;
554
		if( m_oCoreConfig.bRecordDeviceOutputEnabled )
Jonas Stienen's avatar
Jonas Stienen committed
555
		{
556
			m_pStreamProbeFinal = new ITAStreamProbe( pOutputTail, m_oCoreConfig.sRecordFinalOutputFilePath );
Jonas Stienen's avatar
Jonas Stienen committed
557
558
559
560
			pOutputTail = m_pStreamProbeFinal;
		}

		// Attach the stream tracker
561
		m_pOutputTracker = new CVAAudiostreamTracker( pOutputTail, m_pClock, &m_fCoreClockOffset, &m_lSyncModOwner, m_pSignalSourceManager );
Jonas Stienen's avatar
Jonas Stienen committed
562
563
564
565
566
567
568
		pOutputTail = m_pOutputTracker;

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

		// Core-Clock auf 0 initialisieren
		double dNow = m_pClock->getTime();
569
		m_fCoreClockOffset = ( float ) dNow;
Jonas Stienen's avatar
Jonas Stienen committed
570
571
572
		m_dStreamClockOffset = -1;

		// Timer erzeugen und konfigurieren (wird fr Peak-Events benutzt)
573
		m_pTicker = new VistaTicker();
574
		m_pTicker->AddTrigger( new VistaTicker::TriggerContext( m_oCoreConfig.iTriggerUpdateMilliseconds, true ) );
575
		m_pTicker->SetAfterPulseFunctor( this );
Jonas Stienen's avatar
Jonas Stienen committed
576
577

		// Audio-Streaming starten
578
		SetProgress( "Starting audio streaming", "", 8 );
Jonas Stienen's avatar
Jonas Stienen committed
579
580
581
		m_pAudioDriverBackend->startStreaming();

		// Timer fr Peak-Events starten
582
		m_pTicker->StartTicker();
Jonas Stienen's avatar
Jonas Stienen committed
583
584
585
586

		// Initialisierung erfolgreich!
		m_iState = VA_CORESTATE_READY;

587
		SetProgress( "Initialization finished", "", 9 );
Jonas Stienen's avatar
Jonas Stienen committed
588
589
		FinishProgress();

Dipl.-Ing. Jonas Stienen's avatar
Dipl.-Ing. Jonas Stienen committed
590
	}
591
		VA_FINALLY
Dipl.-Ing. Jonas Stienen's avatar
Dipl.-Ing. Jonas Stienen committed
592
	{
Jonas Stienen's avatar
Jonas Stienen committed
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
		// 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;

609
	if( GetUpdateLocked() )
Jonas Stienen's avatar
Jonas Stienen committed
610
	{
611
		VA_WARN( "Core", "Encountered locked scene during reset. Please unlock before resetting, skipping." );
Jonas Stienen's avatar
Jonas Stienen committed
612
613
614
615
616
		m_pCoreThread->Continue();
	}

	VA_TRY
	{
617
		VA_INFO( "Core", "Resetting core" );
Jonas Stienen's avatar
Jonas Stienen committed
618
619

		// Reset audio renderers
620
621
		std::vector< CVAAudioRendererDesc >::iterator it = m_voRenderers.begin();
		while( it != m_voRenderers.end() )
Jonas Stienen's avatar
Jonas Stienen committed
622
623
624
625
		{
			CVAAudioRendererDesc& oRend( *it++ );
			oRend.pInstance->Reset();
		}
626

Jonas Stienen's avatar
Jonas Stienen committed
627
628
629
		if( m_pCurSceneState )
		{
			// Referenz entfernen welche in CoreThreadLoop hinzugefgt wurde
630
			m_pCurSceneState->RemoveReference();
Jonas Stienen's avatar
Jonas Stienen committed
631
632
633
634
			m_pCurSceneState = nullptr;
		}

		// Alle Szenenobjekte lschen
635
636
637
		m_pSceneManager->Reset();
		m_pSignalSourceManager->Reset();
		m_pDirectivityManager->Reset();
Jonas Stienen's avatar
Jonas Stienen committed
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653

		// 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
654
		m_pCurSceneState = m_pSceneManager->GetHeadSceneState();
Dipl.-Ing. Jonas Stienen's avatar
Dipl.-Ing. Jonas Stienen committed
655
656
		m_iCurActiveSoundReceiver = -1;
		m_iNewActiveSoundReceiver = -1;
Jonas Stienen's avatar
Jonas Stienen committed
657
658
659
660
661
662
663

		m_pCoreThread;

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

		// Ereignis generieren, wenn Operation erfolgreich
664
		CVAEvent ev;
665
		ev.iEventType = CVAEvent::RESET;
Jonas Stienen's avatar
Jonas Stienen committed
666
		ev.pSender = this;
667
		m_pEventManager->BroadcastEvent( ev );
Jonas Stienen's avatar
Jonas Stienen committed
668
669

	}
670
		VA_FINALLY
Jonas Stienen's avatar
Jonas Stienen committed
671
672
673
674
675
676
677
678
	{
		Tidyup();
		throw;
	}
}

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

Jonas Stienen's avatar
Jonas Stienen committed
683
684
	VA_TRY
	{
685
686
687
688
689
		if( m_pTicker )
		{
			m_pTicker->StopTicker();
			m_pTicker->SetAfterPulseFunctor( NULL );
		}
Jonas Stienen's avatar
Jonas Stienen committed
690
691

		FinalizeAudioDriver();
692
693
		FinalizeRenderingModules();
		FinalizeReproductionModules();
Jonas Stienen's avatar
Jonas Stienen committed
694

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

		delete m_pCoreThread;
		m_pCoreThread = nullptr;

		delete m_pInputAmp;
		m_pInputAmp = nullptr;

704
705
		delete m_pInputStreamDetector;
		m_pInputStreamDetector = nullptr;
Jonas Stienen's avatar
Jonas Stienen committed
706
707
708
709
710
711
712

		delete m_pR2RPatchbay;
		m_pR2RPatchbay = nullptr;

		delete m_pOutputPatchbay;
		m_pOutputPatchbay = nullptr;

713
714
		delete m_pOutputStreamDetector;
		m_pOutputStreamDetector = nullptr;
Jonas Stienen's avatar
Jonas Stienen committed
715
716
717

		delete m_pOutputTracker;
		m_pOutputTracker = nullptr;
718

Jonas Stienen's avatar
Jonas Stienen committed
719
720
721
722
723
724
		delete m_pStreamProbeDeviceInput;
		m_pStreamProbeDeviceInput = nullptr;

		delete m_pStreamProbeFinal;
		m_pStreamProbeFinal = nullptr;

725
726
		delete m_pSignalSourceManager;
		m_pSignalSourceManager = nullptr;
Jonas Stienen's avatar
Jonas Stienen committed
727
728
729
730
731
732
733

		delete m_pGlobalSampler;
		m_pGlobalSampler = nullptr;

		delete m_pGlobalSamplePool;
		m_pGlobalSamplePool = nullptr;

734
735
736
737
		if( m_pDirectivityManager )
			m_pDirectivityManager->Finalize();
		delete m_pDirectivityManager;
		m_pDirectivityManager = nullptr;
Jonas Stienen's avatar
Jonas Stienen committed
738
739


740
741
742
743
		if( m_pSceneManager )
			m_pSceneManager->Finalize();
		delete m_pSceneManager;
		m_pSceneManager = nullptr;
Jonas Stienen's avatar
Jonas Stienen committed
744
745
746
747

		m_iState = VA_CORESTATE_CREATED;

	}
748
		VA_FINALLY
Jonas Stienen's avatar
Jonas Stienen committed
749
750
751
752
753
	{
		m_iState = VA_CORESTATE_FAIL;
	}
}

754
755
void CVACoreImpl::Finalize()
{
Jonas Stienen's avatar
Jonas Stienen committed
756
757
758
	VA_NO_REENTRANCE;

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

761
762
	VA_TRY
	{
Jonas Stienen's avatar
Jonas Stienen committed
763
		// Mehrfaches Finialisieren fhrt nicht zu Fehlern
764
765
766
767
		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
768
769
770
771
772
773
774
775

		// 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
776

Jonas Stienen's avatar
Jonas Stienen committed
777
		// Reset audio renderers
778
		for( std::vector<CVAAudioRendererDesc>::iterator it = m_voRenderers.begin(); it != m_voRenderers.end(); ++it )
Jonas Stienen's avatar
Jonas Stienen committed
779
780
781
			it->pInstance->Reset();

		// Peak-Nachrichten stoppen
782
		m_pTicker->StopTicker();
Jonas Stienen's avatar
Jonas Stienen committed
783
784
785
786

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

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

789
790
791
792
		// Stop and delete ticker
		m_pTicker->SetAfterPulseFunctor( NULL );
		delete m_pTicker;
		m_pTicker = NULL;
Jonas Stienen's avatar
Jonas Stienen committed
793
794
795
796
797

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

798
		SetProgress( "Releasing audio hardware", "", 1 );
Jonas Stienen's avatar
Jonas Stienen committed
799
		FinalizeAudioDriver();
800
801
		FinalizeRenderingModules();
		FinalizeReproductionModules();
Jonas Stienen's avatar
Jonas Stienen committed
802

803
		SetProgress( "Cleaning up resources", "", 2 );
Jonas Stienen's avatar
Jonas Stienen committed
804
805
806
		delete m_pInputAmp;
		m_pInputAmp = nullptr;

807
808
809
		if( m_pInputStreamDetector )
			if( m_pInputStreamDetector->GetProfilerEnabled() )
				VA_VERBOSE( "Core", "Input stream detector profiler: " << m_pInputStreamDetector->GetProfilerResult() );
810
811
		delete m_pInputStreamDetector;
		m_pInputStreamDetector = nullptr;
Jonas Stienen's avatar
Jonas Stienen committed
812

813
		m_voReproductionModules.clear();
Jonas Stienen's avatar
Jonas Stienen committed
814
815
816
817
818
819
820

		delete m_pR2RPatchbay;
		m_pR2RPatchbay = nullptr;

		delete m_pOutputPatchbay;
		m_pOutputPatchbay = nullptr;

821
822
		if( m_pOutputStreamDetector->GetProfilerEnabled() )
			VA_VERBOSE( "Core", "Output stream detector profiler: " << m_pOutputStreamDetector->GetProfilerResult() );
823
824
		delete m_pOutputStreamDetector;
		m_pOutputStreamDetector = nullptr;
Jonas Stienen's avatar
Jonas Stienen committed
825
826
827
828
829
830
831
832
833
834

		delete m_pOutputTracker;
		m_pOutputTracker = nullptr;

		delete m_pStreamProbeDeviceInput;
		m_pStreamProbeDeviceInput = nullptr;

		delete m_pStreamProbeFinal;
		m_pStreamProbeFinal = nullptr;

835
836
		delete m_pSignalSourceManager;
		m_pSignalSourceManager = nullptr;
Jonas Stienen's avatar
Jonas Stienen committed
837
838
839
840
841
842
843

		delete m_pGlobalSampler;
		m_pGlobalSampler = nullptr;

		delete m_pGlobalSamplePool;
		m_pGlobalSamplePool = nullptr;

844
845
846
		m_pDirectivityManager->Finalize();
		delete m_pDirectivityManager;
		m_pDirectivityManager = nullptr;
Jonas Stienen's avatar
Jonas Stienen committed
847

848
849
850
		m_pSceneManager->Finalize();
		delete m_pSceneManager;
		m_pSceneManager = nullptr;
Jonas Stienen's avatar
Jonas Stienen committed
851
852
853
854
855
856

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

		FinishProgress();

857
858
859
	}
		VA_FINALLY
	{
Jonas Stienen's avatar
Jonas Stienen committed
860
861
862
863
864
865
866
867
868
869
870
871
		// Nochmals versuchen aufzurumen
		Tidyup();

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

		// VAExceptions unverndert nach aussen leiten
		throw;
	}
}


872
void CVACoreImpl::RegisterModule( CVAObject* pModule )
Jonas Stienen's avatar
Jonas Stienen committed
873
{
874
	m_oModules.RegisterObject( pModule );
Jonas Stienen's avatar
Jonas Stienen committed
875
876
}

877
void CVACoreImpl::GetModules( std::vector< CVAModuleInfo >& viModuleInfos ) const
878
{
Jonas Stienen's avatar
Jonas Stienen committed
879
880
881
	VA_NO_REENTRANCE;
	VA_CHECK_INITIALIZED;

882
#ifdef VACORE_MODULE_INTERFACE_ENABLED
883
884
	VA_TRY
	{
Jonas Stienen's avatar
Jonas Stienen committed
885
		std::vector<CVAObjectInfo> v;
886
		m_oModules.GetObjectInfos( v );
Jonas Stienen's avatar
Jonas Stienen committed
887

888
		VA_PRINT( "Available modules (" << v.size() << ")" );
Jonas Stienen's avatar
Jonas Stienen committed
889
890
891

		viModuleInfos.clear();
		viModuleInfos.resize( v.size() );
892
893
894
895
896
		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
897
		}
898
	}
899
900
	VA_RETHROW;

901
#else // VACORE_MODULE_INTERFACE_ENABLED
902

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

905
#endif // VACORE_MODULE_INTERFACE_ENABLED
906

907
}
Jonas Stienen's avatar
Jonas Stienen committed
908

909
CVAStruct CVACoreImpl::CallModule( const std::string& sModuleName, const CVAStruct& oArgs )
910
{
Jonas Stienen's avatar
Jonas Stienen committed
911
912
913
	VA_NO_REENTRANCE;
	VA_CHECK_INITIALIZED;

914
#ifdef VACORE_MODULE_INTERFACE_ENABLED
915
916
917

	VA_TRY
	{
918
		CVAObject* pModule = m_oModules.FindObjectByName( sModuleName );
919
		if( !pModule )
920
		{
921
			VA_EXCEPT2( INVALID_PARAMETER, "Module '" + sModuleName + "' not found" );
922
		}
923
924
925

#ifdef VACORE_MODULE_INTERFACE_MECHANISM_EVENT_BASED

926
		CVAEvent ev;
927
		ev.iEventType = CVAEvent::SIGNALSOURCE_STATE_CHANGED;
928
929
930
		ev.pSender = this;
		ev.sObjectID = sModuleName;
		ev;
931
932
		m_pEventManager->BroadcastEvent( ev );
		m_pEventManager->
933
934
935

#else // not VACORE_MODULE_INTERFACE_MECHANISM_EVENT_BASED

936
		return pModule->CallObject( oArgs );
937
938

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

940
941
	}
	VA_RETHROW;
942

943
#else // VACORE_MODULE_INTERFACE_ENABLED
944

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

949
#endif // VACORE_MODULE_INTERFACE_ENABLED
Jonas Stienen's avatar
Jonas Stienen committed
950
951
}

952
953
954
955
CVAStruct CVACoreImpl::GetSearchPaths() const
{
	VA_NO_REENTRANCE;
	VA_CHECK_INITIALIZED;
Jonas Stienen's avatar
Jonas Stienen committed
956

957
958
959
960
961
962
963
	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;
}

964
CVAStruct CVACoreImpl::GetCoreConfiguration( const bool bFilterEnabled ) const
Jonas Stienen's avatar
Jonas Stienen committed
965
966
967
968
{
	VA_NO_REENTRANCE;
	VA_CHECK_INITIALIZED;

969
970
	CVAStruct oCoreConfig;

971
972
973
974
975
	if( bFilterEnabled )
	{
		CVAStruct::const_iterator cit = m_oCoreConfig.GetStruct().Begin();
		while( cit != m_oCoreConfig.GetStruct().End() )
		{
976
977
978
979
			const std::string sKey( cit->first );
			const CVAStructValue& oVal( cit->second );
			++cit;

980
981
982
983
984
985
			if( oVal.IsStruct() )
			{
				const CVAStruct& oSection( oVal.GetStruct() );
				if( oSection.HasKey( "enabled" ) )
					if( bool( oSection[ "enabled" ] ) == false )
						continue; // Only skip if explicitly not enabled
986
				oCoreConfig[ sKey ] = oVal;
987
988
			}
		}
989

990
991
992
	}
	else
	{
993
		oCoreConfig = m_oCoreConfig.GetStruct();
994
	}
995
996

	return oCoreConfig;
997
998
999
1000
}

CVAStruct CVACoreImpl::GetHardwareConfiguration() const
{
For faster browsing, not all history is shown. View entire blame