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
#ifdef VACORE_WITH_AUDIO_BACKEND_VIRTUAL
#include "Drivers/Audio/VAVirtualAudioDriverBackend.h"
54
#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
		assert( m_oCoreConfig.oAudioDriverConfig.iInputChannels >= 0 );
498
		m_pSignalSourceManager = new CVAAudioSignalSourceManager( this, m_oCoreConfig.oAudioDriverConfig, pInputTail );
499
500
		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
501
		m_pGlobalSampler->AddMonoTrack();
502

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


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

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

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

		oHomogeneousMedium = m_oCoreConfig.oInitialHomogeneousMedium;


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

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

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

527

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

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

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

537
538
539

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

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

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


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

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

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

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

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

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

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

		// Initialisierung erfolgreich!
		m_iState = VA_CORESTATE_READY;

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

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

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

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

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

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

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

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

		m_pCoreThread;

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

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

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

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

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

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

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

		delete m_pCoreThread;
		m_pCoreThread = nullptr;

		delete m_pInputAmp;
		m_pInputAmp = nullptr;

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

		delete m_pR2RPatchbay;
		m_pR2RPatchbay = nullptr;

		delete m_pOutputPatchbay;
		m_pOutputPatchbay = nullptr;

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

		delete m_pOutputTracker;
		m_pOutputTracker = nullptr;
719

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

		delete m_pStreamProbeFinal;
		m_pStreamProbeFinal = nullptr;

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

		delete m_pGlobalSampler;
		m_pGlobalSampler = nullptr;

		delete m_pGlobalSamplePool;
		m_pGlobalSamplePool = nullptr;

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


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

		m_iState = VA_CORESTATE_CREATED;

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

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

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

762
763
	VA_TRY
	{
Jonas Stienen's avatar
Jonas Stienen committed
764
		// Mehrfaches Finialisieren fhrt nicht zu Fehlern
765
766
		if( m_iState == VA_CORESTATE_CREATED )
		return;
767
768
769

		if( m_iState == VA_CORESTATE_FAIL )
			VA_EXCEPT2( MODAL_ERROR, "Core corrupted, finalization impossible" );
Jonas Stienen's avatar
Jonas Stienen committed
770
771
772
773
774
775
776
777

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

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

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

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

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

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

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

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

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

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

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

		delete m_pR2RPatchbay;
		m_pR2RPatchbay = nullptr;

		delete m_pOutputPatchbay;
		m_pOutputPatchbay = nullptr;

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

		delete m_pOutputTracker;
		m_pOutputTracker = nullptr;

		delete m_pStreamProbeDeviceInput;
		m_pStreamProbeDeviceInput = nullptr;

		delete m_pStreamProbeFinal;
		m_pStreamProbeFinal = nullptr;

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

		delete m_pGlobalSampler;
		m_pGlobalSampler = nullptr;

		delete m_pGlobalSamplePool;
		m_pGlobalSamplePool = nullptr;

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

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

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

		FinishProgress();

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

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

		// VAExceptions unverndert nach aussen leiten
		throw;
	}
}


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

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

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

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

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

903
#else // VACORE_MODULE_INTERFACE_ENABLED
904

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

907
#endif // VACORE_MODULE_INTERFACE_ENABLED
908

909
}
Jonas Stienen's avatar
Jonas Stienen committed
910

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

916
#ifdef VACORE_MODULE_INTERFACE_ENABLED
917
918
919

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

#ifdef VACORE_MODULE_INTERFACE_MECHANISM_EVENT_BASED

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

#else // not VACORE_MODULE_INTERFACE_MECHANISM_EVENT_BASED

938
		return pModule->CallObject( oArgs );
939
940

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

942
943
	}
	VA_RETHROW;
944

945
#else // VACORE_MODULE_INTERFACE_ENABLED
946

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

951
#endif // VACORE_MODULE_INTERFACE_ENABLED
Jonas Stienen's avatar
Jonas Stienen committed
952
953
}

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

959
960
961
962
963
964
965
	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;
}

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

971
972
	CVAStruct oCoreConfig;

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

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

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

	return oCoreConfig;
999
1000
}

For faster browsing, not all history is shown. View entire blame