aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorDaniil Cherednik <dan.cherednik@gmail.com>2024-12-07 22:13:42 +0100
committerDaniil Cherednik <dan.cherednik@gmail.com>2024-12-19 22:42:22 +0100
commite2605699b7c79a8cb5d06b0069f32c3b01d4ded4 (patch)
tree0e345479e391394c5571ec5fa76d15e3523c5ec2 /src
parent12dc4f2808637abaf0c8b36ac60802ab1565ac37 (diff)
downloadatracdenc-e2605699b7c79a8cb5d06b0069f32c3b01d4ded4.tar.gz
[AT3] Attempt to improve quality:
* Band energy aware quantization for high frequency bands * Energy aware bit allocation for low frequency bands * Tune bit allocation table and weight coefficients
Diffstat (limited to 'src')
-rw-r--r--src/atrac/atrac3_bitstream.cpp78
-rw-r--r--src/atrac/atrac3_bitstream.h2
-rw-r--r--src/atrac/atrac_scale.cpp24
-rw-r--r--src/atrac/atrac_scale.h2
-rw-r--r--src/atrac/atrac_scale_ut.cpp2
5 files changed, 82 insertions, 26 deletions
diff --git a/src/atrac/atrac3_bitstream.cpp b/src/atrac/atrac3_bitstream.cpp
index 3be3323..7163076 100644
--- a/src/atrac/atrac3_bitstream.cpp
+++ b/src/atrac/atrac3_bitstream.cpp
@@ -34,12 +34,26 @@ using std::vector;
using std::memset;
static const uint32_t FixedBitAllocTable[TAtrac3Data::MaxBfus] = {
- 5, 5, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
- 3, 3, 3, 3, 3, 3, 3, 3,
- 3, 2, 2, 1,
- 1, 0
+ 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 2, 2, 2, 2, 2, 1, 1, 1,
+ 1, 1, 1, 1,
+ 0, 0
};
+#define EAQ 1
+
+#ifdef EAQ
+
+static constexpr size_t LOSY_NAQ_START = 18;
+static constexpr size_t BOOST_NAQ_END = 10;
+
+#else
+
+static constexpr size_t LOSY_NAQ_START = 31;
+static constexpr size_t BOOST_NAQ_END = 0;
+
+#endif
+
std::vector<TFloat> TAtrac3BitStreamWriter::ATH;
TAtrac3BitStreamWriter::TAtrac3BitStreamWriter(ICompressedOutput* container, const TContainerParams& params, uint32_t bfuIdxConst)
: Container(container)
@@ -122,14 +136,14 @@ uint32_t TAtrac3BitStreamWriter::VLCEnc(const uint32_t selector, const int manti
std::pair<uint8_t, uint32_t> TAtrac3BitStreamWriter::CalcSpecsBitsConsumption(const TSingleChannelElement& sce,
- const vector<uint32_t>& precisionPerEachBlocks, int* mantisas)
+ const vector<uint32_t>& precisionPerEachBlocks, int* mantisas, vector<float>& energyErr)
{
const vector<TScaledBlock>& scaledBlocks = sce.ScaledBlocks;
const uint32_t numBlocks = precisionPerEachBlocks.size();
uint32_t bitsUsed = numBlocks * 3;
- auto lambda = [this, numBlocks, mantisas, &precisionPerEachBlocks, &scaledBlocks](bool clcMode, bool calcMant) {
+ auto lambda = [this, numBlocks, mantisas, &precisionPerEachBlocks, &scaledBlocks, &energyErr](bool clcMode, bool calcMant) {
uint32_t bits = 0;
for (uint32_t i = 0; i < numBlocks; ++i) {
if (precisionPerEachBlocks[i] == 0)
@@ -141,7 +155,7 @@ std::pair<uint8_t, uint32_t> TAtrac3BitStreamWriter::CalcSpecsBitsConsumption(co
const TFloat mul = MaxQuant[std::min(precisionPerEachBlocks[i], (uint32_t)7)];
if (calcMant) {
const TFloat* values = scaledBlocks[i].Values.data();
- QuantMantisas(values, first, last, mul, mantisas);
+ energyErr[i] = QuantMantisas(values, first, last, mul, i > LOSY_NAQ_START, mantisas);
}
bits += clcMode ? CLCEnc(precisionPerEachBlocks[i], mantisas + first, blockSize, nullptr) :
VLCEnc(precisionPerEachBlocks[i], mantisas + first, blockSize, nullptr);
@@ -171,8 +185,27 @@ static inline bool CheckBfus(uint16_t* numBfu, const vector<uint32_t>& precision
static const std::pair<uint8_t, vector<uint32_t>> DUMMY_ALLOC{1, vector<uint32_t>{0}};
+bool ConsiderEnergyErr(const vector<float>& err, vector<uint32_t>& bits)
+{
+ if (err.size() < bits.size())
+ abort();
+
+ bool adjusted = false;
+ size_t lim = std::min((size_t)BOOST_NAQ_END, bits.size());
+ for (size_t i = 0; i < lim; i++) {
+ float e = err[i];
+ if (((e > 0 && e < 0.7) || e > 1.2) & (bits[i] < 7)) {
+ //std::cerr << "adjust: " << i << " e: " << e << " b: " << bits[i] << std::endl;
+ bits[i]++;
+ adjusted = true;
+ }
+ }
+
+ return adjusted;
+}
+
std::pair<uint8_t, vector<uint32_t>> TAtrac3BitStreamWriter::CreateAllocation(const TSingleChannelElement& sce,
- const uint16_t targetBits, int mt[MaxSpecs], float laudness)
+ const uint16_t targetBits, int mt[MaxSpecs], float laudness)
{
const vector<TScaledBlock>& scaledBlocks = sce.ScaledBlocks;
if (scaledBlocks.empty()) {
@@ -193,6 +226,7 @@ std::pair<uint8_t, vector<uint32_t>> TAtrac3BitStreamWriter::CreateAllocation(co
}
vector<uint32_t> precisionPerEachBlocks(numBfu);
+ vector<float> energyErr(numBfu);
uint8_t mode;
bool cont = true;
while (cont) {
@@ -201,11 +235,17 @@ std::pair<uint8_t, vector<uint32_t>> TAtrac3BitStreamWriter::CreateAllocation(co
TFloat minShift = -8;
for (;;) {
TFloat shift = (maxShift + minShift) / 2;
- const vector<uint32_t>& tmpAlloc = CalcBitsAllocation(scaledBlocks, numBfu, spread, shift, laudness);
- auto consumption = CalcSpecsBitsConsumption(sce, tmpAlloc, mt);
+ vector<uint32_t> tmpAlloc = CalcBitsAllocation(scaledBlocks, numBfu, spread, shift, laudness);
+ energyErr.clear();
+ energyErr.resize(numBfu);
+ std::pair<uint8_t, uint32_t> consumption;
+
+ do {
+ consumption = CalcSpecsBitsConsumption(sce, tmpAlloc, mt, energyErr);
+ } while (ConsiderEnergyErr(energyErr, tmpAlloc));
auto bitsUsedByTonal = EncodeTonalComponents(sce, tmpAlloc, nullptr);
-// std::cerr << consumption.second << " |tonal: " << bitsUsedByTonal << " target: " << targetBits << " shift " << shift << " max | min " << maxShift << " " << minShift << " numBfu: " << numBfu << std::endl;
+ //std::cerr << consumption.second << " |tonal: " << bitsUsedByTonal << " target: " << targetBits << " shift " << shift << " max | min " << maxShift << " " << minShift << " numBfu: " << numBfu << std::endl;
consumption.second += bitsUsedByTonal;
if (consumption.second < targetBits) {
@@ -471,11 +511,25 @@ vector<uint32_t> TAtrac3BitStreamWriter::CalcBitsAllocation(const std::vector<TS
bitsPerEachBlock[i] = 0;
} else {
const uint32_t fix = FixedBitAllocTable[i];
- int tmp = spread * ( (TFloat)scaledBlocks[i].ScaleFactorIndex/3.2) + (1.0 - spread) * fix - shift;
+ float x = 6;
+ if (i < 3) {
+ x = 2.8;
+ } else if (i < 10) {
+ x = 2.6;
+ } else if (i < 15) {
+ x = 3.3;
+ } else if (i <= 20) {
+ x = 3.6;
+ } else if (i <= 28) {
+ x = 4.2;
+ }
+ int tmp = spread * ( (TFloat)scaledBlocks[i].ScaleFactorIndex / x) + (1.0 - spread) * fix - shift;
if (tmp > 7) {
bitsPerEachBlock[i] = 7;
} else if (tmp < 0) {
bitsPerEachBlock[i] = 0;
+ } else if (tmp == 0) {
+ bitsPerEachBlock[i] = 1;
} else {
bitsPerEachBlock[i] = tmp;
}
diff --git a/src/atrac/atrac3_bitstream.h b/src/atrac/atrac3_bitstream.h
index e67f726..71ff3e0 100644
--- a/src/atrac/atrac3_bitstream.h
+++ b/src/atrac/atrac3_bitstream.h
@@ -73,7 +73,7 @@ private:
std::pair<uint8_t, uint32_t> CalcSpecsBitsConsumption(const TSingleChannelElement& sce,
const std::vector<uint32_t>& precisionPerEachBlocks,
- int* mantisas);
+ int* mantisas, std::vector<float>& energyErr);
void EncodeSpecs(const TSingleChannelElement& sce, NBitStream::TBitStream* bitStream,
const std::pair<uint8_t, std::vector<uint32_t>>&, const int mt[MaxSpecs]);
diff --git a/src/atrac/atrac_scale.cpp b/src/atrac/atrac_scale.cpp
index 05d8c66..eae1d45 100644
--- a/src/atrac/atrac_scale.cpp
+++ b/src/atrac/atrac_scale.cpp
@@ -36,7 +36,7 @@ using std::abs;
static const TFloat MAX_SCALE = 1.0;
-void QuantMantisas(const TFloat* in, const uint32_t first, const uint32_t last, const TFloat mul, int* const mantisas)
+TFloat QuantMantisas(const TFloat* in, const uint32_t first, const uint32_t last, const TFloat mul, bool ea, int* const mantisas)
{
float e1 = 0.0;
float e2 = 0.0;
@@ -52,18 +52,19 @@ void QuantMantisas(const TFloat* in, const uint32_t first, const uint32_t last,
mantisas[f] = ToInt(t);
e2 += mantisas[f] * mantisas[f] * inv2;
- float delta = t - (std::trunc(t) + 0.5);
-
- // 0 ... 0.25 ... 0.5 ... 0.75 ... 1
- // ^----------------^ candidates to be rounded to opposite side
- // to decrease overall energy error in the band
- if (std::abs(delta) < 0.25) {
- candidates.push_back({delta, f});
+ if (ea) {
+ float delta = t - (std::trunc(t) + 0.5);
+ // 0 ... 0.25 ... 0.5 ... 0.75 ... 1
+ // ^----------------^ candidates to be rounded to opposite side
+ // to decrease overall energy error in the band
+ if (std::abs(delta) < 0.25) {
+ candidates.push_back({delta, f});
+ }
}
}
if (candidates.empty()) {
- return;
+ return e1 / e2;
}
static auto cmp = [](const std::pair<float, int>& a, const std::pair<float, int>& b) {
@@ -91,7 +92,7 @@ void QuantMantisas(const TFloat* in, const uint32_t first, const uint32_t last,
}
}
}
- return;
+ return e1 / e2;
}
if (e2 > e1) {
@@ -114,8 +115,9 @@ void QuantMantisas(const TFloat* in, const uint32_t first, const uint32_t last,
}
}
}
- return;
+ return e1 / e2;
}
+ return e1 / e2;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
diff --git a/src/atrac/atrac_scale.h b/src/atrac/atrac_scale.h
index cd94af8..0289961 100644
--- a/src/atrac/atrac_scale.h
+++ b/src/atrac/atrac_scale.h
@@ -27,7 +27,7 @@
namespace NAtracDEnc {
-void QuantMantisas(const TFloat* in, uint32_t first, uint32_t last, TFloat mul, int* mantisas);
+TFloat QuantMantisas(const TFloat* in, uint32_t first, uint32_t last, TFloat mul, bool ea, int* mantisas);
struct TScaledBlock {
TScaledBlock(uint8_t sfi) : ScaleFactorIndex(sfi) {}
diff --git a/src/atrac/atrac_scale_ut.cpp b/src/atrac/atrac_scale_ut.cpp
index afc627a..3d64231 100644
--- a/src/atrac/atrac_scale_ut.cpp
+++ b/src/atrac/atrac_scale_ut.cpp
@@ -53,7 +53,7 @@ TEST(Quant, SaveEnergyLost) {
std::vector<int> mantisas;
mantisas.resize(in.size());
- QuantMantisas(scaled.data(), 0, mantisas.size(), td.Q, mantisas.data());
+ QuantMantisas(scaled.data(), 0, mantisas.size(), td.Q, true, mantisas.data());
float e2 = 0.0;
for (auto x : mantisas) {