diff options
author | Daniil Cherednik <dan.cherednik@gmail.com> | 2025-06-06 22:16:04 +0200 |
---|---|---|
committer | Daniil Cherednik <dan.cherednik@gmail.com> | 2025-06-06 22:16:04 +0200 |
commit | 5dded5cb759635827bd70d8f42295a643dc46087 (patch) | |
tree | a31359f1d5672281ada43015291e77fb50c3d89f | |
parent | 0a0ddd3dd1e9001299537577d5f3cb9e8cdd5739 (diff) | |
download | atracdenc-5dded5cb759635827bd70d8f42295a643dc46087.tar.gz |
[AT3P] Simple delta VLC encoding for wordlen.
-rw-r--r-- | src/atrac/at3p/at3p_bitstream.cpp | 109 | ||||
-rw-r--r-- | src/atrac/at3p/at3p_bitstream_impl.h | 5 | ||||
-rw-r--r-- | src/atrac/at3p/at3p_bitstream_ut.cpp | 2 | ||||
-rw-r--r-- | src/atrac/at3p/at3p_tables.cpp | 5 | ||||
-rw-r--r-- | src/atrac/at3p/at3p_tables.h | 2 |
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 { |