Commit c5b6498e authored by Dipl.-Ing. Jonas Stienen's avatar Dipl.-Ing. Jonas Stienen
Browse files

Refactoring IIR biquad implementation of third octave filtering

parent 7d591483
......@@ -57,73 +57,64 @@ public:
} oParams;
//! Überblendmodus der Ausgabe
//! Output write modes
enum
{
OUTPUT_OVERWRITE = 0, //!< Ausgabe überschreiben
OUTPUT_ADD = 1 //!< Ausgabe addieren
} OutputFadeMode;
OUTPUT_OVERWRITE = 0, //!< Overwrites output
OUTPUT_ADD = 1 //!< Adds to the output
};
//! Standardkonstruktor
/**
* Setzt interne Werte und Koeffizienten für
* einen idealen Übertrager
*/
CITABiquad();
//! Destruktor
virtual inline ~CITABiquad() {};
//! Löscht alle internen Puffer
/**
* Setzt Akkumulatoren auf 0.
*/
//! Clears all accumulators
void Clear();
//! Filtert Samples, einfache Variante ohne Verstärkungsfaktoren
//! Filter samples, simple variant without any gain (factor)
/**
* Filtert samples gemäß der Direkten Form 2 (Kanonische Form)
* Direct second canonical form.
*
* \param in Eingabesamples
* \param in Ausgabesamples
* \param in Anzahl der Eingabe- und Ausgabesamples
* @param[in] pfInputData Input samples
* @param[out] pfOutputData Output samples
* @param[in] iNumSamples Number of samples to be processed
*
* \note Eingabe- und Ausgabepuffer dürfen gleich sein
* @note Input and output samples must have same length
*/
void Process( const float* pfInputData, float* pfOutputData, const int iNumSamples );
//! Filtert Samples, Variante mit Überlenden zu einer vorgegebenen Ausgabeverstärkung
//! Filter samples, simple variant with given gain (factor)
/**
* \param in Eingabesamples
* \param out Ausgabesamples
* \param nsamples Anzahl der Eingabe- und Ausgabesamples
* \param outputGain Ausgabeverstärkung Ausgangsparameter
* \param outputMode Überblendmodus, eines aus #OutputFadeMode
* Direct second canonical form.
*
* @param[in] pfInputData Input samples
* @param[out] pfOutputData Output samples
* @param[in] iNumSamples Number of samples to be processed
* @param[in] fOutputGain Gain (factor) for output
* @param[in] iOutputMode Add to or overwrite output buffer
*
* \note Verändern nicht den internen Verstärkungsfaktor #g (Gain)
* \note Eingabe- und Ausgabepuffer dürfen gleich sein
* @note Input and output samples must have same length
*/
void Process( const float* pfInputData, float* pfOutputData, const int iNumSamples, const float fOutputGain, const int iOutputMode );
//! Filtert Samples. Fette Variante (Ausgabemodus, Überblendung der Gains)
//! Filter samples, simple variant with given gain (factor)
/**
* Filtert Samples und setzt gleichzeitig eine Verstärkungsänderung um.
* Interpoliert lineare zwischen Gain1 und Gain2 auf allen Samples.
* Direct second canonical form.
*
* \param in Eingabesamples
* \param out Ausgabesamples
* \param nsamples Anzahl der Eingabe- und Ausgabesamples
* \param outputGain1 Ausgabeverstärkung Ausgangsparameter
* \param outputGain2 Ausgabeverstärkung Zielparameter
* \param outputMode Überblendmodus, eines aus #OutputFadeMode
* @param[in] pfInputData Input samples
* @param[out] pfOutputData Output samples
* @param[in] iNumSamples Number of samples to be processed
* @param[in] fOutputGain1 Initial gain (factor) for output
* @param[in] fOutputGain2 Target gain (factor) for output
* @param[in] iOutputMode Add to or overwrite output buffer
*
* \note Verändern nicht den internen Verstärkungsfaktor #g (Gain)
* \note Eingabe- und Ausgabepuffer dürfen gleich sein
* @note Input and output samples must have same length
*/
void Process( const float* pfInputData, float* pfOutputData, const int iNumSamples, const float fOutputGain1, const float fOutputGain2, const int iOutputMode );
private:
float z[ 2 ]; //!< Accumulators
float vfAccumulators[ 2 ]; //!< Accumulators
};
#endif // IW_ITA_BIQUAD
......@@ -70,9 +70,9 @@ public:
pFilter->Release(); // Auto-release
}
inline virtual void SetMagnitudes( const CITAThirdOctaveMagnitudeSpectrum& oGains, const bool bSmoothChangeover = true )
inline virtual void SetMagnitudes( const CITAThirdOctaveMagnitudeSpectrum& oMags, const bool bSmoothChangeover = true )
{
m_pGenerator->GenerateFilter( oGains, m_pfFilter );
m_pGenerator->GenerateFilter( oMags, m_pfFilter );
ITAUPFilter* pFilter = m_pConvolver->RequestFilter();
pFilter->Load( m_pfFilter, m_iFilterLength );
m_pConvolver->ExchangeFilter( pFilter, ( bSmoothChangeover ? ITAUPConvolution::AUTO : ITAUPConvolution::SWITCH ) );
......
......@@ -23,40 +23,38 @@
#include <ITAThirdOctaveFilterbank.h>
#include <ITAAmplitudeSpectrum.h>
#include <ITABiquad.h>
#include <ITASampleBuffer.h>
#include <vector>
#include <tbb/concurrent_queue.h>
//! Terzfilterbank mittels Biquads (IIR Filter)
//! Third octave magnitude filtering using Biquads (IIR filter)
/**
* Diese Klasse realisiert eine Terzfilterbank (#CITAThirdOctaveFilterbank) mit der Methode der kaskadierten
* Biquads (#CITABiquad) für Verstärkungsfaktoren eines Terzbank-Betragsspektrums (#CITAThirdOctaveMagnitudeSpectrum).
*
*/
class ITA_DSP_API CITAThirdOctaveFilterbankIIR : public CITAThirdOctaveFilterbank
{
public:
//! Konstruktor mit Samplerate und Blocklänge
//! Constructor
/**
* \param dSamplerate Samplingrate
* \param iBlocklength Blocklänge
* @param[in] dSampleRate Samplingrate
* @param[in] iBlockLength Block length
*/
CITAThirdOctaveFilterbankIIR( const double dSampleRate, const int iBlockLength );
//! Destruktor
virtual ~CITAThirdOctaveFilterbankIIR();
virtual inline ~CITAThirdOctaveFilterbankIIR() {};
//! Filterlatenz in Samples zurückgeben
int GetLatency() const;
//! Verstärkungen (Gains) setzen
//! Set magnitudes (in decibel) of filter bank
/**
* \param oGains Verstärkungsfaktoren
* \param bSmoothChangeover Wenn true, dann überblenden (default), sonst sofort internen Gain umschalten
* @param[in] oMagnitudes Filter magnitudes (dB)
* @param[in] bSmoothChangeover If true, switching is smoothed
*/
void SetMagnitudes( const CITAThirdOctaveMagnitudeSpectrum& oGains, const bool bSmoothChangeover = true );
void SetMagnitudes( const CITAThirdOctaveMagnitudeSpectrum& oMagnitudes, const bool bSmoothChangeover = true );
//! Alle internen Zustände zurücksetzen (Akkumulatoren der Biquads)
//! Clear all internal accumulators
void Clear();
//! Verarbeite Samples (Filtern)
......@@ -68,7 +66,7 @@ public:
private:
//! Interne Datenklasse für das Verarbeiten eines neuen Gain Datensatzes
class GainUpdate
class MagnitudeUpdate
{
public:
CITAThirdOctaveMagnitudeSpectrum oMags; //! New magnitudes
......@@ -79,11 +77,11 @@ private:
int m_iBlockLength; //!< Blocklänge
int m_nBandsInternal; //!< Anzahl der internen Bänder
int m_nBiquadsPerBand; //!< Anzahl von Biqads pro Band
std::vector< CITABiquad > m_vBiquads; //!< Biquads, Zugriff: [Band][BiquadNummer]
tbb::strict_ppl::concurrent_queue< CITAThirdOctaveFilterbankIIR::GainUpdate > m_qGains; //!< Liste von neuen Verstärkungsfaktoren
CITAThirdOctaveMagnitudeSpectrum m_oGainsInternal; //!< Interne Verstärkungsfaktoren
float* m_pfTempFilterBuf; //!< Zwischenpuffer für Filter
float* m_pfTempOutputBuf; //!< Zwischenpuffer für Ausgabe
std::vector< CITABiquad > m_vBiquads; //!< Biquads, access: [Band][BiquadNummer]
tbb::strict_ppl::concurrent_queue< CITAThirdOctaveFilterbankIIR::MagnitudeUpdate > m_vMagnitudesQueue; //!< Liste von neuen Verstärkungsfaktoren
CITAThirdOctaveMagnitudeSpectrum m_oMagnitudesInternal; //!< Interne Verstärkungsfaktoren
ITASampleBuffer m_sfTempFilterBuf; //!< Intermediate buffer for filter
ITASampleBuffer m_pfTempOutputBuf; //!< Intermediate buffer for output assembly
};
#endif // IW_ITA_THIRD_OCTAVE_FILTERBANK_IIR
#include <ITABiquad.h>
#include <ITAException.h>
CITABiquad::CITABiquad()
{
......@@ -7,127 +8,131 @@ CITABiquad::CITABiquad()
void CITABiquad::Clear()
{
z[ 0 ] = z[ 1 ] = 0;
vfAccumulators[ 0 ] = vfAccumulators[ 1 ] = 0;
}
void CITABiquad::Process( const float* pfInputData, float* pfOutputData, const int iNumSamples )
{
// Lokale Akkumulatoren erzeugen
float z0, z1, z2; // w[n], w[n-1], w[n-2]
// Local accumulators
float z0, z1, z2;
// Lokale Akkumulatoren mit gespeicherten Werten besetzen
z1 = z[ 0 ];
z2 = z[ 1 ];
z1 = vfAccumulators[ 0 ];
z2 = vfAccumulators[ 1 ];
for( int i = 0; i < iNumSamples; i++ )
{
// w[n] = x[n] - a_1*w[n-1] - a_2*w[n-2]
z0 = oParams.g*pfInputData[ i ] - oParams.a1*z1 - oParams.a2*z2;
z0 = oParams.g * pfInputData[ i ] - oParams.a1 * z1 - oParams.a2 * z2;
// y[n] = b_0*w[n] + b_1*w[n-1] + b_2*w[n-2]
pfOutputData[ i ] = oParams.b0*z0 + oParams.b1*z1 + oParams.b2*z2;
pfOutputData[ i ] = oParams.b0 * z0 + oParams.b1 * z1 + oParams.b2 * z2;
// Akkumulatoren schieben
// Shift accumulators
z2 = z1;
z1 = z0;
}
// Akkumulatoren für den nächsten Filterprozess speichern
z[ 0 ] = z1;
z[ 1 ] = z2;
// Store accumulators
vfAccumulators[ 0 ] = z1;
vfAccumulators[ 1 ] = z2;
return;
}
void CITABiquad::Process( const float* pfInputData, float* out, const int nsamples, const float outputGain, const int outputMode )
void CITABiquad::Process( const float* pfInputData, float* pfOutputData, const int iNumSamples, const float fOutputGain, const int iOutputMode )
{
// Lokale Akkumulatoren
// Local accumulators
float z0, z1, z2;
z1 = z[ 0 ];
z2 = z[ 1 ];
if( outputMode == OUTPUT_ADD )
z1 = vfAccumulators[ 0 ];
z2 = vfAccumulators[ 1 ];
if( iOutputMode == CITABiquad::OUTPUT_ADD )
{
// Modus: Addieren
for( int i = 0; i < nsamples; i++ )
for( int i = 0; i < iNumSamples; i++ )
{
z0 = oParams.g*pfInputData[ i ] - oParams.a1*z1 - oParams.a2*z2;
out[ i ] += ( oParams.b0*z0 + oParams.b1*z1 + oParams.b2*z2 ) * outputGain;
z0 = oParams.g * pfInputData[ i ] - oParams.a1*z1 - oParams.a2*z2;
pfOutputData[ i ] += ( oParams.b0*z0 + oParams.b1*z1 + oParams.b2*z2 ) * fOutputGain;
// Akkumulatoren schieben
// Shift accumulators
z2 = z1;
z1 = z0;
}
}
else
else if( iOutputMode == CITABiquad::OUTPUT_OVERWRITE )
{
// Modus: Überschreiben
for( int i = 0; i < nsamples; i++ )
for( int i = 0; i < iNumSamples; i++ )
{
z0 = oParams.g*pfInputData[ i ] - oParams.a1*z1 - oParams.a2*z2;
out[ i ] = ( oParams.b0*z0 + oParams.b1*z1 + oParams.b2*z2 ) * outputGain;
pfOutputData[ i ] = ( oParams.b0 * z0 + oParams.b1 * z1 + oParams.b2*z2 ) * fOutputGain;
// Akkumulatoren schieben
// Shift accumulators
z2 = z1;
z1 = z0;
}
}
else
{
ITA_EXCEPT1( INVALID_PARAMETER, "Unrecognized output write mode in CITABiquad" );
}
// Akkumulatoren global speichern
z[ 0 ] = z1;
z[ 1 ] = z2;
// Store accumulators
vfAccumulators[ 0 ] = z1;
vfAccumulators[ 1 ] = z2;
return;
}
void CITABiquad::Process( const float* pfInputData, float* out, const int nsamples, const float outputGain1, const float outputGain2, const int outputMode )
void CITABiquad::Process( const float* pfInputData, float* out, const int iNumSamples, const float fOutputGain1, const float fOutputGain2, const int iOutputWriteMode )
{
if( nsamples == 0 )
if( iNumSamples == 0 )
return;
// Lokale Akkumulatoren
// Local accumulators
float z0, z1, z2;
z1 = z[ 0 ];
z2 = z[ 1 ];
z1 = vfAccumulators[ 0 ];
z2 = vfAccumulators[ 1 ];
// Faktor für Linear-Interpolation des Gains
float c = ( outputGain2 - outputGain1 ) / nsamples; // @todo jst: integer rounding desired?
// Factor for linear gain
const float fLinearGainFactor = ( fOutputGain2 - fOutputGain1 ) / float( iNumSamples );
if( outputMode == OUTPUT_ADD )
if( iOutputWriteMode == OUTPUT_ADD )
{
// Modus: Addieren
for( int i = 0; i < nsamples; i++ )
for( int i = 0; i < iNumSamples; i++ )
{
float sampleGain = outputGain1 + i*c;
const float fSampleGain = fOutputGain1 + i * fLinearGainFactor;
z0 = oParams.g*pfInputData[ i ] - oParams.a1*z1 - oParams.a2*z2;
out[ i ] += ( oParams.b0*z0 + oParams.b1*z1 + oParams.b2*z2 ) * sampleGain;
out[ i ] += ( oParams.b0*z0 + oParams.b1*z1 + oParams.b2*z2 ) * fSampleGain;
// Akkumulatoren schieben
// Shift accumulators
z2 = z1;
z1 = z0;
}
}
else
else if( iOutputWriteMode == CITABiquad::OUTPUT_OVERWRITE )
{
// Modus: Überschreiben
for( int i = 0; i < nsamples; i++ )
for( int i = 0; i < iNumSamples; i++ )
{
float sampleGain = outputGain1 + i*c;
const float fSampleGain = fOutputGain1 + i * fLinearGainFactor;
z0 = oParams.g*pfInputData[ i ] - oParams.a1*z1 - oParams.a2*z2;
out[ i ] = ( oParams.b0*z0 + oParams.b1*z1 + oParams.b2*z2 ) * sampleGain;
out[ i ] = ( oParams.b0*z0 + oParams.b1*z1 + oParams.b2*z2 ) * fSampleGain;
// Akkumulatoren schieben
// Shift accumulators
z2 = z1;
z1 = z0;
}
}
else
{
ITA_EXCEPT1( INVALID_PARAMETER, "Unrecognized output write mode in CITABiquad" );
}
// Akkumulatoren global speichern
z[ 0 ] = z1;
z[ 1 ] = z2;
// Store accumulators
vfAccumulators[ 0 ] = z1;
vfAccumulators[ 1 ] = z2;
}
CITABiquad::CParams::CParams()
......
#ifndef IW_ITA_THIRD_OCTAVE_FILTERBANK_COEFFICIENTS
#define IW_ITA_THIRD_OCTAVE_FILTERBANK_COEFFICIENTS
const double FB_SAMPLINGRATE = 44100; //!< Samplingrate
const int FB_NUM_BANDS = 30; //!< Anzahl Frequenzbnder
const int FB_NUM_BIQUADS_PER_BAND = 5; //!< Anzahl Biquads pro Frequenzband
const double ITA_BIQUAD_FILTER_SAMPLINGRATE = 44100;
const int ITA_BIQUAD_FILTER_NUM_BANDS = 30;
const int ITA_BIQUAD_FILTER_NUM_BIQUADS_PER_BAND = 5;
//!< Parameters (g, b0, b1, b2, a0, a1) for biquad bandpasses, 10th order Buttworth design, Zugriff: [Band][Biquad][Param]
const float FB_BIQUAD_PARAMS[ 30 ][ 5 ][ 6 ] =
//!< Parameters (g, b0, b1, b2, a0, a1) for biquad bandpasses, 10th order Buttworth design, access: [Band][Biquad][Param]
const float ITA_BIQUAD_FILTER_PARAMS[ 30 ][ 5 ][ 6 ] =
{
{ // Band 1, center frequency 25.1 Hz
{ 0.000412886359F, 1.000000000000F, 0.000000000000F, -1.000000000000F, -1.999701032925F, 0.999716977654F },
......
......@@ -12,52 +12,40 @@
CITAThirdOctaveFilterbankIIR::CITAThirdOctaveFilterbankIIR( const double dSampleRate, const int iBlockLength )
: m_dSampleRate( dSampleRate ),
m_iBlockLength( iBlockLength ),
m_nBandsInternal( FB_NUM_BANDS ),
m_nBiquadsPerBand( FB_NUM_BIQUADS_PER_BAND ),
m_pfTempFilterBuf( nullptr ),
m_pfTempOutputBuf( nullptr )
m_nBandsInternal( ITA_BIQUAD_FILTER_NUM_BANDS ),
m_nBiquadsPerBand( ITA_BIQUAD_FILTER_NUM_BIQUADS_PER_BAND )
{
if( dSampleRate != FB_SAMPLINGRATE )
if( dSampleRate != ITA_BIQUAD_FILTER_SAMPLINGRATE )
ITA_EXCEPT1( INVALID_PARAMETER, "Filterbank does not support this samplingrate" );
// Initialize biquads
int nBiquads = m_nBandsInternal*m_nBiquadsPerBand;
int nBiquads = m_nBandsInternal * m_nBiquadsPerBand;
m_vBiquads.resize( nBiquads );
for( int i = 0; i < m_nBandsInternal; i++ )
{
for( int j = 0; j < m_nBiquadsPerBand; j++ )
{
m_vBiquads[ i*m_nBiquadsPerBand + j ].oParams.SetParameters( FB_BIQUAD_PARAMS[ i ][ j ] );
}
}
m_vBiquads[ i * m_nBiquadsPerBand + j ].oParams.SetParameters( ITA_BIQUAD_FILTER_PARAMS[ i ][ j ] );
m_pfTempFilterBuf = fm_falloc( m_iBlockLength, true );
m_pfTempOutputBuf = fm_falloc( m_iBlockLength, true );
}
CITAThirdOctaveFilterbankIIR::~CITAThirdOctaveFilterbankIIR()
{
fm_free( m_pfTempFilterBuf );
fm_free( m_pfTempOutputBuf );
m_sfTempFilterBuf.Init( m_iBlockLength, true );
m_pfTempOutputBuf.Init( m_iBlockLength, true );
}
int CITAThirdOctaveFilterbankIIR::GetLatency() const
{
return 0; // [stienen] sicher?
return 0; // @todo jst: really?
}
void CITAThirdOctaveFilterbankIIR::SetMagnitudes( const CITAThirdOctaveMagnitudeSpectrum& oMagnitudes, bool bSmoothChangeover )
void CITAThirdOctaveFilterbankIIR::SetMagnitudes( const CITAThirdOctaveMagnitudeSpectrum& oMagnitudes, const bool bSmoothChangeover )
{
CITAThirdOctaveFilterbankIIR::GainUpdate oUpdate;
CITAThirdOctaveFilterbankIIR::MagnitudeUpdate oUpdate;
oUpdate.oMags = oMagnitudes;
oUpdate.iBlendSamples = ( bSmoothChangeover ? 1 : 0 );
m_qGains.push( oUpdate );
m_vMagnitudesQueue.push( oUpdate );
}
void CITAThirdOctaveFilterbankIIR::Clear()
{
for( int i = 0; i < ( int )
m_vBiquads.size(); i++ ) m_vBiquads[ i ].Clear();
for( size_t i = 0; i < m_vBiquads.size(); i++ )
m_vBiquads[ i ].Clear();
}
void CITAThirdOctaveFilterbankIIR::Process( const float* pfInputSamples, float* pfOutputSamples )
......@@ -68,38 +56,33 @@ void CITAThirdOctaveFilterbankIIR::Process( const float* pfInputSamples, float*
// Fr Schleifen unten
assert( m_nBiquadsPerBand >= 2 );
// TODO: Fehler lsen. Warum kommt aus den hohen Bndern nix? Scheinen nicht stabil zu sein?!
const int iMaxBand = m_nBandsInternal - 1;
//const int iMaxBand = 10;
const int k = m_nBiquadsPerBand - 1; // Index des letzten Biquads pro Band
if( m_nBandsInternal == 0 )
return; // [stienen] lieber assert? Filter ohne Bnder?
// Gains bernehmen
CITAThirdOctaveFilterbankIIR::GainUpdate oUpdate;
const int iLastBandIndex = m_nBiquadsPerBand - 1;
// Empty queue and use latest magnitude update
CITAThirdOctaveFilterbankIIR::MagnitudeUpdate oLatestMagnitudeUpdate;
bool bUpdateGains = false;
while( m_qGains.try_pop( oUpdate ) )
while( m_vMagnitudesQueue.try_pop( oLatestMagnitudeUpdate ) )
bUpdateGains = true;
// Processing will first work through the biquads per band and then add samples target buffer at last biquad of band
if( bUpdateGains )
{
bool bSwitchGains = ( oUpdate.iBlendSamples == 0 );
bool bSwitchGains = ( oLatestMagnitudeUpdate.iBlendSamples == 0 );
if( bSwitchGains )
{
for( int i = 0; i < iMaxBand; i++ )
{
// Erster Biquad in der Sequenz: input => tmp
m_vBiquads[ i*m_nBiquadsPerBand + 0 ].Process( pfInputSamples, m_pfTempFilterBuf, m_iBlockLength );
m_vBiquads[ i*m_nBiquadsPerBand + 0 ].Process( pfInputSamples, m_sfTempFilterBuf.GetData(), m_iBlockLength );
// Biquads dazwischen: tmp => tmp
for( int j = 1; j < k; j++ )
m_vBiquads[ i*m_nBiquadsPerBand + j ].Process( m_pfTempFilterBuf, m_pfTempFilterBuf, m_iBlockLength );
for( int j = 1; j < iLastBandIndex; j++ )
m_vBiquads[ i*m_nBiquadsPerBand + j ].Process( m_sfTempFilterBuf.GetData(), m_sfTempFilterBuf.GetData(), m_iBlockLength );
// Letztes Biquad mit Gain: tmp => output
const float fGain = float( db10_to_ratio( oUpdate.oMags[ i ] ) );
m_vBiquads[ i*m_nBiquadsPerBand + k ].Process( m_pfTempFilterBuf, m_pfTempOutputBuf, m_iBlockLength, fGain, ( i == 0 ? CITABiquad::OUTPUT_OVERWRITE : CITABiquad::OUTPUT_ADD ) );
const float fGain = float( db10_to_ratio( oLatestMagnitudeUpdate.oMags[ i ] ) );
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 );
}
}
else
......@@ -108,20 +91,20 @@ void CITAThirdOctaveFilterbankIIR::Process( const float* pfInputSamples, float*
for( int i = 0; i < iMaxBand; i++ )
{
// Erster Biquad in der Sequenz: input => tmp
m_vBiquads[ i*m_nBiquadsPerBand + 0 ].Process( pfInputSamples, m_pfTempFilterBuf, m_iBlockLength );
m_vBiquads[ i*m_nBiquadsPerBand + 0 ].Process( pfInputSamples, m_sfTempFilterBuf, m_iBlockLength );
// Biquads dazwischen: tmp => tmp
for( int j = 1; j < k; j++ )
m_vBiquads[ i*m_nBiquadsPerBand + j ].Process( m_pfTempFilterBuf, m_pfTempFilterBuf, m_iBlockLength );
for( int j = 1; j < iLastBandIndex; j++ )
m_vBiquads[ i*m_nBiquadsPerBand + j ].Process( m_sfTempFilterBuf, m_sfTempFilterBuf, m_iBlockLength );
// Letztes Biquad mit Gain: tmp => output
const float fGain1 = m_oGainsInternal[ i ];
const float fGain2 = float( db10_to_ratio( oUpdate.oMags[ i ] ) );
m_vBiquads[ i*m_nBiquadsPerBand + k ].Process( m_pfTempFilterBuf, m_pfTempOutputBuf, m_iBlockLength, fGain1, fGain2, ( i == 0 ? CITABiquad::OUTPUT_OVERWRITE : CITABiquad::OUTPUT_ADD ) );
const float fGain1 = m_oMagnitudesInternal[ i ];
const float fGain2 = float( db10_to_ratio( oLatestMagnitudeUpdate.oMags[ i ] ) );
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 ) );
}
}
m_oGainsInternal = oUpdate.oMags;
m_oMagnitudesInternal = oLatestMagnitudeUpdate.oMags;
}
else
{
......@@ -129,17 +112,17 @@ void CITAThirdOctaveFilterbankIIR::Process( const float* pfInputSamples, float*
for( int i = 0; i < iMaxBand; i++ )
{
// Erster Biquad in der Sequenz: input => tmp
m_vBiquads[ i*m_nBiquadsPerBand + 0 ].Process( pfInputSamples, m_pfTempFilterBuf, m_iBlockLength );
m_vBiquads[ i*m_nBiquadsPerBand + 0 ].Process( pfInputSamples, m_sfTempFilterBuf.GetData(), m_iBlockLength );
// Biquads dazwischen: tmp => tmp
for( int j = 1; j < k; j++ )
m_vBiquads[ i*m_nBiquadsPerBand + j ].Process( m_pfTempFilterBuf, m_pfTempFilterBuf, m_iBlockLength );
for( int j = 1; j < iLastBandIndex; j++ )
m_vBiquads[ i*m_nBiquadsPerBand + j ].Process( m_sfTempFilterBuf.GetData(), m_sfTempFilterBuf.GetData(), m_iBlockLength );
// Letztes Biquad mit Gain: tmp => output
m_vBiquads[ i*m_nBiquadsPerBand + k ].Process( m_pfTempFilterBuf, m_pfTempOutputBuf, m_iBlockLength, m_oGainsInternal[ i ], ( i == 0 ? CITABiquad::OUTPUT_OVERWRITE : CITABiquad::OUTPUT_ADD ) );
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 ) );
}
}
// Ausgabe bereitstellen
memcpy( pfOutputSamples, m_pfTempOutputBuf, m_iBlockLength*sizeof( float ) );
// Hand over output samples
fm_copy( pfOutputSamples, m_pfTempOutputBuf.GetData(), m_iBlockLength );
}
......@@ -31,7 +31,7 @@ void TestThirdOctaveFilterbankIIR()
CITAThirdOctaveMagnitudeSpectrum oMags;
oMags.SetIdentity();
pIIRFilterbank->SetMagnitudes( oMags );
pIIRFilterbank->SetMagnitudes( oMags, false );
ITASampleBuffer y( iSampleLength );
......@@ -45,8 +45,7 @@ void TestThirdOctaveFilterbankIIR()
writeAudiofile( "ITADSPThirdOctaveFilterbankTest_IIR_Identity.wav", &y, g_dSampleRate );
y.Zero();
delete pIIRFilterbank;
pIIRFilterbank = CITAThirdOctaveFilterbank::Create( g_dSampleRate, iSampleLength, CITAThirdOctaveFilterbank::IIR_BIQUADS_ORDER10 );
pIIRFilterbank->Clear();
oMags.SetZero();
pIIRFilterbank->SetMagnitudes( oMags );
......@@ -59,8 +58,7 @@ void TestThirdOctaveFilterbankIIR()