VACoreImpl.cpp 143 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
	CVAStruct oFinalCoreConfigStruct, oCurrentConfig;
203
204

	VistaFileSystemFile oConfigFile( sConfigFilePath );
Jonas Stienen's avatar
Jonas Stienen committed
205
	std::list< VistaFileSystemFile > voConfigFiles;
206
	
Jonas Stienen's avatar
Jonas Stienen committed
207
	std::vector< VistaFileSystemDirectory > voIncludePaths;
208
209
210
	if( oConfigFile.Exists() && oConfigFile.GetParentDirectory().empty() == false )
		voIncludePaths.push_back( oConfigFile.GetParentDirectory() );

211
	voConfigFiles.push_back( VistaFileSystemFile( sConfigFilePath ) );
Jonas Stienen's avatar
Jonas Stienen committed
212

213
	VA_INFO( "Core", "Working directory: '" << VistaFileSystemDirectory::GetCurrentWorkingDirectory() << "'" );
214

Jonas Stienen's avatar
Jonas Stienen committed
215
216
217
218
219
220
221
	while( voConfigFiles.empty() == false )
	{
		VistaFileSystemFile oCurrentConfigFile( voConfigFiles.front() );
		voConfigFiles.pop_front();

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

			if( !oCurrentConfigFile.Exists() )
235
			{
Jonas Stienen's avatar
Jonas Stienen committed
236
237
238
				VA_EXCEPT2( FILE_NOT_FOUND, "Configuration file '" + oCurrentConfigFile.GetLocalName() + "' not found, aborting." );
			}
		}
239

240
		VA_VERBOSE( "Config", std::string( "Reading INI file '" ) + oCurrentConfigFile.GetLocalName() + "'" );
241
		LoadStructFromINIFIle( oCurrentConfigFile.GetName(), oCurrentConfig );
242

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

Jonas Stienen's avatar
Jonas Stienen committed
264
265
266
267
268
269
270
271
272
273
				voConfigFiles.push_back( VistaFileSystemFile( oIncludeFile ) );
			}
		}

		oCurrentConfig.RemoveKey( "files" );

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

274
	return oFinalCoreConfigStruct;
Jonas Stienen's avatar
Jonas Stienen committed
275
276
}

277
#ifdef WIN32
Jonas Stienen's avatar
Jonas Stienen committed
278
279
// Trick um DLL-Pfad zu ermitteln
EXTERN_C IMAGE_DOS_HEADER __ImageBase;
280
#endif
Jonas Stienen's avatar
Jonas Stienen committed
281

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

294
CVACoreImpl::CVACoreImpl( const CVAStruct& oArgs, std::ostream* pOutputStream )
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
323
324
325
326
327
328
	: 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
329
330
331
{
	VA_NO_REENTRANCE;

332
333
334
	if( pOutputStream )
		SetOutputStream( pOutputStream );

335
336
337
338
	VA_TRY
	{
		// read configuration
		m_oCoreConfig.Init( oArgs );
Jonas Stienen's avatar
Jonas Stienen committed
339

340
		// register core itself as a module
Jonas Stienen's avatar
Jonas Stienen committed
341
342
		SetObjectName( "VACore" );
		m_oModules.RegisterObject( this );
343
		VA_VERBOSE( "Core", "Registered core module with name '" << GetObjectName() << "'" );
Jonas Stienen's avatar
Jonas Stienen committed
344
345
346

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

Jonas Stienen's avatar
Jonas Stienen committed
349
350
		m_iState = VA_CORESTATE_CREATED;

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

353
354
	}
	VA_RETHROW;
Jonas Stienen's avatar
Jonas Stienen committed
355
356
}

