add full-frame M/S

This commit is contained in:
Christian R. Helmrich 2020-03-28 02:00:25 +01:00
parent e4bc905be2
commit 5ceb1a0959
10 changed files with 245 additions and 15 deletions

View File

@ -303,7 +303,7 @@ unsigned BitStreamWriter::writeStereoCoreToolInfo (const CoreCoderData& elData,
{
for (g = 0; g < elData.groupingData[0].numWindowGroups; g++)
{
const char* const gMsUsed = &elData.stereoData[m_numSwbShort * g];
const uint8_t* const gMsUsed = &elData.stereoData[m_numSwbShort * g];
for (b = 0; b < maxSfbSte; b++)
{
@ -320,7 +320,7 @@ unsigned BitStreamWriter::writeStereoCoreToolInfo (const CoreCoderData& elData,
{
for (g = 0; g < elData.groupingData[0].numWindowGroups; g++)
{
const char* const gCplxPredUsed = &elData.stereoData[m_numSwbShort * g];
const uint8_t* const gCplxPredUsed = &elData.stereoData[m_numSwbShort * g];
for (b = 0; b < maxSfbSte; b += SFB_PER_PRED_BAND)
{

View File

@ -404,7 +404,7 @@ unsigned ExhaleEncoder::applyTnsToWinGroup (TnsData& tnsData, SfbGroupData& grpD
const uint16_t* grpSO = &grpData.sfbOffsets[m_numSwbShort * tnsData.filteredWindow];
unsigned errorValue = 0; // no error
if ((maxSfb > (eightShorts ? 15 : 51)) || (channelIndex >= USAC_MAX_NUM_CHANNELS))
if ((maxSfb > (eightShorts ? MAX_NUM_SWB_SHORT : MAX_NUM_SWB_LONG)) || (channelIndex >= USAC_MAX_NUM_CHANNELS))
{
return 1; // invalid arguments error
}
@ -712,6 +712,8 @@ unsigned ExhaleEncoder::psychBitAllocation () // perceptual bit-allocation via s
const uint8_t steppFadeOff = ((m_bitRateMode + 1) & 6) << (eightShorts ? 2 : 5);
const int64_t steppWeightI = __min (64, m_perCorrCurr[el] - 128) >> (eightShorts || coreConfig.tnsActive ? 1 : 0);
const int64_t steppWeightD = 128 - steppWeightI; // decrement, (1 - crosstalk) * 128
const TnsData& tnsData0 = coreConfig.tnsData[0];
const TnsData& tnsData1 = coreConfig.tnsData[1];
for (uint16_t gr = 0; gr < coreConfig.groupingData[0].numWindowGroups; gr++)
{
@ -722,7 +724,7 @@ unsigned ExhaleEncoder::psychBitAllocation () // perceptual bit-allocation via s
int32_t* sigR1 = &m_mdctSignals[ci + 1][grpStart];
int64_t xTalkI = 0, xTalkD = 0; // weights for crosstalk
if (coreConfig.tnsActive && (gr == coreConfig.tnsData[0].filteredWindow || gr == coreConfig.tnsData[1].filteredWindow))
if ((tnsData0.numFilters > 0 && gr == tnsData0.filteredWindow) || (tnsData1.numFilters > 0 && gr == tnsData1.filteredWindow))
{
const uint16_t maxLen = (eightShorts ? grpOff[m_numSwbShort] - 1 : __min (nSamplesInFrame - 1u, nSamplesMax)) - grpStart;
int32_t prevR0 = 0; // NOTE: functions also on grouped
@ -773,12 +775,18 @@ unsigned ExhaleEncoder::psychBitAllocation () // perceptual bit-allocation via s
}
} // if coreConfig.commonWindow
if (coreConfig.stereoMode > 0) // synch spectral statistics
if (coreConfig.stereoMode > 0) // use M/S, synch statistics
{
const bool eightShorts = (coreConfig.icsInfoCurr[0].windowSequence == EIGHT_SHORT);
const uint32_t peakIndexSte = __max ((m_specAnaCurr[ci] >> 5) & 2047, (m_specAnaCurr[ci + 1] >> 5) & 2047) << 5;
// TODO: M/S matrixing, update of grpData{0,1}.sfbRmsValues and &sfbStepSizes[(ci + {0,1}) * m_numSwbShort * NUM_WINDOW_GROUPS]
errorValue |= m_stereoCoder.applyFullFrameMatrix (m_mdctSignals[ci], m_mdctSignals[ci + 1],
m_mdstSignals[ci], m_mdstSignals[ci + 1],
coreConfig.groupingData[0], coreConfig.groupingData[1],
coreConfig.tnsData[0], coreConfig.tnsData[1],
(eightShorts ? m_numSwbShort : m_numSwbLong), coreConfig.stereoData,
&sfbStepSizes[ ci * m_numSwbShort * NUM_WINDOW_GROUPS],
&sfbStepSizes[(ci + 1) * m_numSwbShort * NUM_WINDOW_GROUPS]);
m_specAnaCurr[ci ] = (m_specAnaCurr[ci ] & (UINT_MAX - 65504)) | peakIndexSte;
m_specAnaCurr[ci + 1] = (m_specAnaCurr[ci + 1] & (UINT_MAX - 65504)) | peakIndexSte;
meanSpecFlat[ci] = meanSpecFlat[ci + 1] = ((uint16_t) meanSpecFlat[ci] + (uint16_t) meanSpecFlat[ci + 1]) >> 1;
@ -845,7 +853,7 @@ unsigned ExhaleEncoder::psychBitAllocation () // perceptual bit-allocation via s
const unsigned lfAtten = (b <= 5 ? (eightShorts ? 1 : 4) + b * lfConst : 5 * lfConst - 1 + b + ((b + 5) >> 4));
const uint8_t sfbWidth = grpOff[b + 1] - grpOff[b];
const uint64_t rateFac = mSfmFac * s * __min (32, lfAtten * grpData.numWindowGroups); // rate control part 1
const uint64_t sScaled = ((1u << 23) + __max (grpRmsMin, grpStepSizes[b]) * scaleBr * rateFac) >> 24;
const uint64_t sScaled = ((1u << 23) + __max (grpRmsMin, grpStepSizes[b]) * (scaleBr - (coreConfig.stereoMode > 0 ? 1 : 0)) * rateFac) >> 24;
// scale step-sizes according to VBR mode & derive scale factors from step-sizes
grpStepSizes[b] = uint32_t (__max (BA_EPS, __min (UINT_MAX, sScaled)));
@ -1196,7 +1204,7 @@ unsigned ExhaleEncoder::spectralProcessing () // complete ics_info(), calc TNS
const uint16_t nSamplesMax = (samplingRate < 37566 ? nSamplesInFrame : swbo[brModeAndFsToMaxSfbLong (m_bitRateMode, samplingRate)]);
const int16_t steAnaStats = m_specAnalyzer.stereoSigAnalysis (m_mdctSignals[ci], m_mdctSignals[ci + 1],
m_mdstSignals[ci], m_mdstSignals[ci + 1], nSamplesMax,
nSamplesInFrame, eightShorts, (uint8_t* const) coreConfig.stereoData);
nSamplesInFrame, eightShorts, coreConfig.stereoData);
if (steAnaStats == SHRT_MIN) errorValue = 1;
if ((s = abs (steAnaStats)) * m_perCorrCurr[el] == 0) // transitions to/from silence
@ -1212,9 +1220,9 @@ unsigned ExhaleEncoder::spectralProcessing () // complete ics_info(), calc TNS
}
if (s == steAnaStats * -1) coreConfig.stereoConfig = 2; // 2: side > mid, pred_dir=1
// if (s > (UCHAR_MAX * 3) / 4) coreConfig.stereoMode = 2; // 2: all, ms_mask_present=2
if (s > (UCHAR_MAX * 3) / 4) coreConfig.stereoMode = 2; // 2: all, ms_mask_present=2
}
else if (coreConfig.commonWindow) m_perCorrCurr[el] = 128; // update with midway value
else if (nrChannels > 1) m_perCorrCurr[el] = 128; // update history with halfway value
for (unsigned ch = 0; ch < nrChannels; ch++) // channel loop
{
@ -1342,6 +1350,8 @@ unsigned ExhaleEncoder::spectralProcessing () // complete ics_info(), calc TNS
}
maxSfb0 = maxSfb1 = maxSfbSte;
}
else coreConfig.stereoMode = 0; // since a max_sfb is 0
coreConfig.commonMaxSfb = (maxSfb0 == maxSfb1); // synch
} // if coreConfig.commonWindow
}
@ -1601,7 +1611,7 @@ ExhaleEncoder::ExhaleEncoder (int32_t* const inputPcmData, unsigned ch
#if !RESTRICT_TO_AAC
m_nonMpegExt = useEcodisExt;
#endif
m_numSwbLong = 51; // maximum
m_numSwbLong = MAX_NUM_SWB_LONG;
m_numSwbShort = MAX_NUM_SWB_SHORT;
m_outAuData = outputAuData;
m_pcm24Data = inputPcmData;

View File

@ -21,6 +21,7 @@
#include "quantization.h"
#include "specAnalysis.h"
#include "specGapFilling.h"
#include "stereoProcessing.h"
#include "tempAnalysis.h"
// constant and experimental macro
@ -97,6 +98,7 @@ private:
#if !RESTRICT_TO_AAC
SpecGapFiller m_specGapFiller;// for noise/gap filling
#endif
StereoProcessor m_stereoCoder; // for M/S stereo coding
uint8_t m_swbTableIdx;
TempAnalyzer m_tempAnalyzer; // for temporal analysis
uint32_t m_tempAnaCurr[USAC_MAX_NUM_CHANNELS];

View File

@ -1,5 +1,5 @@
/* exhaleLibPch.cpp - pre-compiled source file for classes of exhaleLib coding library
* written by C. R. Helmrich, last modified in 2019 - see License.htm for legal notices
* written by C. R. Helmrich, last modified in 2020 - see License.htm for legal notices
*
* The copyright in this software is being made available under a Modified BSD-Style License
* and comes with ABSOLUTELY NO WARRANTY. This software may be subject to other third-

View File

@ -1,5 +1,5 @@
/* exhaleLibPch.h - pre-compiled header file for classes of exhaleLib coding library
* written by C. R. Helmrich, last modified in 2019 - see License.htm for legal notices
* written by C. R. Helmrich, last modified in 2020 - see License.htm for legal notices
*
* The copyright in this software is being made available under a Modified BSD-Style License
* and comes with ABSOLUTELY NO WARRANTY. This software may be subject to other third-
@ -22,6 +22,7 @@
#define AAC_NUM_SAMPLE_RATES 13
#define MAX_PREDICTION_ORDER 4
#define MAX_NUM_SWB_LFE 6
#define MAX_NUM_SWB_LONG 51
#define MAX_NUM_SWB_SHORT 15
#define MIN_NUM_SWB_SHORT 12
#define NUM_WINDOW_GROUPS 4 // must be between 4 and 8
@ -130,7 +131,7 @@ struct CoreCoderData
uint8_t specFillData[2]; // noise filling data for each channel
#endif
uint8_t stereoConfig; // cplx_pred_data() config: pred_dir etc.
char stereoData[MAX_NUM_SWB_SHORT * NUM_WINDOW_GROUPS];
uint8_t stereoData[MAX_NUM_SWB_SHORT * NUM_WINDOW_GROUPS];
uint8_t stereoMode; // ms_mask_present in StereoCoreToolInfo()
bool tnsActive; // tns_active flag in StereoCoreToolInfo()
TnsData tnsData[2]; // current tns_data() for each channel

View File

@ -234,6 +234,7 @@
<ClInclude Include="quantization.h" />
<ClInclude Include="specAnalysis.h" />
<ClInclude Include="specGapFilling.h" />
<ClInclude Include="stereoProcessing.h" />
<ClInclude Include="tempAnalysis.h" />
</ItemGroup>
<ItemGroup>
@ -254,6 +255,7 @@
<ClCompile Include="quantization.cpp" />
<ClCompile Include="specAnalysis.cpp" />
<ClCompile Include="specGapFilling.cpp" />
<ClCompile Include="stereoProcessing.cpp" />
<ClCompile Include="tempAnalysis.cpp" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />

View File

@ -51,6 +51,9 @@
<ClInclude Include="specGapFilling.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="stereoProcessing.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="tempAnalysis.h">
<Filter>Header Files</Filter>
</ClInclude>
@ -86,6 +89,9 @@
<ClCompile Include="specGapFilling.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="stereoProcessing.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="tempAnalysis.cpp">
<Filter>Source Files</Filter>
</ClCompile>

View File

@ -36,6 +36,7 @@ OBJS = \
$(DIR_OBJ)/quantization.o \
$(DIR_OBJ)/specAnalysis.o \
$(DIR_OBJ)/specGapFilling.o \
$(DIR_OBJ)/stereoProcessing.o \
$(DIR_OBJ)/tempAnalysis.o \
# define libraries to link with

View File

@ -0,0 +1,161 @@
/* stereoProcessing.cpp - source file for class providing M/S stereo coding functionality
* written by C. R. Helmrich, last modified in 2020 - see License.htm for legal notices
*
* The copyright in this software is being made available under a Modified BSD-Style License
* and comes with ABSOLUTELY NO WARRANTY. This software may be subject to other third-
* party rights, including patent rights. No such rights are granted under this License.
*
* Copyright (c) 2018-2020 Christian R. Helmrich, project ecodis. All rights reserved.
*/
#include "exhaleLibPch.h"
#include "stereoProcessing.h"
// static helper functions
// private helper function
// constructor
StereoProcessor::StereoProcessor ()
{
for (unsigned ch = 0; ch < USAC_MAX_NUM_CHANNELS; ch++)
{
m_avgAbsHpPrev[ch] = 0;
m_maxAbsHpPrev[ch] = 0;
m_maxIdxHpPrev[ch] = 1;
m_pitchLagPrev[ch] = 0;
m_tempAnaStats[ch] = 0;
m_transientLoc[ch] = -1;
}
}
// public functions
unsigned StereoProcessor::applyFullFrameMatrix (int32_t* const mdctSpectrum1, int32_t* const mdctSpectrum2,
int32_t* const mdstSpectrum1, int32_t* const mdstSpectrum2,
SfbGroupData& groupingData1, SfbGroupData& groupingData2,
const TnsData& filterData1, const TnsData& filterData2,
const uint8_t numSwbFrame, uint8_t* const sfbStereoData,
uint32_t* const sfbStepSize1, uint32_t* const sfbStepSize2)
{
//const bool applyPredSte = (sfbStereoData != nullptr); // use real-valued predictive stereo
const uint8_t maxSfbSte = __max (groupingData1.sfbsPerGroup, groupingData2.sfbsPerGroup);
if ((mdctSpectrum1 == nullptr) || (mdctSpectrum2 == nullptr) || (groupingData1.numWindowGroups != groupingData2.numWindowGroups) ||
(sfbStepSize1 == nullptr) || (sfbStepSize2 == nullptr) || (numSwbFrame < MIN_NUM_SWB_SHORT) || (numSwbFrame > MAX_NUM_SWB_LONG))
{
return 1; // invalid arguments error
}
for (uint16_t gr = 0; gr < groupingData1.numWindowGroups; gr++)
{
const bool realOnlyCalc = (filterData1.numFilters > 0 && gr == filterData1.filteredWindow) || (mdstSpectrum1 == nullptr) ||
(filterData2.numFilters > 0 && gr == filterData2.filteredWindow) || (mdstSpectrum2 == nullptr);
const uint16_t* grpOff = &groupingData1.sfbOffsets[numSwbFrame * gr];
uint32_t* const grpRms1 = &groupingData1.sfbRmsValues[numSwbFrame * gr];
uint32_t* const grpRms2 = &groupingData2.sfbRmsValues[numSwbFrame * gr];
uint32_t* grpStepSizes1 = &sfbStepSize1[numSwbFrame * gr];
uint32_t* grpStepSizes2 = &sfbStepSize2[numSwbFrame * gr];
int32_t prevReM = 0, prevReS = 0;
if (realOnlyCalc) // preparation for first magnitude value
{
const uint16_t sPlus1 = grpOff[0] + 1;
prevReM = int32_t (((int64_t) mdctSpectrum1[sPlus1] + (int64_t) mdctSpectrum2[sPlus1] + 1) >> 1);
prevReS = int32_t (((int64_t) mdctSpectrum1[sPlus1] - (int64_t) mdctSpectrum2[sPlus1] + 1) >> 1);
}
for (uint16_t sfb = 0; sfb < maxSfbSte; sfb++)
{
const uint32_t sfbRmsL = __max (SP_EPS, grpRms1[sfb]);
const uint32_t sfbRmsR = __max (SP_EPS, grpRms2[sfb]);
const double sfbFacLR = (sfbRmsL < (grpStepSizes1[sfb] >> 1) ? 1.0 : 2.0) * (sfbRmsR < (grpStepSizes2[sfb] >> 1) ? 1.0 : 2.0);
const double sfbRatLR = __min (1.0, grpStepSizes1[sfb] / (sfbRmsL * 2.0)) * __min (1.0, grpStepSizes2[sfb] / (sfbRmsR * 2.0)) * sfbFacLR;
const uint16_t sfbStart = grpOff[sfb];
const uint16_t sfbWidth = grpOff[sfb + 1] - sfbStart;
int32_t* sfbMdct1 = &mdctSpectrum1[sfbStart];
int32_t* sfbMdct2 = &mdctSpectrum2[sfbStart];
double sfbRmsMaxMS;
uint64_t sumAbsValM = 0, sumAbsValS = 0;
if (realOnlyCalc) // real data, only MDCTs are available
{
int32_t* sfbNext1 = &sfbMdct1[1];
int32_t* sfbNext2 = &sfbMdct2[1];
for (uint16_t s = sfbWidth - (sfb + 1 == numSwbFrame ? 1 : 0); s > 0; s--)
{
const int32_t dmixReM = int32_t (((int64_t) *sfbMdct1 + (int64_t) *sfbMdct2 + 1) >> 1);
const int32_t dmixReS = int32_t (((int64_t) *sfbMdct1 - (int64_t) *sfbMdct2 + 1) >> 1);
// TODO: improve the following lines since the calculation is partially redundant!
const int32_t dmixImM = int32_t (((*sfbNext1 + (int64_t) *sfbNext2 + 1) >> 1) - (int64_t) prevReM) >> 1; // estimate, see also
const int32_t dmixImS = int32_t (((*sfbNext1 - (int64_t) *sfbNext2 + 1) >> 1) - (int64_t) prevReS) >> 1; // getMeanAbsValues()
const uint32_t absReM = abs (dmixReM);
const uint32_t absReS = abs (dmixReS); // Richard Lyons, 1997; en.wikipedia.org/
const uint32_t absImM = abs (dmixImM); // wiki/Alpha_max_plus_beta_min_algorithm
const uint32_t absImS = abs (dmixImS);
sumAbsValM += (absReM > absImM ? absReM + ((absImM * 3) >> 3) : absImM + ((absReM * 3) >> 3));
sumAbsValS += (absReS > absImS ? absReS + ((absImS * 3) >> 3) : absImS + ((absReS * 3) >> 3));
*(sfbMdct1++) = dmixReM;
*(sfbMdct2++) = dmixReS;
sfbNext1++; prevReM = dmixReM;
sfbNext2++; prevReS = dmixReS;
}
}
else // complex data, both MDCTs and MDSTs are available
{
int32_t* sfbMdst1 = &mdstSpectrum1[sfbStart];
int32_t* sfbMdst2 = &mdstSpectrum2[sfbStart];
for (uint16_t s = sfbWidth; s > 0; s--)
{
const int32_t dmixReM = int32_t (((int64_t) *sfbMdct1 + (int64_t) *sfbMdct2 + 1) >> 1);
const int32_t dmixReS = int32_t (((int64_t) *sfbMdct1 - (int64_t) *sfbMdct2 + 1) >> 1);
const int32_t dmixImM = int32_t (((int64_t) *sfbMdst1 + (int64_t) *sfbMdst2 + 1) >> 1);
const int32_t dmixImS = int32_t (((int64_t) *sfbMdst1 - (int64_t) *sfbMdst2 + 1) >> 1);
#if SA_EXACT_COMPLEX_ABS
const double cplxSqrM = (double) dmixReM * (double) dmixReM + (double) dmixImM * (double) dmixImM;
const double cplxSqrS = (double) dmixReS * (double) dmixReS + (double) dmixImS * (double) dmixImS;
sumAbsValM += uint64_t (sqrt (cplxSqrM) + 0.5);
sumAbsValS += uint64_t (sqrt (cplxSqrS) + 0.5);
#else
const uint32_t absReM = abs (dmixReM);
const uint32_t absReS = abs (dmixReS); // Richard Lyons, 1997; en.wikipedia.org/
const uint32_t absImM = abs (dmixImM); // wiki/Alpha_max_plus_beta_min_algorithm
const uint32_t absImS = abs (dmixImS);
sumAbsValM += (absReM > absImM ? absReM + ((absImM * 3) >> 3) : absImM + ((absReM * 3) >> 3));
sumAbsValS += (absReS > absImS ? absReS + ((absImS * 3) >> 3) : absImS + ((absReS * 3) >> 3));
#endif
*(sfbMdct1++) = dmixReM;
*(sfbMdct2++) = dmixReS;
*(sfbMdst1++) = dmixImM;
*(sfbMdst2++) = dmixImS;
}
} // realOnlyCalc
// average spectral sample magnitude across current band
grpRms1[sfb] = uint32_t ((sumAbsValM + (sfbWidth >> 1)) / sfbWidth);
grpRms2[sfb] = uint32_t ((sumAbsValS + (sfbWidth >> 1)) / sfbWidth);
sfbRmsMaxMS = __max (grpRms1[sfb], grpRms2[sfb]);
if (sfbFacLR <= 1.0) // total simultaneous masking, no positive SNR in any channel SFB
{
double max = __max (sfbRmsL, sfbRmsR);
grpStepSizes1[sfb] = grpStepSizes2[sfb] = uint32_t (__max (grpStepSizes1[sfb], grpStepSizes2[sfb]) * (sfbRmsMaxMS / max) + 0.5);
}
else // partial or no masking, redistribute positive SNR into at least one channel SFB
{
double min = __min (grpRms1[sfb], grpRms2[sfb]);
grpStepSizes1[sfb] = grpStepSizes2[sfb] = uint32_t (__max (SP_EPS, (min > sfbRatLR * sfbRmsMaxMS ? sqrt (sfbRatLR * sfbRmsMaxMS *
min) : __min (1.0/*TODO*/, sfbRatLR) * sfbRmsMaxMS)) + 0.5);
}
} // for sfb
}
return 0; // no error
}

View File

@ -0,0 +1,47 @@
/* stereoProcessing.h - header file for class providing M/S stereo coding functionality
* written by C. R. Helmrich, last modified in 2020 - see License.htm for legal notices
*
* The copyright in this software is being made available under a Modified BSD-Style License
* and comes with ABSOLUTELY NO WARRANTY. This software may be subject to other third-
* party rights, including patent rights. No such rights are granted under this License.
*
* Copyright (c) 2018-2020 Christian R. Helmrich, project ecodis. All rights reserved.
*/
#ifndef _STEREO_PROCESSING_H_
#define _STEREO_PROCESSING_H_
#include "exhaleLibPch.h"
// constants, experimental macros
#define SP_EPS 1
// joint-channel processing class
class StereoProcessor
{
private:
// member variables
unsigned m_avgAbsHpPrev[USAC_MAX_NUM_CHANNELS];
unsigned m_maxAbsHpPrev[USAC_MAX_NUM_CHANNELS];
unsigned m_maxIdxHpPrev[USAC_MAX_NUM_CHANNELS];
unsigned m_pitchLagPrev[USAC_MAX_NUM_CHANNELS];
uint32_t m_tempAnaStats[USAC_MAX_NUM_CHANNELS];
int16_t m_transientLoc[USAC_MAX_NUM_CHANNELS];
public:
// constructor
StereoProcessor ();
// destructor
~StereoProcessor () { }
// public functions
unsigned applyFullFrameMatrix (int32_t* const mdctSpectrum1, int32_t* const mdctSpectrum2,
int32_t* const mdstSpectrum1, int32_t* const mdstSpectrum2,
SfbGroupData& groupingData1, SfbGroupData& groupingData2,
const TnsData& filterData1, const TnsData& filterData2,
const uint8_t numSwbFrame, uint8_t* const sfbStereoData,
uint32_t* const sfbStepSize1, uint32_t* const sfbStepSize2);
}; // StereoProcessor
#endif // _STEREO_PROCESSING_H_