finish 1.2.1.2 release

This commit is contained in:
Christian R. Helmrich
2025-05-10 11:00:00 +02:00
parent 337506ec7c
commit 069a9fd3fd
7 changed files with 81 additions and 28 deletions

View File

@ -31,7 +31,7 @@ ____________________________________________________________________
Copyright
---------
(c) 2024 Christian R. Helmrich, project ecodis. All rights reserved.
(c) 2025 Christian R. Helmrich, project ecodis. All rights reserved.
License

View File

@ -1,4 +1,4 @@
<!-- www.ecodis.de/exhale/license.htm - created by Christian R. Helmrich - Copyright (c) 2018-2024 Christian R. Helmrich, project ecodis. All rights reserved. -->
<!-- www.ecodis.de/exhale/license.htm - created by Christian R. Helmrich - Copyright (c) 2018-2025 Christian R. Helmrich, project ecodis. All rights reserved. -->
<!doctype html public "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
@ -27,7 +27,7 @@
<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>referred to as &laquo;Software&raquo; below; clarifications introduced in October 2020 in <i>italics</i></sup></span><br><br></h1>
<h3>&nbsp; &nbsp;This Software is being made available and/or distributed under the following <i>exhale Copyright</i> License. For a list of authors which have contributed to this Software, called &laquo;contributors&raquo; in the text below, please refer to the respective files provided with this distribution (source files or binary executable) to which modifications were contributed.</h3>
<h3><br><b>Licensor's Copyright Notice</b></h3>
<h3>&nbsp; &nbsp;Copyright &copy; 2018&#x2013;2024 Christian R. Helmrich, <a href="http://www.ecodis.de">ecodis</a> (Licensor). All rights reserved.</h3>
<h3>&nbsp; &nbsp;Copyright &copy; 2018&#x2013;2025 Christian R. Helmrich, <a href="http://www.ecodis.de">ecodis</a> (Licensor). All rights reserved.</h3>
<h3><br><b>List of License Conditions</b></h3>
<h3>&nbsp; &nbsp;Redistribution and use of this Software in source and binary forms, with or without modification, are permitted provided that all of the following four conditions are met:</h3>
<ul>

View File

@ -1,4 +1,4 @@
<!-- www.ecodis.de/exhale/release.htm - created by Christian R. Helmrich - Copyright (c) 2018-2024 Christian R. Helmrich, project ecodis. All rights reserved. -->
<!-- www.ecodis.de/exhale/release.htm - created by Christian R. Helmrich - Copyright (c) 2018-2025 Christian R. Helmrich, project ecodis. All rights reserved. -->
<!doctype html public "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
@ -25,9 +25,17 @@
<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.2.1</b> (official pub&shy;lic minor release) from December 2023. 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.2.1.2</b> (official pub&shy;lic bugfix release) from May 2025. 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.2.1 <span class="gray">&nbsp;Dec. 2023, this release</span></b></h3>
<h3>&nbsp; &nbsp;Version <b>1.2.1.2 <span class="gray">&nbsp;May 2025, this release</span></b></h3>
<ul>
<li><h3>exhaleApp: avoid out of bounds AU writeouts, fix 5.1 WAV/MPEG channel mapping</h3></li>
<li><h3>exhaleLib: relax max. quantized spectral magnitude restriction<sup>1</sup>, fix MSE test code</h3></li>
<li><h3>exhaleLib: clean quantizer+entropy coder, increase max. IPF AU size to 12 kbit/ch</h3></li>
<li><h3>exhaleLib: fix more high-rate efficiency issues, fix mode-f stereo coding (issue 33)</h3></li>
</ul>
<h4><span class="gray">1: optional, activated via define SFB_QUANT_PERCEPT_OPT = 1 or 0, triggers FFmpeg decoder bug!</span></h4>
<h3>&nbsp; &nbsp;Version <b>1.2.1 <span class="gray">&nbsp;Dec. 2023</span></b></h3>
<ul>
<li><h3>exhaleApp: always determine MPEG-4 instantaneous bit-rate across 2048 samples</h3></li>
<li><h3>exhaleLib: added code for MSE optimized encoding (for tests, disabled by default)</h3></li>
@ -177,11 +185,10 @@
<h3><br><b>Roadmap of Upcoming Features</b></h3>
<h3>&nbsp; &nbsp;If you are in need of an additional library or application feature <b>not</b> mentioned below, please contact ecodis or a contributor with a request, and we will see what we can do.</h3>
<ul>
<li><h3>exhaleLib: finalization of support for 5.1&#x2013;7.1 multichannel coding, no version plan</h3></li>
<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.2.1, Dec. 2023. Available at www.ecodis.de/exhale/release.htm.</span><br><br></h4>
<h4><span class="gray">Written by C. R. Helmrich for exhale 1.2.2, Dec. 2025. Available at www.ecodis.de/exhale/release.htm.</span><br><br></h4>
</td>
<td valign="top" colspan="2">