357
358
CVACoreImpl::~CVACoreImpl()
{
Jonas Stienen's avatar
Jonas Stienen committed
359
360
361
	VA_NO_REENTRANCE;

	// Implizit finalisieren, falls dies nicht durch den Benutzer geschah
362
363
364
365
	if( m_iState == VA_CORESTATE_READY )
	{
		VA_TRY
		{
Jonas Stienen's avatar
Jonas Stienen committed
366
			Finalize();
367
		}
368
			VA_FINALLY
369
		{
Jonas Stienen's avatar
Jonas Stienen committed
370
371
372
373
374
			// Fehler beim Finalisieren ignorieren
		};
	}

	// Nachricht senden [blocking], das die Kerninstanz gelscht wird.
375
	CVAEvent ev;
376
	ev.iEventType = CVAEvent::DESTROY;
Jonas Stienen's avatar
Jonas Stienen committed
377
	ev.pSender = this;
378
	m_pEventManager->BroadcastEvent( ev );
Jonas Stienen's avatar
Jonas Stienen committed
379
380
381
382
383

	// Module deregistrieren
	m_oModules.Clear();

	// Nachrichten-Manager freigeben
384
385
	VA_TRY
	{
386
		delete m_pEventManager;
387
388
	}
	VA_RETHROW;
Jonas Stienen's avatar
Jonas Stienen committed
389

390
	VA_TRACE( "Core", "CVACoreImpl instance deleted [" << this << "]" );
Jonas Stienen's avatar
Jonas Stienen committed
391
392

	// Profiling ausgeben
393
	VA_VERBOSE( "Core", m_oCoreThreadLoopTotalDuration.ToString() );
Jonas Stienen's avatar
Jonas Stienen committed
394
395
}

396
void CVACoreImpl::SetOutputStream( std::ostream* posDebug )
397
{
398
399
	VALog_setOutputStream( posDebug );
	VALog_setErrorStream( posDebug );
Jonas Stienen's avatar
Jonas Stienen committed
400
401
}

402
void CVACoreImpl::GetVersionInfo( CVAVersionInfo* pVersionInfo ) const
Jonas Stienen's avatar
Jonas Stienen committed
403
404
405
406
407
{
	if( !pVersionInfo )
		return;

	std::stringstream ss;
408
	ss << VACORE_VERSION_MAJOR << "." << VACORE_VERSION_MINOR;
Jonas Stienen's avatar
Jonas Stienen committed
409
	pVersionInfo->sVersion = ss.str();
410
411
412
413
	ss.clear();
#ifdef VACORE_CMAKE_DATE
	ss << VACORE_CMAKE_DATE;
#else
414
	ss << "Unkown date";
415
416
#endif
	pVersionInfo->sDate = ss.str();
Jonas Stienen's avatar
Jonas Stienen committed
417
	pVersionInfo->sFlags = "";
418

Jonas Stienen's avatar
Jonas Stienen committed
419
#ifdef DEBUG
420
	pVersionInfo->sComments = "debug";
Jonas Stienen's avatar
Jonas Stienen committed
421
#else
422
	pVersionInfo->sComments = "release";
Jonas Stienen's avatar
Jonas Stienen committed
423
424
425
#endif
}

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

436
437
438
439
void CVACoreImpl::DetachEventHandler( IVAEventHandler* pCoreEventHandler )
{
	VA_TRY
	{
Jonas Stienen's avatar
Jonas Stienen committed
440
		// Immer mglich. Unabhngig vom Zustand. Thread-safety wird im Manager geregelt.
441
		m_pEventManager->DetachHandler( pCoreEventHandler );
442
443
	}
	VA_RETHROW;
Jonas Stienen's avatar
Jonas Stienen committed
444
445
}

446
447
448
int CVACoreImpl::GetState() const
{
	VA_VERBOSE( "Core", "Core state requested, current state is " << m_iState );
Jonas Stienen's avatar
Jonas Stienen committed
449
450
451
452
453
454
455
456
	return m_iState;
}

