VAVBAPFreefieldAudioRenderer.cpp 20.9 KB
Newer Older
1
2
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
12
13
 *        VVVVVV       AAA       Institute of Technical Acoustics (ITA)
 *         VVVV         AAA      RWTH Aachen University
 *
 *  --------------------------------------------------------------------------------------------
 */

Jonas Stienen's avatar
Jonas Stienen committed
14
15
#include "VAVBAPFreefieldAudioRenderer.h"

16
#ifdef VACORE_WITH_RENDERER_VBAP_FREE_FIELD
Jonas Stienen's avatar
Jonas Stienen committed
17

18
19
20
21
22
#include "../../../Scene/VAScene.h"
#include "../../../Utils/VAUtils.h"
#include "../../../VAAudiostreamTracker.h"
#include "../../../VACoreImpl.h"
#include "../../../VACoreConfig.h"
23
#include <VAException.h>
24
#include "../../../VALog.h"
Jonas Stienen's avatar
Jonas Stienen committed
25
26
27

#include <ITAConfigUtils.h>
#include <ITAConstants.h>
28
#include <ITADataSourceRealization.h>
Jonas Stienen's avatar
Jonas Stienen committed
29
30
31
#include <ITANumericUtils.h>
#include <ITAStreamPatchbay.h>
#include <ITAStreamInfo.h>
32
#include <ITAFastMath.h>
Jonas Stienen's avatar
Jonas Stienen committed
33
34
35
36
37

#include <iostream>
#include <string>
#include <sstream>
#include <math.h>
38
#include "VistaMath/VistaGeometries.h"
Jonas Stienen's avatar
Jonas Stienen committed
39
40


41
CVAVBAPFreeFieldAudioRenderer::CVAVBAPFreeFieldAudioRenderer( const CVAAudioRendererInitParams& oParams )
42
43
44
	: m_pCurSceneState( nullptr )
	, m_bResetTrigger( false )
	, m_oParams( oParams )
