aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDaniil Cherednik <dan.cherednik@gmail.com>2025-06-06 22:16:04 +0200
committerDaniil Cherednik <dan.cherednik@gmail.com>2025-06-06 22:16:04 +0200
commit5dded5cb759635827bd70d8f42295a643dc46087 (patch)
treea31359f1d5672281ada43015291e77fb50c3d89f
parent0a0ddd3dd1e9001299537577d5f3cb9e8cdd5739 (diff)
downloadatracdenc-5dded5cb759635827bd70d8f42295a643dc46087.tar.gz
[AT3P] Simple delta VLC encoding for wordlen.
-rw-r--r--src/atrac/at3p/at3p_bitstream.cpp109
-rw-r--r--src/atrac/at3p/at3p_bitstream_impl.h5
-rw-r--r--src/atrac/at3p/at3p_bitstream_ut.cpp2
-rw-r--r--src/atrac/at3p/at3p_tables.cpp5
-rw-r--r--src/atrac/at3p/at3p_tables.h2
5 files changed, 113 insertions, 10 deletions
diff --git a/src/atrac/at3p/at3p_bitstream.cpp b/src/atrac/at3p/at3p_bitstream.cpp
index f95018b..40e860f 100644
--- a/src/atrac/at3p/at3p_bitstream.cpp
+++ b/src/atrac/at3p/at3p_bitstream.cpp
@@ -133,22 +133,113 @@ IBitStreamPartEncoder::EStatus TConfigure::Encode(void* frameData, TBitAllocHand
return EStatus::Ok;
}
+size_t FindBestWlDeltaEncode(const int8_t* delta, uint32_t sz, size_t tableStart, size_t tableEndl) noexcept {
+ size_t best = 0;
+ size_t consumed = std::numeric_limits<size_t>::max();
+ static_assert(HuffTabs.WordLens.size() == 4, "unexpected wordlen huffman code table size");
+ for (size_t i = tableStart; i <= tableEndl; i++) {
+ const std::array<TVlcElement, 8>& wlTab = HuffTabs.WordLens[i];
+ size_t t = 0;
+ for (size_t j = 1; j < sz; j++) {
+ t += wlTab[delta[j]].Len;
+ }
+ if (t < consumed) {
+ consumed = t;
+ best = i;
+ }
+ }
+
+ return best;
+}
+
+void TWordLenEncoder::VlEncode(const std::array<TVlcElement, 8>& wlTab, size_t idx, size_t sz, const int8_t* data) noexcept {
+ Insert(3, 2); // 0 - constant number of bits, 3 - VLC
+ Insert(0, 2); // weight_idx
+ Insert(0, 2); // chan->num_coded_vals = ctx->num_quant_units;
+
+ Insert(idx, 2);
+ Insert(data[0], 3);
+ for (size_t i = 1; i < sz; i++) {
+ Insert(wlTab[data[i]].Code, wlTab[data[i]].Len);
+ }
+}
+
IBitStreamPartEncoder::EStatus TWordLenEncoder::Encode(void* frameData, TBitAllocHandler&) {
auto specFrame = TSpecFrame::Cast(frameData);
ASSERT(specFrame->WordLen.size() > specFrame->NumQuantUnits);
- for (size_t ch = 0; ch < specFrame->Chs.size(); ch++) {
- Insert(0, 2); // 0 - constant number of bits
+ int8_t deltasCh0[32];
+ //int8_t deltasCh1[32];
+ int8_t interChDeltas[32];
+ int8_t maxDeltaCh0 = 0;
+ //int8_t maxDeltaCh1 = 0;
+ int8_t maxInterChDelta;
- if (ch == 0) {
- for (size_t i = 0; i < specFrame->NumQuantUnits; i++) {
- Insert(specFrame->WordLen[i].first, 3);
- }
+ {
+ int8_t t = specFrame->WordLen[0].second - specFrame->WordLen[0].first;
+ maxInterChDelta = abs(t);
+ interChDeltas[0] = t & 7;
+ }
+
+ deltasCh0[0] = specFrame->WordLen[0].first;
+ //deltasCh1[0] = specFrame->WordLen[0].second;
+
+ for (size_t i = 1; i < specFrame->NumQuantUnits; i++) {
+ int8_t deltaCh0 = specFrame->WordLen[i].first - specFrame->WordLen[i-1].first;
+ //int8_t deltaCh1 = specFrame->WordLen[i].second - specFrame->WordLen[i-1].second;
+ int8_t t = specFrame->WordLen[i].second - specFrame->WordLen[i].first;
+ //0 - 7, so only 3 bits
+ maxDeltaCh0 |= abs(deltaCh0);
+ //maxDeltaCh1 |= abs(deltaCh1);
+ deltasCh0[i] = deltaCh0 & 7;
+ //deltasCh1[i] = deltaCh1 & 7;
+
+ maxInterChDelta |= abs(t);
+ interChDeltas[i] = t & 7;
+ }
+
+ {
+ size_t tableStart, tableEnd;
+ if (maxDeltaCh0 >= 3) {
+ tableStart = 2;
+ tableEnd = 3;
+ } else if (maxDeltaCh0 == 2) {
+ tableStart = 1;
+ tableEnd = 1;
} else {
- for (size_t i = 0; i < specFrame->NumQuantUnits; i++) {
- Insert(specFrame->WordLen[i].second, 3);
- }
+ tableStart = 0;
+ tableEnd = 0;
+ }
+
+ const size_t idx = FindBestWlDeltaEncode(deltasCh0, specFrame->NumQuantUnits, tableStart, tableEnd);
+ const std::array<TVlcElement, 8>& wlTab = HuffTabs.WordLens[idx];
+
+ VlEncode(wlTab, idx, specFrame->NumQuantUnits, deltasCh0);
+ }
+
+ if (specFrame->Chs.size() == 2) {
+ size_t tableStart, tableEnd;
+ if (maxInterChDelta >= 3) {
+ tableStart = 2;
+ tableEnd = 3;
+ } else if (maxInterChDelta == 2) {
+ tableStart = 1;
+ tableEnd = 1;
+ } else {
+ tableStart = 0;
+ tableEnd = 0;
+ }
+
+ const size_t idx = FindBestWlDeltaEncode(interChDeltas, specFrame->NumQuantUnits, tableStart, tableEnd);
+ const std::array<TVlcElement, 8>& wlTab = HuffTabs.WordLens[idx];
+
+ Insert(1, 2); // 0 - constant number of bits
+ Insert(0, 2); // chan->num_coded_vals = ctx->num_quant_units;
+
+ Insert(idx, 2);
+ for (size_t i = 0; i < specFrame->NumQuantUnits; i++) {
+ Insert(wlTab[interChDeltas[i]].Code, wlTab[interChDeltas[i]].Len);
}
}
diff --git a/src/atrac/at3p/at3p_bitstream_impl.h b/src/atrac/at3p/at3p_bitstream_impl.h
index 91b2df2..32316f2 100644
--- a/src/atrac/at3p/at3p_bitstream_impl.h
+++ b/src/atrac/at3p/at3p_bitstream_impl.h
@@ -26,6 +26,10 @@
namespace NAtracDEnc {
+namespace NAt3p {
+struct TVlcElement;
+}
+
struct TSpecFrame {
TSpecFrame(uint32_t sz, uint32_t numQuantUnits, size_t channels,
const TAt3PGhaData* tonalBlock,
@@ -90,6 +94,7 @@ public:
TWordLenEncoder() = default;
EStatus Encode(void* frameData, TBitAllocHandler& ba) override;
private:
+ void VlEncode(const std::array<NAt3p::TVlcElement, 8>& wlTab, size_t idx, size_t sz, const int8_t* data) noexcept;
};
class TSfIdxEncoder : public TDumper {
diff --git a/src/atrac/at3p/at3p_bitstream_ut.cpp b/src/atrac/at3p/at3p_bitstream_ut.cpp
index a4d7bd7..92feb17 100644
--- a/src/atrac/at3p/at3p_bitstream_ut.cpp
+++ b/src/atrac/at3p/at3p_bitstream_ut.cpp
@@ -134,6 +134,6 @@ TEST(AT3PBitstream, Wordlen) {
encoder.Do(&frame, bs);
- EXPECT_EQ(bs.GetSizeInBits(), 40);
+ EXPECT_EQ(bs.GetSizeInBits(), 28);
}
diff --git a/src/atrac/at3p/at3p_tables.cpp b/src/atrac/at3p/at3p_tables.cpp
index fee3417..0d0dcd8 100644
--- a/src/atrac/at3p/at3p_tables.cpp
+++ b/src/atrac/at3p/at3p_tables.cpp
@@ -112,6 +112,11 @@ THuffTables::THuffTables()
}
}
+ for (size_t i = 0, x = 0; i < WordLens.size(); i++) {
+ x += GenHuffmanEncTable(&atrac3p_wl_cbs[i][0], &atrac3p_wl_ct_xlats[x], WordLens[i]);
+ x += GenHuffmanEncTable(&atrac3p_ct_cbs[i][0], &atrac3p_wl_ct_xlats[x], CodeTables[i]);
+ }
+
for (int i = 0, x = 0; i < 112; i++) {
if (atrac3p_spectra_cbs[i][0] >= 0) {
x += GenHuffmanEncTable((uint8_t*)&atrac3p_spectra_cbs[i][0], &atrac3p_spectra_xlats[x], VlcSpecs[i]);
diff --git a/src/atrac/at3p/at3p_tables.h b/src/atrac/at3p/at3p_tables.h
index 0840273..ec4032f 100644
--- a/src/atrac/at3p/at3p_tables.h
+++ b/src/atrac/at3p/at3p_tables.h
@@ -37,6 +37,8 @@ struct THuffTables {
THuffTables();
std::array<TVlcElement, 16> NumToneBands;
std::array<std::array<TVlcElement, 256>, 112> VlcSpecs;
+ std::array<std::array<TVlcElement, 8>, 4> WordLens;
+ std::array<std::array<TVlcElement, 8>, 4> CodeTables;
};
struct TScaleTable {