ITAThirdOctaveFilterbankIIR.cpp 4.71 KB
Newer Older
1
2
3
4
5
6
7
#include <ITAThirdOctaveFilterbankIIR.h>

#include "ITAThirdOctaveFilterbankCoefficients.h"

#include <ITAFastMath.h>
#include <ITAStopWatch.h>
#include <ITAException.h>
8
#include <ITANumericUtils.h>
9
10
11
12
13
14

#include <cassert>

CITAThirdOctaveFilterbankIIR::CITAThirdOctaveFilterbankIIR( const double dSampleRate, const int iBlockLength )
	: m_dSampleRate( dSampleRate ),
	m_iBlockLength( iBlockLength ),
15
16
	m_nBandsInternal( ITA_BIQUAD_FILTER_NUM_BANDS ),
	m_nBiquadsPerBand( ITA_BIQUAD_FILTER_NUM_BIQUADS_PER_BAND )
17
{
18
	if( dSampleRate != ITA_BIQUAD_FILTER_SAMPLINGRATE )
19
20
21
		ITA_EXCEPT1( INVALID_PARAMETER, "Filterbank does not support this samplingrate" );

	// Initialize biquads
22
	int nBiquads = m_nBandsInternal * m_nBiquadsPerBand;
23
24
25
	m_vBiquads.resize( nBiquads );
	for( int i = 0; i < m_nBandsInternal; i++ )
		for( int j = 0; j < m_nBiquadsPerBand; j++ )
26
			m_vBiquads[ i * m_nBiquadsPerBand + j ].oParams.SetParameters( ITA_BIQUAD_FILTER_PARAMS[ i ][ j ] );
27

28
29
	m_sfTempFilterBuf.Init( m_iBlockLength, true );
	m_pfTempOutputBuf.Init( m_iBlockLength, true );
30
31
32
33
}

int CITAThirdOctaveFilterbankIIR::GetLatency() const
{
34
	return 0; // @todo jst: really?
35
36
}

37
void CITAThirdOctaveFilterbankIIR::SetMagnitudes( const CITAThirdOctaveGainMagnitudeSpectrum& oMagnitudes, const bool bSmoothChangeover )
38
{
39
	CITAThirdOctaveFilterbankIIR::MagnitudeUpdate oUpdate;
40
	oUpdate.oMags = oMagnitudes;
41
	oUpdate.iBlendSamples = ( bSmoothChangeover ? 1 : 0 );
42
	m_vMagnitudesQueue.push( oUpdate );
43
44
45
46
}

void CITAThirdOctaveFilterbankIIR::Clear()
{
47
48
	for( size_t i = 0; i < m_vBiquads.size(); i++ )
		m_vBiquads[ i ].Clear();
49
50
51
52
53
54
55
56
57
58
59
}

void CITAThirdOctaveFilterbankIIR::Process( const float* pfInputSamples, float* pfOutputSamples )
{
	assert( pfInputSamples != nullptr );
	assert( pfOutputSamples != nullptr );

	// Fr Schleifen unten
	assert( m_nBiquadsPerBand >= 2 );

	const int iMaxBand = m_nBandsInternal - 1;
60
61
62
63
	const int iLastBandIndex = m_nBiquadsPerBand - 1;
	
	// Empty queue and use latest magnitude update
	CITAThirdOctaveFilterbankIIR::MagnitudeUpdate oLatestMagnitudeUpdate;
64
	bool bUpdateGains = false;
65
	while( m_vMagnitudesQueue.try_pop( oLatestMagnitudeUpdate ) )
66
67
		bUpdateGains = true;

68
69
	// Processing will first work through the biquads per band and then add samples target buffer at last biquad of band

70
71
	if( bUpdateGains )
	{
72
		bool bSwitchGains = ( oLatestMagnitudeUpdate.iBlendSamples == 0 );
73
74
75
76
77

		if( bSwitchGains )
		{
			for( int i = 0; i < iMaxBand; i++ )
			{
78
				m_vBiquads[ i*m_nBiquadsPerBand + 0 ].Process( pfInputSamples, m_sfTempFilterBuf.GetData(), m_iBlockLength );
79

80
81
				for( int j = 1; j < iLastBandIndex; j++ )
					m_vBiquads[ i*m_nBiquadsPerBand + j ].Process( m_sfTempFilterBuf.GetData(), m_sfTempFilterBuf.GetData(), m_iBlockLength );
82

83
				const float fGain = oLatestMagnitudeUpdate.oMags[ i ];
84
85
				const int iOutputWriteMode = ( i == 0 ? CITABiquad::OUTPUT_OVERWRITE : CITABiquad::OUTPUT_ADD );
				m_vBiquads[ i*m_nBiquadsPerBand + iLastBandIndex ].Process( m_sfTempFilterBuf.GetData(), m_pfTempOutputBuf.GetData(), m_iBlockLength, fGain, iOutputWriteMode );
86
87
88
89
90
91
92
93
			}
		}
		else
		{
			// Smooth gain changeover
			for( int i = 0; i < iMaxBand; i++ )
			{
				// Erster Biquad in der Sequenz: input => tmp
94
				m_vBiquads[ i*m_nBiquadsPerBand + 0 ].Process( pfInputSamples, m_sfTempFilterBuf.GetData(), m_iBlockLength );
95
96

				// Biquads dazwischen: tmp => tmp
97
				for( int j = 1; j < iLastBandIndex; j++ )
98
					m_vBiquads[ i*m_nBiquadsPerBand + j ].Process( m_sfTempFilterBuf.GetData(), m_sfTempFilterBuf.GetData(), m_iBlockLength );
99
100

				// Letztes Biquad mit Gain: tmp => output
101
				const float fGain1 = m_oMagnitudesInternal[ i ];
102
				const float fGain2 = oLatestMagnitudeUpdate.oMags[ i ];
103
				m_vBiquads[ i*m_nBiquadsPerBand + iLastBandIndex ].Process( m_sfTempFilterBuf.GetData(), m_pfTempOutputBuf.GetData(), m_iBlockLength, fGain1, fGain2, ( i == 0 ? CITABiquad::OUTPUT_OVERWRITE : CITABiquad::OUTPUT_ADD ) );
104
105
106
			}
		}

107
		m_oMagnitudesInternal = oLatestMagnitudeUpdate.oMags;
108
109
110
111
112
113
114
	}
	else
	{
		// No change in gains
		for( int i = 0; i < iMaxBand; i++ )
		{
			// Erster Biquad in der Sequenz: input => tmp
115
			m_vBiquads[ i*m_nBiquadsPerBand + 0 ].Process( pfInputSamples, m_sfTempFilterBuf.GetData(), m_iBlockLength );
116
117

			// Biquads dazwischen: tmp => tmp
118
119
			for( int j = 1; j < iLastBandIndex; j++ )
				m_vBiquads[ i*m_nBiquadsPerBand + j ].Process( m_sfTempFilterBuf.GetData(), m_sfTempFilterBuf.GetData(), m_iBlockLength );
120
121

			// Letztes Biquad mit Gain: tmp => output
122
			m_vBiquads[ i*m_nBiquadsPerBand + iLastBandIndex ].Process( m_sfTempFilterBuf.GetData(), m_pfTempOutputBuf.GetData(), m_iBlockLength, m_oMagnitudesInternal[ i ], ( i == 0 ? CITABiquad::OUTPUT_OVERWRITE : CITABiquad::OUTPUT_ADD ) );
123
124
125
		}
	}

126
127
	// Hand over output samples
	fm_copy( pfOutputSamples, m_pfTempOutputBuf.GetData(), m_iBlockLength );
128
}