Jonas Stienen's avatar
Jonas Stienen committed
45
46
47
48
{
	CVAConfigInterpreter conf( *oParams.pConfig );

	if( !conf.OptInteger( "SetupDimension", m_iSetupDimension, 2 ) )
49
		VA_WARN( "VBAPFreefieldRenderer", "No setup dimension given, using 2D plane (ignoring horizontal Y component)" );
Jonas Stienen's avatar
Jonas Stienen committed
50
51
52
53
54
55
56

	// Hardware output setup
	std::string sOutput;
	conf.ReqString( "Output", sOutput );
	m_pOutput = oParams.pCore->GetCoreConfig()->oHardwareSetup.GetOutput( sOutput );

	if( m_pOutput == nullptr )
57
58
		VA_EXCEPT2( INVALID_PARAMETER, "Unrecognized output '" + sOutput + "' in VBAP Freefield Renderer." );

59
	m_vecCaveCenterPos.SetValues( 0.0f, 0.0f, 0.0f );
60
61
	m_vecCaveCenterOrientYPR.SetToZeroVector();

Jonas Stienen's avatar
Jonas Stienen committed
62
	// Fill loudspeaker vector
63
	for( size_t i = 0; i < m_pOutput->vpDevices.size(); i++ )
Jonas Stienen's avatar
Jonas Stienen committed
64
	{
65
		const CVAHardwareDevice* pDevice( m_pOutput->vpDevices[ i ] );
Jonas Stienen's avatar
Jonas Stienen committed
66
		CLoudspeaker oLS;
67
68
69
		oLS.pos.SetValues( pDevice->vPos.x, pDevice->vPos.y, pDevice->vPos.z );
		oLS.iChannel = int( i );
		oLS.iIdentifier = int( i );
Jonas Stienen's avatar
Jonas Stienen committed
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
		oLS.sIdentifier = pDevice->sIdentifier;
		m_voLoudspeaker.push_back( oLS );
	}

	// Handling der Sektionen
	if( m_iSetupDimension == DIM_1D )
	{
		VA_EXCEPT0( NOT_IMPLEMENTED );
	}
	else if( m_iSetupDimension == DIM_2D )
	{
		// No sectioning required, calculation is performed using nearest neighbour algorithm
	}
	else if( m_iSetupDimension == DIM_3D )
	{
		int iNumSections; //Total number of sections
86
87
88
		conf.ReqInteger( "NumberOfSections", iNumSections );

		for( int j = 0; j < iNumSections; j++ )
Jonas Stienen's avatar
Jonas Stienen committed
89
		{
90
			/* todo implement with vista
Jonas Stienen's avatar
Jonas Stienen committed
91
92
93
94
95
96
			// Identifier fuer Loudspeaker holen
			std::string sHelperSectionName = std::string( "Sec" ) + IntToString( j+1 );
			std::string sHelperSectionLS;
			conf.ReqString( sHelperSectionName, sHelperSectionLS );
			sHelperSectionLS.erase( std::remove(sHelperSectionLS.begin(), sHelperSectionLS.end(), ' '), sHelperSectionLS.end()); //Leerzeichen entfernen
			std::vector<std::string> vsLsSection = splitString( sHelperSectionLS, "," ); // Teilen des Strings in einzelne Identifier(strings)
97

Jonas Stienen's avatar
Jonas Stienen committed
98
99
			//Eckpunkte des Polygons erzeugen aus Lautsprecher Positionen
			std::list< RG_Vector > vVertices;
100
101
			//Abspeichern der Position in der internen Lautsprecherliste
			std::vector <int> viLSIdentifier;
Jonas Stienen's avatar
Jonas Stienen committed
102
103
104
			// Liste mit Eckpunkten fllen
			for( int k=0; k<3; k++ ) //fuer 3 Eckpunkte
			{
105
106
107
108
109
110
111
112
			for ( int l=0; l<m_voLoudspeaker.size(); l++) //Identifier in Lautsprecherliste finden
			{
			if ( m_voLoudspeaker[l].sIdentifier == vsLsSection[k] )
			{
			vVertices.push_back(  m_voLoudspeaker[l].pos );
			viLSIdentifier.push_back(l);
			}
			}
Jonas Stienen's avatar
Jonas Stienen committed
113
114
115
116
117
118
			}

			// Polygone mssen exakt 3 Eckpunkte haben um ein gueltiges VBAP setup zu representieren
			assert( vVertices.size()==3 );

			//Polygon zur Ueberpruefung des Umlaufsinns/Normalenvektores
119
			RG_Polygon polyCheck(vVertices);
Jonas Stienen's avatar
Jonas Stienen committed
120
121
122
123
124
			RG_Line line(m_vecCaveCenterPos, ( *vVertices.begin() - m_vecCaveCenterPos) );

			//Abfrage ob Umlaufsinn korrekt, andernfalls Umlaufsinn ndern
			if ((polyCheck.plane.normal_vector.dot_product(line.getDirectionVector())<0))
			{
125
126
			std::reverse(vVertices.begin(),vVertices.end());
			std::reverse(viLSIdentifier.begin(),viLSIdentifier.end());
Jonas Stienen's avatar
Jonas Stienen committed
127
			}
128

Jonas Stienen's avatar
Jonas Stienen committed
129
130
131
132
133
134
135
136
137
			// Polygon und zustzliche Informationen fr Sektionen erzeugen
			RG_Polygon poly(vVertices);
			poly.create_2D_projection();
			CSection newSection;
			newSection.Polygon = poly;
			newSection.iLSIdentifier = viLSIdentifier;
			newSection.iIdentifier = int(j);
			// Sektion der Sektionenliste hinzufgen
			m_voSectionList.push_back(newSection);
138
			*/
Jonas Stienen's avatar
Jonas Stienen committed
139
140
141
142
143
144
145
146
		}
	}
	else
	{
		VA_EXCEPT2( INVALID_PARAMETER, "Unrecognizes dimension setup for VBAP renderer." );
	}

	int iNumChannels = int( m_voLoudspeaker.size() );
147
148
	double dSampleRate = oParams.pCore->GetCoreConfig()->oAudioDriverConfig.dSampleRate;
	int iBlockLength = oParams.pCore->GetCoreConfig()->oAudioDriverConfig.iBuffersize;
Jonas Stienen's avatar
Jonas Stienen committed
149
150
151
152
153
	m_pdsOutput = new ITADatasourceRealization( iNumChannels, dSampleRate, iBlockLength );

	m_pdsOutput->SetStreamEventHandler( this );
}

154
CVAVBAPFreeFieldAudioRenderer::~CVAVBAPFreeFieldAudioRenderer()
Jonas Stienen's avatar
Jonas Stienen committed
155
156
157
158
{
	delete m_pdsOutput;
}

159
void CVAVBAPFreeFieldAudioRenderer::Init( const CVAStruct& oArgs )
Jonas Stienen's avatar
Jonas Stienen committed
160
161
162
163
{
	return;
}

164
void CVAVBAPFreeFieldAudioRenderer::Reset()
Jonas Stienen's avatar
Jonas Stienen committed
165
166
167
168
{
	m_bResetTrigger = true;
	while( m_bResetTrigger )
	{
169
		VASleep( 10 ); // Wait for acknowledge
Jonas Stienen's avatar
Jonas Stienen committed
170
171
172
173
	}

	m_lSoundPaths.clear();
	m_lNewSoundPaths.clear();
174

Jonas Stienen's avatar
Jonas Stienen committed
175
176
}

