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