ITANCTC.h 9.98 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
 * ----------------------------------------------------------------
 *
 *		ITA core libs
 *		(c) Copyright Institute of Technical Acoustics (ITA)
 *		RWTH Aachen University, Germany, 2015-2017
 *
 * ----------------------------------------------------------------
 *				    ____  __________  _______
 *				   //  / //__   ___/ //  _   |
 *				  //  /    //  /    //  /_|  |
 *				 //  /    //  /    //  ___   |
 *				//__/    //__/    //__/   |__|
 *
 * ----------------------------------------------------------------
 *
 */
Jonas Stienen's avatar
Jonas Stienen committed
18 19 20 21 22 23

#ifndef INCLUDE_WATCHER_ITA_N_CTC
#define INCLUDE_WATCHER_ITA_N_CTC

#include <ITACTCDefinitions.h>

24
#include <atomic>
Jonas Stienen's avatar
Jonas Stienen committed
25 26 27 28 29 30
#include <string>
#include <vector>

#include <ITAAtomicPrimitives.h>
#include <ITAFFT.h>
#include <ITASampleFrame.h>
Dipl.-Ing. Jonas Stienen's avatar
Dipl.-Ing. Jonas Stienen committed
31
#include <ITAStopWatch.h>
Jonas Stienen's avatar
Jonas Stienen committed
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
#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:

111 112 113 114
		enum
		{
			OPTIMIZATION_NONE = 0, //!< No optimization in filter design
		};
Jonas Stienen's avatar
Jonas Stienen committed
115

116 117
		Config();

Jonas Stienen's avatar
Jonas Stienen committed
118 119 120 121
		int N;					//!< Number of loudspeakers
		int iCTCFilterLength;	//!< CTC filter taps, i.e. 4096
		double dSampleRate;		//!< Sampling rate
		float fSpeedOfSound;	//!< Speed of sound, m/s
122
		int iOptimization;		//!< Optimization algorithm (future work, see features/room_compensation)
123 124
		float fCrossTalkCancellationFactor; //!< Factor for cross-talk cancellation (none = 0.0, full = 1.0)
		float fWaveIncidenceAngleCompensationFactor; //!< Factor for cross-talk cancellation (none = 0.0, full = 1.0)
Jonas Stienen's avatar
Jonas Stienen committed
125 126 127 128

		class ITA_CTC_API Loudspeaker
		{
		public:
129 130
			enum
			{
131 132 133
				SIDE_NOT_SPECIFIED = 0, //!@ Side of the loudspeaker not specified
				LEFT_SIDE = 1,          //!@ Loudspeaker is left from listener viewpoint
				RIGHT_SIDE = 2,         //!@ Loudspeaker is right from listener viewpoint
134
			};
Jonas Stienen's avatar
Jonas Stienen committed
135 136 137 138
			Loudspeaker();
			Loudspeaker( const Pose& oStaticPose );
			Pose oPose;							//!< Pose of loudspeaker
			const DAFFContentDFT* pDirectivity;	//!< Directivity data
139
			int iSide;
Jonas Stienen's avatar
Jonas Stienen committed
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
		};
		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
	  */
173

Jonas Stienen's avatar
Jonas Stienen committed
174 175 176 177
	const Config& GetConfig() const;

	//! Get beta parameter
	/**
178 179
	* \return Beta parameter
	*/
Jonas Stienen's avatar
Jonas Stienen committed
180 181 182 183
	float GetBeta();

	//! Set beta parameter
	/**
184 185
	* \param fBeta Set the beta regularization parameter
	*/
Jonas Stienen's avatar
Jonas Stienen committed
186 187
	void SetBeta( float fBeta );

188
	//! Get cross-talk cancellation factor
189 190 191
	/**
	* \return Factor [0..1]
	*/
192
	float GetCrossTalkCancellationFactor();
193

194
	//! Set cross-talk cancellation factor
195 196 197
	/**
	* \param fFactor number between [0..1] (none: 0, max range = 1.0)
	*/
198 199 200 201 202 203 204 205 206 207 208 209 210
	void SetCrossTalkCancellationFactor( float fFactor );

	//! Get cross-talk cancellation factor
	/**
	* \return Factor [0..1]
	*/
	float GetWaveIncidenceAngleCompensation();

	//! Set cross-talk cancellation factor
	/**
	* \param fFactor number between [0..1] (none: 0, max range = 1.0)
	*/
	void SetWaveIncidenceAngleCompensationFactor( float fFactor );
211

Jonas Stienen's avatar
Jonas Stienen committed
212 213 214 215
	//! Get additional delay parameter
	/**
	  * \return Delay in seconds
	  */
216
	std::vector< float > GetDelayTime();
Jonas Stienen's avatar
Jonas Stienen committed
217

218
	//! Set additional delay parameter in seconds (affects all channels)
Jonas Stienen's avatar
Jonas Stienen committed
219
	/**
220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235
      * 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
236
	  */
237
	void SetDelayTime( std::vector< float > vfDelayTime );
Jonas Stienen's avatar
Jonas Stienen committed
238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 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 286 287 288 289 290 291 292 293 294 295 296
	
	//! 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
297
	void WienerHopfFactorization( ITAHDFTSpectrum* voSpecIn, ITAHDFTSpectrum* voSpecOutPlus, ITAHDFTSpectrum* voSpecOutMinus );
Jonas Stienen's avatar
Jonas Stienen committed
298 299 300 301 302 303

protected:

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

304
	std::atomic< float > m_fBeta;		//!< Beta parameter (regularization)
305
	std::vector< float > m_vfDelayTime;	//!< Add a delay [seconds] to the resulting CTC filter (individual channels)
306
	std::atomic <int > m_iOptimization;	//!< Optimization (see Config enum)
307 308
	std::atomic< float > m_fCrossTalkCancellationFactor;		//!< Factor for cross-talk cancellation (none = 0.0, full = 1.0)
	std::atomic< float > m_fWaveIncidenceAngleCompensationFactor;		//!< Factor for cross-talk cancellation (none = 0.0, full = 1.0)
Jonas Stienen's avatar
Jonas Stienen committed
309 310 311 312 313 314 315 316 317 318 319 320
	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
321
	int GetLoudspeakerSide(int);
Jonas Stienen's avatar
Jonas Stienen committed
322 323
	//! Adds a HRIR into the target filter
	/**
324 325 326 327 328 329
	* @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
330 331 332 333 334 335
	bool AddHRIR( const Pose& oLoudspeakerPose, ITASampleFrame& sfTargetIR, bool& bOutOfRange, double dGain = 1.0f ) const;

	friend class ITACTCStreamFilter;
};

#endif // INCLUDE_WATCHER_ITA_N_CTC