177
void CVAVBAPFreeFieldAudioRenderer::UpdateScene( CVASceneState* pNewSceneState )
178
179
180
{
	m_pNewSceneState = pNewSceneState;
	if( m_pNewSceneState == m_pCurSceneState ) return;
Jonas Stienen's avatar
Jonas Stienen committed
181
182
183
184
185
186
187
188
189
190
191

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

	// Unterschiede ermitteln: Neue Szene vs. alte Szene
	CVASceneStateDiff oDiff;
	pNewSceneState->Diff( m_pCurSceneState, &oDiff );

	// Schallpfade aktualisieren
	ManageSoundPaths( &oDiff );

192
193
	double px = 0, py = 0, pz = 0, vx = 0, vy = 0, vz = 0, ux = 0, uy = 0, uz = 0;

Jonas Stienen's avatar
Jonas Stienen committed
194
195
196
197
198
199
200
201
	// Try to receive position from user (aka first listener)
	int iListenerID;
	if( m_pNewSceneState->GetNumListeners() > 0 )
	{
		std::vector< int > viListenerIDs;
		m_pNewSceneState->GetListenerIDs( &viListenerIDs );

		// Use first listener as the user of VBAP system
202
		iListenerID = viListenerIDs[ 0 ];
203
		m_vUserPosVirtualScene = m_pNewSceneState->GetReceiverState( iListenerID )->GetMotionState()->GetPosition();
204
205
		VAVec3 p, v, u;
		m_oParams.pCore->GetSoundReceiverRealWorldPositionOrientationVU( iListenerID, p, v, u );
206
		ConvertVU2YPR_RAD( VAVec3( vx, vy, vz ), VAVec3( ux, uy, uz ), m_oUserYPRRealWorldRAD );
207
		m_vUserPosRealWorld.Set( float( p.x ), float( p.y ), float( p.z ) );
208

Jonas Stienen's avatar
Jonas Stienen committed
209
210
211
212
213
		// Define reproduction system in virtual scene
		m_vReproSystemVirtualPosition = m_vUserPosVirtualScene - m_vUserPosRealWorld;
	}

	// Alte Szene freigeben (deferenzieren)
214
	if( m_pCurSceneState ) m_pCurSceneState->RemoveReference();
Jonas Stienen's avatar
Jonas Stienen committed
215
216
217
218
	m_pCurSceneState = m_pNewSceneState;
	m_pNewSceneState = nullptr;
}

219
void CVAVBAPFreeFieldAudioRenderer::ManageSoundPaths( const CVASceneStateDiff* pDiff )
Jonas Stienen's avatar
Jonas Stienen committed
220
221
222
223
224
225
226
227
{
	// ber aktuelle Pfade iterieren und gelschte markieren
	std::list< SoundPath >::iterator it = m_lSoundPaths.begin();
	while( it != m_lSoundPaths.end() )
	{
		SoundPath& oPath( *it++ );
		int iSourceID = oPath.iSourceID;

228
		for( std::vector< int >::const_iterator cit = pDiff->viDelSoundSourceIDs.begin(); cit != pDiff->viDelSoundSourceIDs.end(); ++cit )
Jonas Stienen's avatar
Jonas Stienen committed
229
		{
230
			if( iSourceID == ( *cit ) )
Jonas Stienen's avatar
Jonas Stienen committed
231
232
233
234
235
236
237
238
			{
				oPath.bMarkDeleted.set( true ); // Pfad zum Lschen markieren
				break;
			}
		}
	}

	// Add new sources in internal list
239
240
	for( std::vector<int>::const_iterator cit = pDiff->viNewSoundSourceIDs.begin();
		cit != pDiff->viNewSoundSourceIDs.end(); ++cit )
Jonas Stienen's avatar
Jonas Stienen committed
241
242
243
244
245
246
247
	{
		SoundPath oPath( m_pdsOutput->GetNumberOfChannels() );
		oPath.iSourceID = *cit;

		// Only add, if no other renderer has been connected explicitly with this source
		const CVASoundSourceDesc* pSoundSourceDesc = m_oParams.pCore->GetSceneManager()->GetSoundSourceDesc( oPath.iSourceID );
		if( pSoundSourceDesc->sExplicitRendererID.empty() || pSoundSourceDesc->sExplicitRendererID == m_oParams.sID )
248
			m_lNewSoundPaths.push_back( oPath );
Jonas Stienen's avatar
Jonas Stienen committed
249
250
251
252
253
	}

	return;
}

254
ITADatasource* CVAVBAPFreeFieldAudioRenderer::GetOutputDatasource()
Jonas Stienen's avatar
Jonas Stienen committed
255
256
257
258
{
	return m_pdsOutput;
}

