VAAmbisonicsFreefieldAudioRenderer.cpp 44.3 KB
Newer Older
michael.kohnen's avatar
cds    
michael.kohnen committed
1
// $Id:  $
Jonas Stienen's avatar
Jonas Stienen committed
2
3
#include "VAAmbisonicsFreefieldAudioRenderer.h"

4
#if ( VACORE_WITH_RENDERER_AMBISONICS_FREE_FIELD == 1 )
Jonas Stienen's avatar
Jonas Stienen committed
5

michael.kohnen's avatar
cds    
michael.kohnen committed
6
7
8
9
10
11
// VA includes
#include "../../../Data/VADirectivity.h"
#include "../../../Filtering/VAAtmosphere.h"
#include "../../../Motion/VAMotionModelBase.h"
#include "../../../Motion/VASharedMotionModel.h"
#include "../../../Motion/VASampleAndHoldMotionModel.h"
12
13
14
#include "../../../Scene/VAScene.h"
#include "../../../Utils/VAUtils.h"
#include "../../../VAAudiostreamTracker.h"
michael.kohnen's avatar
cds    
michael.kohnen committed
15
#include <VACore.h>
16
17
18
#include "../../../VACoreImpl.h"
#include "../../../VACoreConfig.h"
#include "../../../VALog.h"
michael.kohnen's avatar
cds    
michael.kohnen committed
19
20
#include <VAObjectPool.h>
#include <VAReferenceableObject.h>
Jonas Stienen's avatar
Jonas Stienen committed
21

michael.kohnen's avatar
cds    
michael.kohnen committed
22
23
// ITA includes
#include <DAFF.h>
Michael Kohnen's avatar
Michael Kohnen committed
24
25
26
#include <ITAUPConvolution.h>
#include <ITAUPFilter.h>
#include <ITAUPFilterPool.h>
michael.kohnen's avatar
cds    
michael.kohnen committed
27
28
29
#include <ITAAtomicPrimitives.h>
#include <ITAClock.h>
#include <ITACriticalSection.h>
30
#include <ITADataSourceRealization.h>
michael.kohnen's avatar
cds    
michael.kohnen committed
31
32
33
#include <ITASampleBuffer.h>
#include <ITAStopWatch.h>
#include <ITASampleFrame.h>
Jonas Stienen's avatar
Jonas Stienen committed
34
#include <ITAStreamInfo.h>
35
#include <ITAFastMath.h>
michael.kohnen's avatar
cds    
michael.kohnen committed
36
#include <ITAConstants.h>
Michael Kohnen's avatar
Michael Kohnen committed
37
38
39
#include <ITAThirdOctaveFilterbank.h>
#include <ITAThirdOctaveMagnitudeSpectrum.h>
#include <ITANumericUtils.h>
Jonas Stienen's avatar
Jonas Stienen committed
40

michael.kohnen's avatar
cds    
michael.kohnen committed
41
42
// Vista includes
#include <VistaInterProcComm/Concurrency/VistaThreadEvent.h>
Jonas Stienen's avatar
Jonas Stienen committed
43

michael.kohnen's avatar
cds    
michael.kohnen committed
44
45
46
47
48
// STL includes
#include <algorithm>
#include <cassert>
#include <fstream>
#include <iomanip>
Jonas Stienen's avatar
Jonas Stienen committed
49

michael.kohnen's avatar
cds    
michael.kohnen committed
50
51
52
// 3rdParty includes
#include <tbb/atomic.h>
#include <tbb/concurrent_queue.h>
Jonas Stienen's avatar
Jonas Stienen committed
53

54
class CVAAFFSoundPath : public CVAPoolObject
Jonas Stienen's avatar
Jonas Stienen committed
55
{
michael.kohnen's avatar
cds    
michael.kohnen committed
56
public:
57
	virtual ~CVAAFFSoundPath();
Jonas Stienen's avatar
Jonas Stienen committed
58

michael.kohnen's avatar
cds    
michael.kohnen committed
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
	//! Retarded metrics of sound path
	class Metrics
	{
	public:
		double dRetardedDistance;				 //!< Metrical distance to retarded sound position
		VAOrientYPR yprAngleRetSourceToListener; //!< Immediate angle of incidence to retarded source position in listener reference frame in YPR convention
		VAOrientYPR yprAngleListenerToRetSource; //!< Retarded angle of incidence to listener in source reference frame in YPR convention
	};

	//! State of directivity
	class CDirectivityState
	{
	public:
		CDirectivityState()
			: pData(NULL)
			, iRecord(-1)
			, bDirectivityEnabled(true) {}

		IVADirectivity* pData;	//!< Directivity data, may be NULL
		int iRecord;			//!< Directivity index
		bool bDirectivityEnabled;

		bool operator==(const CDirectivityState& rhs) const
		{
			bool bBothEnabled = (bDirectivityEnabled == rhs.bDirectivityEnabled);
			bool bSameRecordIndex = (iRecord == rhs.iRecord);
			bool bSameData = (pData == rhs.pData);

			return (bBothEnabled && bSameRecordIndex && bSameData);
		}
	};
90
	/*
michael.kohnen's avatar
cds    
michael.kohnen committed
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
	class CHRIRState
	{
	public:
		CHRIRState()
			: pData(NULL)
			, iRecord(-1)
			, fDistance(1.0f) {}

		IVAHRIRDataset* pData;	 //!< HRIR data, may be NULL
		int iRecord;			 //!< HRIR index
		float fDistance;		 //!< HRIR dataset distance

		bool operator!=(const CHRIRState& rhs) const
		{
			if (pData != rhs.pData) return true;
			if (fDistance != rhs.fDistance) return true;
			if (iRecord != rhs.iRecord) return true;
			return false;
		}
	};
111
112
113
	*/
	CVAAmbisonicsFreeFieldAudioRenderer::CVAAFFSource* pSource;
	CVAAmbisonicsFreeFieldAudioRenderer::CVAAFFListener* pListener;
michael.kohnen's avatar
cds    
michael.kohnen committed
114

115
	CVASourceListenerMetrics oRelations; //!< Informationen on source and receiver relations (distances & angles)
michael.kohnen's avatar
cds    
michael.kohnen committed
116
117
118
119
120
121

	CDirectivityState oDirectivityStateCur;
	CDirectivityState oDirectivityStateNew;

	ITAAtomicBool bDelete;

Michael Kohnen's avatar
Michael Kohnen committed
122
123
124
	CITAThirdOctaveFilterbank* pThirdOctaveFilterBank;
	CITAVariableDelayLine* pVariableDelayLineCh;
	//ITAUPConvolver* pFIRConvolverCh;
125
	
michael.kohnen's avatar
cds    
michael.kohnen committed
126
127
128
129
130
131
132
133

	void PreRequest()
	{
		pSource = nullptr;
		pListener = nullptr;

		// Reset DSP elements
		pThirdOctaveFilterBank->Clear();
134
		pVariableDelayLineCh->Clear();
Michael Kohnen's avatar
Michael Kohnen committed
135
		//pFIRConvolverCh->clear();
michael.kohnen's avatar
cds    
michael.kohnen committed
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
	};

	void UpdateDir(bool bDIRAuraModeEnabled);
	void UpdateMediumPropagation(double dSpeedOfSound, double dAdditionalDelaySeconds = 0.0f);
	double CalculateInverseDistanceDecrease() const;

	//! Bestimmt die relativen Gren des Pfades
	/**
	* Diese berechneten Gren dienen als Grundlage zur Bestimmung der ausgewhlten
	* Datenstze und Einstellungen der DSP-Elemente. Ein weiteres Update der einzelnen
	* DSP-Elemente fhrt z.B. zum Filteraustausch, wenn die Statusnderung Auswirkungen hat
	* (tatschlich ein neuer Datensatz geholt werden muss).
	*
	* Diese Methode ist besonders leichtgewichtig, da sie im StreamProcess genutzt wird.
	*
	* // spter -> \return Gibt false zurck, falls die retardierten Werte noch nicht zur Verfgung stehen.
	*/
	void UpdateMetrics();
	// bool UpdateMetrics( double dTimestamp, double dSpeedOfSound ); // For retarded information

private:

	//! Standard-Konstruktor deaktivieren
159
	CVAAFFSoundPath();
michael.kohnen's avatar
cds    
michael.kohnen committed
160
161

	//! Konstruktor
162
	CVAAFFSoundPath(double dSamplerate, int iBlocklength, int iDirFilterLength);
michael.kohnen's avatar
cds    
michael.kohnen committed
163
164
165

	int m_iDefaultVDLSwitchingAlgorithm; //!< Umsetzung der Verzgerungsnderung

166
	friend class CVAAFFSoundPathFactory;
michael.kohnen's avatar
cds    
michael.kohnen committed
167
168
};

