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
 *    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
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, std::ostream* pOutputStream )
Jonas Stienen's avatar
Jonas Stienen committed
183
{
184
	VA_TRACE( "Config", oArgs );
185
	return new CVACoreImpl( oArgs, pOutputStream );
Jonas Stienen's avatar
Jonas Stienen committed
186
187
}

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
	VA_INFO( "Core", "Working directory: '" << VistaFileSystemDirectory::GetCurrentWorkingDirectory() << "'" );
201

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
					break;
				}
			}

			if( !oCurrentConfigFile.Exists() )
222
			{   
Jonas Stienen's avatar
Jonas Stienen committed
223
224
225
				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
CVACoreImpl::CVACoreImpl( const CVAStruct& oArgs, std::ostream* pOutputStream )
282
283
284
	: 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
	if( pOutputStream )
		SetOutputStream( pOutputStream );

323
324
325
326
	VA_TRY
	{
		// read configuration
		m_oCoreConfig.Init( oArgs );
Jonas Stienen's avatar
Jonas Stienen committed
327

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

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

Jonas Stienen's avatar
Jonas Stienen committed
337
338
		m_iState = VA_CORESTATE_CREATED;

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

341
342
	}
	VA_RETHROW;
Jonas Stienen's avatar
Jonas Stienen committed
343
344
}

345
346
CVACoreImpl::~CVACoreImpl()
{
Jonas Stienen's avatar
Jonas Stienen committed
347
348
349
	VA_NO_REENTRANCE;

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

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

	// Module deregistrieren
	m_oModules.Clear();

	// Nachrichten-Manager freigeben
372
373
	VA_TRY
	{
374
		delete m_pEventManager;
375
376
	}
	VA_RETHROW;
Jonas Stienen's avatar
Jonas Stienen committed
377

378
	VA_TRACE( "Core", "CVACoreImpl instance deleted [" << this << "]" );
Jonas Stienen's avatar
Jonas Stienen committed
379
380

	// Profiling ausgeben
381
	VA_VERBOSE( "Core", m_pmCoreThreadLoopTotalDuration.ToString() );
Jonas Stienen's avatar
Jonas Stienen committed
382
383
}

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

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

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

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

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

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

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

void CVACoreImpl::Initialize() {
	VA_NO_REENTRANCE;

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

445
	VA_VERBOSE( "Core", "Initializing core" );
Jonas Stienen's avatar
Jonas Stienen committed
446

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

452
453
		if( m_iState == VA_CORESTATE_FAIL )
			VA_EXCEPT2( MODAL_ERROR, "Core corrupted, reinitialization impossible" );
Jonas Stienen's avatar
Jonas Stienen committed
454

455
		m_pCoreThread = new CVACoreThread( this );
Jonas Stienen's avatar
Jonas Stienen committed
456

457
		SetProgress( "Setting up audio hardware", "", 1 );
Jonas Stienen's avatar
Jonas Stienen committed
458
459
		InitializeAudioDriver();

460
		m_pR2RPatchbay = new ITAStreamPatchbay( m_oCoreConfig.oAudioDriverConfig.dSampleRate, m_oCoreConfig.oAudioDriverConfig.iBuffersize );
Jonas Stienen's avatar
Jonas Stienen committed
461
462

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

		m_iGlobalAuralizationMode = VA_AURAMODE_ALL;

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

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

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

491
		m_pSignalSourceManager = new CVAAudioSignalSourceManager( this, m_oCoreConfig.oAudioDriverConfig, pInputTail );
492
493
		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
494
		m_pGlobalSampler->AddMonoTrack();
495

496
497
		m_pDirectivityManager = new CVADirectivityManager( this, m_oCoreConfig.oAudioDriverConfig.dSampleRate );
		m_pDirectivityManager->Initialize();
Jonas Stienen's avatar
Jonas Stienen committed
498
499


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

502
503
504
		m_pSceneManager = new CVASceneManager( m_pClock );
		m_pSceneManager->Initialize();
		m_pCurSceneState = m_pSceneManager->GetHeadSceneState();
505

506
507
508
509
510
511
		SetProgress( "Setting up medium environment", "", 4 );

		oHomogeneousMedium = m_oCoreConfig.oInitialHomogeneousMedium;


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

513
		// Register all renderers and initialize
514
		CVAAudioRendererRegistry::GetInstance()->RegisterInternalCoreFactoryMethods();
Jonas Stienen's avatar
Jonas Stienen committed
515
516
		InitializeAudioRenderers();

517
		if( m_voRenderers.empty() )
Jonas Stienen's avatar
Jonas Stienen committed
518
519
			VA_EXCEPT1( "No audio renderers created" );

520

521
		SetProgress( "Initializing reproduction modules", "", 6 );
522

523
		// Register all reproductions and initialize
524
		CVAAudioReproductionRegistry::GetInstance()->RegisterInternalCoreFactoryMethods();
Jonas Stienen's avatar
Jonas Stienen committed
525
526
		InitializeReproductionModules();

527
		if( m_voReproductionModules.empty() )
Jonas Stienen's avatar
Jonas Stienen committed
528
			VA_EXCEPT1( "No audio reproduction modules created" );
529

530
531
532

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

Jonas Stienen's avatar
Jonas Stienen committed
533
534
535
536
537
538
539
540
		// 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
541

542
		m_pOutputStreamDetector = new ITAStreamDetector( m_pOutputPatchbay->GetOutputDatasource( iPhysicalHardwareOutput ) );
543
		m_pOutputStreamDetector->SetProfilerEnabled( true );
544
545


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

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

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

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

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

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

		// Timer fr Peak-Events starten
576
		m_pTicker->StartTicker();
Jonas Stienen's avatar
Jonas Stienen committed
577
578
579
580

		// Initialisierung erfolgreich!
		m_iState = VA_CORESTATE_READY;

581
		SetProgress( "Initialization finished", "", 9 );
Jonas Stienen's avatar
Jonas Stienen committed
582
583
		FinishProgress();

Dipl.-Ing. Jonas Stienen's avatar
Dipl.-Ing. Jonas Stienen committed
584
	}