259
void CVAVBAPFreeFieldAudioRenderer::SyncInternalData()
Jonas Stienen's avatar
Jonas Stienen committed
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
{
	// ber aktuelle Pfade iterieren und gelschte entfernen
	std::list< SoundPath >::iterator it = m_lSoundPaths.begin();
	while( it != m_lSoundPaths.end() )
	{
		SoundPath& oPath( *it );
		int iSourceID = oPath.iSourceID;

		if( oPath.bMarkDeleted )
			it = m_lSoundPaths.erase( it );
		else
			++it;
	}

	// Add new pathes to internal list
	std::list< SoundPath >::const_iterator cit = m_lNewSoundPaths.begin();
	while( cit != m_lNewSoundPaths.end() )
	{
		m_lSoundPaths.push_back( *cit++ );
	}

	m_lNewSoundPaths.clear();

	return;
}

286
void CVAVBAPFreeFieldAudioRenderer::HandleProcessStream( ITADatasourceRealization*, const ITAStreamInfo* pStreamInfo )
Jonas Stienen's avatar
Jonas Stienen committed
287
288
289
290
{
	// Synchronize internal lists of pathes
	SyncInternalData();
	ITASampleBuffer sbTemp;
291
	sbTemp.Init( m_pdsOutput->GetBlocklength(), true ); // cleared temp buffer
Jonas Stienen's avatar
Jonas Stienen committed
292
293

	// Clear output buffer
294
	for( unsigned int i = 0; i < m_pdsOutput->GetNumberOfChannels(); i++ )
Jonas Stienen's avatar
Jonas Stienen committed
295
296
297
298
299
	{
		float* pfOutputData = m_pdsOutput->GetWritePointer( i );
		fm_zero( pfOutputData, m_pdsOutput->GetBlocklength() );
	}

300
	const CVAAudiostreamState* pStreamState = dynamic_cast< const CVAAudiostreamState* >( pStreamInfo );
Jonas Stienen's avatar
Jonas Stienen committed
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
	double dListenerTime = pStreamState->dSysTime;

	// Iterate over pathes
	std::list< SoundPath >::iterator it = m_lSoundPaths.begin();
	while( it != m_lSoundPaths.end() )
	{
		SoundPath& oPath( *it++ );
		int iID = oPath.iSourceID;

		// If no scene present, immediately return
		if( m_pCurSceneState == nullptr )
			break;

		CVASoundSourceState* pState = m_pCurSceneState->GetSoundSourceState( iID );

		// If no motion state present, skip this source
		if( pState == nullptr )
			continue;

		int iAuralizationMode = ( m_iCurGlobalAuralizationMode & pState->GetAuralizationMode() );

		std::vector< double >& vdLoudspeakerGains( oPath.m_vdNewGains );
		std::vector< double >& vdLoudspeakerLastGains( oPath.m_vdOldGains );
324

Jonas Stienen's avatar
Jonas Stienen committed
325
326
327
328
329
330
331
		CVASoundSourceDesc* pSourceData = m_oParams.pCore->GetSceneManager()->GetSoundSourceDesc( iID );
		const ITASampleBuffer* psbInput = pSourceData->pSignalSourceInputBuf;

		const CVAMotionState* pMotionState = pState->GetMotionState();
		if( pMotionState != nullptr )
		{
			//Quellposition relativ zum Cavemittelpunkt berechnen
332
			VAVec3 vSoundSource = GetSourcePosition( pMotionState );
Jonas Stienen's avatar
Jonas Stienen committed
333
334
335
336

			int iListenerID;
			std::vector< int > viListenerIDs;
			m_pCurSceneState->GetListenerIDs( &viListenerIDs );
337

Jonas Stienen's avatar
Jonas Stienen committed
338
			// Use first listener as the user of VBAP system
339
340
			iListenerID = viListenerIDs[ 0 ];

Jonas Stienen's avatar
Jonas Stienen committed
341
342
343
344
345
			// Quelle und Hrer an der selben Position ... auslassen
			if( vSoundSource.Length() == 0.0f )
				continue;

			bool bRet = true;
346
347
			switch( m_iSetupDimension )
			{
Jonas Stienen's avatar
Jonas Stienen committed
348
349
350
			case 2:
				bRet = CalculateLoudspeakerGains2D( vSoundSource, vdLoudspeakerGains );
				break;
351
352
			case 3:
				bRet = CalculateLoudspeakerGains3D( vSoundSource, vdLoudspeakerGains );
Jonas Stienen's avatar
Jonas Stienen committed
353
354
355
356
357
358
359
360
				break;
			default:
				continue;
			}

			if( !bRet )
				VA_WARN( "VBAP", "Could not calculate gains" );

361
			double dOverallGain = pState->GetVolume( m_oParams.pCore->GetCoreConfig()->dDefaultAmplitudeCalibration );			// Lautsrke der Quelle einstellen
Jonas Stienen's avatar
Jonas Stienen committed
362
			dOverallGain /= vSoundSource.Length();				// 1/r Gesetz
363
364

			for( int k = 0; k < vdLoudspeakerGains.size(); k++ )		// anwenden
Jonas Stienen's avatar
Jonas Stienen committed
365
			{
366
367
				vdLoudspeakerGains[ k ] *= dOverallGain;
				vdLoudspeakerGains[ k ] = min( 1, vdLoudspeakerGains[ k ] );	// limitieren
Jonas Stienen's avatar
Jonas Stienen committed
368
369
370
371
			}

			const float* pfInputData = psbInput->data();
			const int iBlocklength = m_pdsOutput->GetBlocklength();
372
			for( unsigned int j = 0; j < m_pdsOutput->GetNumberOfChannels(); j++ )
Jonas Stienen's avatar
Jonas Stienen committed
373
374
375
			{
				float* pfOutputData = m_pdsOutput->GetWritePointer( j );

376
				if( ( vdLoudspeakerLastGains[ j ] == 0 ) && ( vdLoudspeakerGains[ j ] == 0 ) )
Jonas Stienen's avatar
Jonas Stienen committed
377
378
					continue;

379
				if( !( iAuralizationMode & IVAInterface::VA_AURAMODE_DIRECT_SOUND ) )
380
					vdLoudspeakerGains[ j ] = 0.0f; // No direct sound -> no gains
Jonas Stienen's avatar
Jonas Stienen committed
381

382
				for( int k = 0; k < iBlocklength; k++ )
Jonas Stienen's avatar
Jonas Stienen committed
383
				{
384
					double dcos = cos( k / iBlocklength*( ITAConstants::PI_F / 2 ) );
385
					pfOutputData[ k ] += pfInputData[ k ] * float( ( dcos * dcos * ( vdLoudspeakerLastGains[ j ] - vdLoudspeakerGains[ j ] ) + vdLoudspeakerGains[ j ] ) );
Jonas Stienen's avatar
Jonas Stienen committed
386
				}
387
388
389

				vdLoudspeakerLastGains[ j ] = vdLoudspeakerGains[ j ];
				vdLoudspeakerGains[ j ] = 0.0f;
Jonas Stienen's avatar
Jonas Stienen committed
390
391
392
			}
		}
	}
393

Jonas Stienen's avatar
Jonas Stienen committed
394
395
396
397
398
399
400
401
402
	m_pdsOutput->IncrementWritePointer();

	if( m_bResetTrigger )
	{
		if( m_pCurSceneState )
		{
			m_pCurSceneState->RemoveReference();
			m_pCurSceneState = nullptr;
		}
403
		m_bResetTrigger = false;
Jonas Stienen's avatar
Jonas Stienen committed
404
405
406
	}
}