169
class CVAAFFSoundPathFactory : public IVAPoolObjectFactory {
michael.kohnen's avatar
cds    
michael.kohnen committed
170
public:
171
	CVAAFFSoundPathFactory(double dSamplerate, int iBlocklength, int iDirFilterLength)
michael.kohnen's avatar
cds    
michael.kohnen committed
172
173
174
175
176
177
178
		: m_dSamplerate(dSamplerate)
		, m_iBlocklength(iBlocklength)
		, m_iDirFilterLength(iDirFilterLength)
	{}

	CVAPoolObject* CreatePoolObject()
	{
179
		return new CVAAFFSoundPath(m_dSamplerate, m_iBlocklength, m_iDirFilterLength);
michael.kohnen's avatar
cds    
michael.kohnen committed
180
181
182
183
184
185
186
187
	}

private:
	double m_dSamplerate;		//!< Abtastrate
	int m_iBlocklength;			//!< Blocklnge
	int m_iDirFilterLength;		//!< Filterlnge der Richtcharakteristik
};

188
class CVAAFFListenerPoolFactory : public IVAPoolObjectFactory
michael.kohnen's avatar
cds    
michael.kohnen committed
189
190
{
public:
191
	CVAAFFListenerPoolFactory(CVACoreImpl* pCore, const CVAAmbisonicsFreeFieldAudioRenderer::CVAAFFListener::Config& oConf)
michael.kohnen's avatar
cds    
michael.kohnen committed
192
193
194
195
196
197
		: m_pCore(pCore), m_oListenerConf(oConf)
	{
	};

	CVAPoolObject* CreatePoolObject()
	{
198
199
		CVAAmbisonicsFreeFieldAudioRenderer::CVAAFFListener * pListener;
		pListener = new CVAAmbisonicsFreeFieldAudioRenderer::CVAAFFListener(m_pCore, m_oListenerConf);
michael.kohnen's avatar
cds    
michael.kohnen committed
200
201
202
203
204
		return pListener;
	};

private:
	CVACoreImpl* m_pCore;
205
	const CVAAmbisonicsFreeFieldAudioRenderer::CVAAFFListener::Config& m_oListenerConf;
michael.kohnen's avatar
cds    
michael.kohnen committed
206
207
};

208
class CVAAFFSourcePoolFactory : public IVAPoolObjectFactory
michael.kohnen's avatar
cds    
michael.kohnen committed
209
210
{
public:
211
	CVAAFFSourcePoolFactory(const CVAAmbisonicsFreeFieldAudioRenderer::CVAAFFSource::Config& oConf)
michael.kohnen's avatar
cds    
michael.kohnen committed
212
213
214
215
216
217
		: m_oSourceConf(oConf)
	{
	};

	CVAPoolObject* CreatePoolObject()
	{
218
219
		CVAAmbisonicsFreeFieldAudioRenderer::CVAAFFSource * pSource;
		pSource = new CVAAmbisonicsFreeFieldAudioRenderer::CVAAFFSource(m_oSourceConf);
michael.kohnen's avatar
cds    
michael.kohnen committed
220
221
222
223
		return pSource;
	};

private:
224
	const CVAAmbisonicsFreeFieldAudioRenderer::CVAAFFSource::Config& m_oSourceConf;
michael.kohnen's avatar
cds    
michael.kohnen committed
225
226
227
228
229
};

// Renderer

CVAAmbisonicsFreeFieldAudioRenderer::CVAAmbisonicsFreeFieldAudioRenderer(const CVAAudioRendererInitParams& oParams)
230
: CVAObject(oParams.sClass + ":" + oParams.sID)
michael.kohnen's avatar
cds    
michael.kohnen committed
231
232
233
234
235
236
, m_pCore(oParams.pCore)
, m_pCurSceneState(nullptr)
, m_bDumpListeners(false)
, m_dDumpListenersGain(1.0)
, m_dAdditionalStaticDelaySeconds(0.0f)
, m_oParams(oParams)
237
, m_iMaxOrder(-1)
Michael Kohnen's avatar
Michael Kohnen committed
238
, m_iNumChannels(-1)
michael.kohnen's avatar
cds    
michael.kohnen committed
239
240
241
{
	// read config
	Init(*oParams.pConfig);
242
243
	double dSampleRate = m_pCore->GetCoreConfig()->oAudioDriverConfig.dSampleRate;
	int iBlockLength = m_pCore->GetCoreConfig()->oAudioDriverConfig.iBuffersize;
michael.kohnen's avatar
cds    
michael.kohnen committed
244

245
246
247
	m_pdsOutput = new ITADatasourceRealization(m_iNumChannels, dSampleRate, iBlockLength);
	m_pdsOutput->SetStreamEventHandler(this);
	
248
	IVAPoolObjectFactory* pListenerFactory = new CVAAFFListenerPoolFactory(m_pCore, m_oDefaultListenerConf);
michael.kohnen's avatar
cds    
michael.kohnen committed
249
250
	m_pListenerPool = IVAObjectPool::Create(16, 2, pListenerFactory, true);

251
	IVAPoolObjectFactory* pSourceFactory = new CVAAFFSourcePoolFactory(m_oDefaultSourceConf);
michael.kohnen's avatar
cds    
michael.kohnen committed
252
253
	m_pSourcePool = IVAObjectPool::Create(16, 2, pSourceFactory, true);

254
	m_pSoundPathFactory = new CVAAFFSoundPathFactory(m_pCore->GetCoreConfig()->oAudioDriverConfig.dSampleRate, iBlockLength, 128);
michael.kohnen's avatar
cds    
michael.kohnen committed
255
256
257

	m_pSoundPathPool = IVAObjectPool::Create(64, 8, m_pSoundPathFactory, true);

258
	m_pUpdateMessagePool = IVAObjectPool::Create(2, 1, new CVAPoolObjectDefaultFactory<CVAAFFUpdateMessage>, true);
michael.kohnen's avatar
cds    
michael.kohnen committed
259

260
	ctxAudio.m_sbTemp.Init(iBlockLength, true);
michael.kohnen's avatar
cds    
michael.kohnen committed
261
262
263
264
	ctxAudio.m_iResetFlag = 0; // Normal operation mode
	ctxAudio.m_iStatus = 0; // Stopped

	m_iCurGlobalAuralizationMode = IVACore::VA_AURAMODE_DEFAULT;
Jonas Stienen's avatar
Jonas Stienen committed
265

michael.kohnen's avatar
cds    
michael.kohnen committed
266
267
	// Register the renderer as a module
	oParams.pCore->RegisterModule(this);
Jonas Stienen's avatar
Jonas Stienen committed
268
269
}

michael.kohnen's avatar
cds    
michael.kohnen committed
270
CVAAmbisonicsFreeFieldAudioRenderer::~CVAAmbisonicsFreeFieldAudioRenderer()
Jonas Stienen's avatar
Jonas Stienen committed
271
{
michael.kohnen's avatar
cds    
michael.kohnen committed
272
273
	delete m_pSoundPathPool;
	delete m_pUpdateMessagePool;
Jonas Stienen's avatar
Jonas Stienen committed
274
275
}

