ITANCTC.h 8.63 KB
Newer Older
Jonas Stienen's avatar
Jonas Stienen committed
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
/*
* ----------------------------------------------------------------
*
*		ITA core libs
*		(c) Copyright Institute of Technical Acoustics (ITA)
*		RWTH Aachen University, Germany, 2015-2016
*
* ----------------------------------------------------------------
*				    ____  __________  _______
*				   //  / //__   ___/ //  _   |
*				  //  /    //  /    //  /_|  |
*				 //  /    //  /    //  ___   |
*				//__/    //__/    //__/   |__|
*
* ----------------------------------------------------------------
*
*/
// $Id: ITANCTC.h 2395 2012-04-20 06:58:52Z stienen $

#ifndef INCLUDE_WATCHER_ITA_N_CTC
#define INCLUDE_WATCHER_ITA_N_CTC

#include <ITACTCDefinitions.h>

25
#include <atomic>
Jonas Stienen's avatar
Jonas Stienen committed
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
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
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
#include <string>
#include <vector>

#include <ITAAtomicPrimitives.h>
#include <ITAFFT.h>
#include <ITASampleFrame.h>
#include <ITAStopwatch.h>
#include <ITAHDFTSpectra.h>

#include <VistaBase/VistaVector3D.h>
#include <VistaMath/VistaGeometries.h>
//#include <VistaBase/VistaQuaternion.h>

class ITANCTCStreamFilter;
class DAFFContentIR;
class DAFFContentDFT;
class ITADatasource;

//! ITANCTC - Crosstalk-Cancellation framework
/**
  *
  * See dissertation of Bruno Masiero
  *
  * non-reentrant
  *
  * Crosstalk-Cancellation-Engine for arbitrary loudspeaker
  *					configurations using pseudo-inverse matrix solution with
  *					all channels active
  * 
  */
class ITA_CTC_API ITANCTC
{
public:

	//! CTC filter algorithms
	enum CTCFilterAlgorithms
	{
		CTC_REGULARIZED = 0, //!< Regularized algorithm
		CTC_WIENER_REG,		 //!< Regularized Wiener algorithm
		CTC_WIENER_REG_MIN,	 //!< Regularized Wiener algorithm with minimum phase filter
	};

	//! Data class that encapsules the pose of an object
	/**
	  * The pose of an object such as a loudspeaker or head
	  * stores the position as well as orientation. While
	  * view and up vectors are used to determine the orientation
	  * of the object, they can also be set in yaw, pitch and
	  * roll convention.
	  */
	class ITA_CTC_API Pose
	{
	public:
		inline Pose() {};

		VistaVector3D vPos;			//!< Position vector
		//VistaQuaternion qOrient;	//!< Orientation
		VistaVector3D vView;		//!< View direction (OpenGL convention)
		VistaVector3D vUp;			//!< Up direction (OpenGL convention)

		Pose& operator=( const Pose& );

		//! Set the orientation using yaw-pitch-roll (YPR) convention [degrees]
		/**
		  * \note All angles in degrees [°]
		  */
		void SetOrientationYPRdeg( double fYaw, double fPitch, double fRoll );

		//! Get YPR angles
		void GetOrientationYPRdeg( float& fYaw, float& fPitch, float& fRoll ) const;
	};


	//! NCTC configuration data class
	/**
	  * This static configuration data has to be passed
	  * for each instance if the CircularNCTC class. Changes
	  * cannot be made afterwards.
	  * For dynamic parameters like Beta oder Delay have a look at
	  * the corresponding setters/getters
	  *
	  */
	class ITA_CTC_API Config
	{
	public:


		int N;					//!< Number of loudspeakers
		int iCTCFilterLength;	//!< CTC filter taps, i.e. 4096
		double dSampleRate;		//!< Sampling rate
		float fSpeedOfSound;	//!< Speed of sound, m/s
117
		int iOptimization;		//!< Optimization algorithm (future work, see features/room_compensation)
Jonas Stienen's avatar
Jonas Stienen committed
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176

		class ITA_CTC_API Loudspeaker
		{
		public:
			Loudspeaker();
			Loudspeaker( const Pose& oStaticPose );
			Pose oPose;							//!< Pose of loudspeaker
			const DAFFContentDFT* pDirectivity;	//!< Directivity data
		};
		std::vector< Loudspeaker > voLoudspeaker; //!< Loudspeaker of this setup

	};

	//! Constructor
	/**
	  * Creates the NCTC module for N selected loudspeakers using the poses (position & orientation) 
	  * given by the specified configuration file. The number of loudspeakers is defined 
	  * through the configuration's SelectedSpeakers list. The configuration may have more
	  * loudspeakers defined than are selected in the end.
	  *
	  * \note Throws ITAException errors
	  *
	  * \param oNCTCConfig The configuration, see \Config
	  *
	  */
	ITANCTC( const Config& oNCTCConfig );

	//! Destructor
	~ITANCTC();

	//! Get the number of loudspeaker for this CTC enginge
	/**
	  * \return number of channels (N)
	  *
	  */
	int GetN() const;

	//! Configuration getter
	/**
	  * \return Static configuration parameters
	  */
	const Config& GetConfig() const;

	//! Get beta parameter
	/**
	  * \return Beta parameter
	  */
	float GetBeta();

	//! Set beta parameter
	/**
	  * \param fBeta Set the beta regularization parameter
	  */
	void SetBeta( float fBeta );