void CVACoreImpl::Initialize() {
	VA_NO_REENTRANCE;

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

457
	VA_VERBOSE( "Core", "Initializing core" );
Jonas Stienen's avatar
Jonas Stienen committed
458

459
460
	VA_TRY
	{
461
462
		if( m_iState == VA_CORESTATE_READY )
		VA_EXCEPT2( MODAL_ERROR, "Core already initialized." );
Jonas Stienen's avatar
Jonas Stienen committed
463

464
465
		if( m_iState == VA_CORESTATE_FAIL )
			VA_EXCEPT2( MODAL_ERROR, "Core corrupted, reinitialization impossible" );
Jonas Stienen's avatar
Jonas Stienen committed
466

467
		m_pCoreThread = new CVACoreThread( this );
Jonas Stienen's avatar
Jonas Stienen committed
468

469
		SetProgress( "Setting up audio hardware", "", 1 );
Jonas Stienen's avatar
Jonas Stienen committed
470
471
		InitializeAudioDriver();

472
		m_pR2RPatchbay = new ITAStreamPatchbay( m_oCoreConfig.oAudioDriverConfig.dSampleRate, m_oCoreConfig.oAudioDriverConfig.iBuffersize );
Jonas Stienen's avatar
Jonas Stienen committed
473
474

		// Create output patch bay with a single output that uses all available physical audio outputs from sound card
475
		m_pOutputPatchbay = new ITAStreamPatchbay( m_oCoreConfig.oAudioDriverConfig.dSampleRate, m_oCoreConfig.oAudioDriverConfig.iBuffersize );
Jonas Stienen's avatar
Jonas Stienen committed
476
477
478
479
480
		int iPhysicalHardwareOutput = m_pOutputPatchbay->AddOutput( m_oCoreConfig.oAudioDriverConfig.iOutputChannels );
		m_pOutputPatchbay->SetOutputGain( iPhysicalHardwareOutput, m_dOutputGain );

		m_iGlobalAuralizationMode = VA_AURAMODE_ALL;

481
		// Set up input stream network
Jonas Stienen's avatar
Jonas Stienen committed
482
		ITADatasource* pInputTail = nullptr;
483
484
		if( m_oCoreConfig.oAudioDriverConfig.iInputChannels > 0 )
		{
Jonas Stienen's avatar
Jonas Stienen committed
485
			pInputTail = m_pAudioDriverBackend->getInputStreamDatasource();
486
487
			if( pInputTail )
			{
488
				m_pInputAmp = new ITAStreamAmplifier( pInputTail, ( float ) m_dInputGain );
489
				m_pInputStreamDetector = new ITAStreamDetector( m_pInputAmp );
490
				m_pInputStreamDetector->SetProfilerEnabled( true );
491
				pInputTail = m_pInputStreamDetector;
Jonas Stienen's avatar
Jonas Stienen committed
492

493
494
495
496
497
				if( m_oCoreConfig.bRecordDeviceInputEnabled )
				{
					m_pStreamProbeDeviceInput = new ITAStreamProbe( pInputTail, m_oCoreConfig.sRecordDeviceInputFilePath );
					pInputTail = m_pStreamProbeDeviceInput;
				}
Jonas Stienen's avatar
Jonas Stienen committed
498
499
500
			}
		}

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

503
		assert( m_oCoreConfig.oAudioDriverConfig.iInputChannels >= 0 );
504
		m_pSignalSourceManager = new CVAAudioSignalSourceManager( this, m_oCoreConfig.oAudioDriverConfig, pInputTail );
505
506
		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
507
		m_pGlobalSampler->AddMonoTrack();
508

509
510
		m_pDirectivityManager = new CVADirectivityManager( this, m_oCoreConfig.oAudioDriverConfig.dSampleRate );
		m_pDirectivityManager->Initialize();
Jonas Stienen's avatar
Jonas Stienen committed
511
512


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

515
516
517
		m_pSceneManager = new CVASceneManager( m_pClock );
		m_pSceneManager->Initialize();
		m_pCurSceneState = m_pSceneManager->GetHeadSceneState();
518

519
520
521
522
523
524
		SetProgress( "Setting up medium environment", "", 4 );

		oHomogeneousMedium = m_oCoreConfig.oInitialHomogeneousMedium;


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

526
		// Register all renderers and initialize
527
		CVAAudioRendererRegistry::GetInstance()->RegisterInternalCoreFactoryMethods();
Jonas Stienen's avatar
Jonas Stienen committed
528
529
		InitializeAudioRenderers();

530
		if( m_voRenderers.empty() )
Jonas Stienen's avatar
Jonas Stienen committed
531
532
			VA_EXCEPT1( "No audio renderers created" );

533

534
		SetProgress( "Initializing reproduction modules", "", 6 );
535

536
		// Register all reproductions and initialize
537
		CVAAudioReproductionRegistry::GetInstance()->RegisterInternalCoreFactoryMethods();
Jonas Stienen's avatar
Jonas Stienen committed
538
539
		InitializeReproductionModules();

540
		if( m_voReproductionModules.empty() )
Jonas Stienen's avatar
Jonas Stienen committed
541
			VA_EXCEPT1( "No audio reproduction modules created" );
542

543
544
545

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

Jonas Stienen's avatar
Jonas Stienen committed
546
547
548
549
550
551
552
553
		// 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
554

555
		m_pOutputStreamDetector = new ITAStreamDetector( m_pOutputPatchbay->GetOutputDatasource( iPhysicalHardwareOutput ) );
556
		m_pOutputStreamDetector->SetProfilerEnabled( true );
557
558


Jonas Stienen's avatar
Jonas Stienen committed
559
		// Setup output dump (if set)
560
		ITADatasource* pOutputTail = m_pOutputStreamDetector;
561
		if( m_oCoreConfig.bRecordDeviceOutputEnabled )
Jonas Stienen's avatar
Jonas Stienen committed
562
		{
563
			m_pStreamProbeFinal = new ITAStreamProbe( pOutputTail, m_oCoreConfig.sRecordFinalOutputFilePath );
Jonas Stienen's avatar
Jonas Stienen committed
564
565
566
567
			pOutputTail = m_pStreamProbeFinal;
		}

		// Attach the stream tracker
568
		m_pOutputTracker = new CVAAudiostreamTracker( pOutputTail, m_pClock, &m_fCoreClockOffset, &m_lSyncModOwner, m_pSignalSourceManager );
Jonas Stienen's avatar
Jonas Stienen committed
569
570
571
572
573
574
575
		pOutputTail = m_pOutputTracker;

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

		// Core-Clock auf 0 initialisieren
		double dNow = m_pClock->getTime();
576
		m_fCoreClockOffset = ( float ) dNow;
Jonas Stienen's avatar
Jonas Stienen committed
577
578
579
		m_dStreamClockOffset = -1;

		// Timer erzeugen und konfigurieren (wird fr Peak-Events benutzt)
580
		m_pTicker = new VistaTicker();
581
		m_pTicker->AddTrigger( new VistaTicker::TriggerContext( m_oCoreConfig.iTriggerUpdateMilliseconds, true ) );
582
		m_pTicker->SetAfterPulseFunctor( this );
Jonas Stienen's avatar
Jonas Stienen committed
583
584

		// Audio-Streaming starten
585
		SetProgress( "Starting audio streaming", "", 8 );
Jonas Stienen's avatar
Jonas Stienen committed
586
587
588
		m_pAudioDriverBackend->startStreaming();

		// Timer fr Peak-Events starten
589
		m_pTicker->StartTicker();
Jonas Stienen's avatar
Jonas Stienen committed
590
591
592
593

		// Initialisierung erfolgreich!
		m_iState = VA_CORESTATE_READY;

594
		SetProgress( "Initialization finished", "", 9 );
Jonas Stienen's avatar
Jonas Stienen committed
595
596
		FinishProgress();

Dipl.-Ing. Jonas Stienen's avatar
Dipl.-Ing. Jonas Stienen committed
597
	}
598
		VA_FINALLY
Dipl.-Ing. Jonas Stienen's avatar
Dipl.-Ing. Jonas Stienen committed
599
	{
Jonas Stienen's avatar
Jonas Stienen committed
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
		// 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;

616
	if( GetUpdateLocked() )
Jonas Stienen's avatar
Jonas Stienen committed
617
	{
618
		VA_WARN( "Core", "Encountered locked scene during reset. Please unlock before resetting, skipping." );
Jonas Stienen's avatar
Jonas Stienen committed
619
620
621
622
623
		m_pCoreThread->Continue();
	}

	VA_TRY
	{
624
		VA_INFO( "Core", "Resetting core" );
Jonas Stienen's avatar
Jonas Stienen committed
625
626

		// Reset audio renderers
627
628
		std::vector< CVAAudioRendererDesc >::iterator it = m_voRenderers.begin();
		while( it != m_voRenderers.end() )
Jonas Stienen's avatar
Jonas Stienen committed
629
630
631
632
		{
			CVAAudioRendererDesc& oRend( *it++ );
			oRend.pInstance->Reset();
		}
633

Jonas Stienen's avatar
Jonas Stienen committed
634
635
636
		if( m_pCurSceneState )
		{
			// Referenz entfernen welche in CoreThreadLoop hinzugefgt wurde
637
			m_pCurSceneState->RemoveReference();
Jonas Stienen's avatar
Jonas Stienen committed
638
639
640
641
			m_pCurSceneState = nullptr;
		}

		// Alle Szenenobjekte lschen
642
643
644
		m_pSceneManager->Reset();
		m_pSignalSourceManager->Reset();
		m_pDirectivityManager->Reset();
Jonas Stienen's avatar
Jonas Stienen committed
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660

		// 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
661
		m_pCurSceneState = m_pSceneManager->GetHeadSceneState();
Dipl.-Ing. Jonas Stienen's avatar
Dipl.-Ing. Jonas Stienen committed
662
663
		m_iCurActiveSoundReceiver = -1;
		m_iNewActiveSoundReceiver = -1;
Jonas Stienen's avatar
Jonas Stienen committed
664
665
666
667
668
669
670

		m_pCoreThread;

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

		// Ereignis generieren, wenn Operation erfolgreich
671
		CVAEvent ev;
672
		ev.iEventType = CVAEvent::RESET;
Jonas Stienen's avatar
Jonas Stienen committed
673
		ev.pSender = this;
674
		m_pEventManager->BroadcastEvent( ev );
Jonas Stienen's avatar
Jonas Stienen committed
675
676

	}
677
		VA_FINALLY
Jonas Stienen's avatar
Jonas Stienen committed
678
679
680
681
682
683
684
685
	{
		Tidyup();
		throw;
	}
}

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

Jonas Stienen's avatar
Jonas Stienen committed
690
691
	VA_TRY
	{
692
693
694
695
696
		if( m_pTicker )
		{
			m_pTicker->StopTicker();
			m_pTicker->SetAfterPulseFunctor( NULL );
		}
Jonas Stienen's avatar
Jonas Stienen committed
697
698

		FinalizeAudioDriver();
699
700
		FinalizeRenderingModules();
		FinalizeReproductionModules();
Jonas Stienen's avatar
Jonas Stienen committed
701

702
703
		delete m_pTicker;
		m_pTicker = nullptr;
Jonas Stienen's avatar
Jonas Stienen committed
704
705
706
707
708
709
710

		delete m_pCoreThread;
		m_pCoreThread = nullptr;

		delete m_pInputAmp;
		m_pInputAmp = nullptr;

711
712
		delete m_pInputStreamDetector;
		m_pInputStreamDetector = nullptr;
Jonas Stienen's avatar
Jonas Stienen committed
713
714
715
716
717
718
719

		delete m_pR2RPatchbay;
		m_pR2RPatchbay = nullptr;

		delete m_pOutputPatchbay;
		m_pOutputPatchbay = nullptr;

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

		delete m_pOutputTracker;
		m_pOutputTracker = nullptr;
725

Jonas Stienen's avatar
Jonas Stienen committed
726
727
728
729
730
731
		delete m_pStreamProbeDeviceInput;
		m_pStreamProbeDeviceInput = nullptr;

		delete m_pStreamProbeFinal;
		m_pStreamProbeFinal = nullptr;

732
733
		delete m_pSignalSourceManager;
		m_pSignalSourceManager = nullptr;
Jonas Stienen's avatar
Jonas Stienen committed
734
735
736
737
738
739
740

		delete m_pGlobalSampler;
		m_pGlobalSampler = nullptr;

		delete m_pGlobalSamplePool;
		m_pGlobalSamplePool = nullptr;

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


747
748
749
750
		if( m_pSceneManager )
			m_pSceneManager->Finalize();
		delete m_pSceneManager;
		m_pSceneManager = nullptr;
Jonas Stienen's avatar
Jonas Stienen committed
751
752
753
754

		m_iState = VA_CORESTATE_CREATED;

	}
755
		VA_FINALLY
Jonas Stienen's avatar
Jonas Stienen committed
756
757
758
759
760
	{
		m_iState = VA_CORESTATE_FAIL;
	}
}