michael.kohnen's avatar
cds    
michael.kohnen committed
276
void CVAAmbisonicsFreeFieldAudioRenderer::Init(const CVAStruct& oArgs)
Jonas Stienen's avatar
Jonas Stienen committed
277
{
michael.kohnen's avatar
cds    
michael.kohnen committed
278
279
280
	CVAConfigInterpreter conf(oArgs);

	conf.OptNumber("SpeedOfSound", m_dSpeedOfSound, 344.0f);
281
282
	conf.ReqInteger("TruncationOrder", m_iMaxOrder);
	m_iNumChannels = (m_iMaxOrder + 1)*(m_iMaxOrder + 1);
michael.kohnen's avatar
cds    
michael.kohnen committed
283
284
285
286
287
288

	std::string sVLDInterpolationAlgorithm;
	conf.OptString("SwitchingAlgorithm", sVLDInterpolationAlgorithm, "cubicspline");
	sVLDInterpolationAlgorithm = toLowercase(sVLDInterpolationAlgorithm);

	if (sVLDInterpolationAlgorithm == "switch")
Michael Kohnen's avatar
Michael Kohnen committed
289
		m_iDefaultVDLSwitchingAlgorithm = CITAVariableDelayLine::SWITCH;
michael.kohnen's avatar
cds    
michael.kohnen committed
290
	else if (sVLDInterpolationAlgorithm == "crossfade")
Michael Kohnen's avatar
Michael Kohnen committed
291
		m_iDefaultVDLSwitchingAlgorithm = CITAVariableDelayLine::CROSSFADE;
michael.kohnen's avatar
cds    
michael.kohnen committed
292
	else if (sVLDInterpolationAlgorithm == "linear")
Michael Kohnen's avatar
Michael Kohnen committed
293
		m_iDefaultVDLSwitchingAlgorithm = CITAVariableDelayLine::LINEAR_INTERPOLATION;
michael.kohnen's avatar
cds    
michael.kohnen committed
294
	else if (sVLDInterpolationAlgorithm == "cubicspline")
Michael Kohnen's avatar
Michael Kohnen committed
295
		m_iDefaultVDLSwitchingAlgorithm = CITAVariableDelayLine::CUBIC_SPLINE_INTERPOLATION;
michael.kohnen's avatar
cds    
michael.kohnen committed
296
	else if (sVLDInterpolationAlgorithm == "windowedsinc")
Michael Kohnen's avatar
Michael Kohnen committed
297
		m_iDefaultVDLSwitchingAlgorithm = CITAVariableDelayLine::WINDOWED_SINC_INTERPOLATION;
michael.kohnen's avatar
cds    
michael.kohnen committed
298
299
300
	else
		ITA_EXCEPT1(INVALID_PARAMETER, "Unrecognized interpolation algorithm '" + sVLDInterpolationAlgorithm + "' in AmbisonicsFreefieldAudioRendererConfig");

301
	
michael.kohnen's avatar
cds    
michael.kohnen committed
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
329
330
331
332
333
334
335
336
337
338
339
340
341
342
	conf.OptNumber("AdditionalStaticDelaySeconds", m_dAdditionalStaticDelaySeconds, 0.0f);

	// Motion model Listener
	conf.OptInteger("MotionModelNumHistoryKeys", m_oDefaultListenerConf.iMotionModelNumHistoryKeys, 1000);

	if (m_oDefaultListenerConf.iMotionModelNumHistoryKeys < 1)
		VA_EXCEPT2(INVALID_PARAMETER, "Basic motion model history needs to be greater than zero");

	conf.OptNumber("MotionModelWindowSize", m_oDefaultListenerConf.dMotionModelWindowSize, 0.1f);
	conf.OptNumber("MotionModelWindowDelay", m_oDefaultListenerConf.dMotionModelWindowDelay, 0.1f);

	if ((m_oDefaultListenerConf.dMotionModelWindowSize <= 0) || (m_oDefaultListenerConf.dMotionModelWindowDelay < 0))
		VA_EXCEPT2(INVALID_PARAMETER, "Basic motion model window parameters parse error (zero or negative?)");

	conf.OptBool("MotionModelLogInputListener", m_oDefaultListenerConf.bMotionModelLogInputEnabled, false);
	conf.OptBool("MotionModelLogEstimatedOutputListener", m_oDefaultListenerConf.bMotionModelLogEstimatedEnabled, false);

	// Motion model Source
	conf.OptInteger("MotionModelNumHistoryKeys", m_oDefaultSourceConf.iMotionModelNumHistoryKeys, 1000);

	if (m_oDefaultSourceConf.iMotionModelNumHistoryKeys < 1)
		VA_EXCEPT2(INVALID_PARAMETER, "Basic motion model history needs to be greater than zero");

	conf.OptNumber("MotionModelWindowSize", m_oDefaultSourceConf.dMotionModelWindowSize, 0.1f);
	conf.OptNumber("MotionModelWindowDelay", m_oDefaultSourceConf.dMotionModelWindowDelay, 0.1f);

	if ((m_oDefaultSourceConf.dMotionModelWindowSize <= 0) || (m_oDefaultSourceConf.dMotionModelWindowDelay < 0))
		VA_EXCEPT2(INVALID_PARAMETER, "Basic motion model window parameters parse error (zero or negative?)");

	conf.OptBool("MotionModelLogInputSources", m_oDefaultSourceConf.bMotionModelLogInputEnabled, false);
	conf.OptBool("MotionModelLogEstimatedOutputSources", m_oDefaultSourceConf.bMotionModelLogEstimatedEnabled, false);

	return;
}

void CVAAmbisonicsFreeFieldAudioRenderer::Reset()
{
	VA_VERBOSE("VAAmbisonicsFreeFieldAudioRenderer", "Received reset call, indicating reset now");
	ctxAudio.m_iResetFlag = 1; // Request reset

	if (ctxAudio.m_iStatus == 0)
Jonas Stienen's avatar
Jonas Stienen committed
343
	{
michael.kohnen's avatar
cds    
michael.kohnen committed
344
345
346
347
		VA_VERBOSE("VAAmbisonicsFreeFieldAudioRenderer", "Was not streaming, will reset manually");
		// if no streaming active, reset manually
		//SyncInternalData();
		ResetInternalData();
Jonas Stienen's avatar
Jonas Stienen committed
348
	}
michael.kohnen's avatar
cds    
michael.kohnen committed
349
350
351
352
353
354
355
356
357
358
359
360
	else
	{
		VA_VERBOSE("VAAmbisonicsFreeFieldAudioRenderer", "Still streaming, will now wait for reset acknownledge");
	}

	// Wait for last streaming block before internal reset
	while (ctxAudio.m_iResetFlag != 2)
	{
		VASleep(10); // Wait for acknowledge
	}

	VA_VERBOSE("VAAmbisonicsFreeFieldAudioRenderer", "Operation reset has green light, clearing items");
Jonas Stienen's avatar
Jonas Stienen committed
361

michael.kohnen's avatar
cds    
michael.kohnen committed
362
	// Iterate over sound pathes and free items
363
	std::list< CVAAFFSoundPath* >::iterator it = m_lSoundPaths.begin();
michael.kohnen's avatar
cds    
michael.kohnen committed
364
365
	while (it != m_lSoundPaths.end())
	{
366
		CVAAFFSoundPath* pPath = *it;
michael.kohnen's avatar
cds    
michael.kohnen committed
367
368
369
370
371
372
373

		int iNumRefs = pPath->GetNumReferences();
		assert(iNumRefs == 1);
		pPath->RemoveReference();

		++it;
	}
Jonas Stienen's avatar
Jonas Stienen committed
374
	m_lSoundPaths.clear();
michael.kohnen's avatar
cds    
michael.kohnen committed
375
376

	// Iterate over listener and free items
377
	std::map< int, CVAAFFListener* >::const_iterator lcit = m_mListeners.begin();
michael.kohnen's avatar
cds    
michael.kohnen committed
378
379
	while (lcit != m_mListeners.end())
	{
380
		CVAAFFListener* pListener(lcit->second);
michael.kohnen's avatar
cds    
michael.kohnen committed
381
382
383
384
385
386
387
388
		pListener->pData->RemoveReference();
		assert(pListener->GetNumReferences() == 1);
		pListener->RemoveReference();
		lcit++;
	}
	m_mListeners.clear();

	// Iterate over sources and free items
389
	std::map< int, CVAAFFSource* >::const_iterator scit = m_mSources.begin();
michael.kohnen's avatar
cds    
michael.kohnen committed
390
391
	while (scit != m_mSources.end())
	{
392
		CVAAFFSource* pSource(scit->second);
michael.kohnen's avatar
cds    
michael.kohnen committed
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
		pSource->pData->RemoveReference();
		assert(pSource->GetNumReferences() == 1);
		pSource->RemoveReference();
		scit++;
	}
	m_mSources.clear();

	// Scene frei geben
	if (m_pCurSceneState)
	{
		m_pCurSceneState->RemoveReference();
		m_pCurSceneState = nullptr;
	}

	ctxAudio.m_iResetFlag = 0; // Enter normal mode

	VA_VERBOSE("VAAmbisonicsFreeFieldAudioRenderer", "Reset successful");
Jonas Stienen's avatar
Jonas Stienen committed
410
411
}