	//! Get additional delay parameter
	/**
	  * \return Delay in seconds
	  */
177
	std::vector< float > GetDelayTime();
Jonas Stienen's avatar
Jonas Stienen committed
178

179
	//! Set additional delay parameter in seconds (affects all channels)
Jonas Stienen's avatar
Jonas Stienen committed
180
	/**
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
      * The default value is half of the filter length.
      *
      * @note Will overwrite existing individual values.
	  *
	  * @param fDelayTime Set the time delay (all channels)
	  */
	void SetDelayTime( float fDelayTime );

	//! Set delay parameter in seconds for each loudspeaker channel individually
	/**
	  * The CTC filter set for each channel (loudspeaker) will be delayd by given time. This is
	  * helpful to overcome latency issues with different types of loudspeakers.
	  *
      * The default value is half of the filter length.
      *
	  * \param vfDelayTime Set the time delay (each channel/loudspeaker individually)
Jonas Stienen's avatar
Jonas Stienen committed
197
	  */
198
	void SetDelayTime( std::vector< float > vfDelayTime );
Jonas Stienen's avatar
Jonas Stienen committed
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
	
	//! Sets the optimization
	/**
	  * Optimization setter, i.e. early reflection compensation for aixCAVE (see enum of Config)
	  */
	void SetOptimization( int iOptimization );

	//! Optimization getter
	/**
	  * Optimization getter, i.e. early reflection compensation for aixCAVE (see enum of Config)
	  */
	int GetOptimization() const;

	//! Get loudspeaker pose
	/**
	  * \param	iLoudspeakerID Identifier of loudspeaker (begins with 0, max N-1)
	  * \return	Returns the pose of a loudspeaker
	  */

	const Pose& GetLoudspeakerPose( int iLoudspeakerID ) const;

	//! Set HRIR dataset
	/**
	  * \param pHRIRDatabase The DAFF impulse response file with the head-related information
	  *
	  */
	void SetHRIR( const DAFFContentIR* pHRIR );
	
	//! Update the head position and orientation (combination = pose)
	/**
	  * Use this method to update the head pose (position and/or orientation). This is
	  * usually data that your tracking device provides. The CircularNCTC will then update
	  * for the new sweet spot.
	  *
	  * \param oHead	Pose of head (from tracking device)
	  */
	void UpdateHeadPose( const Pose& oHead );

	//! Returns the pointer to the currently used HRIR dataset
	/**
	  * \important	Not thread safe
	  */
	bool GetHRTF( std::vector< ITAHDFTSpectra* >& vpHRTF ) const;

	//! Returns the currently used head pose
	/**
	  * \important	Not thread safe
	  */
	Pose GetHeadPose() const;
	
	//! Calculate the CTC filters
	/**
	  * Starts calculation
	  * \param vpSpectra vector of two-channel CTC filter spectra for each loudspeaker (call-by-ref), will update filter in vector if possible
	  * \return True, if calculation was possible
	  */
	bool CalculateFilter( std::vector< ITAHDFTSpectra* >& vpSpectra );

	//! Calculate the Wiener-Hopf factorization
258
	void WienerHopfFactorization( ITAHDFTSpectrum* voSpecIn, ITAHDFTSpectrum* voSpecOutPlus, ITAHDFTSpectrum* voSpecOutMinus );
Jonas Stienen's avatar
Jonas Stienen committed
259
260
261
262
263
264

protected:

private:
	const Config m_oConfig;			//!< CTC Configuration

265
	std::atomic< float > m_fBeta;		//!< Beta parameter (regularization)
266
	std::vector< float > m_vfDelayTime;	//!< Add a delay [seconds] to the resulting CTC filter (individual channels)
267
	std::atomic <int > m_iOptimization;	//!< Optimization (see Config enum)
Jonas Stienen's avatar
Jonas Stienen committed
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
	const DAFFContentIR* m_pHRIR;	//!< HRIR dataset pointer
	
	Pose m_oHeadPose;				//!< Current head Pose data

	ITAFFT m_fft, m_ifft;			//!< Internal FFT and IFFT transformations
	ITASampleFrame m_sfCTC_temp;	//!< Internal CTC helper

	std::vector< double > m_vdWeights;				//!< Diagonal values for the weighting matrix (W or Z), only non-zero entries allowed
	std::vector< ITAHDFTSpectra* > m_vpHRTFs;		//!< N-dim vector with two-channel HRTF sets for each LS direction
	std::vector< ITAHDFTSpectra* > m_vpHelper2x2;	//!< Two-by-two helper matrix
	ITAHDFTSpectrum* t;		//!< Helper
	ITAHDFTSpectrum* det;	//!< Helper

	//! Adds a HRIR into the target filter
	/**
283
284
285
286
287
288
	* @param oLoudspeakerPose	Pose of loudspeaker (or virtual source)
	* @param bOutOfRange	Indicator if the HRIR data for the required position is out of range
	* @param sfTargetIR	Target impulse response, where the HRIR will be placed by mul-adding with given gain
	*
	* @return True, if samples from HRIR could be copied into target filter, false, if target filter is too short
	*/
Jonas Stienen's avatar
Jonas Stienen committed
289
290
291
292
293
294
	bool AddHRIR( const Pose& oLoudspeakerPose, ITASampleFrame& sfTargetIR, bool& bOutOfRange, double dGain = 1.0f ) const;

	friend class ITACTCStreamFilter;
};

#endif // INCLUDE_WATCHER_ITA_N_CTC