407
void CVAVBAPFreeFieldAudioRenderer::LoadScene( const std::string& sFilename ) {}
Jonas Stienen's avatar
Jonas Stienen committed
408

409
void CVAVBAPFreeFieldAudioRenderer::UpdateGlobalAuralizationMode( int iAuraMode )
Jonas Stienen's avatar
Jonas Stienen committed
410
411
412
413
{
	m_iCurGlobalAuralizationMode = iAuraMode;
}

414
void CVAVBAPFreeFieldAudioRenderer::CalculateInverseMatrix3x3( const double *dOriginalMatrix, double *dInverseMatrix ) const
Jonas Stienen's avatar
Jonas Stienen committed
415
416
417
418
419
{
	// Matritzen werden zeilenweise gelesen/geschrieben

	// bennene Koeffizienten
	//Zeile 1
420
421
422
	const double& a11 = dOriginalMatrix[ 0 ];
	const double& a12 = dOriginalMatrix[ 1 ];
	const double& a13 = dOriginalMatrix[ 2 ];
Jonas Stienen's avatar
Jonas Stienen committed
423
	//Zeile 2
424
425
426
	const double& a21 = dOriginalMatrix[ 3 ];
	const double& a22 = dOriginalMatrix[ 4 ];
	const double& a23 = dOriginalMatrix[ 5 ];
Jonas Stienen's avatar
Jonas Stienen committed
427
	//Zeile 3
428
429
430
	const double& a31 = dOriginalMatrix[ 6 ];
	const double& a32 = dOriginalMatrix[ 7 ];
	const double& a33 = dOriginalMatrix[ 8 ];
Jonas Stienen's avatar
Jonas Stienen committed
431
432

	// finde Determinante
433
	double dDetOriginalMatrix = ( a11*a22*a33 ) + ( a12*a23*a31 ) + ( a13*a21*a32 ) - ( a13*a22*a31 ) - ( a12*a21*a33 ) - ( a11*a23*a32 );
Jonas Stienen's avatar
Jonas Stienen committed
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451

	//Koeffizienten der Transponierten
	//Zeile 1
	const double& t11 = a11;
	const double& t12 = a21;
	const double& t13 = a31;
	//Zeile 2
	const double& t21 = a12;
	const double& t22 = a22;
	const double& t23 = a32;
	//Zeile 3
	const double& t31 = a13;
	const double& t32 = a23;
	const double& t33 = a33;


	//Finde die Determinanten der Untermatrix
	//Zeile 1
452
453
454
	dInverseMatrix[ 0 ] = t22*t33 - t23*t32;
	dInverseMatrix[ 1 ] = t21*t33 - t23*t31;
	dInverseMatrix[ 2 ] = t21*t32 - t22*t31;
Jonas Stienen's avatar
Jonas Stienen committed
455
	//Zeile 2
456
457
458
	dInverseMatrix[ 3 ] = t12*t33 - t13*t32;
	dInverseMatrix[ 4 ] = t11*t33 - t13*t31;
	dInverseMatrix[ 5 ] = t11*t32 - t12*t31;
Jonas Stienen's avatar
Jonas Stienen committed
459
	//Zeile 3
460
461
462
	dInverseMatrix[ 6 ] = t12*t23 - t13*t22;
	dInverseMatrix[ 7 ] = t11*t23 - t13*t21;
	dInverseMatrix[ 8 ] = t11*t22 - t12*t21;
Jonas Stienen's avatar
Jonas Stienen committed
463
464
465
466


	// Bilde neue Matrix mit Vorzeichen
	//Zeile 1
467
468
469
	dInverseMatrix[ 0 ] /= dDetOriginalMatrix;
	dInverseMatrix[ 1 ] /= -dDetOriginalMatrix;
	dInverseMatrix[ 2 ] /= dDetOriginalMatrix;
Jonas Stienen's avatar
Jonas Stienen committed
470
	//Zeile 2
471
472
473
	dInverseMatrix[ 3 ] /= -dDetOriginalMatrix;
	dInverseMatrix[ 4 ] /= dDetOriginalMatrix;
	dInverseMatrix[ 5 ] /= -dDetOriginalMatrix;
Jonas Stienen's avatar
Jonas Stienen committed
474
	//Zeile 3
475
476
477
	dInverseMatrix[ 6 ] /= dDetOriginalMatrix;
	dInverseMatrix[ 7 ] /= -dDetOriginalMatrix;
	dInverseMatrix[ 8 ] /= dDetOriginalMatrix;
Jonas Stienen's avatar
Jonas Stienen committed
478
479
480
}