michael.kohnen's avatar
cds    
michael.kohnen committed
412
413
414
void CVAAmbisonicsFreeFieldAudioRenderer::UpdateScene(CVASceneState* pNewSceneState)
{
	assert(pNewSceneState);
Jonas Stienen's avatar
Jonas Stienen committed
415
416

	m_pNewSceneState = pNewSceneState;
michael.kohnen's avatar
cds    
michael.kohnen committed
417
418
	if (m_pNewSceneState == m_pCurSceneState)
		return;
Jonas Stienen's avatar
Jonas Stienen committed
419
420
421
422
423
424

	// Neue Szene referenzieren (gegen Freigabe sperren)
	m_pNewSceneState->AddReference();

	// Unterschiede ermitteln: Neue Szene vs. alte Szene
	CVASceneStateDiff oDiff;
michael.kohnen's avatar
cds    
michael.kohnen committed
425
	pNewSceneState->Diff(m_pCurSceneState, &oDiff);
Jonas Stienen's avatar
Jonas Stienen committed
426

michael.kohnen's avatar
cds    
michael.kohnen committed
427
	// Leere Update-Nachricht zusammenstellen
428
	m_pUpdateMessage = dynamic_cast< CVAAFFUpdateMessage* >(m_pUpdateMessagePool->RequestObject());
Jonas Stienen's avatar
Jonas Stienen committed
429

michael.kohnen's avatar
cds    
michael.kohnen committed
430
431
432
433
434
	// Quellen, Hrer und Pfade verwalten
	ManageSoundPaths(m_pCurSceneState, pNewSceneState, &oDiff);

	// Bewegungsinformationen der Quellen und Hrer aktualisieren
	UpdateTrajectories();
Jonas Stienen's avatar
Jonas Stienen committed
435

michael.kohnen's avatar
cds    
michael.kohnen committed
436
437
438
439
440
441
442
443
	// Entitten der Schallpfade aktualisieren
	UpdateSoundPaths();

	// Update-Nachricht an den Audiokontext schicken
	ctxAudio.m_qpUpdateMessages.push(m_pUpdateMessage);

	// Alte Szene freigeben (dereferenzieren)
	if (m_pCurSceneState) m_pCurSceneState->RemoveReference();
Jonas Stienen's avatar
Jonas Stienen committed
444
445
446
447
	m_pCurSceneState = m_pNewSceneState;
	m_pNewSceneState = nullptr;
}

michael.kohnen's avatar
cds    
michael.kohnen committed
448
ITADatasource* CVAAmbisonicsFreeFieldAudioRenderer::GetOutputDatasource()
Jonas Stienen's avatar
Jonas Stienen committed
449
{
450
	return m_pdsOutput;
michael.kohnen's avatar
cds    
michael.kohnen committed
451
452
453
454
455
456
457
458
459
}

