Skip to content
GitLab
Menu
Projects
Groups
Snippets
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in
Toggle navigation
Menu
Open sidebar
Institute of Technical Acoustics (ITA)
ITADSP
Commits
c5b6498e
Commit
c5b6498e
authored
Jun 02, 2017
by
Dipl.-Ing. Jonas Stienen
Browse files
Refactoring IIR biquad implementation of third octave filtering
parent
7d591483
Changes
7
Hide whitespace changes
Inline
Side-by-side
include/ITABiquad.h
View file @
c5b6498e
...
...
@@ -57,73 +57,64 @@ public:
}
oParams
;
//!
Überblendmodus der Ausgabe
//!
Output write modes
enum
{
OUTPUT_OVERWRITE
=
0
,
//!<
Ausgabe überschreiben
OUTPUT_ADD
=
1
//!< A
usgabe addieren
}
OutputFadeMode
;
OUTPUT_OVERWRITE
=
0
,
//!<
Overwrites output
OUTPUT_ADD
=
1
//!< A
dds 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
();
//! Filter
t S
amples,
einfach
e
V
ariant
e ohne Verstärkungs
fa
k
tor
en
//! Filter
s
amples,
simpl
e
v
ariant
without any gain (
fa
c
tor
)
/**
*
Filtert samples gemäß der Direkten Form 2 (Kanonische F
orm
)
*
Direct second canonical f
orm
.
*
*
\
param
in
Eingabe
samples
*
\
param
in Ausgabe
samples
*
\
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
);
//! Filter
t S
amples,
Variante mit Überlenden zu einer vorgegebenen Ausgabeverstärkung
//! Filter
s
amples,
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
Eingabe
samples
*
\
param
out
Ausgabe
samples
*
\
param
nsamples Anzahl der Eingabe- und Ausgabesamples
*
\
param
o
utputGain1
Ausgabeverstärkung Ausgangsparameter
*
\
param
o
utputGain2
Ausgabeverstärkung Zielparameter
*
\
param
o
utputMode
Ü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] fO
utputGain1
Initial gain (factor) for output
*
@
param
[in] fO
utputGain2
Target gain (factor) for output
*
@
param
[in] iO
utputMode
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
include/ITAThirdOctaveFilterbankFIR.h
View file @
c5b6498e
...
...
@@ -70,9 +70,9 @@ public:
pFilter
->
Release
();
// Auto-release
}
inline
virtual
void
SetMagnitudes
(
const
CITAThirdOctaveMagnitudeSpectrum
&
o
Gain
s
,
const
bool
bSmoothChangeover
=
true
)
inline
virtual
void
SetMagnitudes
(
const
CITAThirdOctaveMagnitudeSpectrum
&
o
Mag
s
,
const
bool
bSmoothChangeover
=
true
)
{
m_pGenerator
->
GenerateFilter
(
o
Gain
s
,
m_pfFilter
);
m_pGenerator
->
GenerateFilter
(
o
Mag
s
,
m_pfFilter
);
ITAUPFilter
*
pFilter
=
m_pConvolver
->
RequestFilter
();
pFilter
->
Load
(
m_pfFilter
,
m_iFilterLength
);
m_pConvolver
->
ExchangeFilter
(
pFilter
,
(
bSmoothChangeover
?
ITAUPConvolution
::
AUTO
:
ITAUPConvolution
::
SWITCH
)
);
...
...
include/ITAThirdOctaveFilterbankIIR.h
View file @
c5b6498e
...
...
@@ -23,40 +23,38 @@
#include <ITAThirdOctaveFilterbank.h>
#include <ITAAmplitudeSpectrum.h>
#include <ITABiquad.h>
#include <ITASampleBuffer.h>
#include <vector>
#include <tbb/concurrent_queue.h>
//! T
erzfilterbank mittels
Biquads (IIR
F
ilter)
//! T
hird octave magnitude filtering using
Biquads (IIR
f
ilter)
/**
* 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:
//!
K
onstru
k
tor
mit Samplerate und Blocklänge
//!
C
onstru
c
tor
/**
*
\
param dSample
r
ate Samplingrate
*
\
param iBlock
l
ength Block
länge
*
@
param
[in]
dSample
R
ate Samplingrate
*
@
param
[in]
iBlock
L
ength 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
&
o
Gain
s
,
const
bool
bSmoothChangeover
=
true
);
void
SetMagnitudes
(
const
CITAThirdOctaveMagnitudeSpectrum
&
o
Magnitude
s
,
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
Gain
Update
class
Magnitude
Update
{
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
::
Gain
Update
>
m_
qGains
;
//!< Liste von neuen Verstärkungsfaktoren
CITAThirdOctaveMagnitudeSpectrum
m_o
Gain
sInternal
;
//!< Interne Verstärkungsfaktoren
float
*
m_
p
fTempFilterBuf
;
//!<
Zwischenp
uffer f
ü
r
F
ilter
float
*
m_pfTempOutputBuf
;
//!<
Zwischenp
uffer f
ü
r
Ausgabe
std
::
vector
<
CITABiquad
>
m_vBiquads
;
//!< Biquads,
access
: [Band][BiquadNummer]
tbb
::
strict_ppl
::
concurrent_queue
<
CITAThirdOctaveFilterbankIIR
::
Magnitude
Update
>
m_
vMagnitudesQueue
;
//!< Liste von neuen Verstärkungsfaktoren
CITAThirdOctaveMagnitudeSpectrum
m_o
Magnitude
sInternal
;
//!< Interne Verstärkungsfaktoren
ITASampleBuffer
m_
s
fTempFilterBuf
;
//!<
Intermediate b
uffer f
o
r
f
ilter
ITASampleBuffer
m_pfTempOutputBuf
;
//!<
Intermediate b
uffer f
o
r
output assembly
};
#endif // IW_ITA_THIRD_OCTAVE_FILTERBANK_IIR
src/ITABiquad.cpp
View file @
c5b6498e
#
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
)
{
// Lo
k
al
e Akk
umulator
en erzeugen
float
z0
,
z1
,
z2
;
// w[n], w[n-1], w[n-2]
// Lo
c
al
acc
umulator
s
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
ns
amples
,
const
float
o
utputGain
,
const
int
o
utputMode
)
void
CITABiquad
::
Process
(
const
float
*
pfInputData
,
float
*
pfOutputData
,
const
int
iNumS
amples
,
const
float
fO
utputGain
,
const
int
iO
utputMode
)
{
// Lo
k
al
e Akk
umulator
en
// Lo
c
al
acc
umulator
s
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
)
*
o
utputGain
;
z0
=
oParams
.
g
*
pfInputData
[
i
]
-
oParams
.
a1
*
z1
-
oParams
.
a2
*
z2
;
pfOutputData
[
i
]
+=
(
oParams
.
b0
*
z0
+
oParams
.
b1
*
z1
+
oParams
.
b2
*
z2
)
*
fO
utputGain
;
//
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
)
*
o
utputGain
;
pfOutputData
[
i
]
=
(
oParams
.
b0
*
z0
+
oParams
.
b1
*
z1
+
oParams
.
b2
*
z2
)
*
fO
utputGain
;
//
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
ns
amples
,
const
float
o
utputGain1
,
const
float
o
utputGain2
,
const
int
o
utputMode
)
void
CITABiquad
::
Process
(
const
float
*
pfInputData
,
float
*
out
,
const
int
iNumS
amples
,
const
float
fO
utputGain1
,
const
float
fO
utputGain2
,
const
int
iO
utput
Write
Mode
)
{
if
(
ns
amples
==
0
)
if
(
iNumS
amples
==
0
)
return
;
// Lo
k
al
e Akk
umulator
en
// Lo
c
al
acc
umulator
s
float
z0
,
z1
,
z2
;
z1
=
z
[
0
];
z2
=
z
[
1
];
z1
=
vfAccumulators
[
0
];
z2
=
vfAccumulators
[
1
];
// Fa
k
tor f
ü
r
L
inear
-Interpolation des G
ain
s
float
c
=
(
o
utputGain2
-
o
utputGain1
)
/
nsamples
;
// @todo jst: integer rounding desired?
// Fa
c
tor f
o
r
l
inear
g
ain
const
float
fLinearGainFactor
=
(
fO
utputGain2
-
fO
utputGain1
)
/
float
(
iNumSamples
);
if
(
o
utputMode
==
OUTPUT_ADD
)
if
(
iO
utput
Write
Mode
==
OUTPUT_ADD
)
{
// Modus: Addieren
for
(
int
i
=
0
;
i
<
nsamples
;
i
++
)
for
(
int
i
=
0
;
i
<
iNumSamples
;
i
++
)
{
float
s
ampleGain
=
o
utputGain1
+
i
*
c
;
const
float
fS
ampleGain
=
fO
utputGain1
+
i
*
fLinearGainFactor
;
z0
=
oParams
.
g
*
pfInputData
[
i
]
-
oParams
.
a1
*
z1
-
oParams
.
a2
*
z2
;
out
[
i
]
+=
(
oParams
.
b0
*
z0
+
oParams
.
b1
*
z1
+
oParams
.
b2
*
z2
)
*
s
ampleGain
;
out
[
i
]
+=
(
oParams
.
b0
*
z0
+
oParams
.
b1
*
z1
+
oParams
.
b2
*
z2
)
*
fS
ampleGain
;
//
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
s
ampleGain
=
o
utputGain1
+
i
*
c
;
const
float
fS
ampleGain
=
fO
utputGain1
+
i
*
fLinearGainFactor
;
z0
=
oParams
.
g
*
pfInputData
[
i
]
-
oParams
.
a1
*
z1
-
oParams
.
a2
*
z2
;
out
[
i
]
=
(
oParams
.
b0
*
z0
+
oParams
.
b1
*
z1
+
oParams
.
b2
*
z2
)
*
s
ampleGain
;
out
[
i
]
=
(
oParams
.
b0
*
z0
+
oParams
.
b1
*
z1
+
oParams
.
b2
*
z2
)
*
fS
ampleGain
;
//
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
()
...
...
src/ITAThirdOctaveFilterbankCoefficients.h
View file @
c5b6498e
#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
.
000412
886359
F
,
1
.
000000000000
F
,
0
.
000000000000
F
,
-
1
.
000000000000
F
,
-
1
.
999701032925
F
,
0
.
999716977654
F
},
...
...
src/ITAThirdOctaveFilterbankIIR.cpp
View file @
c5b6498e
...
...
@@ -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
::
Gain
Update
oUpdate
;
CITAThirdOctaveFilterbankIIR
::
Magnitude
Update
oUpdate
;
oUpdate
.
oMags
=
oMagnitudes
;
oUpdate
.
iBlendSamples
=
(
bSmoothChangeover
?
1
:
0
);
m_
qGains
.
push
(
oUpdate
);
m_
vMagnitudesQueue
.
push
(
oUpdate
);
}
void
CITAThirdOctaveFilterbankIIR
::
Clear
()
{
for
(
in
t
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
(
o
Update
)
)
while
(
m_
vMagnitudesQueue
.
try_pop
(
oLatestMagnitude
Update
)
)
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
=
(
o
LatestMagnitude
Update
.
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 mi
t Gain
: tmp => output
const
float
fGain
=
float
(
db10_to_ratio
(
oUpdate
.
oMags
[
i
]
)
);
m_vBiquads
[
i
*
m_nBiquadsPerBand
+
k
].
Process
(
m_
p
fTempFilterBuf
,
m_pfTempOutputBuf
,
m_iBlockLength
,
fGain
,
(
i
==
0
?
CITABiquad
::
OUTPUT_OVERWRITE
:
CITABiquad
::
OUTPUT_ADD
)
);
const
floa
t
f
Gain
=
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_
s
fTempFilterBuf
.
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_
p
fTempFilterBuf
,
m_iBlockLength
);
m_vBiquads
[
i
*
m_nBiquadsPerBand
+
0
].
Process
(
pfInputSamples
,
m_
s
fTempFilterBuf
,
m_iBlockLength
);
// Biquads dazwischen: tmp => tmp
for
(
int
j
=
1
;
j
<
k
;
j
++
)
m_vBiquads
[
i
*
m_nBiquadsPerBand
+
j
].
Process
(
m_
p
fTempFilterBuf
,
m_
p
fTempFilterBuf
,
m_iBlockLength
);
for
(
int
j
=
1
;
j
<
iLastBandIndex
;
j
++
)
m_vBiquads
[
i
*
m_nBiquadsPerBand
+
j
].
Process
(
m_
s
fTempFilterBuf
,
m_
s
fTempFilterBuf
,
m_iBlockLength
);
// Letztes Biquad mit Gain: tmp => output
const
float
fGain1
=
m_o
Gain
sInternal
[
i
];
const
float
fGain2
=
float
(
db10_to_ratio
(
oUpdate
.
oMags
[
i
]
)
);
m_vBiquads
[
i
*
m_nBiquadsPerBand
+
k
].
Process
(
m_
p
fTempFilterBuf
,
m_pfTempOutputBuf
,
m_iBlockLength
,
fGain1
,
fGain2
,
(
i
==
0
?
CITABiquad
::
OUTPUT_OVERWRITE
:
CITABiquad
::
OUTPUT_ADD
)
);
const
float
fGain1
=
m_o
Magnitude
sInternal
[
i
];
const
float
fGain2
=
float
(
db10_to_ratio
(
o
LatestMagnitude
Update
.
oMags
[
i
]
)
);
m_vBiquads
[
i
*
m_nBiquadsPerBand
+
iLastBandIndex
].
Process
(
m_
s
fTempFilterBuf
.
GetData
()
,
m_pfTempOutputBuf
.
GetData
()
,
m_iBlockLength
,
fGain1
,
fGain2
,
(
i
==
0
?
CITABiquad
::
OUTPUT_OVERWRITE
:
CITABiquad
::
OUTPUT_ADD
)
);
}
}
m_o
Gain
sInternal
=
oUpdate
.
oMags
;
m_o
Magnitude
sInternal
=
o
LatestMagnitude
Update
.
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_
p
fTempFilterBuf
,
m_iBlockLength
);
m_vBiquads
[
i
*
m_nBiquadsPerBand
+
0
].
Process
(
pfInputSamples
,
m_
s
fTempFilterBuf
.
GetData
()
,
m_iBlockLength
);
// Biquads dazwischen: tmp => tmp
for
(
int
j
=
1
;
j
<
k
;
j
++
)
m_vBiquads
[
i
*
m_nBiquadsPerBand
+
j
].
Process
(
m_
p
fTempFilterBuf
,
m_
p
fTempFilterBuf
,
m_iBlockLength
);
for
(
int
j
=
1
;
j
<
iLastBandIndex
;
j
++
)
m_vBiquads
[
i
*
m_nBiquadsPerBand
+
j
].
Process
(
m_
s
fTempFilterBuf
.
GetData
()
,
m_
s
fTempFilterBuf
.
GetData
()
,
m_iBlockLength
);
// Letztes Biquad mit Gain: tmp => output
m_vBiquads
[
i
*
m_nBiquadsPerBand
+
k
].
Process
(
m_
p
fTempFilterBuf
,
m_pfTempOutputBuf
,
m_iBlockLength
,
m_o
Gain
sInternal
[
i
],
(
i
==
0
?
CITABiquad
::
OUTPUT_OVERWRITE
:
CITABiquad
::
OUTPUT_ADD
)
);
m_vBiquads
[
i
*
m_nBiquadsPerBand
+
iLastBandIndex
].
Process
(
m_
s
fTempFilterBuf
.
GetData
()
,
m_pfTempOutputBuf
.
GetData
()
,
m_iBlockLength
,
m_o
Magnitude
sInternal
[
i
],
(
i
==
0
?
CITABiquad
::
OUTPUT_OVERWRITE
:
CITABiquad
::
OUTPUT_ADD
)
);
}
}
//
Ausgabe bereitstel
le
n
memc
py
(
pfOutputSamples
,
m_pfTempOutputBuf
,
m_iBlockLength
*
sizeof
(
float
)
);
//
Hand over output samp
le
s
fm_co
py
(
pfOutputSamples
,
m_pfTempOutputBuf
.
GetData
()
,
m_iBlockLength
);
}
tests/ITADSPThirdOctaveFilterbankTest.cpp
View file @
c5b6498e
...
...
@@ -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()