VADirectivityDAFFHRIR.cpp 6.26 KB
Newer Older
Jonas Stienen's avatar
Jonas Stienen committed
1
/*
2
 *  --------------------------------------------------------------------------------------------
Jonas Stienen's avatar
Jonas Stienen committed
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
 *        VVVVVV       AAA       Institute of Technical Acoustics (ITA)
 *         VVVV         AAA      RWTH Aachen University
Jonas Stienen's avatar
Jonas Stienen committed
10
 *
11
 *  --------------------------------------------------------------------------------------------
Jonas Stienen's avatar
Jonas Stienen committed
12 13
 */

14
#include "VADirectivityDAFFHRIR.h"
Jonas Stienen's avatar
Jonas Stienen committed
15 16 17 18 19 20 21 22 23

#include <VAException.h>
#include "../VALog.h"

#include <ITANumericUtils.h>
#include <ITASampleFrame.h>
#include <ITAStringUtils.h>

#include <cassert>
24
#include <DAFF.h>
Jonas Stienen's avatar
Jonas Stienen committed
25 26
#include <sstream>

27 28 29
CVADirectivityDAFFHRIR::CVADirectivityDAFFHRIR( const std::string& sFilename, const std::string& sName, const double dDesiredSamplerate )
	: m_sName( sName )
	, m_pReader( nullptr )
Jonas Stienen's avatar
Jonas Stienen committed
30
{
31 32
	m_iType = IVADirectivity::DAFF_HRIR;

Jonas Stienen's avatar
Jonas Stienen committed
33 34 35
	// Der DAFF-Reader wirft std::exceptions
	m_pReader = DAFFReader::create();

36
	int iError = m_pReader->openFile( sFilename );
Jonas Stienen's avatar
Jonas Stienen committed
37 38 39
	if( iError != DAFF_NO_ERROR )
	{
		delete m_pReader;
40
		std::string sErrorStr = DAFFUtils::StrError( iError );
41
		VA_EXCEPT1( std::string( "Could not load HRIR dataset from file \"" ) + sFilename + std::string( "\". " ) + sErrorStr + std::string( "." ) );
Jonas Stienen's avatar
Jonas Stienen committed
42 43
	}

44 45
	if( m_pReader->getContentType() != DAFF_IMPULSE_RESPONSE )
	{
Jonas Stienen's avatar
Jonas Stienen committed
46
		delete m_pReader;
47
		VA_EXCEPT1( std::string( "The file \"" ) + sFilename + std::string( "\" does not contain impulse response content." ) );
Jonas Stienen's avatar
Jonas Stienen committed
48 49
	}

50
	m_pContent = dynamic_cast< DAFFContentIR* >( m_pReader->getContent() );
51
	assert( m_pContent );
Jonas Stienen's avatar
Jonas Stienen committed
52

53 54
	if( m_pContent->getSamplerate() != dDesiredSamplerate )
	{
Jonas Stienen's avatar
Jonas Stienen committed
55
		delete m_pReader;
56
		VA_EXCEPT1( std::string( "The file \"" ) + sFilename + std::string( "\" does not have the required sampling rate of " ) + DoubleToString( dDesiredSamplerate ) + std::string( " Hz." ) );
Jonas Stienen's avatar
Jonas Stienen committed
57
	}
58

Jonas Stienen's avatar
Jonas Stienen committed
59
	// Sicherheitshalber, auch wenn was paranoid ...
60 61
	if( m_pContent->getMaxEffectiveFilterLength() == 0 )
	{
Jonas Stienen's avatar
Jonas Stienen committed
62
		delete m_pReader;
63
		VA_EXCEPT1( std::string( "The file \"" ) + sFilename + std::string( "\" contains empty filters." ) );
Jonas Stienen's avatar
Jonas Stienen committed
64 65 66 67
	}

	m_pMetadata = m_pReader->getMetadata();

68 69
	m_fLatency = 0.0f;

70
	// Latency compensation
71 72
	if( !m_pMetadata->hasKey( "DELAY_SAMPLES" ) )
	{
73
		VA_WARN( "DirectivityDAFFIR", std::string( "The file \"" ) + sFilename + std::string( "\" is missing the meta tag DELAY_SAMPLES." ) );
Jonas Stienen's avatar
Jonas Stienen committed
74
	}
75
	else
76
	{
77 78 79 80 81 82
		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" );
Jonas Stienen's avatar
Jonas Stienen committed
83 84
	}

85 86
	if( m_fLatency < 0 )
	{
Jonas Stienen's avatar
Jonas Stienen committed
87
		delete m_pReader;
88
		VA_EXCEPT1( std::string( "In file \"" ) + sFilename + std::string( "\": " ) + std::string( " The meta tag DELAY_SAMPLES must be positive." ) );
Jonas Stienen's avatar
Jonas Stienen committed
89 90 91 92 93
	}

	m_iMinOffset = m_pContent->getMinEffectiveFilterOffset();
	m_iFilterLength = m_pContent->getFilterLength();

94
	if( !m_pReader->getProperties()->coversFullSphere() )
95
		VA_WARN( "DirectivityDAFFIR", "The HRIR dataset file " << sFilename << " does not cover all directions" );
Jonas Stienen's avatar
Jonas Stienen committed
96

97 98 99 100 101 102
	if( m_pReader->getProperties()->getNumberOfChannels() < 2 )
		VA_EXCEPT1( std::string( "In file \"" ) + sFilename + std::string( "\": " ) + std::string( " Number of channels for a HRIR must be at least two." ) );
	
	if( m_pReader->getProperties()->getNumberOfChannels() > 2 )
		VA_WARN( "DirectivityDAFFIR", "The HRIR dataset file " << sFilename << " has more than two channels, but will only use first two (left, right)" );

Jonas Stienen's avatar
Jonas Stienen committed
103 104 105 106 107 108 109 110 111
	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;
}