481
bool CVAVBAPFreeFieldAudioRenderer::IsSourceDirectionWithinSection( const VAVec3& vDirection, const CSection& oSection ) const
Jonas Stienen's avatar
Jonas Stienen committed
482
{
483
484
485
486
	/* @todo implement with Vista
	const VistaPolygon& poly( oSection.Polygon);
	VistaRay line( m_vecCaveCenterPos, VistaVector3D( vDirection.comp ) );
	VistaVector3D point;
Jonas Stienen's avatar
Jonas Stienen committed
487
	//Abfrage ob Quelle berhaupt treffbar ist
488
489
490
	VistaVector3D v3Dir = poly.GetUpVector();
	if( v3Dir.Dot(line.GetDir()) <= 0 )
	return false;
Jonas Stienen's avatar
Jonas Stienen committed
491
492
	//Abfrage ob Polygon parallel zum Quellenvektor (falls hier treffen wrde, ungltiges VBAP set-up)
	if(intersection(line, poly.plane, point)==2)
493
494
	return false;

Jonas Stienen's avatar
Jonas Stienen committed
495
	return poly.point_in_polygon(point);
496
497
	*/
	return false;
Jonas Stienen's avatar
Jonas Stienen committed
498
499
}

500
bool CVAVBAPFreeFieldAudioRenderer::CalculateLoudspeakerGains3D( const VAVec3& vSoundSource, std::vector< double >& vdLoudspeakerGains ) const
Jonas Stienen's avatar
Jonas Stienen committed
501
502
{
	const CSection* pActiveSection = NULL;
503
	for( size_t i = 0; i < m_voSectionList.size(); i++ )
Jonas Stienen's avatar
Jonas Stienen committed
504
	{
505
		const CSection& oSection( m_voSectionList[ i ] );
Jonas Stienen's avatar
Jonas Stienen committed
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520

		if( IsSourceDirectionWithinSection( vSoundSource, oSection ) )
		{
			pActiveSection = &oSection;
			break;
		}

	}

	if( pActiveSection == nullptr )
	{
		return false;
	}

	// --= calculate gains =--
521
522

	/* @todo implement with Vista
Jonas Stienen's avatar
Jonas Stienen committed
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
	RG_Polygon poly = pActiveSection->Polygon;
	const RG_Vector &posLS1 = poly.vertices[0];
	const RG_Vector &posLS2 = poly.vertices[1];
	const RG_Vector &posLS3 = poly.vertices[2];

	double *pMatrix;
	double *pInverse;
	double Matrix[9];
	double dInverseMatrix[9];

	Matrix[0] = posLS1.x;
	Matrix[1] = posLS1.y;
	Matrix[2] = posLS1.z;

	Matrix[3] = posLS2.x;
	Matrix[4] = posLS2.y;
	Matrix[5] = posLS2.z;

	Matrix[6] = posLS3.x;
	Matrix[7] = posLS3.y;
	Matrix[8] = posLS3.z;

	dInverseMatrix[0] = 0;
	dInverseMatrix[1] = 0;
	dInverseMatrix[2] = 0;

	dInverseMatrix[3] = 0;
	dInverseMatrix[4] = 0;
	dInverseMatrix[5] = 0;

	dInverseMatrix[6] = 0;
	dInverseMatrix[7] = 0;
	dInverseMatrix[8] = 0;

	pInverse = dInverseMatrix;
	pMatrix = Matrix;
	CalculateInverseMatrix3x3( pMatrix, pInverse );

	// Get loudspeaker identifier
562

Jonas Stienen's avatar
Jonas Stienen committed
563
564
565
566
567
	const int &LSID1 = pActiveSection->iLSIdentifier[0];
	const int &LSID2 = pActiveSection->iLSIdentifier[1];
	const int &LSID3 = pActiveSection->iLSIdentifier[2];

	vdLoudspeakerGains[LSID1] = vSoundSource.x*dInverseMatrix[0]+vSoundSource.y*dInverseMatrix[3]+vSoundSource.z*dInverseMatrix[6];
568
	vdLoudspeakerGains[LSID2] = vSoundSource.x*dInverseMatrix[1]+vSoundSource.y*dInverseMatrix[4]+vSoundSource.z*dInverseMatrix[7];
Jonas Stienen's avatar
Jonas Stienen committed
569
570
571
572
573
574
575
576
	vdLoudspeakerGains[LSID3] = vSoundSource.x*dInverseMatrix[2]+vSoundSource.y*dInverseMatrix[5]+vSoundSource.z*dInverseMatrix[8];

	double dCorrection = sqrt(vdLoudspeakerGains[LSID1]*vdLoudspeakerGains[LSID1]+vdLoudspeakerGains[LSID2]*vdLoudspeakerGains[LSID2]+vdLoudspeakerGains[LSID3]*vdLoudspeakerGains[LSID3]);

	vdLoudspeakerGains[LSID1]/=dCorrection;
	vdLoudspeakerGains[LSID2]/=dCorrection;
	vdLoudspeakerGains[LSID3]/=dCorrection;

577
578
	*/

Jonas Stienen's avatar
Jonas Stienen committed
579
580
581
	return true;
}

