finish 1.1.8 release

This commit is contained in:
Christian R. Helmrich 2021-10-27 10:00:00 +02:00
parent f145f63fe5
commit 7688ab502e
11 changed files with 73 additions and 31 deletions

View File

@ -16,7 +16,7 @@ if("${CMAKE_CURRENT_SOURCE_DIR}" STREQUAL "${CMAKE_CURRENT_BINARY_DIR}")
endif()
project(exhale VERSION 1.1.7 LANGUAGES CXX)
project(exhale VERSION 1.1.8 LANGUAGES CXX)
if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
set(CMAKE_BUILD_TYPE Release

View File

@ -41,7 +41,7 @@ exhale is being made available under an open-source license which is
based on the 3-clause BSD license but modified to address particular
aspects dictated by the nature and the output of this application.
The license text and release notes for the current version 1.1.7 can
The license text and release notes for the current version 1.1.8 can
be found in the `include` subdirectory of the exhale distribution.

View File

@ -25,9 +25,14 @@
<td valign="top">
<h1><br><span class="pink">exhale</span> - <span class="pink">e</span>codis e<span class="pink">x</span>tended <span class="pink">h</span>igh-efficiency <span class="pink">a</span>nd <span class="pink">l</span>ow-complexity <span class="pink">e</span>ncoder<br><span class="gray"><sup><br>Software Release Notes, Version History, Known Issues, Upcoming Feature Roadmap</sup></span><br><br></h1>
<h3>&nbsp; &nbsp;The version of this distribution of the &laquo;exhale&raquo; software release is <b>1.1.7</b> (official pub&shy;lic minor release) from August 2021. Please check <a href="http://www.ecodis.de/audio.htm#mpeg">www.ecodis.de</a> regularly for new versions of this software. A summary of each version up to this release, a list of known issues with this release, and a roadmap of additional functionality are provided below.</h3>
<h3>&nbsp; &nbsp;The version of this distribution of the &laquo;exhale&raquo; software release is <b>1.1.8</b> (official pub&shy;lic minor release) from October 2021. Please check <a href="http://www.ecodis.de/audio.htm#mpeg">www.ecodis.de</a> regularly for new versions of this software. A summary of each version up to this release, a list of known issues with this release, and a roadmap of additional functionality are provided below.</h3>
<h3><br><b>Chronological Version History</b></h3>
<h3>&nbsp; &nbsp;Version <b>1.1.7 <span class="gray">&nbsp;Aug. 2021, this release</span></b></h3>
<h3>&nbsp; &nbsp;Version <b>1.1.8 <span class="gray">&nbsp;Oct. 2021, this release</span></b></h3>
<ul>
<li><h3>some final code cleanup, small code corrections and editorial changes for this year</h3></li>
<li><h3>exhaleLib: minor stereo quality tuning for low rates, optional CBR mode via macro</h3></li>
</ul>
<h3>&nbsp; &nbsp;Version <b>1.1.7 <span class="gray">&nbsp;Aug. 2021</span></b></h3>
<ul>
<li><h3>minor tuning at low SBR rates, enabled SBR coding at 22050 Hz input sample rate</h3></li>
<li><h3>exhaleApp: added expert modes for loudness leveling, custom Intra frame interval</h3></li>
@ -158,7 +163,7 @@
<li><h3>exhaleLib: speed-ups and further quality tuning for difficult signals, as necessary.</h3></li>
</ul>
<h3><br></h3>
<h4><span class="gray">Written by C. R. Helmrich for exhale 1.1.7, Aug. 2021. Available at www.ecodis.de/exhale/release.htm.</span><br><br></h4>
<h4><span class="gray">Written by C. R. Helmrich for exhale 1.1.8, Oct. 2021. Available at www.ecodis.de/exhale/release.htm.</span><br><br></h4>
</td>
<td valign="top" colspan="2">

View File

@ -15,5 +15,5 @@
# define EXHALELIB_VERSION_MINOR "1"
#endif
#ifndef EXHALELIB_VERSION_BUGFIX
# define EXHALELIB_VERSION_BUGFIX ".7" // "RC" or ".0", ".1", ...
# define EXHALELIB_VERSION_BUGFIX ".8" // "RC" or ".0", ".1", ...
#endif

View File

@ -13,7 +13,7 @@
0 ICON "exhaleApp.ico"
VS_VERSION_INFO VERSIONINFO
FILEVERSION 1,1,7,1
FILEVERSION 1,1,8
BEGIN
BLOCK "StringFileInfo"
BEGIN

View File

@ -107,11 +107,12 @@ uint16_t BitAllocator::getRateCtrlFac (const int32_t rateRatio, const unsigned s
#if BA_MORE_CBR
const int32_t ratioFac = rateRatio * (40 - 5 * m_rateIndex);
const uint32_t brRatio = __max ((prevEightShorts ? (ratioFac * ratioFac + (1 << 16)) >> 17 : 0) - SHRT_MIN, __min (USHRT_MAX, ratioFac)) -
(m_rateIndex == 2 ? (1 << 11) : 0);
(m_rateIndex == 2 ? 1 << 12 : 0); // rate tuning
const uint16_t mSfmSqr = (m_rateIndex <= 2 && samplingRate >= 27713 ? (specFlatness * specFlatness) >> m_rateIndex : 0);
#else
const uint32_t brRatio = __max (1 << 15, __min (USHRT_MAX, rateRatio * (36 - 9 * m_rateIndex)));
#endif
const uint16_t mSfmSqr = (m_rateIndex < 2 && samplingRate >= 27713 ? (specFlatness * specFlatness) >> m_rateIndex : 0);
#endif
const uint16_t mSfmFac = 256 - (((32 + m_rateIndex) * (specFlatness << 4) - mSfmSqr + (1 << 9)) >> 10);
return uint16_t ((brRatio * mSfmFac + (1 << 7)) >> 8);

View File

@ -1324,7 +1324,7 @@ unsigned ExhaleEncoder::quantizationCoding () // apply MDCT quantization and en
}
} // for el
#if !RESTRICT_TO_AAC
m_rateFactor = samplingRate; // for RC
m_rateFactor = samplingRate; // rate ctrl
#endif
return (errorValue > 0 ? 0 : m_outStream.createAudioFrame (m_elementData, m_entropyCoder, m_mdctSignals, m_mdctQuantMag, m_indepFlag,
m_numElements, m_numSwbShort, (uint8_t* const) m_tempIntBuf,
@ -1389,9 +1389,8 @@ unsigned ExhaleEncoder::spectralProcessing () // complete ics_info(), calc TNS
const uint8_t meanSpecFlat = (((m_specAnaCurr[ci] >> 16) & UCHAR_MAX) + ((m_specAnaCurr[ci + 1] >> 16) & UCHAR_MAX) + 1) >> 1;
const uint16_t* const swbo = swbOffsetsL[m_swbTableIdx];
const uint16_t nSamplesMax = (useMaxBandwidth ? 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.stereoDataCurr);
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.stereoDataCurr);
if (steAnaStats == SHRT_MIN) errorValue = 1;
if ((s = abs (steAnaStats)) * m_perCorrHCurr[el] == 0) // transition to/from silence
@ -1455,7 +1454,7 @@ unsigned ExhaleEncoder::spectralProcessing () // complete ics_info(), calc TNS
{
icsCurr.maxSfb = __min (icsCurr.maxSfb, brModeAndFsToMaxSfbShort (m_bitRateMode, samplingRate));
}
#if SA_OPT_WINDOW_GROUPING
if (ch > 0 && coreConfig.commonWindow) // resynchronize the scale_factor_grouping
{
if (icsCurr.windowGrouping != coreConfig.icsInfoCurr[0].windowGrouping)
@ -1471,15 +1470,15 @@ unsigned ExhaleEncoder::spectralProcessing () // complete ics_info(), calc TNS
}
}
memcpy (grpData.windowGroupLength, windowGroupingTable[icsCurr.windowGrouping], NUM_WINDOW_GROUPS * sizeof (uint8_t));
#endif
findActualBandwidthShort (&icsCurr.maxSfb, grpSO, m_mdctSignals[ci], nChannels < 2 ? nullptr : m_mdstSignals[ci], nSamplesInShort);
errorValue |= eightShortGrouping (grpData, grpSO, m_mdctSignals[ci], nChannels < 2 ? nullptr : m_mdstSignals[ci]);
} // if EIGHT_SHORT
// compute and quantize optimal TNS coefficients, then find optimal TNS filter order
s /*max. pred gain*/ = getOptParCorCoeffs (grpData, icsCurr.maxSfb, tnsData, ci,
ch > 0 && coreConfig.commonWindow ? coreConfig.tnsData[0].firstTnsWindow : 0);
s = getOptParCorCoeffs (grpData, icsCurr.maxSfb, tnsData, ci, (ch > 0 && coreConfig.commonWindow ? coreConfig.tnsData[0].firstTnsWindow : 0));
for (uint16_t n = 0, gr = 0; gr < grpData.numWindowGroups; gr++)
{
if (grpData.windowGroupLength[gr] == 1)
@ -1780,6 +1779,7 @@ unsigned ExhaleEncoder::temporalProcessing () // determine time-domain aspects o
memcpy (coreConfig.stereoDataPrev, &coreConfig.stereoDataCurr[lastGrpOffset], __min (60 - lastGrpOffset, maxSfbStePrev) * sizeof (uint8_t));
}
coreConfig.stereoDataCurr[0] = (m_bitRateMode <= 1 ? m_tempAnalyzer.stereoPreAnalysis (&m_timeSignals[ci - 2], &m_specFlatPrev[ci - 2], nSamplesInFrame) : 0);
} // if nrChannels > 1
}

