Commit d68722ff authored by Dipl.-Ing. Jonas Stienen's avatar Dipl.-Ing. Jonas Stienen

Merging HATO support for binaural free field renderer

parents a3a2a6db fc418805
......@@ -21,6 +21,7 @@
// VA core includes
#include "../../../directivities/VADirectivityDAFFEnergetic.h"
#include "../../../directivities/VADirectivityDAFFHRIR.h"
#include "../../../directivities/VADirectivityDAFFHATOHRIR.h"
#include "../../../Filtering/VAAtmosphere.h"
#include "../../../Motion/VAMotionModelBase.h"
#include "../../../Motion/VASharedMotionModel.h"
......@@ -83,44 +84,49 @@ public:
class CDirectivityState
{
public:
CDirectivityState()
inline CDirectivityState()
: pData( NULL )
, iRecord( -1 )
, bDirectivityEnabled( true ) {}
, bDirectivityEnabled( true )
{};
IVADirectivity* pData; //!< Directivity data, may be NULL
int iRecord; //!< Directivity index
bool bDirectivityEnabled;
bool operator==( const CDirectivityState& rhs ) const
inline 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 );
}
};
};
class CHRIRState
{
public:
CHRIRState()
inline CHRIRState()
: pData( NULL )
, iRecord( -1 )
, fDistance( 1.0f ) {}
, fDistance( 1.0f )
, dHATODeg( 0.0f )
{};
IVADirectivity* pData; //!< HRIR data, may be NULL
int iRecord; //!< HRIR index
float fDistance; //!< HRIR dataset distance
double dHATODeg; //!< HRIR head-above-torso orientation
bool operator!=( const CHRIRState& rhs ) const
inline bool operator!=( const CHRIRState& rhs ) const
{
if( pData != rhs.pData ) return true;
if( fDistance != rhs.fDistance ) return true;
if( iRecord != rhs.iRecord ) return true;
if( dHATODeg != rhs.dHATODeg ) return true;
return false;
}
};
};
CVABinauralFreeFieldAudioRenderer::CVABFFSource* pSource;
......@@ -142,7 +148,7 @@ public:
ITAUPConvolution* pFIRConvolverChL;
ITAUPConvolution* pFIRConvolverChR;
void PreRequest()
inline void PreRequest()
{
pSource = nullptr;
pListener = nullptr;
......@@ -158,7 +164,7 @@ public:
void UpdateDir( bool bDIRAuraModeEnabled );
void UpdateMediumPropagation( double dSpeedOfSound, double dAdditionalDelaySeconds = 0.0f );
double CalculateInverseDistanceDecrease( const double dMinimumDistance ) const;
void UpdateHRIR( const CVAReceiverState::CVAAnthropometricParameter& );
void UpdateHRIR( const CVAReceiverState::CVAAnthropometricParameter&, const double dHATODeg );
//! Bestimmt die relativen Gren des Pfades
/**
......@@ -303,7 +309,7 @@ CVABinauralFreeFieldAudioRenderer::~CVABinauralFreeFieldAudioRenderer()
void CVABinauralFreeFieldAudioRenderer::Init( const CVAStruct& oArgs )
{
CVAConfigInterpreter conf( oArgs );
std::string sVLDInterpolationAlgorithm;
conf.OptString( "SwitchingAlgorithm", sVLDInterpolationAlgorithm, "linear" );
sVLDInterpolationAlgorithm = toLowercase( sVLDInterpolationAlgorithm );
......@@ -729,7 +735,11 @@ void CVABinauralFreeFieldAudioRenderer::ProcessStream( const ITAStreamInfo* pStr
bool bDIREnabled = ( bDIREnabledSource && bDIREnabledListener && bDIREnabledGlobal );
pPath->UpdateDir( bDIREnabled );
pPath->UpdateHRIR( pListenerState->GetAnthropometricData() );
// HATO
const VAQuat qHATO = pListenerState->GetMotionState()->GetHeadAboveTorsoOrientation();
const double dHATODenominator = sqrt( 1 - qHATO.w * qHATO.w );
const double dHATODeg = rad2grad( dHATODenominator == 0.0f ? 0.0f : qHATO.y / dHATODenominator );
pPath->UpdateHRIR( pListenerState->GetAnthropometricData(), dHATODeg );
// Sound source gain / direct sound audibility via AuraMode flags
bool bDSSourceStatusEnabled = ( pSourceState->GetAuralizationMode() & IVAInterface::VA_AURAMODE_DIRECT_SOUND );
......@@ -1084,7 +1094,7 @@ void CVABinauralFreeFieldAudioRenderer::ResetInternalData()
void CVABinauralFreeFieldAudioRenderer::UpdateSoundPaths()
{
int iGlobalAuralisationMode = m_iCurGlobalAuralizationMode;
const int iGlobalAuralisationMode = m_iCurGlobalAuralizationMode;
// Check for new data
std::list< CVABFFSoundPath* >::iterator it = m_lSoundPaths.begin();
......@@ -1258,32 +1268,52 @@ double CVABFFSoundPath::CalculateInverseDistanceDecrease( const double dMinimumD
return fInverseDistanceDecrease;
}
void CVABFFSoundPath::UpdateHRIR( const CVAReceiverState::CVAAnthropometricParameter& oAnthroParameters )
void CVABFFSoundPath::UpdateHRIR( const CVAReceiverState::CVAAnthropometricParameter& oAnthroParameters, const double dHATODeg )
{
CVADirectivityDAFFHRIR* pHRIRDataNew = ( CVADirectivityDAFFHRIR * ) oHRIRStateNew.pData;
bool bForeUpdate = false;
if( pHRIRDataNew != nullptr )
double dITDCorrectionShift = .0f;
IVADirectivity* pCurHRIR = oHRIRStateCur.pData;
IVADirectivity* pNewHRIR = oHRIRStateNew.pData;
// No new directivity
if( pNewHRIR == nullptr )
{
// Quick check if nearest neighbour is equal
if( pHRIRDataNew->GetProperties()->bSpaceDiscrete )
pHRIRDataNew->GetNearestNeighbour( float( oRelations.dAzimuthL2S ), float( oRelations.dElevationL2S ), &oHRIRStateNew.iRecord );
else
bForeUpdate = true; // Update always required, if non-discrete data
if( pCurHRIR )
{
// Directivity has been removed, set zero filters once
ITAUPFilter* pHRIRFilterChL = pFIRConvolverChL->GetFilterPool()->RequestFilter();
ITAUPFilter* pHRIRFilterChR = pFIRConvolverChR->GetFilterPool()->RequestFilter();
pHRIRFilterChL->Zeros();
pHRIRFilterChR->Zeros();
pFIRConvolverChL->ExchangeFilter( pHRIRFilterChL );
pFIRConvolverChR->ExchangeFilter( pHRIRFilterChR );
pFIRConvolverChL->ReleaseFilter( pHRIRFilterChL );
pFIRConvolverChR->ReleaseFilter( pHRIRFilterChR );
}
return;
}
if( ( oHRIRStateCur != oHRIRStateNew ) || bForeUpdate )
switch( pNewHRIR->GetType() )
{
ITAUPFilter* pHRIRFilterChL = pFIRConvolverChL->GetFilterPool()->RequestFilter();
ITAUPFilter* pHRIRFilterChR = pFIRConvolverChR->GetFilterPool()->RequestFilter();
if( pHRIRDataNew == nullptr )
{
pHRIRFilterChL->identity();
pHRIRFilterChR->identity();
}
case IVADirectivity::DAFF_HATO_HRIR:
{
CVADirectivityDAFFHATOHRIR* pHATOHRIR = ( CVADirectivityDAFFHATOHRIR * ) pNewHRIR;
oHRIRStateNew.dHATODeg = dHATODeg; // Overwrite current HATO
// Quick check if nearest neighbour is equal
bool bForceUpdate = false;
if( pHATOHRIR->GetProperties()->bSpaceDiscrete )
pHATOHRIR->GetNearestSpatialNeighbourIndex( float( oRelations.dAzimuthL2S ), float( oRelations.dElevationL2S ), &oHRIRStateNew.iRecord );
else
bForceUpdate = true; // Update always required, if non-discrete data
if( ( oHRIRStateCur != oHRIRStateNew ) || bForceUpdate )
{
int iNewFilterLength = pHRIRDataNew->GetProperties()->iFilterLength;
int iNewFilterLength = pHATOHRIR->GetProperties()->iFilterLength;
if( m_sfHRIRTemp.length() != iNewFilterLength )
{
m_sfHRIRTemp.init( 2, iNewFilterLength, false );
......@@ -1295,32 +1325,36 @@ void CVABFFSoundPath::UpdateHRIR( const CVAReceiverState::CVAAnthropometricParam
iNewFilterLength = pFIRConvolverChL->GetMaxFilterlength();
}
if( pHRIRDataNew->GetProperties()->bSpaceDiscrete )
if( pHATOHRIR->GetProperties()->bSpaceDiscrete )
{
pHRIRDataNew->GetHRIRByIndex( &m_sfHRIRTemp, oHRIRStateNew.iRecord, float( oRelations.dDistance ) );
pHATOHRIR->GetHRIRByIndexAndHATO( &m_sfHRIRTemp, oHRIRStateNew.iRecord, float( dHATODeg ) );
oHRIRStateNew.fDistance = float( oRelations.dDistance );
}
else
{
pHRIRDataNew->GetHRIR( &m_sfHRIRTemp, float( oRelations.dAzimuthL2S ), float( oRelations.dElevationL2S ), float( oRelations.dDistance ) );
int iRecordIndex = -1;
pHATOHRIR->GetNearestSpatialNeighbourIndex( float( oRelations.dAzimuthL2S ), float( oRelations.dElevationL2S ), &iRecordIndex );
pHATOHRIR->GetHRIRByIndexAndHATO( &m_sfHRIRTemp, iRecordIndex, dHATODeg );
}
// Update DSP element
ITAUPFilter* pHRIRFilterChL = pFIRConvolverChL->GetFilterPool()->RequestFilter();
ITAUPFilter* pHRIRFilterChR = pFIRConvolverChR->GetFilterPool()->RequestFilter();
pHRIRFilterChL->Load( m_sfHRIRTemp[ 0 ].data(), iNewFilterLength );
pHRIRFilterChR->Load( m_sfHRIRTemp[ 1 ].data(), iNewFilterLength );
}
pFIRConvolverChL->ExchangeFilter( pHRIRFilterChL );
pFIRConvolverChR->ExchangeFilter( pHRIRFilterChR );
pFIRConvolverChL->ReleaseFilter( pHRIRFilterChL );
pFIRConvolverChR->ReleaseFilter( pHRIRFilterChR );
pFIRConvolverChL->ExchangeFilter( pHRIRFilterChL );
pFIRConvolverChR->ExchangeFilter( pHRIRFilterChR );
pFIRConvolverChL->ReleaseFilter( pHRIRFilterChL );
pFIRConvolverChR->ReleaseFilter( pHRIRFilterChR );
// Ack
oHRIRStateCur = oHRIRStateNew;
}
// Ack
oHRIRStateCur = oHRIRStateNew;
}
double dITDCorrectionShift = .0f;
if( pHRIRDataNew )
{
// Calculate individualized ITD based on anthropometric data
// Source: ???
double daw = -8.7231e-4;
......@@ -1329,18 +1363,101 @@ void CVABFFSoundPath::UpdateHRIR( const CVAReceiverState::CVAAnthropometricParam
double dbh = 6.0476e-4;
double dad = 4.2308e-4;
double dbd = oAnthroParameters.GetHeadDepthParameterFromLUT( oAnthroParameters.dHeadDepth );
double dDeltaWidth = oAnthroParameters.dHeadWidth - pHRIRDataNew->GetProperties()->oAnthroParams.dHeadWidth;
double dDeltaHeight = oAnthroParameters.dHeadHeight - pHRIRDataNew->GetProperties()->oAnthroParams.dHeadHeight;
double dDeltaDepth = oAnthroParameters.dHeadDepth - pHRIRDataNew->GetProperties()->oAnthroParams.dHeadDepth;
double dDeltaWidth = oAnthroParameters.dHeadWidth - pHATOHRIR->GetProperties()->oAnthroParams.dHeadWidth;
double dDeltaHeight = oAnthroParameters.dHeadHeight - pHATOHRIR->GetProperties()->oAnthroParams.dHeadHeight;
double dDeltaDepth = oAnthroParameters.dHeadDepth - pHATOHRIR->GetProperties()->oAnthroParams.dHeadDepth;
double dPhiRad = oRelations.dAzimuthL2S * ITAConstants::PI_F / 180.0;
double dThetaRad = -( oRelations.dElevationL2S * ITAConstants::PI_F / 180.0 - ITAConstants::PI_F / 2.0f );
double dAmplitude = dPhiRad * ( dDeltaWidth * ( dThetaRad * dThetaRad * daw + dThetaRad * dbw ) + dDeltaHeight * ( dThetaRad * dThetaRad * dah + dThetaRad * dbh ) + dDeltaDepth * ( dThetaRad * dThetaRad * dad + dThetaRad * dbd ) );
dITDCorrectionShift = std::sin( dPhiRad ) * dAmplitude;
}
case IVADirectivity::DAFF_HRIR:
{
CVADirectivityDAFFHRIR* pHRIRDataNew = ( CVADirectivityDAFFHRIR * ) pNewHRIR;
bool bForeUpdate = false;
if( pHRIRDataNew != nullptr )
{
// Quick check if nearest neighbour is equal
if( pHRIRDataNew->GetProperties()->bSpaceDiscrete )
pHRIRDataNew->GetNearestNeighbour( float( oRelations.dAzimuthL2S ), float( oRelations.dElevationL2S ), &oHRIRStateNew.iRecord );
else
bForeUpdate = true; // Update always required, if non-discrete data
}
if( ( oHRIRStateCur != oHRIRStateNew ) || bForeUpdate )
{
ITAUPFilter* pHRIRFilterChL = pFIRConvolverChL->GetFilterPool()->RequestFilter();
ITAUPFilter* pHRIRFilterChR = pFIRConvolverChR->GetFilterPool()->RequestFilter();
if( pHRIRDataNew == nullptr )
{
pHRIRFilterChL->Zeros();
pHRIRFilterChR->Zeros();
}
else
{
int iNewFilterLength = pHRIRDataNew->GetProperties()->iFilterLength;
if( m_sfHRIRTemp.length() != iNewFilterLength )
{
m_sfHRIRTemp.init( 2, iNewFilterLength, false );
}
if( iNewFilterLength > pFIRConvolverChL->GetMaxFilterlength() )
{
VA_WARN( "BFFSoundPath", "HRIR too long for convolver, cropping. Increase HRIR filter length in BinauralFreefieldAudioRenderer configuration." );
iNewFilterLength = pFIRConvolverChL->GetMaxFilterlength();
}
if( pHRIRDataNew->GetProperties()->bSpaceDiscrete )
{
pHRIRDataNew->GetHRIRByIndex( &m_sfHRIRTemp, oHRIRStateNew.iRecord, float( oRelations.dDistance ) );
oHRIRStateNew.fDistance = float( oRelations.dDistance );
}
else
{
pHRIRDataNew->GetHRIR( &m_sfHRIRTemp, float( oRelations.dAzimuthL2S ), float( oRelations.dElevationL2S ), float( oRelations.dDistance ) );
}
pHRIRFilterChL->Load( m_sfHRIRTemp[ 0 ].data(), iNewFilterLength );
pHRIRFilterChR->Load( m_sfHRIRTemp[ 1 ].data(), iNewFilterLength );
}
pFIRConvolverChL->ExchangeFilter( pHRIRFilterChL );
pFIRConvolverChR->ExchangeFilter( pHRIRFilterChR );
pFIRConvolverChL->ReleaseFilter( pHRIRFilterChL );
pFIRConvolverChR->ReleaseFilter( pHRIRFilterChR );
// Ack
oHRIRStateCur = oHRIRStateNew;
}
if( pHRIRDataNew )
{
// Calculate individualized ITD based on anthropometric data
// Source: ???
double daw = -8.7231e-4;
double dbw = 0.0029;
double dah = -3.942e-4;
double dbh = 6.0476e-4;
double dad = 4.2308e-4;
double dbd = oAnthroParameters.GetHeadDepthParameterFromLUT( oAnthroParameters.dHeadDepth );
double dDeltaWidth = oAnthroParameters.dHeadWidth - pHRIRDataNew->GetProperties()->oAnthroParams.dHeadWidth;
double dDeltaHeight = oAnthroParameters.dHeadHeight - pHRIRDataNew->GetProperties()->oAnthroParams.dHeadHeight;
double dDeltaDepth = oAnthroParameters.dHeadDepth - pHRIRDataNew->GetProperties()->oAnthroParams.dHeadDepth;
double dPhiRad = oRelations.dAzimuthL2S * ITAConstants::PI_F / 180.0;
double dThetaRad = -( oRelations.dElevationL2S * ITAConstants::PI_F / 180.0 - ITAConstants::PI_F / 2.0f );
double dAmplitude = dPhiRad * ( dDeltaWidth * ( dThetaRad * dThetaRad * daw + dThetaRad * dbw ) + dDeltaHeight * ( dThetaRad * dThetaRad * dah + dThetaRad * dbh ) + dDeltaDepth * ( dThetaRad * dThetaRad * dad + dThetaRad * dbd ) );
dITDCorrectionShift = std::sin( dPhiRad ) * dAmplitude;
}
}
}
// Apply individualized delay
float fPreviousDelayTimeL = pVariableDelayLineChL->GetNewDelayTime();
float fPreviousDelayTimeR = pVariableDelayLineChR->GetNewDelayTime();
const float fPreviousDelayTimeL = pVariableDelayLineChL->GetNewDelayTime();
const float fPreviousDelayTimeR = pVariableDelayLineChR->GetNewDelayTime();
pVariableDelayLineChL->SetDelayTime( fPreviousDelayTimeL - float( dITDCorrectionShift ) );
pVariableDelayLineChR->SetDelayTime( fPreviousDelayTimeR + float( dITDCorrectionShift ) );
......
......@@ -11,8 +11,8 @@
* --------------------------------------------------------------------------------------------
*/
#ifndef IW_VACORE_LISTENER_STATE
#define IW_VACORE_LISTENER_STATE
#ifndef IW_VACORE_SOUND_RECEIVER_STATE
#define IW_VACORE_SOUND_RECEIVER_STATE
#include "VASceneStateBase.h"
......@@ -35,8 +35,6 @@ public:
, dHeadHeight( 0.10f )
, dHeadDepth( 0.15f )
{
// Create Lookup Table (LUT)
const double dHeadDepthParameterTemp[ 15 ][ 15 ] = { { -1.32663502405705e-09, -2.43503275907386e-05, -3.80753613782314e-05, -4.59024528641772e-05, -5.05613751010658e-05, -5.29709167498282e-05, -5.38916705479231e-05, -5.39388265685670e-05, -5.31921127823187e-05, -5.22322866046698e-05, -5.07496814787789e-05, -4.91103641909740e-05, -4.74237095774432e-05, -4.56737851716182e-05, -4.37754742472762e-05 },
{ 2.43476742738391e-05, -1.32663502405705e-09, -1.37263688705369e-05, -2.15534545322527e-05, -2.62123766865408e-05, -2.86219184142400e-05, -2.95426735188453e-05, -2.95898282018925e-05, -2.88431144145340e-05, -2.78832882389946e-05, -2.64006963994756e-05, -2.47613515994560e-05, -2.30747113284524e-05, -2.13247868936506e-05, -1.94264760042806e-05 },
......@@ -131,4 +129,4 @@ private:
} data; //!< Listener state internal data
};
#endif // IW_VACORE_LISTENER_STATE
#endif // IW_VACORE_SOUND_RECEIVER_STATE
......@@ -86,17 +86,21 @@ void ConvertQuaternionToViewUp( const VAQuat& qOrient, VAVec3& v3View, VAVec3& v
qVistaQuat[ Vista::Z ] = float( qOrient.z );
qVistaQuat[ Vista::W ] = float( qOrient.w );
const VistaVector3D vVistaView = qVistaQuat.GetViewDir();
VistaVector3D vVistaView = qVistaQuat.GetViewDir();
vVistaView.Normalize();
v3View.Set( vVistaView[ Vista::X ], vVistaView[ Vista::Y ], vVistaView[ Vista::Z ] );
const VistaVector3D vVistaUp = qVistaQuat.GetUpDir();
VistaVector3D vVistaUp = qVistaQuat.GetUpDir();
vVistaUp.Normalize();
v3Up.Set( vVistaUp[ Vista::X ], vVistaUp[ Vista::Y ], vVistaUp[ Vista::Z ] );
}
void ConvertViewUpToQuaternion( const VAVec3& vView, const VAVec3& vUp, VAQuat& qOrient )
{
const VistaVector3D vVistaView( float( vView.x ), float( vView.y ), float( vView.z ) );
const VistaVector3D vVistaUp( float( vUp.x ), float( vUp.y ), float( vUp.z ) );
VistaVector3D vVistaView( float( vView.x ), float( vView.y ), float( vView.z ) );
vVistaView.Normalize();
VistaVector3D vVistaUp( float( vUp.x ), float( vUp.y ), float( vUp.z ) );
vVistaUp.Normalize();
VistaQuaternion qVistaQuat;
qVistaQuat.SetFromViewAndUpDir( vVistaView, vVistaUp );
......
......@@ -1049,11 +1049,12 @@ int CVACoreImpl::CreateDirectivityFromParameters( const CVAStruct& oParams, cons
ev.iObjectID = iDirID;
m_pEventManager->BroadcastEvent( ev );
VA_INFO( "Core", "Directivity successfully loaded, assigned directivity ID " << iDirID );
VA_INFO( "Core", "Directivity successfully created, assigned identifier " << iDirID );
return iDirID;
} VA_RETHROW;
}
VA_RETHROW;
}
bool CVACoreImpl::DeleteDirectivity( const int iDirID )
......
......@@ -30,7 +30,8 @@ public:
DAFF_HRIR = 1,
DAFF_ENERGETIC,
MULTIPOLE,
SPHERICAL_HARMONICS
SPHERICAL_HARMONICS,
DAFF_HATO_HRIR
};
inline IVADirectivity()
......
/*
* --------------------------------------------------------------------------------------------
*
* VVV VVV A Virtual Acoustics (VA) | http://www.virtualacoustics.org
* VVV VVV AAA Licensed under the Apache License, Version 2.0
* VVV VVV AAA
* VVV VVV AAA Copyright 2015-2017
* VVVVVV AAA Institute of Technical Acoustics (ITA)
* VVVV AAA RWTH Aachen University
*
* --------------------------------------------------------------------------------------------
*/
#include "VADirectivityDAFFHATOHRIR.h"
#include <VAException.h>
#include "../VALog.h"
#include <ITANumericUtils.h>
#include <ITASampleFrame.h>
#include <ITAStringUtils.h>
#include <cassert>
#include <DAFF.h>
#include <sstream>
#include <math.h>
CVADirectivityDAFFHATOHRIR::CVADirectivityDAFFHATOHRIR( const std::string& sFilename, const std::string& sName, const double dDesiredSamplerate )
: m_sName( sName )
, m_pReader( nullptr )
{
m_iType = IVADirectivity::DAFF_HATO_HRIR;
// Der DAFF-Reader wirft std::exceptions
m_pReader = DAFFReader::create();
int iError = m_pReader->openFile( sFilename );
if( iError != DAFF_NO_ERROR )
{
delete m_pReader;
std::string sErrorStr = DAFFUtils::StrError( iError );
VA_EXCEPT1( std::string( "Could not load HRIR dataset from file \"" ) + sFilename + std::string( "\". " ) + sErrorStr + std::string( "." ) );
}
if( m_pReader->getContentType() != DAFF_IMPULSE_RESPONSE )
{
delete m_pReader;
VA_EXCEPT1( std::string( "The file \"" ) + sFilename + std::string( "\" does not contain impulse response content." ) );
}
m_pContent = dynamic_cast< DAFFContentIR* >( m_pReader->getContent() );
if( m_pContent->getSamplerate() != dDesiredSamplerate )
{
delete m_pReader;
VA_EXCEPT1( std::string( "The file \"" ) + sFilename + std::string( "\" does not have the required sampling rate of " ) + DoubleToString( dDesiredSamplerate ) + std::string( " Hz." ) );
}
// Sicherheitshalber, auch wenn was paranoid ...
if( m_pContent->getMaxEffectiveFilterLength() == 0 )
{
delete m_pReader;
VA_EXCEPT1( std::string( "The file \"" ) + sFilename + std::string( "\" contains empty filters." ) );
}
m_pMetadata = m_pReader->getMetadata();
m_fLatency = 0.0f;
// Filter-Latenz
if( !m_pMetadata->hasKey( "DELAY_SAMPLES" ) )
{
VA_WARN( "DirectivityDAFFIR", std::string( "The file \"" ) + sFilename + std::string( "\" is missing the meta tag DELAY_SAMPLES." ) );
}
else
{
if( ( m_pMetadata->getKeyType( "DELAY_SAMPLES" ) != DAFFMetadata::DAFF_INT ) && ( m_pMetadata->getKeyType( "DELAY_SAMPLES" ) != DAFFMetadata::DAFF_FLOAT ) )
{
delete m_pReader;
VA_EXCEPT1( std::string( "In file \"" ) + sFilename + std::string( "\": " ) + std::string( " The meta tag DELAY_SAMPLES must be numeric." ) );
}
m_fLatency = ( float ) m_pMetadata->getKeyFloat( "DELAY_SAMPLES" );
}
if( m_fLatency < 0 )
{
delete m_pReader;
VA_EXCEPT1( std::string( "In file \"" ) + sFilename + std::string( "\": " ) + std::string( " The meta tag DELAY_SAMPLES must be positive." ) );
}
m_iMinOffset = m_pContent->getMinEffectiveFilterOffset();
m_iFilterLength = m_pContent->getFilterLength();
// Warnung, falls keine Vollkugel
if( !m_pReader->getProperties()->coversFullSphere() )
VA_WARN( "DirectivityDAFFIR", "The HRIR dataset file " << sFilename << " does not cover all directions" );
// Eigenschaften definieren
m_oProps.sFilename = sFilename;
m_oProps.sName = sName;
m_oProps.iFilterLength = m_iFilterLength;
m_oProps.fFilterLatency = m_fLatency;
m_oProps.bFullSphere = m_pReader->getProperties()->coversFullSphere();
m_oProps.bSpaceDiscrete = true;
m_oProps.bDistanceDependent = false;
if( m_pReader->getProperties()->getNumberOfChannels() % 2 == 1 )
VA_EXCEPT1( std::string( "In file \"" ) + sFilename + std::string( "\": odd number detected for HATO HRIR DAFF file" ) );
m_iNumHATODirections = m_pReader->getProperties()->getNumberOfChannels() / 2;
if( !m_pMetadata->hasKey( "HATO_START_DEG" ) )
VA_EXCEPT2( INVALID_PARAMETER, std::string( "In file \"" ) + sFilename + std::string( "\": missing 'HATO_START_DEG' metadata key, can't use this DAFF file for a HATO HRIR" ) );
if( !m_pMetadata->hasKey( "HATO_END_DEG" ) )
VA_EXCEPT2( INVALID_PARAMETER, std::string( "In file \"" ) + sFilename + std::string( "\": missing 'HATO_END_DEG' metadata key, can't use this DAFF file for a HATO HRIR" ) );
m_dHATOStartDeg = m_pMetadata->getKeyFloat( "HATO_START_DEG" );
m_dHATOEndDeg = m_pMetadata->getKeyFloat( "HATO_END_DEG" );
}
CVADirectivityDAFFHATOHRIR::~CVADirectivityDAFFHATOHRIR()
{
if( m_pReader )
m_pReader->closeFile();
delete m_pReader;
}
std::string CVADirectivityDAFFHATOHRIR::GetFilename() const
{
return m_pReader->getFilename();
}
std::string CVADirectivityDAFFHATOHRIR::GetName() const {
return m_sName;
}
std::string CVADirectivityDAFFHATOHRIR::GetDesc() const
{
char buf[ 1024 ];
sprintf( buf, "DAFF, 2D, %s, discrete %0.0fx%0.0f, %d taps",
( m_oProps.bFullSphere ? "full sphere" : "partial sphere" ),
m_pContent->getProperties()->getAlphaResolution(),
m_pContent->getProperties()->getBetaResolution(),
m_oProps.iFilterLength );
return buf;
}
const CVAHRIRProperties* CVADirectivityDAFFHATOHRIR::GetProperties() const
{
return &m_oProps;
}
void CVADirectivityDAFFHATOHRIR::GetNearestSpatialNeighbourIndex( const float fAzimuthDeg, const float fElevationDeg, int* piIndex, bool* pbOutOfBounds ) const
{
assert( m_pContent );
if( !piIndex )
return;
bool bOutOfBounds;