View File

@ -294,7 +294,7 @@ static inline uint8_t brModeAndFsToMaxSfbShort(const unsigned bitRateMode, const
return (samplingRate > 51200 ? 11 : 13) - 2 + (bitRateMode >> 2);
}
#if SFB_QUANT_PERCEPT_OPT && !EE_MORE_MSE
#if !EE_MORE_MSE
static inline void findActualBandwidthShort (uint8_t* const maxSfbShort, const uint16_t* sfbOffsets,
const int32_t* mdctSignals, const int32_t* mdstSignals, const unsigned nSamplesInShort)
{
@ -322,7 +322,7 @@ static inline void findActualBandwidthShort (uint8_t* const maxSfbShort, const u
maxAbs = __max (maxAbs, abs (mdctSignals[e + w * nSamplesInShort]));
}
}
if (maxAbs > maxSfb * (SA_EPS >> 1)) break;
if (maxAbs > maxSfb * (SA_EPS >> (3 - SFB_QUANT_PERCEPT_OPT))) break;
if (e == sfbOffs) sfbOffs = sfbOffsets[(--maxSfb) - 1];
}
@ -761,9 +761,9 @@ uint32_t ExhaleEncoder::getThr (const unsigned channelIndex, const unsigned sfbI
uint32_t sumSfbLoud = 0;
for (int16_t s = 31; s >= 0; s--) sumSfbLoud += sfbLoudMem[s];
sumSfbLoud = (sumSfbLoud + 32) >> 6; // -6 dB
sumSfbLoud = (sumSfbLoud + 16) >> 5;
return sumSfbLoud * (sumSfbLoud >> (toSamplingRate (m_frequencyIdx) >> 13)); // scaled SMR
return (sumSfbLoud * sumSfbLoud + 3) >> 2;
}
unsigned ExhaleEncoder::psychBitAllocation () // perceptual bit-allocation via scale factors
@ -776,7 +776,7 @@ unsigned ExhaleEncoder::psychBitAllocation () // perceptual bit-allocation via s
const uint8_t maxSfbLong = (useMaxBandwidth ? m_numSwbLong : brModeAndFsToMaxSfbLong (m_bitRateMode, samplingRate));
const uint16_t scaleSBR = (m_shiftValSBR > 0 || m_nonMpegExt ? sbrRateOffset[m_bitRateMode] : 0); // -25% rate
const uint64_t scaleSr = (samplingRate < 27713 ? (samplingRate < 23004 ? 32 : 34) - __min (3 << m_shiftValSBR, m_bitRateMode)
: (m_bitRateMode != 3 && samplingRate < 37566 ? 36 : 37)) - (nChannels >> 1) - 4 + 4 * ((SFB_QUANT_PERCEPT_OPT + 1) / 2);
: (m_bitRateMode != 3 && samplingRate < 37566 ? 36 : 37) - 4 + 4 * ((SFB_QUANT_PERCEPT_OPT + 1) / 2)) - (nChannels >> 1);
const uint64_t scaleBr = (m_bitRateMode == 0 || m_frameCount <= 1 ? __min (32, 17u + (((samplingRate + (1 << 11)) >> 12) << 1) - (nChannels >> 1))
: scaleSr - eightTimesSqrt256Minus[256 - m_bitRateMode] - __min (3, (m_bitRateMode - 1) >> 1)) + scaleSBR;
uint32_t* sfbStepSizes = (uint32_t*) m_tempIntBuf;
@ -975,7 +975,7 @@ unsigned ExhaleEncoder::psychBitAllocation () // perceptual bit-allocation via s
}
if (grpOff[maxSfbCh] > grpOff[0])
{
s = BA_EPS + unsigned ((s * (eightShorts ? 1u + 55u/grpData.windowGroupLength[gr] : 7u) + 16383u) >> 14);
s = BA_EPS + unsigned ((s * (eightShorts ? 1u + 55u / grpData.windowGroupLength[gr] : 7u) + 16383u) >> 14);
# ifndef NO_PREROLL_DATA
if (((m_frameCount - 1u) % (m_indepPeriod << 1)) == 1 && m_numElements == 1 && !eightShorts) s = (4u + 9u * s) >> 3;
# endif
@ -1013,6 +1013,52 @@ unsigned ExhaleEncoder::psychBitAllocation () // perceptual bit-allocation via s
#endif
grpScaleFacs[b] = m_bitAllocator.getScaleFac (grpStepSizes[b], &m_mdctSignals[ci][grpOff[b]], sfbWidth, grpRms[b]);
}
#if !SFB_QUANT_PERCEPT_OPT
if (m_bitRateMode > 0 && m_numElements == 1)
{
if (maxSfbCh < (samplingRate < 18783 ? 17 : 24) || !m_frameCount)
{
for (s = 0; s < 26; s++) m_sfbLoudMem[ch][s][m_frameCount & 31] = uint16_t (m_frameCount ? sqrt ((double) getThr (ch, s)) : 32);
}
else // limit step-sizes around background noise level
{
const uint8_t* sd = coreConfig.stereoDataCurr;
const unsigned ns = __max (samplingRate < 27713 ? (samplingRate < 18783 ? 17 : 24) : 22, m_specGapFiller.getFirstGapFillSfb ());
uint32_t minFrRMS = TA_EPS >> EE_MORE_MSE;
for (s = ns; s < __min (ns + 26u, maxSfbCh); s++)
{
uint16_t* const lm = m_sfbLoudMem[ch][s - ns];
uint32_t minSfbMem = INT_MAX;
lm[m_frameCount & 31] = __max (BA_EPS, uint16_t (sqrt (double (sd[s] ? __max (grpRms[s], coreConfig.groupingData[1 - ch].sfbRmsValues[s]) : grpRms[s]))));
for (int f = 0; f < 32; f++)
{
const uint32_t slm = (uint32_t) lm[f] * lm[f];
if (minSfbMem > slm && slm > BA_EPS) minSfbMem = slm;
}
if (minSfbMem < INT_MAX)
{
const uint32_t w = grpOff[s + 1] - grpOff[s];
minSfbMem = (((minSfbMem + 2u) >> 2) + getThr (ch, s - ns) + w - 1u) / w;
if (minFrRMS > minSfbMem) minFrRMS = minSfbMem;
}
}
for (s -= ns; s < 26; s++) m_sfbLoudMem[ch][s][m_frameCount & 31] = BA_EPS;
for (s = (minFrRMS < (TA_EPS >> EE_MORE_MSE) ? ns : 99); s < maxSfbCh; s++)
{
const uint32_t w = grpOff[s + 1] - grpOff[s];
if (stepSizes[s] < minFrRMS * (w >> (sd[s] ? 1 : 0)))
grpScaleFacs[s] = m_bitAllocator.getScaleFac (minFrRMS * (w >> (sd[s] ? 1 : 0)), &m_mdctSignals[ci][grpOff[s]], w, grpRms[s]);
}
}
}
#endif
} // for gr
#if !RESTRICT_TO_AAC
@ -1026,7 +1072,7 @@ unsigned ExhaleEncoder::psychBitAllocation () // perceptual bit-allocation via s
if ((m_bitRateMode == 0) && (m_numElements == 1) && (samplingRate < 27713) && eightShorts)
{
for (s = 0; s < 26; s++) m_sfbLoudMem[ch][s][m_frameCount & 31] = uint16_t (sqrt (double (getThr (ch, s) << (samplingRate >> 13))));
for (s = 0; s < 26; s++) m_sfbLoudMem[ch][s][m_frameCount & 31] = uint16_t (sqrt ((double) getThr (ch, s)));
}
if ((maxSfbCh < numSwbFrame) || (m_bitRateMode <= 2)) // increase coding bandwidth
{
@ -1046,7 +1092,7 @@ unsigned ExhaleEncoder::psychBitAllocation () // perceptual bit-allocation via s
const unsigned sfbIdx = s - sfbStart;
m_sfbLoudMem[ch][sfbIdx][m_frameCount & 31] = __max (BA_EPS, uint16_t (sqrt (rmsValue)));
if (grpRms[s] < getThr (ch, sfbIdx)) grpData.scaleFactors[s + m_numSwbShort * gr] = 0;
if (grpRms[s] < (getThr (ch, sfbIdx) >> (samplingRate >> 13))) grpData.scaleFactors[s + m_numSwbShort * gr] = 0;
}
}
else if ((m_bitRateMode <= 4) && (meanSpecFlat[ci] <= (SCHAR_MAX >> 1))) // lo
@ -1424,7 +1470,7 @@ unsigned ExhaleEncoder::spectralProcessing () // complete ics_info(), calc TNS
m_specAnalyzer.getSpectralBandwidth (m_bandwidPrev, nChannels);
// spectral analysis for current MCLT signal (windowed time-samples for the current frame)
errorValue |= m_specAnalyzer.spectralAnalysis (m_mdctSignals, m_mdstSignals, nChannels, nSamplesInFrame, samplingRate, lfeChannelIndex);
errorValue |= m_specAnalyzer.spectralAnalysis (m_mdctSignals, m_mdstSignals, nChannels, nSamplesInFrame, samplingRate, lfeChannelIndex, SFB_QUANT_PERCEPT_OPT);
// get spectral channel statistics for this frame, used for perceptual model & BW detector
m_specAnalyzer.getSpecAnalysisStats (m_specAnaCurr, nChannels);
@ -1518,7 +1564,7 @@ unsigned ExhaleEncoder::spectralProcessing () // complete ics_info(), calc TNS
}
icsCurr.maxSfb = __min (icsCurr.maxSfb, brModeAndFsToMaxSfbLong (m_bitRateMode, samplingRate));
}
#if SFB_QUANT_PERCEPT_OPT && !EE_MORE_MSE
#if !EE_MORE_MSE
while (grpSO[icsCurr.maxSfb] > __max (m_bandwidCurr[ci], m_bandwidPrev[ci]) + (icsCurr.maxSfb >> 1)) icsCurr.maxSfb--; // detect BW
#endif
}
@ -1551,7 +1597,7 @@ unsigned ExhaleEncoder::spectralProcessing () // complete ics_info(), calc TNS
}
}
memcpy (grpData.windowGroupLength, windowGroupingTable[icsCurr.windowGrouping], NUM_WINDOW_GROUPS * sizeof (uint8_t));
#if SFB_QUANT_PERCEPT_OPT && !EE_MORE_MSE
#if !EE_MORE_MSE
findActualBandwidthShort (&icsCurr.maxSfb, grpSO, m_mdctSignals[ci], nChannels < 2 ? nullptr : m_mdstSignals[ci], nSamplesInShort);
#endif
errorValue |= eightShortGrouping (grpData, grpSO, m_mdctSignals[ci], nChannels < 2 ? nullptr : m_mdstSignals[ci]);
@ -2190,7 +2236,7 @@ unsigned ExhaleEncoder::initEncoder (unsigned char* const audioConfigBuffer, uin
m_elementData[el]->elementType = elementTypeConfig[chConf][el]; // usacElementType[el]
}
}
memset (m_sfbLoudMem, 1, 2 * 26 * 32 * sizeof (uint16_t));
memset (m_sfbLoudMem, SFB_QUANT_PERCEPT_OPT, 2 * 26 * 32 * sizeof (uint16_t));
// allocate all signal buffers
if (m_shiftValSBR > 0)