void CVAAmbisonicsFreeFieldAudioRenderer::ManageSoundPaths(const CVASceneState* pCurScene,
	const CVASceneState* pNewScene,
	const CVASceneStateDiff* pDiff)
{
	// Warning: take care for explicit sources and listeners for this renderer!

	// Iterate over current paths and mark deleted (will be removed within internal sync of audio context thread)
460
	std::list< CVAAFFSoundPath* >::iterator itp = m_lSoundPaths.begin();
michael.kohnen's avatar
cds    
michael.kohnen committed
461
	while (itp != m_lSoundPaths.end())
Jonas Stienen's avatar
Jonas Stienen committed
462
	{
463
		CVAAFFSoundPath* pPath(*itp);
michael.kohnen's avatar
cds    
michael.kohnen committed
464
465
466
		int iSourceID = pPath->pSource->pData->iID;
		int iListenerID = pPath->pListener->pData->iID;
		bool bDeletetionRequired = false;
Jonas Stienen's avatar
Jonas Stienen committed
467

michael.kohnen's avatar
cds    
michael.kohnen committed
468
469
470
		// Source deleted?
		std::vector< int >::const_iterator cits = pDiff->viDelSoundSourceIDs.begin();
		while (cits != pDiff->viDelSoundSourceIDs.end())
Jonas Stienen's avatar
Jonas Stienen committed
471
		{
michael.kohnen's avatar
cds    
michael.kohnen committed
472
473
			const int& iIDDeletedSource(*cits++);
			if (iSourceID == iIDDeletedSource)
Jonas Stienen's avatar
Jonas Stienen committed
474
			{
michael.kohnen's avatar
cds    
michael.kohnen committed
475
				bDeletetionRequired = true; // Source removed, deletion required
Jonas Stienen's avatar
Jonas Stienen committed
476
477
478
				break;
			}
		}
michael.kohnen's avatar
cds    
michael.kohnen committed
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503

		if (bDeletetionRequired == false)
		{
			// Receiver deleted?
			std::vector< int >::const_iterator citr = pDiff->viDelListenerIDs.begin();
			while (citr != pDiff->viDelListenerIDs.end())
			{
				const int& iIDListenerDeleted(*citr++);
				if (iListenerID == iIDListenerDeleted)
				{
					bDeletetionRequired = true; // Listener removed, deletion required
					break;
				}
			}
		}

		if (bDeletetionRequired)
		{
			DeleteSoundPath(pPath);
			itp = m_lSoundPaths.erase(itp); // Increment via erase on path list
		}
		else
		{
			++itp; // no deletion detected, continue
		}
Jonas Stienen's avatar
Jonas Stienen committed
504
505
	}

michael.kohnen's avatar
cds    
michael.kohnen committed
506
507
508
	// Deleted sources
	std::vector< int >::const_iterator cits = pDiff->viDelSoundSourceIDs.begin();
	while (cits != pDiff->viDelSoundSourceIDs.end())
Jonas Stienen's avatar
Jonas Stienen committed
509
	{
michael.kohnen's avatar
cds    
michael.kohnen committed
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
		const int& iID(*cits++);
		DeleteSource(iID);
	}

	// Deleted receivers
	std::vector< int >::const_iterator citr = pDiff->viDelListenerIDs.begin();
	while (citr != pDiff->viDelListenerIDs.end())
	{
		const int& iID(*citr++);
		DeleteListener(iID);
	}

	// New sources
	cits = pDiff->viNewSoundSourceIDs.begin();
	while (cits != pDiff->viNewSoundSourceIDs.end())
	{
		const int& iID(*cits++);
Jonas Stienen's avatar
Jonas Stienen committed
527
528

		// Only add, if no other renderer has been connected explicitly with this source
michael.kohnen's avatar
cds    
michael.kohnen committed
529
530
		const CVASoundSourceDesc* pSoundSourceDesc = m_pCore->GetSceneManager()->GetSoundSourceDesc(iID);
		if (pSoundSourceDesc->sExplicitRendererID.empty() || pSoundSourceDesc->sExplicitRendererID == m_oParams.sID)
531
			CVAAFFSource* pSource = CreateSource(iID, pNewScene->GetSoundSourceState(iID));
michael.kohnen's avatar
cds    
michael.kohnen committed
532
533
534
535
536
537
538
	}

	// New receivers
	citr = pDiff->viNewListenerIDs.begin();
	while (citr != pDiff->viNewListenerIDs.end())
	{
		const int& iID(*citr++);
539
		CVAAFFListener* pListener = CreateListener(iID, pNewScene->GetListenerState(iID));
michael.kohnen's avatar
cds    
michael.kohnen committed
540
541
542
543
544
545
546
	}

	// New paths: (1) new receivers, current sources
	citr = pDiff->viNewListenerIDs.begin();
	while (citr != pDiff->viNewListenerIDs.end())
	{
		int iListenerID = (*citr++);
547
		CVAAFFListener* pListener = m_mListeners[iListenerID];
michael.kohnen's avatar
cds    
michael.kohnen committed
548
549
550
551
552
553

		for (size_t i = 0; i<pDiff->viComSoundSourceIDs.size(); i++)
		{
			// Only add, if no other renderer has been connected explicitly with this source
			// and only, if not marked for deletion
			int iSourceID = pDiff->viComSoundSourceIDs[i];
554
			std::map< int, CVAAFFSource* >::iterator it = m_mSources.find(iSourceID);
michael.kohnen's avatar
cds    
michael.kohnen committed
555
556
			if (it == m_mSources.end())
				continue; // This source is skipped by the renderer
557
			CVAAFFSource* pSource = it->second;
michael.kohnen's avatar
cds    
michael.kohnen committed
558
559
560
561

			const CVASoundSourceDesc* pSoundSourceDesc = m_pCore->GetSceneManager()->GetSoundSourceDesc(iSourceID);
			if (!pSource->bDeleted &&
				(pSoundSourceDesc->sExplicitRendererID.empty() || pSoundSourceDesc->sExplicitRendererID == m_oParams.sID))
562
				CVAAFFSoundPath* pPath = CreateSoundPath(pSource, pListener);
michael.kohnen's avatar
cds    
michael.kohnen committed
563
564
565
566
567
568
569
570
		}
	}

	// New paths: (2) new sources, current receivers
	cits = pDiff->viNewSoundSourceIDs.begin();
	while (cits != pDiff->viNewSoundSourceIDs.end())
	{
		const int& iSourceID(*cits++);
571
		std::map< int, CVAAFFSource* >::iterator it = m_mSources.find(iSourceID);
michael.kohnen's avatar
cds    
michael.kohnen committed
572
573
574
		if (it == m_mSources.end())
			continue; // Explicit source is not connected to this renderer

575
		CVAAFFSource* pSource = it->second;
michael.kohnen's avatar
cds    
michael.kohnen committed
576
577
578
		for (size_t i = 0; i<pDiff->viComListenerIDs.size(); i++)
		{
			int iListenerID = pDiff->viComListenerIDs[i];
579
			CVAAFFListener* pListener = m_mListeners[iListenerID];
michael.kohnen's avatar
cds    
michael.kohnen committed
580
			if (!pListener->bDeleted)
581
				CVAAFFSoundPath* pPath = CreateSoundPath(pSource, pListener);
michael.kohnen's avatar
cds    
michael.kohnen committed
582
583
584
585
586
587
588
589
		}
	}

	// New paths: (3) new sources, new receivers
	cits = pDiff->viNewSoundSourceIDs.begin();
	while (cits != pDiff->viNewSoundSourceIDs.end())
	{
		const int& iSourceID(*cits++);
590
		std::map< int, CVAAFFSource* >::iterator it = m_mSources.find(iSourceID);
michael.kohnen's avatar
cds    
michael.kohnen committed
591
592
593
594

		if (it == m_mSources.end())
			continue;

595
		CVAAFFSource* pSource = it->second;
michael.kohnen's avatar
cds    
michael.kohnen committed
596
597
598
599
600
601
		assert(pSource);

		citr = pDiff->viNewListenerIDs.begin();
		while (citr != pDiff->viNewListenerIDs.end())
		{
			const int& iListenerID(*citr++);
602
603
			CVAAFFListener* pListener = m_mListeners[iListenerID];
			CVAAFFSoundPath* pPath = CreateSoundPath(pSource, pListener);
michael.kohnen's avatar
cds    
michael.kohnen committed
604
		}
Jonas Stienen's avatar
Jonas Stienen committed
605
606
607
608
609
	}

	return;
}

