mirror of
https://gitlab.com/ecodis/exhale.git
synced 2025-03-12 09:10:17 +01:00
add full-frame M/S
This commit is contained in:
parent
e4bc905be2
commit
5ceb1a0959
@ -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)
|
||||
{
|
||||
|
@ -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;
|
||||
|
@ -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];
|
||||
|
@ -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-
|
||||
|
@ -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
|
||||
|
@ -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" />
|
||||
|
@ -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>
|
||||
|
@ -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
|
||||
|
161
src/lib/stereoProcessing.cpp
Normal file
161
src/lib/stereoProcessing.cpp
Normal 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
|
||||
}
|
47
src/lib/stereoProcessing.h
Normal file
47
src/lib/stereoProcessing.h
Normal 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_
|
Loading…
x
Reference in New Issue
Block a user