761
762
void CVACoreImpl::Finalize()
{
Jonas Stienen's avatar
Jonas Stienen committed
763
764
765
	VA_NO_REENTRANCE;

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

768
769
	VA_TRY
	{
Jonas Stienen's avatar
Jonas Stienen committed
770
		// Mehrfaches Finialisieren fhrt nicht zu Fehlern
771
772
		if( m_iState == VA_CORESTATE_CREATED )
		return;
773
774
775

		if( m_iState == VA_CORESTATE_FAIL )
			VA_EXCEPT2( MODAL_ERROR, "Core corrupted, finalization impossible" );
Jonas Stienen's avatar
Jonas Stienen committed
776
777
778
779
780
781
782
783

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

Jonas Stienen's avatar
Jonas Stienen committed
785
		// Reset audio renderers
786
		for( std::vector<CVAAudioRendererDesc>::iterator it = m_voRenderers.begin(); it != m_voRenderers.end(); ++it )
Jonas Stienen's avatar
Jonas Stienen committed
787
788
789
			it->pInstance->Reset();

		// Peak-Nachrichten stoppen
790
		m_pTicker->StopTicker();
Jonas Stienen's avatar
Jonas Stienen committed
791
792
793
794

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

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

797
798
799
800
		// Stop and delete ticker
		m_pTicker->SetAfterPulseFunctor( NULL );
		delete m_pTicker;
		m_pTicker = NULL;
Jonas Stienen's avatar
Jonas Stienen committed
801
802
803
804
805

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

806
		SetProgress( "Releasing audio hardware", "", 1 );
Jonas Stienen's avatar
Jonas Stienen committed
807
		FinalizeAudioDriver();
808
809
		FinalizeRenderingModules();
		FinalizeReproductionModules();
Jonas Stienen's avatar
Jonas Stienen committed
810

811
		SetProgress( "Cleaning up resources", "", 2 );
Jonas Stienen's avatar
Jonas Stienen committed
812
813
814
		delete m_pInputAmp;
		m_pInputAmp = nullptr;

815
816
817
		if( m_pInputStreamDetector )
			if( m_pInputStreamDetector->GetProfilerEnabled() )
				VA_VERBOSE( "Core", "Input stream detector profiler: " << m_pInputStreamDetector->GetProfilerResult() );
818
819
		delete m_pInputStreamDetector;
		m_pInputStreamDetector = nullptr;
Jonas Stienen's avatar
Jonas Stienen committed
820

821
		m_voReproductionModules.clear();
Jonas Stienen's avatar
Jonas Stienen committed
822
823
824
825
826
827
828

		delete m_pR2RPatchbay;
		m_pR2RPatchbay = nullptr;

		delete m_pOutputPatchbay;
		m_pOutputPatchbay = nullptr;

829
830
		if( m_pOutputStreamDetector->GetProfilerEnabled() )
			VA_VERBOSE( "Core", "Output stream detector profiler: " << m_pOutputStreamDetector->GetProfilerResult() );
831
832
		delete m_pOutputStreamDetector;
		m_pOutputStreamDetector = nullptr;
Jonas Stienen's avatar
Jonas Stienen committed
833
834
835
836
837
838
839
840
841
842

		delete m_pOutputTracker;
		m_pOutputTracker = nullptr;

		delete m_pStreamProbeDeviceInput;
		m_pStreamProbeDeviceInput = nullptr;

		delete m_pStreamProbeFinal;
		m_pStreamProbeFinal = nullptr;

843
844
		delete m_pSignalSourceManager;
		m_pSignalSourceManager = nullptr;
Jonas Stienen's avatar
Jonas Stienen committed
845
846
847
848
849
850
851

		delete m_pGlobalSampler;
		m_pGlobalSampler = nullptr;

		delete m_pGlobalSamplePool;
		m_pGlobalSamplePool = nullptr;

852
853
854
		m_pDirectivityManager->Finalize();
		delete m_pDirectivityManager;
		m_pDirectivityManager = nullptr;
Jonas Stienen's avatar
Jonas Stienen committed
855

856
857
858
		m_pSceneManager->Finalize();
		delete m_pSceneManager;
		m_pSceneManager = nullptr;
Jonas Stienen's avatar
Jonas Stienen committed
859
860
861
862
863
864

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

		FinishProgress();

865
866
867
	}
		VA_FINALLY
	{
Jonas Stienen's avatar
Jonas Stienen committed
868
869
870
871
872
873
874
875
876
877
878
879
		// Nochmals versuchen aufzurumen
		Tidyup();

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

		// VAExceptions unverndert nach aussen leiten
		throw;
	}
}


