fix M/S, delta-time

This commit is contained in:
Christian R. Helmrich
2020-04-06 02:00:41 +02:00
parent 96a41f676d
commit 69e1d998a2
5 changed files with 89 additions and 29 deletions

View File

@ -11,6 +11,50 @@
#include "exhaleLibPch.h"
#include "bitStreamWriter.h"
// static helper function
static uint32_t getDeltaCodeTimeFlag (const uint8_t* const alphaQCurr, const unsigned numWinGroups, const unsigned numSwbShort,
const uint8_t* const alphaQPrev, const unsigned maxSfbSte, const EntropyCoder& entrCoder,
const bool complexCoef)
{
unsigned b, g, bitCountFreq = 0, bitCountTime = 0;
if ((alphaQCurr == nullptr) || (alphaQPrev == nullptr)) return 0;
for (g = 0; g < numWinGroups; g++)
{
const uint8_t* const aqReIdxPrvGrp = (g == 0 ? alphaQPrev : &alphaQCurr[numSwbShort * (g - 1)]);
const uint8_t* const aqImIdxPrvGrp = &aqReIdxPrvGrp[1];
const uint8_t* const gCplxPredUsed = &alphaQCurr[numSwbShort * g];
int aqReIdxPred = 16, aqImIdxPred = 16; // init alpha_q_.. = 0
for (b = 0; b < maxSfbSte; b += SFB_PER_PRED_BAND)
{
if (gCplxPredUsed[b] > 0) // count dpcm_alpha_q_re/_q_im bits
{
int aqIdx = gCplxPredUsed[b] & 31; // range -15,...0,...,15
bitCountFreq += entrCoder.indexGetBitCount (aqIdx - aqReIdxPred);
bitCountTime += entrCoder.indexGetBitCount (aqIdx - int (aqReIdxPrvGrp[b] & 31));
aqReIdxPred = aqIdx;
if (complexCoef)
{
aqIdx = gCplxPredUsed[b + 1] & 31; // TODO: <32 kHz short
bitCountFreq += entrCoder.indexGetBitCount (aqIdx - aqImIdxPred);
bitCountTime += entrCoder.indexGetBitCount (aqIdx - int (aqImIdxPrvGrp[b] & 31));
aqImIdxPred = aqIdx;
}
}
else aqReIdxPred = aqImIdxPred = 16;
}
} // for g
return (bitCountFreq > bitCountTime ? 1 : 0);
}
// private helper functions
void BitStreamWriter::writeByteAlignment () // write '0' bits until stream is byte-aligned
{
@ -281,7 +325,7 @@ unsigned BitStreamWriter::writeStereoCoreToolInfo (const CoreCoderData& elData,
const IcsInfo& icsInfo1 = elData.icsInfoCurr[1];
const TnsData& tnsData0 = elData.tnsData[0];
const TnsData& tnsData1 = elData.tnsData[1];
const SfbGroupData& grp = elData.groupingData[0];
const unsigned nWinGrps = elData.groupingData[0].numWindowGroups;
unsigned bitCount = 2, g, b;
m_auBitStream.write (elData.tnsActive ? 1 : 0, 1); // tns_active
@ -302,9 +346,9 @@ unsigned BitStreamWriter::writeStereoCoreToolInfo (const CoreCoderData& elData,
bitCount += 3;
if (elData.stereoMode == 1) // write SFB-wise ms_used[][] flag
{
for (g = 0; g < grp.numWindowGroups; g++)
for (g = 0; g < nWinGrps; g++)
{
const uint8_t* const gMsUsed = &elData.stereoData[m_numSwbShort * g];
const uint8_t* const gMsUsed = &elData.stereoDataCurr[m_numSwbShort * g];
for (b = 0; b < maxSfbSte; b++)
{
@ -317,13 +361,14 @@ unsigned BitStreamWriter::writeStereoCoreToolInfo (const CoreCoderData& elData,
else if (elData.stereoMode >= 3) // SFB-wise cplx_pred_data()
{
const bool complexCoef = (elData.stereoConfig & 1);
uint32_t deltaCodeTime = 0;
m_auBitStream.write (elData.stereoMode - 3, 1); // _pred_all
if (elData.stereoMode == 3)
{
for (g = 0; g < grp.numWindowGroups; g++)
for (g = 0; g < nWinGrps; g++)
{
const uint8_t* const gCplxPredUsed = &elData.stereoData[m_numSwbShort * g];
const uint8_t* const gCplxPredUsed = &elData.stereoDataCurr[m_numSwbShort * g];
for (b = 0; b < maxSfbSte; b += SFB_PER_PRED_BAND)
{
@ -334,46 +379,49 @@ unsigned BitStreamWriter::writeStereoCoreToolInfo (const CoreCoderData& elData,
}
m_auBitStream.write (elData.stereoConfig & 3, 2);// pred_dir
bitCount += 3;
if (!indepFlag) // use_prev_frame (&4), delta_code_time (&8)
if (!indepFlag) // write use_prev_frame and delta_code_time
{
if (complexCoef)
{
m_auBitStream.write (elData.stereoConfig & 4 ? 1 : 0, 1);
bitCount++;
}
m_auBitStream.write (elData.stereoConfig & 8 ? 1 : 0, 1);
deltaCodeTime = getDeltaCodeTimeFlag (elData.stereoDataCurr, nWinGrps, m_numSwbShort, elData.stereoDataPrev, maxSfbSte, entrCoder, complexCoef);
m_auBitStream.write (deltaCodeTime, 1);
bitCount++;
}
// TODO: complete the following code for delta_code_time > 0
for (g = 0; g < grp.numWindowGroups; g++)
for (g = 0; g < nWinGrps; g++)
{
const uint8_t* const gCplxPredUsed = &elData.stereoData[m_numSwbShort * g];
uint8_t aqReIdxPred = 16, aqImIdxPred = 16; // alpha_q = 0
const uint8_t* const aqReIdxPrvGrp = (g == 0 ? elData.stereoDataPrev : &elData.stereoDataCurr[m_numSwbShort * (g - 1)]);
const uint8_t* const aqImIdxPrvGrp = &aqReIdxPrvGrp[1];
const uint8_t* const gCplxPredUsed = &elData.stereoDataCurr[m_numSwbShort * g];
int aqReIdxPred = 16, aqImIdxPred = 16; // alpha_q_.. = 0
for (b = 0; b < maxSfbSte; b += SFB_PER_PRED_BAND)
{
if (gCplxPredUsed[b] > 0) // write dpcm_alpha_q_re/_q_im
{
uint8_t aqIdx = gCplxPredUsed[b] & 31; // -15,..0,..15
int aqIdxDpcm = (int) aqIdx - aqReIdxPred;
int aqIdx = gCplxPredUsed[b] & 31; // range -15,...,15
int aqIdxDpcm = aqIdx - (deltaCodeTime > 0 ? int (aqReIdxPrvGrp[b] & 31) : aqReIdxPred);
unsigned bits = entrCoder.indexGetBitCount (aqIdxDpcm);
aqReIdxPred = aqIdx;
if (deltaCodeTime == 0) aqReIdxPred = aqIdx;
m_auBitStream.write (entrCoder.indexGetHuffCode (aqIdxDpcm), bits);
bitCount += bits;
if (complexCoef)
{
aqIdx = gCplxPredUsed[b + 1] & 31; // <32 kHz short!
aqIdxDpcm = (int) aqIdx - aqImIdxPred;
aqIdxDpcm = aqIdx - (deltaCodeTime > 0 ? int (aqImIdxPrvGrp[b] & 31) : aqImIdxPred);
bits = entrCoder.indexGetBitCount (aqIdxDpcm);
aqImIdxPred = aqIdx;
if (deltaCodeTime == 0) aqImIdxPred = aqIdx;
m_auBitStream.write (entrCoder.indexGetHuffCode (aqIdxDpcm), bits);
bitCount += bits;
}
}
else aqReIdxPred = aqImIdxPred = 16;
else if (deltaCodeTime == 0) aqReIdxPred = aqImIdxPred = 16;
}
} // for g
}

View File

@ -788,12 +788,12 @@ unsigned ExhaleEncoder::psychBitAllocation () // perceptual bit-allocation via s
const uint8_t numSwbFrame = (coreConfig.icsInfoCurr[0].windowSequence == EIGHT_SHORT ? m_numSwbShort : __min (m_numSwbLong, maxSfbLong));
const uint32_t peakIndexSte = __max ((m_specAnaCurr[ci] >> 5) & 2047, (m_specAnaCurr[ci + 1] >> 5) & 2047) << 5;
coreConfig.stereoData[0] = (coreConfig.stereoData[0] & 0xFE) | (coreConfig.stereoConfig >> 1); // TODO: pass pred_dir, complex_coef as args
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],
numSwbFrame, coreConfig.stereoData,
numSwbFrame, coreConfig.stereoDataCurr,
coreConfig.stereoConfig >> 1, coreConfig.stereoConfig & 1,
&sfbStepSizes[m_numSwbShort * NUM_WINDOW_GROUPS * ci],
&sfbStepSizes[m_numSwbShort * NUM_WINDOW_GROUPS * (ci + 1)]);
if (errorValue == 2) // use frame M/S with cplx_pred_all=1
@ -1217,7 +1217,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, coreConfig.stereoData);
nSamplesInFrame, eightShorts, coreConfig.stereoDataCurr);
if (steAnaStats == SHRT_MIN) errorValue = 1;
if ((s = abs (steAnaStats)) * m_perCorrCurr[el] == 0) // transitions to/from silence
@ -1532,8 +1532,8 @@ unsigned ExhaleEncoder::temporalProcessing () // determine time-domain aspects o
if (winSeq0 != winSeq1) // try to synch window_sequences
{
const USAC_WSEQ initialWs0 = (USAC_WSEQ) winSeq0;
const USAC_WSEQ initialWs1 = (USAC_WSEQ) winSeq1;
const USAC_WSEQ initialWs0 = winSeq0;
const USAC_WSEQ initialWs1 = winSeq1;
winSeq0 = winSeq1 = windowSequenceSynch[initialWs0][initialWs1]; // equalization
if ((winSeq0 != initialWs0) && (winSeq0 == EIGHT_SHORT))
@ -1572,6 +1572,16 @@ unsigned ExhaleEncoder::temporalProcessing () // determine time-domain aspects o
icsInfo1.windowShape = WINDOW_KBD; // encourage synch in next frame; KBD dominates
}
coreConfig.commonWindow = (winSeq0 == winSeq1); // synch
memset (coreConfig.stereoDataPrev, 16, (MAX_NUM_SWB_LONG + 1) * sizeof (uint8_t));
if (((winSeq0 == EIGHT_SHORT) == (coreConfig.icsInfoPrev[0].windowSequence == EIGHT_SHORT)) && !m_indepFlag &&
((winSeq1 == EIGHT_SHORT) == (coreConfig.icsInfoPrev[1].windowSequence == EIGHT_SHORT)) && (coreConfig.stereoMode > 0))
{
const unsigned lastGrpOffset = (coreConfig.icsInfoPrev[0].windowSequence == EIGHT_SHORT ? m_numSwbShort * (NUM_WINDOW_GROUPS - 1) : 0);
memcpy (coreConfig.stereoDataPrev, &coreConfig.stereoDataCurr[lastGrpOffset], (coreConfig.icsInfoPrev[0].maxSfb + 1) * sizeof (uint8_t));
}
} // if nrChannels > 1
}

View File

@ -131,7 +131,8 @@ struct CoreCoderData
uint8_t specFillData[2]; // noise filling data for each channel
#endif
uint8_t stereoConfig; // cplx_pred_data() config: pred_dir etc.
uint8_t stereoData[MAX_NUM_SWB_SHORT * NUM_WINDOW_GROUPS];
uint8_t stereoDataCurr[MAX_NUM_SWB_SHORT * NUM_WINDOW_GROUPS];
uint8_t stereoDataPrev[MAX_NUM_SWB_LONG + 1]; // .._q_prev_frame
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

@ -23,10 +23,11 @@ unsigned StereoProcessor::applyFullFrameMatrix (int32_t* const mdctSpectrum1, in
SfbGroupData& groupingData1, SfbGroupData& groupingData2,
const TnsData& filterData1, const TnsData& filterData2,
const uint8_t numSwbFrame, uint8_t* const sfbStereoData,
const uint8_t useAltPredDir, const uint8_t useComplexCoef,
uint32_t* const sfbStepSize1, uint32_t* const sfbStepSize2)
{
const bool applyPredSte = (sfbStereoData != nullptr); // use real-valued predictive stereo
const bool alterPredDir = (applyPredSte && (sfbStereoData[0] & 1)); // true: mid from side
const bool alterPredDir = (applyPredSte && (useAltPredDir > 0)); // predict mid from side?
const SfbGroupData& grp = groupingData1;
const bool eightShorts = (grp.numWindowGroups > 1);
const uint8_t maxSfbSte = (eightShorts ? __max (grp.sfbsPerGroup, groupingData2.sfbsPerGroup) : numSwbFrame);
@ -292,7 +293,7 @@ unsigned StereoProcessor::applyFullFrameMatrix (int32_t* const mdctSpectrum1, in
const double min = (applyPredSte ? __min (rmsSfbM[b], rmsSfbS[b]) : __min (grpRms1[idx], grpRms2[idx]));
const double rat = __min (1.0, grpStepSizes1[idx] / (sfbRmsL * 2.0)) * __min (1.0, grpStepSizes2[idx] / (sfbRmsR * 2.0)) * sfbFacLR;
grpStepSizes1[sfb] = grpStepSizes2[sfb] = uint32_t (__max (SP_EPS, (min > rat * sfbTempVar ? sqrt (rat * sfbTempVar * min) :
grpStepSizes1[idx] = grpStepSizes2[idx] = uint32_t (__max (SP_EPS, (min > rat * sfbTempVar ? sqrt (rat * sfbTempVar * min) :
__min (1.0, rat) * sfbTempVar)) + 0.5);
}
}
@ -300,13 +301,11 @@ unsigned StereoProcessor::applyFullFrameMatrix (int32_t* const mdctSpectrum1, in
}
} // for gr
if (numSfbPredSte <= 1) // discard prediction coefficients and stay with legacy M/S stereo
if (numSfbPredSte == 0) // discard prediction coefficients and stay with legacy M/S stereo
{
if (applyPredSte) memset (sfbStereoData, 16, numSwbFrame * grp.numWindowGroups * sizeof (uint8_t));
numSfbPredSte = 0;
}
else // at least two "significant" prediction bands - apply prediction and update RMS data
else // at least one "significant" prediction band, apply prediction and update RMS values
{
for (uint16_t gr = 0; gr < grp.numWindowGroups; gr++)
{
@ -400,6 +399,7 @@ unsigned StereoProcessor::applyFullFrameMatrix (int32_t* const mdctSpectrum1, in
sumAbsValR = (sumAbsValR + (sfbWidth >> 1)) / sfbWidth;
if (alterPredDir) grpRms1[sfb] = (uint32_t) sumAbsValR; else grpRms2[sfb] = (uint32_t) sumAbsValR;
}
if (numSwbFrame > maxSfbSte) memset (&sfbStereoData[maxSfbSte + numSwbFrame * gr], 16, (numSwbFrame - maxSfbSte) * sizeof (uint8_t));
if (alterPredDir) // swap channel data when pred_dir = 1
{

View File

@ -38,6 +38,7 @@ public:
SfbGroupData& groupingData1, SfbGroupData& groupingData2,
const TnsData& filterData1, const TnsData& filterData2,
const uint8_t numSwbFrame, uint8_t* const sfbStereoData,
const uint8_t useAltPredDir, const uint8_t useComplexCoef,
uint32_t* const sfbStepSize1, uint32_t* const sfbStepSize2);
}; // StereoProcessor