610
void CVAAmbisonicsFreeFieldAudioRenderer::HandleProcessStream(ITADatasourceRealization*, const ITAStreamInfo* pStreamInfo)
Jonas Stienen's avatar
Jonas Stienen committed
611
{
michael.kohnen's avatar
cds    
michael.kohnen committed
612
613
614
615
616
617
618
619
	if (ctxAudio.m_iStatus == 0)
	{
		// If streaming is active, set to 1
		ctxAudio.m_iStatus = 1;
	}

	// Schallpfade abgleichen
	SyncInternalData();
Michael Kohnen's avatar
Michael Kohnen committed
620
621
	std::vector<float*> pfOutputCh;

622
623
624
625
626
627
	for (int i = 0; i < m_iNumChannels; i++)
	{
		float* helper = m_pdsOutput->GetWritePointer(i);
		fm_zero(helper, m_pdsOutput->GetBlocklength());
		pfOutputCh.push_back(helper);
	}
michael.kohnen's avatar
cds    
michael.kohnen committed
628

629
630
	
	
michael.kohnen's avatar
cds    
michael.kohnen committed
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651

	const CVAAudiostreamState* pStreamState = dynamic_cast< const CVAAudiostreamState* >(pStreamInfo);
	double dListenerTime = pStreamState->dSysTime;

	// Check for reset request
	if (ctxAudio.m_iResetFlag == 1)
	{
		VA_VERBOSE("VAAmbisonicsFreeFieldAudioRenderer", "Process stream detecting reset request, will reset internally now");
		ResetInternalData();

		return;
	}
	else if (ctxAudio.m_iResetFlag == 2)
	{
		VA_VERBOSE("VAAmbisonicsFreeFieldAudioRenderer", "Process stream detecting ongoing reset, will stop processing here");

		return;
	}

	SampleTrajectoriesInternal(dListenerTime);

652
	std::list< CVAAFFListener* >::iterator lit = ctxAudio.m_lListeners.begin();
michael.kohnen's avatar
cds    
michael.kohnen committed
653
654
	while (lit != ctxAudio.m_lListeners.end())
	{
655
		CVAAFFListener* pListener(*(lit++));
michael.kohnen's avatar
cds    
michael.kohnen committed
656
657
658
659
		pListener->psfOutput->zero();
	}

	// Update sound pathes
660
	std::list< CVAAFFSoundPath* >::iterator spit = ctxAudio.m_lSoundPaths.begin();
michael.kohnen's avatar
cds    
michael.kohnen committed
661
662
	while (spit != ctxAudio.m_lSoundPaths.end())
	{
663
		CVAAFFSoundPath* pPath(*spit);
michael.kohnen's avatar
cds    
michael.kohnen committed
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
		CVAListenerState* pListenerState = (m_pCurSceneState ? m_pCurSceneState->GetListenerState(pPath->pListener->pData->iID) : NULL);
		CVASoundSourceState* pSourceState = (m_pCurSceneState ? m_pCurSceneState->GetSoundSourceState(pPath->pSource->pData->iID) : NULL);

		if (pListenerState == nullptr || pSourceState == nullptr)
		{
			// Skip if no data is present
			spit++;
			continue;
		}

		if (!pPath->pListener->bValidTrajectoryPresent || !pPath->pSource->bValidTrajectoryPresent)
		{
			// Skip if no valid trajectory data is present
			spit++;
			continue;
		}

		// --= Parameter update =--

		pPath->UpdateMetrics();

		// VDL Doppler shift settings
		bool bDPEnabledGlobal = (m_iCurGlobalAuralizationMode & IVACore::VA_AURAMODE_DOPPLER) > 0;
		bool bDPEnabledListener = (pListenerState->GetAuralizationMode() & IVACore::VA_AURAMODE_DOPPLER) > 0;
		bool bDPEnabledSource = (pSourceState->GetAuralizationMode() & IVACore::VA_AURAMODE_DOPPLER) > 0;
Michael Kohnen's avatar
Michael Kohnen committed
689
		bool bDPEnabledCurrent = (pPath->pVariableDelayLineCh->GetAlgorithm() != CITAVariableDelayLine::SWITCH); // switch = disabled
michael.kohnen's avatar
cds    
michael.kohnen committed
690
691
692
		bool bDPStatusChanged = (bDPEnabledCurrent != (bDPEnabledGlobal && bDPEnabledListener && bDPEnabledSource));
		if (bDPStatusChanged)
		{
Michael Kohnen's avatar
Michael Kohnen committed
693
			pPath->pVariableDelayLineCh->SetAlgorithm(!bDPEnabledCurrent ? m_iDefaultVDLSwitchingAlgorithm : CITAVariableDelayLine::SWITCH);
michael.kohnen's avatar
cds    
michael.kohnen committed
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
		}
		pPath->UpdateMediumPropagation(m_dSpeedOfSound, m_dAdditionalStaticDelaySeconds);

		// Spherical spreading loss
		bool bSSLEnabledSource = (pSourceState->GetAuralizationMode() & IVACore::VA_AURAMODE_SPREADING_LOSS) > 0;
		bool bSSLEnabledListener = (pListenerState->GetAuralizationMode() & IVACore::VA_AURAMODE_SPREADING_LOSS) > 0;
		bool bSSLEnabledGlobal = (m_iCurGlobalAuralizationMode & IVACore::VA_AURAMODE_SPREADING_LOSS) > 0;
		bool bSSLEnabled = (bSSLEnabledSource && bSSLEnabledListener && bSSLEnabledGlobal);
		double dDistanceDecrease = pPath->CalculateInverseDistanceDecrease();
		if (!bSSLEnabled)
			dDistanceDecrease = 1.0f;

		bool bDIREnabledSource = (pSourceState->GetAuralizationMode() & IVACore::VA_AURAMODE_DIRECTIVITY) > 0;
		bool bDIREnabledListener = (pListenerState->GetAuralizationMode() & IVACore::VA_AURAMODE_DIRECTIVITY) > 0;
		bool bDIREnabledGlobal = (m_iCurGlobalAuralizationMode & IVACore::VA_AURAMODE_DIRECTIVITY) > 0;
		bool bDIREnabled = (bDIREnabledSource && bDIREnabledListener && bDIREnabledGlobal);
		pPath->UpdateDir(bDIREnabled);

712
		
michael.kohnen's avatar
cds    
michael.kohnen committed
713
714
715
716
717
718
719
720
721
722

		// Sound source gain / direct sound audibility via AuraMode flags
		bool bDSSourceStatusEnabled = (pSourceState->GetAuralizationMode() & IVACore::VA_AURAMODE_DIRECT_SOUND);
		bool bDSListenerStatusEnabled = (pListenerState->GetAuralizationMode() & IVACore::VA_AURAMODE_DIRECT_SOUND);
		bool bDSGlobalStatusEnabled = (m_iCurGlobalAuralizationMode & IVACore::VA_AURAMODE_DIRECT_SOUND);
		bool bDSEnabled = bDSSourceStatusEnabled && bDSListenerStatusEnabled && bDSGlobalStatusEnabled;

		float fSoundSourceGain = float(dDistanceDecrease * pSourceState->GetVolume());
		if (pPath->pSource->pData->bMuted || (bDSEnabled == false))
			fSoundSourceGain = 0.0f;
Michael Kohnen's avatar
Michael Kohnen committed
723
		
724
		
michael.kohnen's avatar
cds    
michael.kohnen committed
725
726
727
728
729
		// --= DSP =--

		CVASoundSourceDesc* pSourceData = pPath->pSource->pData;
		const ITASampleBuffer* psbInput = pSourceData->pSignalSourceInputBuf;
		assert(psbInput); // Knallt es hier, dann ist die Eingabequelle noch nicht gesetzt
Michael Kohnen's avatar
Michael Kohnen committed
730
		assert(pSourceData->iID >= 0); // Knallt es hier, dann wurde dem SoundPath unterm Hintern die Quelle entzogen! -> Problem mit Referenzierung und Reset?
michael.kohnen's avatar
cds    
michael.kohnen committed
731

Michael Kohnen's avatar
Michael Kohnen committed
732

733
734
		pPath->pThirdOctaveFilterBank->Process(psbInput->data(), ctxAudio.m_sbTemp.data());
		pPath->pVariableDelayLineCh->Process(&(ctxAudio.m_sbTemp), &(ctxAudio.m_sbTemp));
Michael Kohnen's avatar
Michael Kohnen committed
735
	
736
		
737
738
		//std::vector<double> gains = vdRealvalued_basefunctions( (90-pPath->oRelations.dElevationL2S), pPath->oRelations.dAzimuthL2S, m_iMaxOrder);
		std::vector<double> gains = SHRealvaluedBasefunctions((90 - pPath->oRelations.dElevationL2S) / 180 * 3.14159265359, pPath->oRelations.dAzimuthL2S / 180 * 3.14159265359, m_iMaxOrder);
Michael Kohnen's avatar
Michael Kohnen committed
739
740
741

		for (int i = 0; i < m_iNumChannels; i++)
		{
742
			(*pPath->pListener->psfOutput)[i].MulAdd(ctxAudio.m_sbTemp, gains[i] * fSoundSourceGain, 0, 0, m_pdsOutput->GetBlocklength());
Michael Kohnen's avatar
Michael Kohnen committed
743
		}
michael.kohnen's avatar
cds    
michael.kohnen committed
744
745
746
747
748
749
		spit++;
	}

	// TODO: Select active listener
	if (!ctxAudio.m_lListeners.empty())
	{
750
		CVAAFFListener* pActiveListener = *(ctxAudio.m_lListeners.begin());
751
752
753
754
		for (int i = 0; i < m_iNumChannels; i++)
		{
			fm_copy(pfOutputCh[i], (*pActiveListener->psfOutput)[i].data(), m_pdsOutput->GetBlocklength());
		}
michael.kohnen's avatar
cds    
michael.kohnen committed
755
756
757
		// Listener dumping
		if (m_iDumpListenersFlag > 0)
		{
758
			std::map< int, CVAAFFListener* >::iterator it = m_mListeners.begin();
michael.kohnen's avatar
cds    
michael.kohnen committed
759
760
			while (it != m_mListeners.end())
			{
761
				CVAAFFListener* pListener = it++->second;
michael.kohnen's avatar
cds    
michael.kohnen committed
762
763
764
765
766
767
768
769
770
771
				pListener->psfOutput->mul_scalar(float(m_dDumpListenersGain));
				pListener->pListenerOutputAudioFileWriter->write(pListener->psfOutput);
			}

			// Ack on dump stop
			if (m_iDumpListenersFlag == 2)
				m_iDumpListenersFlag = 0;
		}
	}

772
	m_pdsOutput->IncrementWritePointer();
michael.kohnen's avatar
cds    
michael.kohnen committed
773
774

	return;
Jonas Stienen's avatar
Jonas Stienen committed
775
776
}