880
void CVACoreImpl::RegisterModule( CVAObject* pModule )
Jonas Stienen's avatar
Jonas Stienen committed
881
{
882
	m_oModules.RegisterObject( pModule );
Jonas Stienen's avatar
Jonas Stienen committed
883
884
}

885
void CVACoreImpl::GetModules( std::vector< CVAModuleInfo >& viModuleInfos ) const
886
{
Jonas Stienen's avatar
Jonas Stienen committed
887
888
889
	VA_NO_REENTRANCE;
	VA_CHECK_INITIALIZED;

890
#ifdef VACORE_MODULE_INTERFACE_ENABLED
891
892
	VA_TRY
	{
Jonas Stienen's avatar
Jonas Stienen committed
893
		std::vector<CVAObjectInfo> v;
894
		m_oModules.GetObjectInfos( v );
Jonas Stienen's avatar
Jonas Stienen committed
895

896
		VA_PRINT( "Available modules (" << v.size() << ")" );
Jonas Stienen's avatar
Jonas Stienen committed
897
898
899

		viModuleInfos.clear();
		viModuleInfos.resize( v.size() );
900
901
902
903
904
		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
905
		}
906
	}
907
908
	VA_RETHROW;

909
#else // VACORE_MODULE_INTERFACE_ENABLED
910