112
CVADirectivityDAFFHRIR::~CVADirectivityDAFFHRIR()
113 114
{
	if( m_pReader ) m_pReader->closeFile();
Jonas Stienen's avatar
Jonas Stienen committed
115 116 117
	delete m_pReader;
}

118
std::string CVADirectivityDAFFHRIR::GetFilename() const
119
{
Jonas Stienen's avatar
Jonas Stienen committed
120 121 122
	return m_pReader->getFilename();
}

123
std::string CVADirectivityDAFFHRIR::GetName() const {
Jonas Stienen's avatar
Jonas Stienen committed
124 125 126
	return m_sName;
}

127
std::string CVADirectivityDAFFHRIR::GetDesc() const
128 129 130 131 132 133 134
{
	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 );
Jonas Stienen's avatar
Jonas Stienen committed
135 136 137
	return buf;
}

138
const CVAHRIRProperties* CVADirectivityDAFFHRIR::GetProperties() const
139
{
Jonas Stienen's avatar
Jonas Stienen committed
140 141 142
	return &m_oProps;
}

143
void CVADirectivityDAFFHRIR::GetNearestNeighbour( const float fAzimuthDeg, const float fElevationDeg, int* piIndex, bool* pbOutOfBounds ) const
144
{
Jonas Stienen's avatar
Jonas Stienen committed
145 146
	assert( m_pContent );

147 148 149
	if( !piIndex )
		return;

Jonas Stienen's avatar
Jonas Stienen committed
150
	bool bOutOfBounds;
151 152
	m_pContent->getNearestNeighbour( DAFF_OBJECT_VIEW, fAzimuthDeg, fElevationDeg, *piIndex, bOutOfBounds );
	if( pbOutOfBounds ) *pbOutOfBounds = bOutOfBounds;
Jonas Stienen's avatar
Jonas Stienen committed
153 154
}

155 156 157 158 159 160 161
const DAFFMetadata* CVADirectivityDAFFHRIR::GetMetadataByIndex(const int iIndex) const
{
	assert(m_pContent);

	return m_pContent->getRecordMetadata( iIndex );
}

162

163
void CVADirectivityDAFFHRIR::GetHRIRByIndex( ITASampleFrame* psfDest, const int iIndex, const float ) const
164
{
Jonas Stienen's avatar
Jonas Stienen committed
165 166
	assert( m_pContent );

167 168
	if( psfDest->channels() > m_pReader->getProperties()->getNumberOfChannels() )
		VA_EXCEPT1( std::string( "HRIRDatasetDAFF2D::GetHRIRByIndex - Target SampleFrame contains more channels than HRIR database" ) );
Jonas Stienen's avatar
Jonas Stienen committed
169 170

	int iResult;
171
	for( int iChan = 0; iChan < psfDest->channels(); iChan++ )
Jonas Stienen's avatar
Jonas Stienen committed
172
	{
173 174 175
		iResult = m_pContent->getFilterCoeffs( iIndex, iChan, ( *psfDest )[ iChan ].data() );
		if( iResult != DAFF_NO_ERROR )
			VA_EXCEPT1( DAFFUtils::StrError( iResult ) );
Jonas Stienen's avatar
Jonas Stienen committed
176 177 178
	}
}

179
void CVADirectivityDAFFHRIR::GetHRIR( ITASampleFrame* psfDest, const float fAzimuthDeg, const float fElevationDeg, const float fDistanceMeters, int* piIndex, bool* pbOutOfBounds ) const
180
{
Jonas Stienen's avatar
Jonas Stienen committed
181
	int i;
182 183 184 185
	GetNearestNeighbour( fAzimuthDeg, fElevationDeg, &i, pbOutOfBounds );
	if( piIndex )
		*piIndex = i;
	GetHRIRByIndex( psfDest, i, fDistanceMeters );
Jonas Stienen's avatar
Jonas Stienen committed
186 187
}

188
DAFFContentIR* CVADirectivityDAFFHRIR::GetDAFFContent() const
189
{
Jonas Stienen's avatar
Jonas Stienen committed
190 191
	return m_pContent;
}