582
bool CVAVBAPFreeFieldAudioRenderer::CalculateLoudspeakerGains2D( const VAVec3& vSoundSource, std::vector< double >& vdLoudspeakerGains ) const
Jonas Stienen's avatar
Jonas Stienen committed
583
584
{
	std::vector< int > viMinIDs; //Die Indices der zu nutzenden Lautsprecher
585
	viMinIDs.resize( 2 );
Jonas Stienen's avatar
Jonas Stienen committed
586
	std::vector <double> vdMinValues; //Der Abstand des Lautsprecher zur Quelle
587
	vdMinValues.resize( 2 );
Jonas Stienen's avatar
Jonas Stienen committed
588

589
	for( int j = 0; j < 2; j++ )
Jonas Stienen's avatar
Jonas Stienen committed
590
	{
591
592
		viMinIDs[ j ] = -1;
		vdMinValues[ j ] = 8e9; //unendlich wert spezifizieren (optional)
Jonas Stienen's avatar
Jonas Stienen committed
593
594
595
	}

	// Aktive Lautsprecher finden 2D
596
597
	for( size_t j = 0; j < m_voLoudspeaker.size(); j++ ) // Schleife ber LS
	{
Jonas Stienen's avatar
Jonas Stienen committed
598
		// Entfernung berechnen
599
600
		VistaVector3D vDifference = m_voLoudspeaker[ j ].pos - VistaVector3D( vSoundSource.comp );
		double dDistance = vDifference.GetLength();
Jonas Stienen's avatar
Jonas Stienen committed
601

602
		if( dDistance < *max_element( vdMinValues.begin(), vdMinValues.end() ) )
Jonas Stienen's avatar
Jonas Stienen committed
603
604
		{
			// @todo: Warning klren ...
605
606
607
			int iIDChange = int( max_element( vdMinValues.begin(), vdMinValues.end() ) - vdMinValues.begin() );
			viMinIDs[ iIDChange ] = int( j );
			vdMinValues[ iIDChange ] = dDistance;
Jonas Stienen's avatar
Jonas Stienen committed
608
609
610
		}
	}

611
612
613
614
615
	int iLS1 = viMinIDs[ 0 ];
	int iLS2 = viMinIDs[ 1 ];

	const VistaVector3D &posLS1 = m_voLoudspeaker[ iLS1 ].pos;
	const VistaVector3D &posLS2 = m_voLoudspeaker[ iLS2 ].pos;
Jonas Stienen's avatar
Jonas Stienen committed
616

617
	if( ( viMinIDs[ 0 ] == -1 ) || ( viMinIDs[ 1 ] == -1 ) )
Jonas Stienen's avatar
Jonas Stienen committed
618
619
620
		return false;

	// Berechnung der Gains ber die Inverse
621
622
	double dDetA = ( -posLS1[ 2 ] * posLS2[ 0 ] ) - ( -posLS2[ 2 ] * posLS1[ 0 ] );

Jonas Stienen's avatar
Jonas Stienen committed
623
624
625
626
	if( dDetA == 0.0f )
		return false;

	// Berechnung der Gains nach Pulkki
627
628
629
	vdLoudspeakerGains[ viMinIDs[ 0 ] ] = ( 1 / dDetA*( ( -vSoundSource.z*posLS2[ 0 ] ) + ( vSoundSource.x*posLS2[ 2 ] ) ) );
	vdLoudspeakerGains[ viMinIDs[ 1 ] ] = ( 1 / dDetA*( ( -vSoundSource.z*-posLS1[ 0 ] ) + ( vSoundSource.x*-posLS1[ 2 ] ) ) );

Jonas Stienen's avatar
Jonas Stienen committed
630
	// Normalisierung nach Pulkki
631
632
633
634
	double dCorrection = sqrt( vdLoudspeakerGains[ viMinIDs[ 0 ] ] * vdLoudspeakerGains[ viMinIDs[ 0 ] ] + vdLoudspeakerGains[ viMinIDs[ 1 ] ] * vdLoudspeakerGains[ viMinIDs[ 1 ] ] );
	vdLoudspeakerGains[ viMinIDs[ 0 ] ] /= dCorrection;
	vdLoudspeakerGains[ viMinIDs[ 1 ] ] /= dCorrection;

Jonas Stienen's avatar
Jonas Stienen committed
635
636
637
	return true;
}