michael.kohnen's avatar
cds    
michael.kohnen committed
777
void CVAAmbisonicsFreeFieldAudioRenderer::UpdateTrajectories()
Jonas Stienen's avatar
Jonas Stienen committed
778
{
michael.kohnen's avatar
cds    
michael.kohnen committed
779
	// Neue Quellendaten bernehmen
780
	for (std::map< int, CVAAFFSource* >::iterator it = m_mSources.begin(); it != m_mSources.end(); ++it)
Jonas Stienen's avatar
Jonas Stienen committed
781
	{
michael.kohnen's avatar
cds    
michael.kohnen committed
782
		int iSourceID = it->first;
783
		CVAAFFSource* pSource = it->second;
Jonas Stienen's avatar
Jonas Stienen committed
784

michael.kohnen's avatar
cds    
michael.kohnen committed
785
786
787
788
789
790
791
792
793
794
795
		CVASoundSourceState* pSourceCur = (m_pCurSceneState ? m_pCurSceneState->GetSoundSourceState(iSourceID) : nullptr);
		CVASoundSourceState* pSourceNew = (m_pNewSceneState ? m_pNewSceneState->GetSoundSourceState(iSourceID) : nullptr);

		const CVAMotionState* pMotionCur = (pSourceCur ? pSourceCur->GetMotionState() : nullptr);
		const CVAMotionState* pMotionNew = (pSourceNew ? pSourceNew->GetMotionState() : nullptr);

		if (pMotionNew && (pMotionNew != pMotionCur))
		{
			VA_TRACE("VAAmbisonicsFreeFieldAudioRenderer", "Source " << iSourceID << " new motion state");
			pSource->pMotionModel->InputMotionKey(pMotionNew);
		}
Jonas Stienen's avatar
Jonas Stienen committed
796
797
	}

michael.kohnen's avatar
cds    
michael.kohnen committed
798
	// Neue Hrerdaten bernehmen
799
	for (std::map< int, CVAAFFListener* >::iterator it = m_mListeners.begin(); it != m_mListeners.end(); ++it)
Jonas Stienen's avatar
Jonas Stienen committed
800
	{
michael.kohnen's avatar
cds    
michael.kohnen committed
801
		int iListenerID = it->first;
802
		CVAAFFListener* pListener = it->second;
michael.kohnen's avatar
cds    
michael.kohnen committed
803
804
805
806
807
808
809
810
811
812
813
814

		CVAListenerState* pListenerCur = (m_pCurSceneState ? m_pCurSceneState->GetListenerState(iListenerID) : nullptr);
		CVAListenerState* pListenerNew = (m_pNewSceneState ? m_pNewSceneState->GetListenerState(iListenerID) : nullptr);

		const CVAMotionState* pMotionCur = (pListenerCur ? pListenerCur->GetMotionState() : nullptr);
		const CVAMotionState* pMotionNew = (pListenerNew ? pListenerNew->GetMotionState() : nullptr);

		if (pMotionNew && (pMotionNew != pMotionCur))
		{
			VA_TRACE("VAAmbisonicsFreeFieldAudioRenderer", "Listener " << iListenerID << " new position ");// << *pMotionNew);
			pListener->pMotionModel->InputMotionKey(pMotionNew);
		}
Jonas Stienen's avatar
Jonas Stienen committed
815
	}
michael.kohnen's avatar
cds    
michael.kohnen committed
816
}
Jonas Stienen's avatar
Jonas Stienen committed
817

michael.kohnen's avatar
cds    
michael.kohnen committed
818
819
820
void CVAAmbisonicsFreeFieldAudioRenderer::SampleTrajectoriesInternal(double dTime)
{
	bool bValid = true;
821
	for (std::list< CVAAFFSource* >::iterator it = ctxAudio.m_lSources.begin(); it != ctxAudio.m_lSources.end(); ++it)
michael.kohnen's avatar
cds    
michael.kohnen committed
822
	{
823
		CVAAFFSource* pSource = *it;
michael.kohnen's avatar
cds    
michael.kohnen committed
824
825
826
827
828
829
830
831

		pSource->pMotionModel->HandleMotionKeys();
		bValid &= pSource->pMotionModel->EstimatePosition(dTime, pSource->vPredPos);
		bValid &= pSource->pMotionModel->EstimateOrientation(dTime, pSource->vPredView, pSource->vPredUp);
		pSource->bValidTrajectoryPresent = bValid;
	}

	bValid = true;
832
	for (std::list< CVAAFFListener* >::iterator it = ctxAudio.m_lListeners.begin(); it != ctxAudio.m_lListeners.end(); ++it)
michael.kohnen's avatar
cds    
michael.kohnen committed
833
	{
834
		CVAAFFListener* pListener = *it;
michael.kohnen's avatar
cds    
michael.kohnen committed
835
836
837
838
839
840
841
842

		pListener->pMotionModel->HandleMotionKeys();
		bValid &= pListener->pMotionModel->EstimatePosition(dTime, pListener->vPredPos);
		bValid &= pListener->pMotionModel->EstimateOrientation(dTime, pListener->vPredView, pListener->vPredUp);
		pListener->bValidTrajectoryPresent = bValid;
	}
}

843
CVAAFFSoundPath* CVAAmbisonicsFreeFieldAudioRenderer::CreateSoundPath(CVAAFFSource* pSource, CVAAFFListener* pListener)
michael.kohnen's avatar
cds    
michael.kohnen committed
844
845
846
847
848
849
850
851
{
	int iSourceID = pSource->pData->iID;
	int iListenerID = pListener->pData->iID;

	assert(!pSource->bDeleted && !pListener->bDeleted);

	VA_VERBOSE("VAAmbisonicsFreeFieldAudioRenderer", "Creating sound path from source " << iSourceID << " -> listener " << iListenerID);

852
	CVAAFFSoundPath* pPath = dynamic_cast<CVAAFFSoundPath*>(m_pSoundPathPool->RequestObject());
michael.kohnen's avatar
cds    
michael.kohnen committed
853
854
855
856
857
858
859
860
861
862
863

	pPath->pSource = pSource;
	pPath->pListener = pListener;

	pPath->bDelete = false;

	CVASoundSourceState* pSourceNew = (m_pNewSceneState ? m_pNewSceneState->GetSoundSourceState(iSourceID) : nullptr);
	if (pSourceNew != nullptr)
		pPath->oDirectivityStateNew.pData = (IVADirectivity*)pSourceNew->GetDirectivityData();

	CVAListenerState* pListenerNew = (m_pNewSceneState ? m_pNewSceneState->GetListenerState(iListenerID) : nullptr);
864
865
	//if (pListenerNew != nullptr)
	//	pPath->oHRIRStateNew.pData = (IVAHRIRDataset*)pListenerNew->GetHRIRDataset();
michael.kohnen's avatar
cds    
michael.kohnen committed
866
867
868
869
870
871
872

	m_lSoundPaths.push_back(pPath);
	m_pUpdateMessage->vNewPaths.push_back(pPath);

	return pPath;
}

873
void CVAAmbisonicsFreeFieldAudioRenderer::DeleteSoundPath(CVAAFFSoundPath* pPath)
michael.kohnen's avatar
cds    
michael.kohnen committed
874
875
876
877
878
879
880
881
{
	VA_VERBOSE("VAAmbisonicsFreeFieldAudioRenderer", "Marking sound path from source " << pPath->pSource->pData->iID << " -> listener " << pPath->pListener->pData->iID << " for deletion");

	pPath->bDelete = true;
	pPath->RemoveReference();
	m_pUpdateMessage->vDelPaths.push_back(pPath);
}