View File

@ -179,7 +179,6 @@ unsigned SpecAnalyzer::initSigAnaMemory (LinearPredictor* const linPredictor, co
return 0; // no error
}
#if SA_OPT_WINDOW_GROUPING
unsigned SpecAnalyzer::optimizeGrouping (const unsigned channelIndex, const unsigned prefBandwidth, const unsigned prefGroupingIndex)
{
const uint32_t* meanAbsValCurr = m_meanAbsValue[channelIndex];
@ -226,7 +225,6 @@ unsigned SpecAnalyzer::optimizeGrouping (const unsigned channelIndex, const unsi
return __min (grpIdxCurr, prefGroupingIndex); // final optimized grouping index
}
#endif // SA_OPT_WINDOW_GROUPING
unsigned SpecAnalyzer::spectralAnalysis (const int32_t* const mdctSignals[USAC_MAX_NUM_CHANNELS],
const int32_t* const mdstSignals[USAC_MAX_NUM_CHANNELS],
@ -349,14 +347,12 @@ unsigned SpecAnalyzer::spectralAnalysis (const int32_t* const mdctSignals[USAC_M
// --- spectral analysis statistics for frame
b = 1;
#if SA_IMPROVED_FILT_CALC
if (samplingRate < 27713) sumAvgBand -= m_meanAbsValue[ch][b++];
#endif
while (((unsigned) b + 1 < lpcStopBand16k) && ((uint64_t) m_meanAbsValue[ch][b] * (m_numAnaBands[ch] - 1) > sumAvgBand)) b++;
b = __min (m_bandwidthOff[ch], b << SA_BW_SHIFT);
#if SA_IMPROVED_FILT_CALC
if (samplingRate < 27713) sumAvgBand += m_meanAbsValue[ch][1];
#endif
// obtain prediction gain across spectrum
m_tnsPredGains[ch] = m_tnsPredictor->calcParCorCoeffs (&chMdct[b], __min (m_bandwidthOff[ch], lpcStopBand16k << SA_BW_SHIFT) - b,
MAX_PREDICTION_ORDER, m_parCorCoeffs[ch]);
@ -378,7 +374,7 @@ unsigned SpecAnalyzer::spectralAnalysis (const int32_t* const mdctSignals[USAC_M
int16_t SpecAnalyzer::stereoSigAnalysis (const int32_t* const mdctSignal1, const int32_t* const mdctSignal2,
const int32_t* const mdstSignal1, const int32_t* const mdstSignal2,
const unsigned nSamplesMax, const unsigned nSamplesInFrame, const bool shortTransforms,
uint8_t* const stereoCorrValue /*= nullptr*/) // per-band perceptual correlation data
uint8_t* const stereoCorrValue) // per-band LR correlation
{
const uint64_t anaBwOffset = SA_BW >> 1;
const uint16_t numAnaBands = (shortTransforms ? nSamplesInFrame : nSamplesMax) >> SA_BW_SHIFT;
@ -392,7 +388,8 @@ int16_t SpecAnalyzer::stereoSigAnalysis (const int32_t* const mdctSignal1, const
}
else
{
uint16_t currPC = 0, numPC = 0; // frame-average correlation
const uint16_t tempPreAnaPC = stereoCorrValue[0];
uint16_t currPC = 0, numPC = 0;
uint64_t sumReM = 0, sumReS = 0;// mid-side RMS distribution
for (b = numAnaBands - 1; b >= 0; b--)
@ -457,6 +454,8 @@ int16_t SpecAnalyzer::stereoSigAnalysis (const int32_t* const mdctSignal1, const
if (numPC > 1) currPC = (currPC + (numPC >> 1)) / numPC; // frame's perceptual correlation
if (currPC < tempPreAnaPC) currPC = (currPC + tempPreAnaPC + 1) >> 1;
b = (int16_t) currPC * (sumReS * 2 > sumReM * 3 ? -1 : 1); // negation implies side > mid
}

View File

@ -19,8 +19,6 @@
#define SA_BW (1 << SA_BW_SHIFT)
#define SA_EPS 1024
#define SA_EXACT_COMPLEX_ABS 0
#define SA_IMPROVED_FILT_CALC 1
#define SA_OPT_WINDOW_GROUPING 1
// spectral signal analysis class
class SpecAnalyzer
@ -52,9 +50,7 @@ public:
void getSpecAnalysisStats (uint32_t avgSpecAnaStats[USAC_MAX_NUM_CHANNELS], const unsigned nChannels);
void getSpectralBandwidth (uint16_t bandwidthOffset[USAC_MAX_NUM_CHANNELS], const unsigned nChannels);
unsigned initSigAnaMemory (LinearPredictor* const linPredictor, const unsigned nChannels, const unsigned maxTransfLength);
#if SA_OPT_WINDOW_GROUPING
unsigned optimizeGrouping (const unsigned channelIndex, const unsigned preferredBandwidth, const unsigned preferredGrouping);
#endif
unsigned spectralAnalysis (const int32_t* const mdctSignals[USAC_MAX_NUM_CHANNELS],
const int32_t* const mdstSignals[USAC_MAX_NUM_CHANNELS],
const unsigned nChannels, const unsigned nSamplesInFrame, const unsigned samplingRate,
@ -62,7 +58,7 @@ public:
int16_t stereoSigAnalysis (const int32_t* const mdctSignal1, const int32_t* const mdctSignal2,
const int32_t* const mdstSignal1, const int32_t* const mdstSignal2,
const unsigned nSamplesMax, const unsigned nSamplesInFrame, const bool shortTransforms,
uint8_t* const stereoCorrValue = nullptr); // per-band perceptual correlation data
uint8_t* const stereoCorrValue); // per-band LR correlation
}; // SpecAnalyzer
#endif // _SPEC_ANALYSIS_H_

View File

@ -126,6 +126,46 @@ void TempAnalyzer::getTransientAndPitch (int16_t transIdxAndPitch[USAC_MAX_NUM_C
memcpy (transIdxAndPitch, m_transientLoc, nChannels * sizeof (int16_t));
}
uint8_t TempAnalyzer::stereoPreAnalysis (const int32_t* const timeSignals[2], const uint8_t specFlatness[2], const unsigned nSamplesInSig)
{
const double offsetSfmLR = __max (0.0, ((double) specFlatness[0] + specFlatness[1] - 256.0) * 0.5);
const int32_t* const sigL = timeSignals[0] + (nSamplesInSig >> 1);
const int32_t* const sigLM1 = sigL - 1;
const int32_t* const sigR = timeSignals[1] + (nSamplesInSig >> 1);
const int32_t* const sigRM1 = sigR - 1;
int64_t hpNextL = sigL[nSamplesInSig] - sigLM1[nSamplesInSig];
int64_t hpNextR = sigR[nSamplesInSig] - sigRM1[nSamplesInSig];
int64_t sumSqrL = hpNextL * hpNextL, sumSqrR = hpNextR * hpNextR;
int64_t sumPC00 = (hpNextL * hpNextR) >> 1, sumPC01 = 0, sumPC10 = 0;
double d;
for (int s = nSamplesInSig - 1; s >= 0; s--)
{
// compute correlation between high-pass channel signals with and without 1 smp time delay
const int64_t hpL = sigL[s] - sigLM1[s];
const int64_t hpR = sigR[s] - sigRM1[s];
sumSqrL += hpL * hpL;
sumSqrR += hpR * hpR;
sumPC00 += hpL * hpR;
sumPC01 += hpL * hpNextR;
sumPC10 += hpR * hpNextL;
hpNextL = hpL;
hpNextR = hpR;
}
if (sumSqrL < nSamplesInSig || sumSqrR < nSamplesInSig) return 0; // stop on low-level input
sumPC00 = abs (sumPC00);
sumPC01 = abs (sumPC01);
sumPC10 = abs (sumPC10);
d = 256.0 * __max (sumPC00, __max (sumPC01, sumPC10)); // max. corr. regardless of the delay
return (uint8_t) __max (0.0, d / sqrt ((double) sumSqrL * sumSqrR) - offsetSfmLR);
}
unsigned TempAnalyzer::temporalAnalysis (const int32_t* const timeSignals[USAC_MAX_NUM_CHANNELS], const unsigned nChannels,
const int nSamplesInFrame, const unsigned lookaheadOffset, const uint8_t sbrShift,
int32_t* const lrCoreTimeSignals[USAC_MAX_NUM_CHANNELS] /*= nullptr*/, // if using SBR

View File

@ -1,5 +1,5 @@
/* tempAnalysis.h - header file for class providing temporal analysis of PCM signals
* written by C. R. Helmrich, last modified in 2020 - see License.htm for legal notices
* written by C. R. Helmrich, last modified in 2021 - see License.htm for legal notices
*
* The copyright in this software is being made available under the exhale Copyright License
* and comes with ABSOLUTELY NO WARRANTY. This software may be subject to other third-
@ -40,6 +40,7 @@ public:
// public functions
void getTempAnalysisStats (uint32_t avgTempAnaStats[USAC_MAX_NUM_CHANNELS], const unsigned nChannels);
void getTransientAndPitch (int16_t transIdxAndPitch[USAC_MAX_NUM_CHANNELS], const unsigned nChannels);
uint8_t stereoPreAnalysis (const int32_t* const timeSignals[2], const uint8_t specFlatness[2], const unsigned nSamplesInSig);
unsigned temporalAnalysis (const int32_t* const timeSignals[USAC_MAX_NUM_CHANNELS], const unsigned nChannels,
const int nSamplesInFrame, const unsigned lookaheadOffset, const uint8_t sbrShift,
int32_t* const lrCoreTimeSignals[USAC_MAX_NUM_CHANNELS] = nullptr, // if using SBR