911
912
	VA_EXCEPT1( "This VACore version does not provide modules" );

913
#endif // VACORE_MODULE_INTERFACE_ENABLED
914

915
}
Jonas Stienen's avatar
Jonas Stienen committed
916

917
CVAStruct CVACoreImpl::CallModule( const std::string& sModuleName, const CVAStruct& oArgs )
918
{
Jonas Stienen's avatar
Jonas Stienen committed
919
920
921
	VA_NO_REENTRANCE;
	VA_CHECK_INITIALIZED;

922
#ifdef VACORE_MODULE_INTERFACE_ENABLED
923
924
925

	VA_TRY
	{
926
		CVAObject* pModule = m_oModules.FindObjectByName( sModuleName );
927
		if( !pModule )
928
		{
929
			VA_EXCEPT2( INVALID_PARAMETER, "Module '" + sModuleName + "' not found" );
930
		}
931
932
933

#ifdef VACORE_MODULE_INTERFACE_MECHANISM_EVENT_BASED

934
		CVAEvent ev;
935
		ev.iEventType = CVAEvent::SIGNALSOURCE_STATE_CHANGED;
936
937
938
		ev.pSender = this;
		ev.sObjectID = sModuleName;
		ev;
939
940
		m_pEventManager->BroadcastEvent( ev );
		m_pEventManager->
941
942
943

#else // not VACORE_MODULE_INTERFACE_MECHANISM_EVENT_BASED

944
		return pModule->CallObject( oArgs );
945
946

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

948
949
	}
	VA_RETHROW;
950

951
#else // VACORE_MODULE_INTERFACE_ENABLED
952

953
#ifdef VACORE_NO_MODULE_INTERFACE_THROW_EXCEPTION
954
	VA_EXCEPT1( "This VACore version does not provide modules" );
955
956
#endif // VACORE_NO_MODULE_INTERFACE_THROW_EXCEPTION

957
#endif // VACORE_MODULE_INTERFACE_ENABLED
Jonas Stienen's avatar
Jonas Stienen committed
958
959
}