882
CVAAmbisonicsFreeFieldAudioRenderer::CVAAFFListener* CVAAmbisonicsFreeFieldAudioRenderer::CreateListener(const int iID, const CVAListenerState* pListenerState)
michael.kohnen's avatar
cds    
michael.kohnen committed
883
884
885
{
	VA_VERBOSE("VAAmbisonicsFreeFieldAudioRenderer", "Creating listener with ID " << iID);

886
	CVAAFFListener* pListener = dynamic_cast<CVAAFFListener*>(m_pListenerPool->RequestObject()); // Reference = 1
michael.kohnen's avatar
cds    
michael.kohnen committed
887
888
889
890
891

	pListener->pData = m_pCore->GetSceneManager()->GetListenerDesc(iID);
	pListener->pData->AddReference();

	// Move to prerequest of pool?
892
	pListener->psfOutput = new ITASampleFrame(m_iNumChannels,
michael.kohnen's avatar
cds    
michael.kohnen committed
893
894
895
896
897
898
899
900
901
902
		m_pCore->GetCoreConfig()->oAudioDriverConfig.iBuffersize,
		true);
	assert(pListener->pData);
	pListener->bDeleted = false;

	// Motion model
	CVABasicMotionModel* pMotionInstance = dynamic_cast< CVABasicMotionModel* >(pListener->pMotionModel->GetInstance());
	pMotionInstance->SetName(std::string("bfrend_mm_listener_" + pListener->pData->sName));
	pMotionInstance->Reset();

903
	m_mListeners.insert(std::pair< int, CVAAmbisonicsFreeFieldAudioRenderer::CVAAFFListener* >(iID, pListener));
michael.kohnen's avatar
cds    
michael.kohnen committed
904
905
906
907
908
909
910
911
912

	m_pUpdateMessage->vNewListeners.push_back(pListener);

	return pListener;
}

void CVAAmbisonicsFreeFieldAudioRenderer::DeleteListener(int iListenerID)
{
	VA_VERBOSE("VAAmbisonicsFreeFieldAudioRenderer", "Marking listener with ID " << iListenerID << " for removal");
913
914
	std::map< int, CVAAFFListener* >::iterator it = m_mListeners.find(iListenerID);
	CVAAFFListener* pListener = it->second;
michael.kohnen's avatar
cds    
michael.kohnen committed
915
916
917
918
919
920
	m_mListeners.erase(it);
	pListener->bDeleted = true;
	pListener->pData->RemoveReference();
	pListener->RemoveReference();

	m_pUpdateMessage->vDelListeners.push_back(pListener);
Jonas Stienen's avatar
Jonas Stienen committed
921
922
923
924

	return;
}

925
CVAAmbisonicsFreeFieldAudioRenderer::CVAAFFSource* CVAAmbisonicsFreeFieldAudioRenderer::CreateSource(int iID, const CVASoundSourceState* pSourceState)
Jonas Stienen's avatar
Jonas Stienen committed
926
{
michael.kohnen's avatar
cds    
michael.kohnen committed
927
	VA_VERBOSE("VAAmbisonicsFreeFieldAudioRenderer", "Creating source with ID " << iID);
928
	CVAAFFSource* pSource = dynamic_cast< CVAAFFSource* >(m_pSourcePool->RequestObject());
michael.kohnen's avatar
cds    
michael.kohnen committed
929
930
931
932
933
934
935
936
937
938

	pSource->pData = m_pCore->GetSceneManager()->GetSoundSourceDesc(iID);
	pSource->pData->AddReference();

	pSource->bDeleted = false;

	CVABasicMotionModel* pMotionInstance = dynamic_cast< CVABasicMotionModel* >(pSource->pMotionModel->GetInstance());
	pMotionInstance->SetName(std::string("bfrend_mm_source_" + pSource->pData->sName));
	pMotionInstance->Reset();

939
	m_mSources.insert(std::pair< int, CVAAFFSource* >(iID, pSource));
michael.kohnen's avatar
cds    
michael.kohnen committed
940
941
942
943
944
945
946
947
948

	m_pUpdateMessage->vNewSources.push_back(pSource);

	return pSource;
}

void CVAAmbisonicsFreeFieldAudioRenderer::DeleteSource(int iSourceID)
{
	VA_VERBOSE("VAAmbisonicsFreeFieldAudioRenderer", "Marking source with ID " << iSourceID << " for removal");
949
	std::map< int, CVAAFFSource* >::iterator it = m_mSources.find(iSourceID);
michael.kohnen's avatar
cds    
michael.kohnen committed
950
951

	if (it == m_mSources.end()) // Not found in internal list ...
Jonas Stienen's avatar
Jonas Stienen committed
952
	{
michael.kohnen's avatar
cds    
michael.kohnen committed
953
954
955
956
		CVASoundSourceDesc* pDesc = m_pCore->GetSceneManager()->GetSoundSourceDesc(iSourceID);
		if (!pDesc->sExplicitRendererID.empty() || pDesc->sExplicitRendererID == GetObjectName())
			VA_WARN("AmbisonicsFreeFieldAudioRenderer", "Attempted to remote an explicit sound source for this renderer which could not be found.");
		return;
Jonas Stienen's avatar
Jonas Stienen committed
957
958
	}

959
	CVAAFFSource* pSource = it->second;
michael.kohnen's avatar
cds    
michael.kohnen committed
960
961
962
963
964
965
966
967
968
	m_mSources.erase(it);
	pSource->bDeleted = true;
	pSource->pData->RemoveReference();
	pSource->RemoveReference();

	m_pUpdateMessage->vDelSources.push_back(pSource);

	return;
}
Jonas Stienen's avatar
Jonas Stienen committed
969

michael.kohnen's avatar
cds    
michael.kohnen committed
970
971
void CVAAmbisonicsFreeFieldAudioRenderer::SyncInternalData()
{
972
	CVAAFFUpdateMessage* pUpdate;
michael.kohnen's avatar
cds    
michael.kohnen committed
973
	while (ctxAudio.m_qpUpdateMessages.try_pop(pUpdate))
Jonas Stienen's avatar
Jonas Stienen committed
974
	{
975
		std::list< CVAAFFSoundPath* >::const_iterator citp = pUpdate->vDelPaths.begin();
michael.kohnen's avatar
cds    
michael.kohnen committed
976
977
		while (citp != pUpdate->vDelPaths.end())
		{
978
			CVAAFFSoundPath* pPath(*citp++);
michael.kohnen's avatar
cds    
michael.kohnen committed
979
980
981
			ctxAudio.m_lSoundPaths.remove(pPath);
			pPath->RemoveReference();
		}
Jonas Stienen's avatar
Jonas Stienen committed
982

michael.kohnen's avatar
cds    
michael.kohnen committed
983
984
985
		citp = pUpdate->vNewPaths.begin();
		while (citp != pUpdate->vNewPaths.end())
		{
986
			CVAAFFSoundPath* pPath(*citp++);
michael.kohnen's avatar
cds    
michael.kohnen committed
987
988
989
			pPath->AddReference();
			ctxAudio.m_lSoundPaths.push_back(pPath);
		}
Jonas Stienen's avatar
Jonas Stienen committed
990

991
		std::list< CVAAFFSource* >::const_iterator cits = pUpdate->vDelSources.begin();
michael.kohnen's avatar
cds    
michael.kohnen committed
992
993
		while (cits != pUpdate->vDelSources.end())
		{
994
			CVAAFFSource* pSource(*cits++);
michael.kohnen's avatar
cds    
michael.kohnen committed
995
996
997
998
			ctxAudio.m_lSources.remove(pSource);
			pSource->pData->RemoveReference();
			pSource->RemoveReference();
		}
Jonas Stienen's avatar
Jonas Stienen committed
999

michael.kohnen's avatar
cds    
michael.kohnen committed
1000
		cits = pUpdate->vNewSources.begin();