585
		VA_FINALLY
Dipl.-Ing. Jonas Stienen's avatar
Dipl.-Ing. Jonas Stienen committed
586
	{
Jonas Stienen's avatar
Jonas Stienen committed
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
		// 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;

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

	VA_TRY
	{
611
		VA_INFO( "Core", "Resetting core" );
Jonas Stienen's avatar
Jonas Stienen committed
612
613

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

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

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

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

		m_pCoreThread;

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

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

	}
664
		VA_FINALLY
Jonas Stienen's avatar
Jonas Stienen committed
665
666
667
668
669
670
671
672
	{
		Tidyup();
		throw;
	}
}

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

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

		FinalizeAudioDriver();
686
687
		FinalizeRenderingModules();
		FinalizeReproductionModules();
Jonas Stienen's avatar
Jonas Stienen committed
688

689
690
		delete m_pTicker;
		m_pTicker = nullptr;
Jonas Stienen's avatar
Jonas Stienen committed
691
692
693
694
695
696
697

		delete m_pCoreThread;
		m_pCoreThread = nullptr;

		delete m_pInputAmp;
		m_pInputAmp = nullptr;

698
699
		delete m_pInputStreamDetector;
		m_pInputStreamDetector = nullptr;
Jonas Stienen's avatar
Jonas Stienen committed
700
701
702
703
704
705
706

		delete m_pR2RPatchbay;
		m_pR2RPatchbay = nullptr;

		delete m_pOutputPatchbay;
		m_pOutputPatchbay = nullptr;

707
708
		delete m_pOutputStreamDetector;
		m_pOutputStreamDetector = nullptr;
Jonas Stienen's avatar
Jonas Stienen committed
709
710
711

		delete m_pOutputTracker;
		m_pOutputTracker = nullptr;
712

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

		delete m_pStreamProbeFinal;
		m_pStreamProbeFinal = nullptr;

719
720
		delete m_pSignalSourceManager;
		m_pSignalSourceManager = nullptr;
Jonas Stienen's avatar
Jonas Stienen committed
721
722
723
724
725
726
727

		delete m_pGlobalSampler;
		m_pGlobalSampler = nullptr;

		delete m_pGlobalSamplePool;
		m_pGlobalSamplePool = nullptr;

728
729
730
731
		if( m_pDirectivityManager )
			m_pDirectivityManager->Finalize();
		delete m_pDirectivityManager;
		m_pDirectivityManager = nullptr;
Jonas Stienen's avatar
Jonas Stienen committed
732
733


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

		m_iState = VA_CORESTATE_CREATED;

	}
742
		VA_FINALLY
Jonas Stienen's avatar
Jonas Stienen committed
743
744
745
746
747
	{
		m_iState = VA_CORESTATE_FAIL;
	}
}

