aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorDaniil Cherednik <dan.cherednik@gmail.com>2025-05-03 22:07:17 +0200
committerDaniil Cherednik <dan.cherednik@gmail.com>2025-05-03 22:07:17 +0200
commit98338613d8821f592682928c1096550596cb2550 (patch)
treeabc2318c96ee2a14f06ba1028fb8663f6a6ee35a /src
parent177622ee9513784a21d9f10ab0c1e9774c0ddc71 (diff)
downloadatracdenc-98338613d8821f592682928c1096550596cb2550.tar.gz
[AT3P] Adjust number of quant units during encoding.
Diffstat (limited to 'src')
-rw-r--r--src/atrac/at3p/at3p_bitstream.cpp172
-rw-r--r--src/atrac/at3p/at3p_bitstream.h1
-rw-r--r--src/atrac/at3p/at3p_bitstream_impl.h34
-rw-r--r--src/atrac/at3p/at3p_bitstream_ut.cpp2
-rw-r--r--src/lib/bs_encode/encode.cpp20
-rw-r--r--src/lib/bs_encode/encode.h6
-rw-r--r--src/lib/bs_encode/encode_ut.cpp16
7 files changed, 179 insertions, 72 deletions
diff --git a/src/atrac/at3p/at3p_bitstream.cpp b/src/atrac/at3p/at3p_bitstream.cpp
index f00fe31..f95018b 100644
--- a/src/atrac/at3p/at3p_bitstream.cpp
+++ b/src/atrac/at3p/at3p_bitstream.cpp
@@ -92,32 +92,30 @@ TTonePackResult CreateFreqBitPack(const TAt3PGhaData::TWaveParam* const param, i
}
}
-size_t TDumper::GetConsumption() const noexcept
+uint32_t TDumper::GetConsumption() const noexcept
{
return std::accumulate(Buf.begin(), Buf.end(), 0,
- [](size_t acc, const std::pair<uint8_t, uint8_t>& x) noexcept -> size_t { return acc + x.second; });
+ [](uint32_t acc, const std::pair<uint16_t, uint8_t>& x) noexcept -> uint32_t { return acc + x.second; });
}
IBitStreamPartEncoder::EStatus TConfigure::Encode(void* frameData, TBitAllocHandler&)
{
TSpecFrame* frame = TSpecFrame::Cast(frameData);
- size_t numQuantUnits = 28;
- frame->NumQuantUnits = numQuantUnits;
- frame->WordLen.resize(numQuantUnits);
+ frame->WordLen.resize(frame->NumQuantUnits);
for (size_t i = 0; i < frame->WordLen.size(); i++) {
static uint8_t allocTable[32] = {
- 7, 7, 7, 7, 7, 6, 6, 6,
- 6, 6, 6, 5, 5, 5, 5, 5,
- 5, 5, 5, 5, 5, 5, 5, 4,
- 3, 2, 1, 1, 1, 1, 1, 1
+ 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 6, 6, 6, 6, 6, 6, 6,
+ 6, 6, 5, 5, 4, 3, 2, 1
};
frame->WordLen[i].first = allocTable[i];
frame->WordLen[i].second = allocTable[i];
}
- frame->SfIdx.resize(numQuantUnits);
+ frame->SfIdx.resize(frame->NumQuantUnits);
for (size_t i = 0; i < frame->SfIdx.size(); i++) {
frame->SfIdx[i].first = frame->Chs[0].ScaledBlocks.at(i).ScaleFactorIndex;
@@ -125,9 +123,9 @@ IBitStreamPartEncoder::EStatus TConfigure::Encode(void* frameData, TBitAllocHand
frame->SfIdx[i].second = frame->Chs[1].ScaledBlocks.at(i).ScaleFactorIndex;
}
- frame->SpecTabIdx.resize(numQuantUnits);
+ frame->SpecTabIdx.resize(frame->NumQuantUnits);
- Insert(numQuantUnits - 1, 5);
+ Insert(frame->NumQuantUnits - 1, 5);
Insert(0, 1); //mute flag
frame->AllocatedBits = GetConsumption();
@@ -381,6 +379,7 @@ static std::vector<IBitStreamPartEncoder::TPtr> CreateEncParts()
parts.emplace_back(new TWordLenEncoder());
parts.emplace_back(new TSfIdxEncoder());
parts.emplace_back(new TQuantUnitsEncoder());
+ parts.emplace_back(new TTonalComponentEncoder());
return parts;
}
@@ -388,52 +387,53 @@ static std::vector<IBitStreamPartEncoder::TPtr> CreateEncParts()
TAt3PBitStream::TAt3PBitStream(ICompressedOutput* container, uint16_t frameSz)
: Container(container)
, Encoder(CreateEncParts())
+ , FrameSzToAllocBits((uint32_t)frameSz * 8 - 3) //Size of frame in bits for allocation. 3 bits is start bit and channel configuration
, FrameSz(frameSz)
{
NEnv::SetRoundFloat();
}
-static void WriteSubbandFlags(NBitStream::TBitStream& bs, const bool* flags, int numFlags)
+void TTonalComponentEncoder::WriteSubbandFlags(const bool* flags, size_t numFlags)
{
- int sum = 0;
- for (int i = 0; i < numFlags; i++) {
+ size_t sum = 0;
+ for (size_t i = 0; i < numFlags; i++) {
sum += (uint32_t)flags[i];
}
if (sum == 0) {
- bs.Write(0, 1);
+ Insert(0, 1);
} else if (sum == numFlags) {
- bs.Write(1, 1);
- bs.Write(0, 1);
+ Insert(1, 1);
+ Insert(0, 1);
} else {
- bs.Write(1, 1);
- bs.Write(1, 1);
- for (int i = 0; i < numFlags; i++) {
- bs.Write(flags[i], 1);
+ Insert(1, 1);
+ Insert(1, 1);
+ for (size_t i = 0; i < numFlags; i++) {
+ Insert(flags[i], 1);
}
}
}
-static void WriteTonalBlock(NBitStream::TBitStream& bs, int channels, const TAt3PGhaData* tonalBlock)
+void TTonalComponentEncoder::WriteTonalBlock(size_t channels, const TAt3PGhaData* tonalBlock)
{
//GHA amplidude mode 1
- bs.Write(1, 1);
+ Insert(1, 1);
//Num tone bands
const TVlcElement& tbHuff = HuffTabs.NumToneBands[tonalBlock->NumToneBands - 1];
- bs.Write(tbHuff.Code, tbHuff.Len);
+ Insert(tbHuff.Code, tbHuff.Len);
if (channels == 2) {
- WriteSubbandFlags(bs, tonalBlock->ToneSharing, tonalBlock->NumToneBands);
- WriteSubbandFlags(bs, &tonalBlock->SecondIsLeader, 1);
- bs.Write(0, 1);
+ WriteSubbandFlags(tonalBlock->ToneSharing, tonalBlock->NumToneBands);
+ WriteSubbandFlags(&tonalBlock->SecondIsLeader, 1);
+ Insert(0, 1);
}
- for (int ch = 0; ch < channels; ch++) {
+ for (size_t ch = 0; ch < channels; ch++) {
if (ch) {
// each channel has own envelope
- bs.Write(0, 1);
+ Insert(0, 1);
}
// Envelope data
for (int i = 0; i < tonalBlock->NumToneBands; i++) {
@@ -445,35 +445,35 @@ static void WriteTonalBlock(NBitStream::TBitStream& bs, int channels, const TAt3
if (envelope.first != TAt3PGhaData::EMPTY_POINT) {
// start point present
- bs.Write(1, 1);
- bs.Write(envelope.first, 5);
+ Insert(1, 1);
+ Insert(envelope.first, 5);
} else {
- bs.Write(0, 1);
+ Insert(0, 1);
}
if (envelope.second != TAt3PGhaData::EMPTY_POINT) {
// stop point present
- bs.Write(1, 1);
- bs.Write(envelope.second, 5);
+ Insert(1, 1);
+ Insert(envelope.second, 5);
} else {
- bs.Write(0, 1);
+ Insert(0, 1);
}
}
// Num waves
int mode = 0; //TODO: Calc mode
- bs.Write(mode, ch + 1);
+ Insert(mode, ch + 1);
for (int i = 0; i < tonalBlock->NumToneBands; i++) {
if (ch && tonalBlock->ToneSharing[i]) {
continue;
}
- bs.Write(tonalBlock->GetNumWaves(ch, i), 4);
+ Insert(tonalBlock->GetNumWaves(ch, i), 4);
}
// Tones freq
if (ch) {
// 0 - independed
// 1 - delta to leader
- bs.Write(0, 1);
+ Insert(0, 1);
}
for (int i = 0; i < tonalBlock->NumToneBands; i++) {
@@ -490,17 +490,17 @@ static void WriteTonalBlock(NBitStream::TBitStream& bs, int channels, const TAt3
const auto pkt = CreateFreqBitPack(w.first, w.second);
if (numWaves > 1) {
- bs.Write(static_cast<bool>(pkt.Order), 1);
+ Insert(static_cast<bool>(pkt.Order), 1);
}
for (const auto& d : pkt.Data) {
- bs.Write(d.Code, d.Bits);
+ Insert(d.Code, d.Bits);
}
}
// Amplitude
mode = 0; //TODO: Calc mode
- bs.Write(mode, ch + 1);
+ Insert(mode, ch + 1);
for (int i = 0; i < tonalBlock->NumToneBands; i++) {
if (ch && tonalBlock->ToneSharing[i]) {
@@ -514,7 +514,7 @@ static void WriteTonalBlock(NBitStream::TBitStream& bs, int channels, const TAt3
const auto w = tonalBlock->GetWaves(ch, i);
for (size_t j = 0; j < numWaves; j++) {
- bs.Write(w.first[j].AmpSf, 6);
+ Insert(w.first[j].AmpSf, 6);
}
}
@@ -531,52 +531,92 @@ static void WriteTonalBlock(NBitStream::TBitStream& bs, int channels, const TAt3
const auto w = tonalBlock->GetWaves(ch, i);
for (size_t j = 0; j < w.second; j++) {
- bs.Write(w.first[j].PhaseIndex, 5);
+ Insert(w.first[j].PhaseIndex, 5);
}
}
}
}
-void TAt3PBitStream::WriteFrame(int channels, const TAt3PGhaData* tonalBlock, const std::vector<std::vector<TScaledBlock>>& scaledBlocks)
+IBitStreamPartEncoder::EStatus TTonalComponentEncoder::CheckFrameDone(TSpecFrame* frame, TBitAllocHandler& ba) noexcept
{
- NBitStream::TBitStream bitStream;
- // First bit must be zero
- bitStream.Write(0, 1);
- // Channel block type
- // 0 - MONO block
- // 1 - STEREO block
- // 2 - Nobody know
- bitStream.Write(channels - 1, 2);
+ uint32_t totalConsumption = BitsUsed + ba.GetCurGlobalConsumption();
- TSpecFrame frame(FrameSz * 8, channels, scaledBlocks);
+ if (totalConsumption > frame->SizeBits) {
+ if (frame->NumQuantUnits == 32) {
+ frame->NumQuantUnits = 28;
+ } else {
+ frame->NumQuantUnits--;
+ }
+ return EStatus::Repeat;
+ }
+ return EStatus::Ok;
+}
- Encoder.Do(&frame, bitStream);
+IBitStreamPartEncoder::EStatus TTonalComponentEncoder::Encode(void* frameData, TBitAllocHandler& ba)
+{
+ auto specFrame = TSpecFrame::Cast(frameData);
+ auto tonalBlock = specFrame->TonalBlock;
- if (channels == 2) {
- bitStream.Write(0, 2); //swap_channels and negate_coeffs
+ // Check tonal component already encoded
+ if (BitsUsed != 0) {
+ if (tonalBlock && tonalBlock->NumToneBands > specFrame->NumQuantUnits) {
+ std::cerr << "TODO" << std::endl;
+ abort();
+ }
+ return CheckFrameDone(specFrame, ba);
+ }
+
+ const size_t chNum = specFrame->Chs.size();
+
+ if (chNum == 2) {
+ Insert(0, 2); //swap_channels and negate_coeffs
}
- for (size_t ch = 0; ch < frame.Chs.size(); ch++) {
- bitStream.Write(0, 1); // window shape
+ for (size_t ch = 0; ch < chNum; ch++) {
+ Insert(0, 1); // window shape
}
- for (size_t ch = 0; ch < frame.Chs.size(); ch++) {
- bitStream.Write(0, 1); //gain comp
+ for (size_t ch = 0; ch < chNum; ch++) {
+ Insert(0, 1); //gain comp
}
if (tonalBlock && tonalBlock->NumToneBands) {
- bitStream.Write(1, 1);
- WriteTonalBlock(bitStream, channels, tonalBlock);
+ Insert(1, 1);
+ WriteTonalBlock(chNum, tonalBlock);
} else {
- bitStream.Write(0, 1);
+ Insert(0, 1);
}
- bitStream.Write(0, 1); // no noise info
+ Insert(0, 1); // no noise info
// Terminator
- bitStream.Write(3, 2);
+ Insert(3, 2);
+
+ BitsUsed = GetConsumption();
+
+ return CheckFrameDone(specFrame, ba);
+}
+
+void TAt3PBitStream::WriteFrame(int channels, const TAt3PGhaData* tonalBlock, const std::vector<std::vector<TScaledBlock>>& scaledBlocks)
+{
+ NBitStream::TBitStream bitStream;
+ // First bit must be zero
+ bitStream.Write(0, 1);
+ // Channel block type
+ // 0 - MONO block
+ // 1 - STEREO block
+ // 2 - Nobody know
+ bitStream.Write(channels - 1, 2);
+
+ const uint32_t initialNumQuantUnits = 32;
+
+ TSpecFrame frame(FrameSzToAllocBits, initialNumQuantUnits, channels, tonalBlock, scaledBlocks);
+
+ Encoder.Do(&frame, bitStream);
std::vector<char> buf = bitStream.GetBytes();
+ ASSERT(bitStream.GetSizeInBits() > FrameSz * 8);
+
buf.resize(FrameSz);
Container->WriteFrame(buf);
}
diff --git a/src/atrac/at3p/at3p_bitstream.h b/src/atrac/at3p/at3p_bitstream.h
index 4baba4d..c42a151 100644
--- a/src/atrac/at3p/at3p_bitstream.h
+++ b/src/atrac/at3p/at3p_bitstream.h
@@ -52,6 +52,7 @@ public:
private:
ICompressedOutput* Container;
TBitStreamEncoder Encoder;
+ const uint32_t FrameSzToAllocBits;
const uint16_t FrameSz;
};
diff --git a/src/atrac/at3p/at3p_bitstream_impl.h b/src/atrac/at3p/at3p_bitstream_impl.h
index 52a86a5..91b2df2 100644
--- a/src/atrac/at3p/at3p_bitstream_impl.h
+++ b/src/atrac/at3p/at3p_bitstream_impl.h
@@ -18,6 +18,7 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
+#include "atrac/at3p/at3p_gha.h"
#include <lib/bitstream/bitstream.h>
#include <lib/bs_encode/encode.h>
#include <atrac/atrac_scale.h>
@@ -26,9 +27,12 @@
namespace NAtracDEnc {
struct TSpecFrame {
- TSpecFrame(size_t sz, size_t channels,
+ TSpecFrame(uint32_t sz, uint32_t numQuantUnits, size_t channels,
+ const TAt3PGhaData* tonalBlock,
const std::vector<std::vector<TScaledBlock>>& scaledBlocks)
: SizeBits(sz)
+ , NumQuantUnits(numQuantUnits)
+ , TonalBlock(tonalBlock)
, AllocatedBits(0)
{
Chs.reserve(channels);
@@ -37,8 +41,9 @@ struct TSpecFrame {
}
}
- const size_t SizeBits;
- size_t NumQuantUnits;
+ const uint32_t SizeBits;
+ uint32_t NumQuantUnits;
+ const TAt3PGhaData* TonalBlock;
std::vector<std::pair<uint8_t, uint8_t>> WordLen;
std::vector<std::pair<uint8_t, uint8_t>> SfIdx;
std::vector<std::pair<uint8_t, uint8_t>> SpecTabIdx;
@@ -63,8 +68,12 @@ public:
}
Buf.clear();
}
+ void Reset() noexcept override {
+ Buf.clear();
+ }
+ uint32_t GetConsumption() const noexcept override;
protected:
- size_t GetConsumption() const noexcept;
+
// value, nbits
void Insert(uint16_t value, uint8_t nbits) { Buf.emplace_back(std::make_pair(value, nbits)); }
std::vector<std::pair<uint16_t, uint8_t>> Buf;
@@ -120,4 +129,21 @@ private:
std::map<size_t, TUnit> UnitBuffers;
};
+class TTonalComponentEncoder : public TDumper {
+public:
+ TTonalComponentEncoder() = default;
+ EStatus Encode(void* frameData, TBitAllocHandler& ba) override;
+ //TODO: find the common way
+ void Dump(NBitStream::TBitStream& bs) override {
+ TDumper::Dump(bs);
+ BitsUsed = 0;
+ }
+private:
+ EStatus CheckFrameDone(TSpecFrame* frame, TBitAllocHandler& ba) noexcept;
+ void WriteTonalBlock(size_t channels, const TAt3PGhaData* tonalBlock);
+ void WriteSubbandFlags(const bool* flags, size_t numFlags);
+ size_t BitsUsed = 0;
+};
+
+
}
diff --git a/src/atrac/at3p/at3p_bitstream_ut.cpp b/src/atrac/at3p/at3p_bitstream_ut.cpp
index ddc33f3..a4d7bd7 100644
--- a/src/atrac/at3p/at3p_bitstream_ut.cpp
+++ b/src/atrac/at3p/at3p_bitstream_ut.cpp
@@ -128,7 +128,7 @@ TEST(AT3PBitstream, Wordlen) {
std::vector<std::vector<TScaledBlock>> scaledBlocks;
scaledBlocks.resize(2);
- TSpecFrame frame(444, 2, scaledBlocks);
+ TSpecFrame frame(444, 28, 2, nullptr, scaledBlocks);
FillFrameData(frame);
diff --git a/src/lib/bs_encode/encode.cpp b/src/lib/bs_encode/encode.cpp
index 4c17ce9..230ae0f 100644
--- a/src/lib/bs_encode/encode.cpp
+++ b/src/lib/bs_encode/encode.cpp
@@ -32,6 +32,7 @@ public:
void DoSubmit(size_t gotBits) noexcept;
bool DoCheck(size_t gotBits) const noexcept;
void DoRun(void* frameData, TBitStream& bs);
+ uint32_t DoGetCurGlobalConsumption() const noexcept;
private:
std::vector<IBitStreamPartEncoder::TPtr> Encoders;
size_t CurEncPos;
@@ -109,6 +110,9 @@ void TBitStreamEncoder::TImpl::DoRun(void* frameData, TBitStream& bs)
}
if (status == IBitStreamPartEncoder::EStatus::Repeat) {
cont = true;
+ for (size_t i = 0; i < CurEncPos; i++) {
+ Encoders[i]->Reset();
+ }
RepeatEncPos = 0;
break;
}
@@ -120,6 +124,15 @@ void TBitStreamEncoder::TImpl::DoRun(void* frameData, TBitStream& bs)
}
}
+uint32_t TBitStreamEncoder::TImpl::DoGetCurGlobalConsumption() const noexcept
+{
+ uint32_t consumption = 0;
+ for (size_t i = 0; i < CurEncPos; i++) {
+ consumption += Encoders[i]->GetConsumption();
+ }
+ return consumption;
+}
+
/////
TBitStreamEncoder::TBitStreamEncoder(std::vector<IBitStreamPartEncoder::TPtr>&& encoders)
@@ -161,4 +174,11 @@ bool TBitAllocHandler::Check(size_t gotBits) const noexcept
const TBitStreamEncoder::TImpl* self = static_cast<const TBitStreamEncoder::TImpl*>(this);
return self->DoCheck(gotBits);
}
+
+uint32_t TBitAllocHandler::GetCurGlobalConsumption() const noexcept
+{
+ const TBitStreamEncoder::TImpl* self = static_cast<const TBitStreamEncoder::TImpl*>(this);
+ return self->DoGetCurGlobalConsumption();
+}
+
}
diff --git a/src/lib/bs_encode/encode.h b/src/lib/bs_encode/encode.h
index 9671e10..3302d10 100644
--- a/src/lib/bs_encode/encode.h
+++ b/src/lib/bs_encode/encode.h
@@ -34,6 +34,9 @@ public:
float Continue() noexcept;
bool Check(size_t gitBits) const noexcept;
void Submit(size_t gotBits) noexcept;
+
+ // Returns consumption of all previous encoded parts (except part from this method called)
+ uint32_t GetCurGlobalConsumption() const noexcept;
};
class IBitStreamPartEncoder {
@@ -47,7 +50,8 @@ public:
virtual ~IBitStreamPartEncoder() = default;
virtual EStatus Encode(void* frameData, TBitAllocHandler& ba) = 0;
virtual void Dump(NBitStream::TBitStream& bs) = 0;
-
+ virtual void Reset() noexcept {};
+ virtual uint32_t GetConsumption() const noexcept = 0;
};
class TBitStreamEncoder {
diff --git a/src/lib/bs_encode/encode_ut.cpp b/src/lib/bs_encode/encode_ut.cpp
index e9293a2..39f0ff1 100644
--- a/src/lib/bs_encode/encode_ut.cpp
+++ b/src/lib/bs_encode/encode_ut.cpp
@@ -47,6 +47,10 @@ public:
void Dump(NBitStream::TBitStream& bs) override {
EXPECT_EQ(EncCalls, ExpCalls);
}
+
+ uint32_t GetConsumption() const noexcept override {
+ return 0;
+ }
private:
const size_t ExpCalls;
size_t EncCalls = 0;
@@ -74,6 +78,10 @@ public:
bs.Write(1, 1);
}
}
+
+ uint32_t GetConsumption() const noexcept override {
+ return 1 * Bits;
+ }
private:
const size_t ExpCalls;
size_t EncCalls = 0;
@@ -94,6 +102,10 @@ public:
void Dump(NBitStream::TBitStream& bs) override {
EXPECT_EQ(EncCalls, ExpCalls);
}
+
+ uint32_t GetConsumption() const noexcept override {
+ return 0;
+ }
private:
const size_t ExpCalls;
size_t EncCalls = 0;
@@ -115,6 +127,10 @@ public:
void Dump(NBitStream::TBitStream& bs) override {
EXPECT_EQ(EncCalls, 1);
}
+
+ uint32_t GetConsumption() const noexcept override {
+ return 0;
+ }
private:
size_t EncCalls = 0;
};