960
961
962
963
CVAStruct CVACoreImpl::GetSearchPaths() const
{
	VA_NO_REENTRANCE;
	VA_CHECK_INITIALIZED;
Jonas Stienen's avatar
Jonas Stienen committed
964

965
966
967
968
969
970
971
	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;
}

972
CVAStruct CVACoreImpl::GetCoreConfiguration( const bool bFilterEnabled ) const
Jonas Stienen's avatar
Jonas Stienen committed
973
974
975
976
{
	VA_NO_REENTRANCE;
	VA_CHECK_INITIALIZED;

977
978
	CVAStruct oCoreConfig;

979
980
981
982
983
	if( bFilterEnabled )
	{
		CVAStruct::const_iterator cit = m_oCoreConfig.GetStruct().Begin();
		while( cit != m_oCoreConfig.GetStruct().End() )
		{
984
985
986
987
			const std::string sKey( cit->first );
			const CVAStructValue& oVal( cit->second );
			++cit;

988
989
990
991
992
993
			if( oVal.IsStruct() )
			{
				const CVAStruct& oSection( oVal.GetStruct() );
				if( oSection.HasKey( "enabled" ) )
					if( bool( oSection[ "enabled" ] ) == false )
						continue; // Only skip if explicitly not enabled
994
				oCoreConfig[ sKey ] = oVal;
995
996
			}
		}
997

998
999
1000
	}
	else
	{