748
749
void CVACoreImpl::Finalize()
{
Jonas Stienen's avatar
Jonas Stienen committed
750
751
752
	VA_NO_REENTRANCE;

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

755
756
	VA_TRY
	{
Jonas Stienen's avatar
Jonas Stienen committed
757
		// Mehrfaches Finialisieren fhrt nicht zu Fehlern
758
759
760
761
		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
762
763
764
765
766
767
768
769

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

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

		// Peak-Nachrichten stoppen
776
		m_pTicker->StopTicker();
Jonas Stienen's avatar
Jonas Stienen committed
777
778
779
780

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

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

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

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

792
		SetProgress( "Releasing audio hardware", "", 1 );
Jonas Stienen's avatar
Jonas Stienen committed
793
		FinalizeAudioDriver();
794
795
		FinalizeRenderingModules();
		FinalizeReproductionModules();
Jonas Stienen's avatar
Jonas Stienen committed
796

797
		SetProgress( "Cleaning up resources", "", 2 );
Jonas Stienen's avatar
Jonas Stienen committed
798
799
800
		delete m_pInputAmp;
		m_pInputAmp = nullptr;

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

807
		m_voReproductionModules.clear();
Jonas Stienen's avatar
Jonas Stienen committed
808
809
810
811
812
813
814

		delete m_pR2RPatchbay;
		m_pR2RPatchbay = nullptr;

		delete m_pOutputPatchbay;
		m_pOutputPatchbay = nullptr;

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

		delete m_pOutputTracker;
		m_pOutputTracker = nullptr;

		delete m_pStreamProbeDeviceInput;
		m_pStreamProbeDeviceInput = nullptr;

		delete m_pStreamProbeFinal;
		m_pStreamProbeFinal = nullptr;

829
830
		delete m_pSignalSourceManager;
		m_pSignalSourceManager = nullptr;
Jonas Stienen's avatar
Jonas Stienen committed
831
832
833
834
835
836
837

		delete m_pGlobalSampler;
		m_pGlobalSampler = nullptr;

		delete m_pGlobalSamplePool;
		m_pGlobalSamplePool = nullptr;

838
839
840
		m_pDirectivityManager->Finalize();
		delete m_pDirectivityManager;
		m_pDirectivityManager = nullptr;
Jonas Stienen's avatar
Jonas Stienen committed
841

842
843
844
		m_pSceneManager->Finalize();
		delete m_pSceneManager;
		m_pSceneManager = nullptr;
Jonas Stienen's avatar
Jonas Stienen committed
845
846
847
848
849
850

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

		FinishProgress();

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

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

		// VAExceptions unverndert nach aussen leiten
		throw;
	}
}


866
void CVACoreImpl::RegisterModule( CVAObject* pModule )
Jonas Stienen's avatar
Jonas Stienen committed
867
{
868
	m_oModules.RegisterObject( pModule );
Jonas Stienen's avatar
Jonas Stienen committed
869
870
}

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

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

882
		VA_PRINT( "Available modules (" << v.size() << ")" );
Jonas Stienen's avatar
Jonas Stienen committed
883
884
885

		viModuleInfos.clear();
		viModuleInfos.resize( v.size() );
886
887
888
889
890
		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
891
		}
892
		}
893
894
	VA_RETHROW;

895
#else // VACORE_MODULE_INTERFACE_ENABLED
896

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

899
#endif // VACORE_MODULE_INTERFACE_ENABLED
900

901
	}
Jonas Stienen's avatar
Jonas Stienen committed
902

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

908
#ifdef VACORE_MODULE_INTERFACE_ENABLED
909
910
911

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

#ifdef VACORE_MODULE_INTERFACE_MECHANISM_EVENT_BASED

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

#else // not VACORE_MODULE_INTERFACE_MECHANISM_EVENT_BASED

930
		return pModule->CallObject( oArgs );
931
932

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

934
935
	}
	VA_RETHROW;
936

937
#else // VACORE_MODULE_INTERFACE_ENABLED
938

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

943
#endif // VACORE_MODULE_INTERFACE_ENABLED
Jonas Stienen's avatar
Jonas Stienen committed
944
945
}

946
947
948
949
CVAStruct CVACoreImpl::GetSearchPaths() const
{
	VA_NO_REENTRANCE;
	VA_CHECK_INITIALIZED;
Jonas Stienen's avatar
Jonas Stienen committed
950

951
952
953
954
955
956
957
	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;
}

958
CVAStruct CVACoreImpl::GetCoreConfiguration( const bool bFilterEnabled ) const
Jonas Stienen's avatar
Jonas Stienen committed
959
960
961
962
{
	VA_NO_REENTRANCE;
	VA_CHECK_INITIALIZED;

963
964
	CVAStruct oCoreConfig;

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

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

984
985
986
	}
	else
	{
987
		oCoreConfig = m_oCoreConfig.GetStruct();
988
	}
989
990

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