638
VAVec3 CVAVBAPFreeFieldAudioRenderer::GetSourcePosition( const CVAMotionState* pMotionState )
Jonas Stienen's avatar
Jonas Stienen committed
639
{
640
	VAVec3 vSoundSource;
Jonas Stienen's avatar
Jonas Stienen committed
641
642
643
644
	vSoundSource.x = ( pMotionState->GetPosition().x - m_vReproSystemVirtualPosition.x );
	vSoundSource.y = ( pMotionState->GetPosition().y - m_vReproSystemVirtualPosition.y );
	vSoundSource.z = ( pMotionState->GetPosition().z - m_vReproSystemVirtualPosition.z );

645
646
647
	VAVec3 vRotYaw( m_vRotYaw[ 0 ], m_vRotYaw[ 1 ], m_vRotYaw[ 2 ] );
	VAVec3 vRotPitch( m_vRotPitch[ 0 ], m_vRotPitch[ 1 ], m_vRotPitch[ 2 ] );
	VAVec3 vRotRoll( m_vRotRoll[ 0 ], m_vRotRoll[ 1 ], m_vRotRoll[ 2 ] );
648
649
650
651

	vSoundSource.rotatedAround( vRotYaw, float( m_oUserYPRRealWorldRAD.yaw ) );
	vSoundSource.rotatedAround( vRotPitch, float( m_oUserYPRRealWorldRAD.pitch ) );
	vSoundSource.rotatedAround( vRotRoll, float( m_oUserYPRRealWorldRAD.roll ) );
Jonas Stienen's avatar
Jonas Stienen committed
652

653
654
655
	vSoundSource.rotatedAround( vRotYaw, float( -m_oUserYPRVirtualScene.yaw ) );
	vSoundSource.rotatedAround( vRotPitch, float( -m_oUserYPRVirtualScene.pitch ) );
	vSoundSource.rotatedAround( vRotRoll, float( -m_oUserYPRVirtualScene.roll ) );
Jonas Stienen's avatar
Jonas Stienen committed
656
657
658
659

	return VAVec3( vSoundSource.x, vSoundSource.y, vSoundSource.z );
}

660
#endif // VACORE_WITH_RENDERER_VBAP_FREE_FIELD