View File

@ -21,7 +21,7 @@
#define SF_THRESH_NEG 0.92044821 // round -1.5 dB
#define SF_THRESH_POS 1.09460356 // round +1.5 dB
#define SFB_QUANT_OFFSET 0.496094 // 13 - 29^(3/4)
#define SFB_QUANT_PERCEPT_OPT 1 // psych. quant.
#define SFB_QUANT_PERCEPT_OPT 2 // psych. quant.
#define QUANT_MAX 85 + (170 >> SFB_QUANT_PERCEPT_OPT)
// class for BL USAC quantization

View File

@ -1,11 +1,11 @@
/* specAnalysis.cpp - source file for class providing spectral analysis of MCLT signals
* written by C. R. Helmrich, last modified in 2021 - see License.htm for legal notices
* written by C. R. Helmrich, last modified in 2025 - 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-
* party rights, including patent rights. No such rights are granted under this License.
*
* Copyright (c) 2018-2021 Christian R. Helmrich, project ecodis. All rights reserved.
* Copyright (c) 2018-2025 Christian R. Helmrich, project ecodis. All rights reserved.
*/
#include "exhaleLibPch.h"
@ -228,11 +228,11 @@ unsigned SpecAnalyzer::optimizeGrouping (const unsigned channelIndex, const unsi
unsigned SpecAnalyzer::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,
const unsigned lfeChannelIndex /*= USAC_MAX_NUM_CHANNELS*/) // to skip an LFE channel
const unsigned lfeChannelIndex /*= USAC_MAX_NUM_CHANNELS*/, const unsigned scale /*= 2*/)
{
const uint64_t anaBwOffset = SA_BW >> 1;
const unsigned lpcStopBand16k = (samplingRate <= 32000 ? nSamplesInFrame : (32000 * nSamplesInFrame) / samplingRate) >> SA_BW_SHIFT;
const unsigned thresholdSlope = (48000 + SA_EPS * samplingRate) / 96000;
const unsigned thresholdSlope = (96000 + SA_EPS * scale * samplingRate) / 192000;
const unsigned thresholdStart = samplingRate >> 15;
if ((mdctSignals == nullptr) || (mdstSignals == nullptr) || (nChannels > USAC_MAX_NUM_CHANNELS) || (lfeChannelIndex > USAC_MAX_NUM_CHANNELS) ||

View File

@ -1,11 +1,11 @@
/* specAnalysis.h - header file for class providing spectral analysis of MCLT signals
* written by C. R. Helmrich, last modified in 2021 - see License.htm for legal notices
* written by C. R. Helmrich, last modified in 2025 - 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-
* party rights, including patent rights. No such rights are granted under this License.
*
* Copyright (c) 2018-2021 Christian R. Helmrich, project ecodis. All rights reserved.
* Copyright (c) 2018-2025 Christian R. Helmrich, project ecodis. All rights reserved.
*/
#ifndef _SPEC_ANALYSIS_H_
@ -54,7 +54,7 @@ public:
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,
const unsigned lfeChannelIndex = USAC_MAX_NUM_CHANNELS); // to skip an LFE channel
const unsigned lfeChannelIndex = USAC_MAX_NUM_CHANNELS, const unsigned scale = 2);
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,