diff options
author | Daniil Cherednik <dan.cherednik@gmail.com> | 2016-06-19 02:58:23 +0300 |
---|---|---|
committer | Daniil Cherednik <dan.cherednik@gmail.com> | 2016-06-19 03:31:55 +0300 |
commit | 1151d5831f19a9f24dd0c545a4968606712a62d2 (patch) | |
tree | c978c1b9a3fc86fef531dd412fe6b7668b7c0567 /src/atrac | |
parent | 8d65a0bd0774e03b3d10354e15f2f3361a2ce26a (diff) | |
download | atracdenc-1151d5831f19a9f24dd0c545a4968606712a62d2.tar.gz |
some improvements of ATRAC3 implementation:atrac3
- simple (ATRAC1 like) psychoacoustic added
- possibility to encode tonal components
- simple tonal component extractor
- refactoring
Diffstat (limited to 'src/atrac')
-rw-r--r-- | src/atrac/atrac1.cpp | 13 | ||||
-rw-r--r-- | src/atrac/atrac1.h | 73 | ||||
-rw-r--r-- | src/atrac/atrac1_bitalloc.cpp | 75 | ||||
-rw-r--r-- | src/atrac/atrac1_bitalloc.h | 11 | ||||
-rw-r--r-- | src/atrac/atrac1_dequantiser.cpp | 22 | ||||
-rw-r--r-- | src/atrac/atrac1_dequantiser.h | 8 | ||||
-rw-r--r-- | src/atrac/atrac1_qmf.h | 24 | ||||
-rw-r--r-- | src/atrac/atrac3.cpp | 7 | ||||
-rw-r--r-- | src/atrac/atrac3.h | 46 | ||||
-rw-r--r-- | src/atrac/atrac3_bitstream.cpp | 308 | ||||
-rw-r--r-- | src/atrac/atrac3_bitstream.h | 54 | ||||
-rw-r--r-- | src/atrac/atrac3_qmf.h | 10 | ||||
-rw-r--r-- | src/atrac/atrac_psy_common.cpp | 26 | ||||
-rw-r--r-- | src/atrac/atrac_psy_common.h | 8 | ||||
-rw-r--r-- | src/atrac/atrac_scale.cpp | 76 | ||||
-rw-r--r-- | src/atrac/atrac_scale.h | 46 |
16 files changed, 624 insertions, 183 deletions
diff --git a/src/atrac/atrac1.cpp b/src/atrac/atrac1.cpp index 26d8218..b71e5ae 100644 --- a/src/atrac/atrac1.cpp +++ b/src/atrac/atrac1.cpp @@ -1,10 +1,15 @@ #include "atrac1.h" -constexpr uint32_t TAtrac1Data::BlocksPerBand[QMF_BANDS + 1]; -constexpr uint32_t TAtrac1Data::SpecsPerBlock[MAX_BFUS]; -constexpr uint32_t TAtrac1Data::SpecsStartLong[MAX_BFUS]; -constexpr uint32_t TAtrac1Data::SpecsStartShort[MAX_BFUS]; +namespace NAtracDEnc { +namespace NAtrac1 { + +constexpr uint32_t TAtrac1Data::BlocksPerBand[NumQMF + 1]; +constexpr uint32_t TAtrac1Data::SpecsPerBlock[MaxBfus]; +constexpr uint32_t TAtrac1Data::SpecsStartLong[MaxBfus]; +constexpr uint32_t TAtrac1Data::SpecsStartShort[MaxBfus]; constexpr uint32_t TAtrac1Data::BfuAmountTab[8]; double TAtrac1Data::ScaleTable[64] = {0}; double TAtrac1Data::SineWindow[32] = {0}; +} //namespace NAtrac1 +} //namespace NAtracDEnc diff --git a/src/atrac/atrac1.h b/src/atrac/atrac1.h index cb0df1f..9736ea7 100644 --- a/src/atrac/atrac1.h +++ b/src/atrac/atrac1.h @@ -4,23 +4,52 @@ #include <map> #include <math.h> #include "../bitstream/bitstream.h" -const int QMF_BANDS = 3; -const int MAX_BFUS = 52; +namespace NAtracDEnc { +namespace NAtrac1 { + +class TAtrac1EncodeSettings { +public: + enum class EWindowMode { + EWM_NOTRANSIENT, + EWM_AUTO + }; +private: + const uint32_t BfuIdxConst = 0; + const bool FastBfuNumSearch = false; + EWindowMode WindowMode = EWindowMode::EWM_AUTO; + const uint32_t WindowMask = 0; +public: + TAtrac1EncodeSettings() + {} + TAtrac1EncodeSettings(uint32_t bfuIdxConst, bool fastBfuNumSearch, EWindowMode windowMode, uint32_t windowMask) + : BfuIdxConst(bfuIdxConst) + , FastBfuNumSearch(fastBfuNumSearch) + , WindowMode(windowMode) + , WindowMask(windowMask) + {} + uint32_t GetBfuIdxConst() const { return BfuIdxConst; } + bool GetFastBfuNumSearch() const { return FastBfuNumSearch; } + EWindowMode GetWindowMode() const {return WindowMode; } + uint32_t GetWindowMask() const {return WindowMask; } +}; class TAtrac1Data { +public: + static constexpr uint8_t MaxBfus = 52; + static constexpr uint8_t NumQMF = 3; protected: - static constexpr uint32_t SpecsPerBlock[MAX_BFUS] = { + static constexpr uint32_t SpecsPerBlock[MaxBfus] = { 8, 8, 8, 8, 4, 4, 4, 4, 8, 8, 8, 8, 6, 6, 6, 6, 6, 6, 6, 6, // low band 6, 6, 6, 6, 7, 7, 7, 7, 9, 9, 9, 9, 10, 10, 10, 10, // middle band 12, 12, 12, 12, 12, 12, 12, 12, 20, 20, 20, 20, 20, 20, 20, 20 // high band }; - static constexpr uint32_t BlocksPerBand[QMF_BANDS + 1] = {0, 20, 36, 52}; - static constexpr uint32_t SpecsStartLong[MAX_BFUS] = { + static constexpr uint32_t BlocksPerBand[NumQMF + 1] = {0, 20, 36, 52}; + static constexpr uint32_t SpecsStartLong[MaxBfus] = { 0, 8, 16, 24, 32, 36, 40, 44, 48, 56, 64, 72, 80, 86, 92, 98, 104, 110, 116, 122, 128, 134, 140, 146, 152, 159, 166, 173, 180, 189, 198, 207, 216, 226, 236, 246, 256, 268, 280, 292, 304, 316, 328, 340, 352, 372, 392, 412, 432, 452, 472, 492, }; - static constexpr uint32_t SpecsStartShort[MAX_BFUS] = { + static constexpr uint32_t SpecsStartShort[MaxBfus] = { 0, 32, 64, 96, 8, 40, 72, 104, 12, 44, 76, 108, 20, 52, 84, 116, 26, 58, 90, 122, 128, 160, 192, 224, 134, 166, 198, 230, 141, 173, 205, 237, 150, 182, 214, 246, 256, 288, 320, 352, 384, 416, 448, 480, 268, 300, 332, 364, 396, 428, 460, 492 @@ -30,8 +59,6 @@ protected: static const uint32_t BitsPerBfuAmountTabIdx = 3; static const uint32_t BitsPerIDWL = 4; static const uint32_t BitsPerIDSF = 6; - static const uint32_t NumSamples = 512; - static const uint8_t NumQMF = QMF_BANDS; static double ScaleTable[64]; static double SineWindow[32]; @@ -43,6 +70,7 @@ protected: return 2; } public: + static const uint32_t NumSamples = 512; TAtrac1Data() { if (ScaleTable[0] == 0) { for (uint32_t i = 0; i < 64; i++) { @@ -57,30 +85,5 @@ public: } }; -class TBlockSize { - static std::array<int, QMF_BANDS> Parse(NBitStream::TBitStream* stream) { - std::array<int,QMF_BANDS> tmp; - tmp[0] = 2 - stream->Read(2); - tmp[1] = 2 - stream->Read(2); - tmp[2] = 3 - stream->Read(2); - stream->Read(2); //skip unused 2 bits - return tmp; - } - static std::array<int,QMF_BANDS> Create(bool lowShort, bool midShort, bool hiShort) { - std::array<int,QMF_BANDS> tmp; - tmp[0] = lowShort ? 2 : 0; - tmp[1] = midShort ? 2 : 0; - tmp[2] = hiShort ? 3 : 0; - return tmp; - } -public: - TBlockSize(NBitStream::TBitStream* stream) - : LogCount(Parse(stream)) - {} - TBlockSize(bool lowShort, bool midShort, bool hiShort) - : LogCount(Create(lowShort, midShort, hiShort)) - {} - const std::array<int,QMF_BANDS> LogCount; -}; - - +} //namespace NAtrac1 +} //namespace NAtracDEnc diff --git a/src/atrac/atrac1_bitalloc.cpp b/src/atrac/atrac1_bitalloc.cpp index 68af205..11cbc4f 100644 --- a/src/atrac/atrac1_bitalloc.cpp +++ b/src/atrac/atrac1_bitalloc.cpp @@ -1,9 +1,12 @@ #include "atrac1_bitalloc.h" +#include "atrac_psy_common.h" #include "atrac_scale.h" #include "atrac1.h" #include <math.h> #include <cassert> #include "../bitstream/bitstream.h" + +namespace NAtracDEnc { namespace NAtrac1 { using std::vector; @@ -11,47 +14,26 @@ using std::cerr; using std::endl; using std::pair; -static const uint32_t FixedBitAllocTableLong[MAX_BFUS] = { +static const uint32_t FixedBitAllocTableLong[TAtrac1BitStreamWriter::MaxBfus] = { 7, 7, 7, 6, 6, 6, 6, 6, 6, 6, 6, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 4, 4, 4, 3, 3, 3, 3, 3, 3, 2, 2, 2, 1, 1, 0, 0, 0 }; -static const uint32_t FixedBitAllocTableShort[MAX_BFUS] = { +static const uint32_t FixedBitAllocTableShort[TAtrac1BitStreamWriter::MaxBfus] = { 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0 }; -static const uint32_t BitBoostMask[MAX_BFUS] = { +static const uint32_t BitBoostMask[TAtrac1BitStreamWriter::MaxBfus] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; -//returns 1 for tone-like, 0 - noise-like -static double AnalizeSpread(const std::vector<TScaledBlock>& scaledBlocks) { - double s = 0.0; - for (int i = 0; i < scaledBlocks.size(); ++i) { - s += scaledBlocks[i].ScaleFactorIndex; - } - s /= scaledBlocks.size(); - double sigma = 0.0; - double xxx = 0.0; - for (int i = 0; i < scaledBlocks.size(); ++i) { - xxx = (scaledBlocks[i].ScaleFactorIndex - s); - xxx *= xxx; - sigma += xxx; - } - sigma /= scaledBlocks.size(); - sigma = sqrt(sigma); - if (sigma > 14.0) - sigma = 14.0; - return sigma/14.0; -} - TBitsBooster::TBitsBooster() { - for (uint32_t i = 0; i < MAX_BFUS; ++i) { + for (uint32_t i = 0; i < MaxBfus; ++i) { if (BitBoostMask[i] == 0) continue; const uint32_t nBits = SpecsPerBlock[i]; @@ -68,7 +50,6 @@ uint32_t TBitsBooster::ApplyBoost(std::vector<uint32_t>* bitsPerEachBlock, uint3 //the key too low if (maxIt == BitsBoostMap.begin()) return surplus; - //std::cout << "key: " << key << " min key: " << MinKey << " it pos: " << maxIt->first << endl; while (surplus >= MinKey) { bool done = true; @@ -76,7 +57,6 @@ uint32_t TBitsBooster::ApplyBoost(std::vector<uint32_t>* bitsPerEachBlock, uint3 const uint32_t curBits = it->first; const uint32_t curPos = it->second; - //std::cout << "key: " << key << " curBits: " << curBits << endl; assert(key >= curBits); if (curPos >= bitsPerEachBlock->size()) break; @@ -90,23 +70,25 @@ uint32_t TBitsBooster::ApplyBoost(std::vector<uint32_t>* bitsPerEachBlock, uint3 (*bitsPerEachBlock)[curPos] += nBitsPerSpec; surplus -= curBits * nBitsPerSpec; - //std::cout << "added: " << curPos << " " << nBitsPerSpec << " got: " << (*bitsPerEachBlock)[curPos] << endl; done = false; } if (done) break; } - //std::cout << "boost: " << surplus << " was " << target - cur << endl; return surplus; } -vector<uint32_t> TAtrac1SimpleBitAlloc::CalcBitsAllocation(const std::vector<TScaledBlock>& scaledBlocks, const uint32_t bfuNum, const double spread, const double shift, const TBlockSize& blockSize) { +vector<uint32_t> TAtrac1SimpleBitAlloc::CalcBitsAllocation(const std::vector<TScaledBlock>& scaledBlocks, + const uint32_t bfuNum, + const TFloat spread, + const TFloat shift, + const TBlockSize& blockSize) { vector<uint32_t> bitsPerEachBlock(bfuNum); for (int i = 0; i < bitsPerEachBlock.size(); ++i) { const uint32_t fix = blockSize.LogCount[BfuToBand(i)] ? FixedBitAllocTableShort[i] : FixedBitAllocTableLong[i]; - int tmp = spread * ( (double)scaledBlocks[i].ScaleFactorIndex/3.2) + (1.0 - spread) * fix - shift; + int tmp = spread * ( (TFloat)scaledBlocks[i].ScaleFactorIndex/3.2) + (1.0 - spread) * fix - shift; if (tmp > 16) { bitsPerEachBlock[i] = 16; } else if (tmp < 2) { @@ -143,7 +125,8 @@ uint32_t TAtrac1SimpleBitAlloc::GetMaxUsedBfuId(const vector<uint32_t>& bitsPerE return idx; } -uint32_t TAtrac1SimpleBitAlloc::CheckBfuUsage(bool* changed, uint32_t curBfuId, const vector<uint32_t>& bitsPerEachBlock) { +uint32_t TAtrac1SimpleBitAlloc::CheckBfuUsage(bool* changed, + uint32_t curBfuId, const vector<uint32_t>& bitsPerEachBlock) { uint32_t usedBfuId = GetMaxUsedBfuId(bitsPerEachBlock); if (usedBfuId < curBfuId) { *changed = true; @@ -151,32 +134,34 @@ uint32_t TAtrac1SimpleBitAlloc::CheckBfuUsage(bool* changed, uint32_t curBfuId, } return curBfuId; } + uint32_t TAtrac1SimpleBitAlloc::Write(const std::vector<TScaledBlock>& scaledBlocks, const TBlockSize& blockSize) { uint32_t bfuIdx = BfuIdxConst ? BfuIdxConst - 1 : 7; bool autoBfu = !BfuIdxConst; - double spread = AnalizeSpread(scaledBlocks); + TFloat spread = AnalizeScaleFactorSpread(scaledBlocks); vector<uint32_t> bitsPerEachBlock(BfuAmountTab[bfuIdx]); uint32_t targetBitsPerBfus; uint32_t curBitsPerBfus; for (;;) { bitsPerEachBlock.resize(BfuAmountTab[bfuIdx]); - const uint32_t bitsAvaliablePerBfus = SoundUnitSize * 8 - BitsPerBfuAmountTabIdx - 32 - 2 - 3 - bitsPerEachBlock.size() * (BitsPerIDWL + BitsPerIDSF); - double maxShift = 15; - double minShift = -3; - double shift = 3.0; + const uint32_t bitsAvaliablePerBfus = SoundUnitSize * 8 - BitsPerBfuAmountTabIdx - 32 - 2 - 3 - + bitsPerEachBlock.size() * (BitsPerIDWL + BitsPerIDSF); + TFloat maxShift = 15; + TFloat minShift = -3; + TFloat shift = 3.0; const uint32_t maxBits = bitsAvaliablePerBfus; const uint32_t minBits = bitsAvaliablePerBfus - 110; bool bfuNumChanged = false; for (;;) { - const vector<uint32_t>& tmpAlloc = CalcBitsAllocation(scaledBlocks, BfuAmountTab[bfuIdx], spread, shift, blockSize); + const vector<uint32_t>& tmpAlloc = CalcBitsAllocation(scaledBlocks, BfuAmountTab[bfuIdx], + spread, shift, blockSize); uint32_t bitsUsed = 0; for (int i = 0; i < tmpAlloc.size(); i++) { bitsUsed += SpecsPerBlock[i] * tmpAlloc[i]; } - //std::cout << spread << " bitsUsed: " << bitsUsed << " min " << minBits << " max " << maxBits << " " << maxShift << " " << minShift << " " << endl; if (bitsUsed < minBits) { if (maxShift - minShift < 0.1) { if (autoBfu) { @@ -214,7 +199,10 @@ uint32_t TAtrac1SimpleBitAlloc::Write(const std::vector<TScaledBlock>& scaledBlo return BfuAmountTab[bfuIdx]; } -void TAtrac1BitStreamWriter::WriteBitStream(const vector<uint32_t>& bitsPerEachBlock, const std::vector<TScaledBlock>& scaledBlocks, uint32_t bfuAmountIdx, const TBlockSize& blockSize) { +void TAtrac1BitStreamWriter::WriteBitStream(const vector<uint32_t>& bitsPerEachBlock, + const std::vector<TScaledBlock>& scaledBlocks, + uint32_t bfuAmountIdx, + const TBlockSize& blockSize) { NBitStream::TBitStream bitStream; int bitUsed = 0; if (bfuAmountIdx >= (1 << BitsPerBfuAmountTabIdx)) { @@ -252,8 +240,8 @@ void TAtrac1BitStreamWriter::WriteBitStream(const vector<uint32_t>& bitsPerEachB if (wordLength == 0 || wordLength == 1) continue; - const double multiple = ((1 << (wordLength - 1)) - 1); - for (const double val : scaledBlocks[i].Values) { + const TFloat multiple = ((1 << (wordLength - 1)) - 1); + for (const TFloat val : scaledBlocks[i].Values) { const int tmp = round(val * multiple); const int testwl = bitsPerEachBlock[i] ? (bitsPerEachBlock[i] - 1) : 0; const int a = !!testwl + testwl; @@ -280,4 +268,5 @@ void TAtrac1BitStreamWriter::WriteBitStream(const vector<uint32_t>& bitsPerEachB Container->WriteFrame(bitStream.GetBytes()); } -} +} //namespace NAtrac1 +} //namespace NAtracDEnc diff --git a/src/atrac/atrac1_bitalloc.h b/src/atrac/atrac1_bitalloc.h index ce7b6fb..c5c4ad2 100644 --- a/src/atrac/atrac1_bitalloc.h +++ b/src/atrac/atrac1_bitalloc.h @@ -7,7 +7,9 @@ #include <map> #include <cstdint> +namespace NAtracDEnc { namespace NAtrac1 { + using NAtracDEnc::TScaledBlock; class IAtrac1BitAlloc { @@ -32,11 +34,13 @@ public: explicit TAtrac1BitStreamWriter(TAea* container) : Container(container) {}; - void WriteBitStream(const std::vector<uint32_t>& bitsPerEachBlock, const std::vector<TScaledBlock>& scaledBlocks, uint32_t bfuAmountIdx, const TBlockSize& blockSize); + void WriteBitStream(const std::vector<uint32_t>& bitsPerEachBlock, const std::vector<TScaledBlock>& scaledBlocks, + uint32_t bfuAmountIdx, const TBlockSize& blockSize); }; class TAtrac1SimpleBitAlloc : public TAtrac1BitStreamWriter, public TBitsBooster, public virtual IAtrac1BitAlloc { - std::vector<uint32_t> CalcBitsAllocation(const std::vector<TScaledBlock>& scaledBlocks, const uint32_t bfuNum, const double spread, const double shift, const TBlockSize& blockSize); + std::vector<uint32_t> CalcBitsAllocation(const std::vector<TScaledBlock>& scaledBlocks, const uint32_t bfuNum, + const TFloat spread, const TFloat shift, const TBlockSize& blockSize); const uint32_t BfuIdxConst; const bool FastBfuNumSearch; uint32_t GetMaxUsedBfuId(const std::vector<uint32_t>& bitsPerEachBlock); @@ -51,4 +55,5 @@ public: uint32_t Write(const std::vector<TScaledBlock>& scaledBlocks, const TBlockSize& blockSize) override; }; -} +} //namespace NAtrac1 +} //namespace NAtracDEnc diff --git a/src/atrac/atrac1_dequantiser.cpp b/src/atrac/atrac1_dequantiser.cpp index 8229822..83abc76 100644 --- a/src/atrac/atrac1_dequantiser.cpp +++ b/src/atrac/atrac1_dequantiser.cpp @@ -1,15 +1,16 @@ #include "atrac1_dequantiser.h" #include <string.h> - +namespace NAtracDEnc { namespace NAtrac1 { + using namespace NBitStream; TAtrac1Dequantiser::TAtrac1Dequantiser() { } -void TAtrac1Dequantiser::Dequant(TBitStream* stream, const TBlockSize& bs, double specs[512]) { - uint32_t wordLens[MAX_BFUS]; - uint32_t idScaleFactors[MAX_BFUS]; +void TAtrac1Dequantiser::Dequant(TBitStream* stream, const TBlockSize& bs, TFloat specs[512]) { + uint32_t wordLens[MaxBfus]; + uint32_t idScaleFactors[MaxBfus]; const uint32_t numBFUs = BfuAmountTab[stream->Read(3)]; stream->Read(2); stream->Read(3); @@ -21,28 +22,29 @@ void TAtrac1Dequantiser::Dequant(TBitStream* stream, const TBlockSize& bs, doubl for (uint32_t i = 0; i < numBFUs; i++) { idScaleFactors[i] = stream->Read(6); } - for (uint32_t i = numBFUs; i < MAX_BFUS; i++) { + for (uint32_t i = numBFUs; i < MaxBfus; i++) { wordLens[i] = idScaleFactors[i] = 0; } - for (uint32_t bandNum = 0; bandNum < QMF_BANDS; bandNum++) { + for (uint32_t bandNum = 0; bandNum < NumQMF; bandNum++) { for (uint32_t bfuNum = BlocksPerBand[bandNum]; bfuNum < BlocksPerBand[bandNum + 1]; bfuNum++) { const uint32_t numSpecs = SpecsPerBlock[bfuNum]; const uint32_t wordLen = !!wordLens[bfuNum] + wordLens[bfuNum]; - const double scaleFactor = ScaleTable[idScaleFactors[bfuNum]]; + const TFloat scaleFactor = ScaleTable[idScaleFactors[bfuNum]]; const uint32_t startPos = bs.LogCount[bandNum] ? SpecsStartShort[bfuNum] : SpecsStartLong[bfuNum]; if (wordLen) { - double maxQuant = 1.0 / (double)((1 << (wordLen - 1)) - 1); + TFloat maxQuant = 1.0 / (TFloat)((1 << (wordLen - 1)) - 1); //cout << "BFU ("<< bfuNum << ") :" << "wordLen " << wordLen << " maxQuant " << maxQuant << " scaleFactor " << scaleFactor << " id " << idScaleFactors[bfuNum] << " num Specs " << numSpecs << " short: "<< (int)bs.LogCount[bandNum] << endl; for (uint32_t i = 0; i < numSpecs; i++ ) { specs[startPos + i] = scaleFactor * maxQuant * MakeSign(stream->Read(wordLen), wordLen); } } else { - memset(&specs[startPos], 0, numSpecs * sizeof(double)); + memset(&specs[startPos], 0, numSpecs * sizeof(TFloat)); } } } } -} +} //namespace NAtrac1 +} //namespace NAtracDEnc diff --git a/src/atrac/atrac1_dequantiser.h b/src/atrac/atrac1_dequantiser.h index 112fc8b..8b2a8b4 100644 --- a/src/atrac/atrac1_dequantiser.h +++ b/src/atrac/atrac1_dequantiser.h @@ -1,12 +1,16 @@ #pragma once #include "atrac1.h" +#include "atrac_scale.h" +namespace NAtracDEnc { namespace NAtrac1 { class TAtrac1Dequantiser : public TAtrac1Data { public: TAtrac1Dequantiser(); - void Dequant(NBitStream::TBitStream* stream, const TBlockSize& bs, double specs[512]); + void Dequant(NBitStream::TBitStream* stream, const TBlockSize& bs, TFloat specs[512]); }; -} + +} //namespace NAtrac1 +} //namespace NAtracDEnc diff --git a/src/atrac/atrac1_qmf.h b/src/atrac/atrac1_qmf.h index 8550932..37d0bba 100644 --- a/src/atrac/atrac1_qmf.h +++ b/src/atrac/atrac1_qmf.h @@ -2,24 +2,26 @@ #include "../qmf/qmf.h" +namespace NAtracDEnc { + template<class TIn> class Atrac1SplitFilterBank { const static int nInSamples = 512; const static int delayComp = 39; TQmf<TIn, nInSamples> Qmf1; TQmf<TIn, nInSamples / 2> Qmf2; - std::vector<double> MidLowTmp; - std::vector<double> DelayBuf; + std::vector<TFloat> MidLowTmp; + std::vector<TFloat> DelayBuf; public: Atrac1SplitFilterBank() { MidLowTmp.resize(512); DelayBuf.resize(delayComp + 512); } - void Split(TIn* pcm, double* low, double* mid, double* hi) { - memcpy(&DelayBuf[0], &DelayBuf[256], sizeof(double) * delayComp); + void Split(TIn* pcm, TFloat* low, TFloat* mid, TFloat* hi) { + memcpy(&DelayBuf[0], &DelayBuf[256], sizeof(TFloat) * delayComp); Qmf1.Split(pcm, &MidLowTmp[0], &DelayBuf[delayComp]); Qmf2.Split(&MidLowTmp[0], low, mid); - memcpy(hi, &DelayBuf[0], sizeof(double) * 256); + memcpy(hi, &DelayBuf[0], sizeof(TFloat) * 256); } }; @@ -29,19 +31,19 @@ class Atrac1SynthesisFilterBank { const static int delayComp = 39; TQmf<TOut, nInSamples> Qmf1; TQmf<TOut, nInSamples / 2> Qmf2; - std::vector<double> MidLowTmp; - std::vector<double> DelayBuf; + std::vector<TFloat> MidLowTmp; + std::vector<TFloat> DelayBuf; public: Atrac1SynthesisFilterBank() { MidLowTmp.resize(512); DelayBuf.resize(delayComp + 512); } - void Synthesis(TOut* pcm, double* low, double* mid, double* hi) { - memcpy(&DelayBuf[0], &DelayBuf[256], sizeof(double) * delayComp); - memcpy(&DelayBuf[delayComp], hi, sizeof(double) * 256); + void Synthesis(TOut* pcm, TFloat* low, TFloat* mid, TFloat* hi) { + memcpy(&DelayBuf[0], &DelayBuf[256], sizeof(TFloat) * delayComp); + memcpy(&DelayBuf[delayComp], hi, sizeof(TFloat) * 256); Qmf2.Merge(&MidLowTmp[0], &low[0], &mid[0]); Qmf1.Merge(&pcm[0], &MidLowTmp[0], &DelayBuf[0]); } }; - +} //namespace NAtracDEnc diff --git a/src/atrac/atrac3.cpp b/src/atrac/atrac3.cpp index cdf6b3f..e587d2c 100644 --- a/src/atrac/atrac3.cpp +++ b/src/atrac/atrac3.cpp @@ -1,5 +1,9 @@ #include "atrac3.h" #include <algorithm> + +namespace NAtracDEnc { +namespace NAtrac3 { + constexpr uint32_t TAtrac3Data::BlockSizeTab[33]; constexpr uint32_t TAtrac3Data::ClcLengthTab[8]; constexpr double TAtrac3Data::MaxQuant[8]; @@ -24,3 +28,6 @@ const TContainerParams* TAtrac3Data::GetContainerParamsForBitrate(uint32_t bitra std::cout << bitrate << std::endl; return std::lower_bound(ContainerParams, ContainerParams+8, bitrate); } + +} // namespace NAtrac3 +} // namespace NAtracDEnc diff --git a/src/atrac/atrac3.h b/src/atrac/atrac3.h index 02e694b..e65e71a 100644 --- a/src/atrac/atrac3.h +++ b/src/atrac/atrac3.h @@ -5,6 +5,8 @@ #include <cassert> #include <iostream> +namespace NAtracDEnc { +namespace NAtrac3 { struct TContainerParams { const uint32_t Bitrate; @@ -30,6 +32,9 @@ inline bool operator> (const TContainerParams& x, const unsigned int y) } class TAtrac3Data { +public: + static constexpr uint8_t MaxBfus = 32; + static constexpr uint32_t NumSamples = 1024; protected: static const uint32_t MDCTSz = 512; static double ScaleTable[64]; @@ -42,7 +47,7 @@ protected: static constexpr int32_t LocSz = 1 << LocScale; static constexpr int32_t GainInterpolationPosShift = 15; - static const uint32_t NumSamples=1024; + static constexpr uint32_t NumSpecs = NumSamples; static const uint32_t frameSz = 152; static constexpr double MaxQuant[8] = { 0.0, 1.5, 2.5, 3.5, @@ -59,8 +64,9 @@ protected: static constexpr uint32_t const * const SpecsStartLong = &BlockSizeTab[0]; static constexpr uint32_t ClcLengthTab[8] = { 0, 4, 3, 3, 4, 4, 5, 6 }; - static const int NumQMF = 4; - static const uint32_t MAX_SPECS = 1024; + static constexpr int NumQMF = 4; + static constexpr uint32_t MaxSpecs = NumSamples; //1024 + static constexpr uint32_t MaxSpecsPerBlock = 128; static constexpr uint32_t BlocksPerBand[NumQMF + 1] = {0, 18, 26, 30, 32}; static constexpr uint32_t SpecsPerBlock[33] = { @@ -114,13 +120,16 @@ protected: static constexpr THuffEntry HuffTable7[HuffTable7Sz] = { { 0x0, 3 }, //{ 0x2, 4 }, { 0x3, 4 }, - { 0x8, 5 }, { 0x9, 5 }, { 0xA, 5}, { 0xB, 5 }, { 0xC, 5 }, { 0xD, 5 }, { 0xE, 5}, { 0xF, 5 }, { 0x10, 5 }, { 0x11, 5 }, + { 0x8, 5 }, { 0x9, 5 }, { 0xA, 5}, { 0xB, 5 }, { 0xC, 5 }, { 0xD, 5 }, { 0xE, 5}, { 0xF, 5 }, { 0x10, 5 }, + { 0x11, 5 }, { 0x24, 6 }, { 0x25, 6 }, { 0x26, 6 }, { 0x27, 6 }, { 0x28, 6 }, { 0x29, 6 }, { 0x2A, 6 }, { 0x2B, 6 }, { 0x2C, 6 }, { 0x2D, 6 }, { 0x2E, 6 }, { 0x2F, 6 }, { 0x30, 6 }, { 0x31, 6 }, { 0x32, 6 }, { 0x33, 6 }, { 0x68, 7 }, { 0x69, 7 }, { 0x6A, 7 }, { 0x6B, 7 }, { 0x6C, 7 }, { 0x6D, 7 }, { 0x6E, 7 }, { 0x6F, 7 }, { 0x70, 7 }, { 0x71, 7 }, { 0x72, 7 }, { 0x73, 7 }, { 0x74, 7 }, { 0x75, 7 }, - { 0xEC, 8 }, { 0xED, 8 }, { 0xEE, 8 }, { 0xEF, 8 }, { 0xF0, 8 }, { 0xF1, 8 }, { 0xF2, 8 }, { 0xF3, 8 }, { 0xF4, 8 }, { 0xF5, 8 }, - { 0xF6, 8 }, { 0xF7, 8 }, { 0xF8, 8 }, { 0xF9, 8 }, { 0xFA, 8 }, { 0xFB, 8 }, { 0xFC, 8 }, { 0xFD, 8 }, { 0xFE, 8 }, { 0xFF, 8 }, + { 0xEC, 8 }, { 0xED, 8 }, { 0xEE, 8 }, { 0xEF, 8 }, { 0xF0, 8 }, { 0xF1, 8 }, { 0xF2, 8 }, { 0xF3, 8 }, + { 0xF4, 8 }, { 0xF5, 8 }, + { 0xF6, 8 }, { 0xF7, 8 }, { 0xF8, 8 }, { 0xF9, 8 }, { 0xFA, 8 }, { 0xFB, 8 }, { 0xFC, 8 }, { 0xFD, 8 }, + { 0xFE, 8 }, { 0xFF, 8 }, { 0x2, 4 }, { 0x3, 4 } //TODO: is it right table??? }; @@ -146,7 +155,7 @@ public: } } for (int i = 0; i < 256; i++) { - EncodeWindow[i] = (sin(((i + 0.5) / 256.0 - 0.5) * M_PI) + 1.0) * 0.5; + EncodeWindow[i] = (sin(((i + 0.5) / 256.0 - 0.5) * M_PI) + 1.0)/* * 0.5*/; } for (int i = 0; i < 256; i++) { const double a = EncodeWindow[i]; @@ -186,6 +195,7 @@ public: class SubbandInfo { public: + static const uint32_t MaxGainPointsNum = 8; struct TGainPoint { const uint32_t Level; const uint32_t Location; @@ -207,4 +217,26 @@ public: return Info[i]; } }; + + struct TTonalVal { + const uint16_t Pos; + const double Val; + }; + typedef std::vector<TTonalVal> TTonalComponents; }; + +struct TAtrac3EncoderSettings { + explicit TAtrac3EncoderSettings(uint32_t bitrate, bool noGainControll, bool noTonalComponents) + : ConteinerParams(TAtrac3Data::GetContainerParamsForBitrate(bitrate)) + , NoGainControll(noGainControll) + , NoTonalComponents(noTonalComponents) + { + std::cout << bitrate << " " << ConteinerParams->Bitrate << std::endl; + } + const TContainerParams* ConteinerParams; + const bool NoGainControll; + const bool NoTonalComponents; +}; + +} // namespace NAtrac3 +} // namespace NAtracDEnc diff --git a/src/atrac/atrac3_bitstream.cpp b/src/atrac/atrac3_bitstream.cpp index ff28132..3822a67 100644 --- a/src/atrac/atrac3_bitstream.cpp +++ b/src/atrac/atrac3_bitstream.cpp @@ -1,4 +1,5 @@ #include "atrac3_bitstream.h" +#include "atrac_psy_common.h" #include "../bitstream/bitstream.h" #include <cassert> #include <algorithm> @@ -6,10 +7,21 @@ #include <vector> #include <cstdlib> -using NAtracDEnc::TScaledBlock; +namespace NAtracDEnc { +namespace NAtrac3 { + using std::vector; -uint32_t TAtrac3BitStreamWriter::CLCEnc(const uint32_t selector, const int mantissas[MAXSPECPERBLOCK], const uint32_t blockSize, NBitStream::TBitStream* bitStream) { +static const uint32_t FixedBitAllocTable[TAtrac3Data::MaxBfus] = { + 6, 6, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 3, 3, 3, 3, 3, + 3, 2, 2, 1, + 1, 0 +}; + +uint32_t TAtrac3BitStreamWriter::CLCEnc(const uint32_t selector, const int mantissas[MaxSpecsPerBlock], + const uint32_t blockSize, NBitStream::TBitStream* bitStream) +{ const uint32_t numBits = ClcLengthTab[selector]; const uint32_t bitsUsed = (selector > 1) ? numBits * blockSize : numBits * blockSize / 2; if (!bitStream) @@ -29,7 +41,10 @@ uint32_t TAtrac3BitStreamWriter::CLCEnc(const uint32_t selector, const int manti return bitsUsed; } -uint32_t TAtrac3BitStreamWriter::VLCEnc(const uint32_t selector, const int mantissas[MAXSPECPERBLOCK], const uint32_t blockSize, NBitStream::TBitStream* bitStream) { +uint32_t TAtrac3BitStreamWriter::VLCEnc(const uint32_t selector, const int mantissas[MaxSpecsPerBlock], + const uint32_t blockSize, NBitStream::TBitStream* bitStream) +{ + assert(selector > 0); const THuffEntry* huffTable = HuffTables[selector - 1].Table; const uint8_t tableSz = HuffTables[selector - 1].Sz; uint32_t bitsUsed = 0; @@ -58,7 +73,10 @@ uint32_t TAtrac3BitStreamWriter::VLCEnc(const uint32_t selector, const int manti } return bitsUsed; } -std::pair<uint8_t, uint32_t> TAtrac3BitStreamWriter::CalcSpecsBitsConsumption(const vector<TScaledBlock>& scaledBlocks, const vector<uint32_t>& precisionPerEachBlocks, int* mantisas) { + +std::pair<uint8_t, uint32_t> TAtrac3BitStreamWriter::CalcSpecsBitsConsumption(const vector<TScaledBlock>& scaledBlocks, + const vector<uint32_t>& precisionPerEachBlocks, int* mantisas) +{ uint32_t bitsUsed = 5 + 1; //numBlocks + codingMode const uint32_t numBlocks = precisionPerEachBlocks.size(); bitsUsed += numBlocks * 3; //used VLC or CLC table (precision) @@ -72,7 +90,7 @@ std::pair<uint8_t, uint32_t> TAtrac3BitStreamWriter::CalcSpecsBitsConsumption(co const uint32_t first = BlockSizeTab[i]; const uint32_t last = BlockSizeTab[i+1]; const uint32_t blockSize = last - first; - const double mul = MaxQuant[std::min(precisionPerEachBlocks[i], (uint32_t)7)]; + const TFloat mul = MaxQuant[std::min(precisionPerEachBlocks[i], (uint32_t)7)]; if (calcMant) { for (uint32_t j = 0, f = first; f < last; f++, j++) { mantisas[f] = round(scaledBlocks[i].Values[j] * mul); @@ -86,14 +104,73 @@ std::pair<uint8_t, uint32_t> TAtrac3BitStreamWriter::CalcSpecsBitsConsumption(co const uint32_t clcBits = lambda(true, true); const uint32_t vlcBits = lambda(false, false); bool mode = clcBits <= vlcBits; - //std::cout << "mode: " << mode << " " << clcBits << " " <<vlcBits << std::endl; return std::make_pair(mode, bitsUsed + (mode ? clcBits : vlcBits)); } -void TAtrac3BitStreamWriter::EncodeSpecs(const vector<TScaledBlock>& scaledBlocks, const vector<uint32_t>& precisionPerEachBlocks, NBitStream::TBitStream* bitStream) { + + +std::pair<uint8_t, vector<uint32_t>> TAtrac3BitStreamWriter::CreateAllocation(const vector<TScaledBlock>& scaledBlocks, + uint16_t bitsUsed, int mt[MaxSpecs]) +{ + TFloat spread = AnalizeScaleFactorSpread(scaledBlocks); + + uint8_t numBfu = 32; + vector<uint32_t> precisionPerEachBlocks(numBfu); + uint32_t targetBitsPerBfus; + uint32_t curBitsPerBfus; + uint8_t mode; + for (;;) { + precisionPerEachBlocks.resize(numBfu); + uint32_t usedBfus = 0; + for (auto v : precisionPerEachBlocks) { + if (v) + usedBfus++; + } + const uint32_t bitsAvaliablePerBfus = 8 * Params.FrameSz/2 - bitsUsed - + 5 - 1 - (numBfu * 3) - (usedBfus * 6); + TFloat maxShift = 15; + TFloat minShift = -3; + TFloat shift = 3.0; + const uint32_t maxBits = bitsAvaliablePerBfus; + const uint32_t minBits = bitsAvaliablePerBfus - 90; + for (;;) { + const vector<uint32_t>& tmpAlloc = CalcBitsAllocation(scaledBlocks, numBfu, spread, shift); + const auto consumption = CalcSpecsBitsConsumption(scaledBlocks, tmpAlloc, mt); + + if (consumption.second < minBits) { + if (maxShift - minShift < 0.1) { + precisionPerEachBlocks = tmpAlloc; + curBitsPerBfus = consumption.second; + mode = consumption.first; + break; + } + maxShift = shift; + shift -= (shift - minShift) / 2; + } else if (consumption.second > maxBits) { + minShift = shift; + shift += (maxShift - shift) / 2; + } else { + precisionPerEachBlocks = tmpAlloc; + curBitsPerBfus = consumption.second; + mode = consumption.first; + break; + } + } + targetBitsPerBfus = bitsAvaliablePerBfus; + break; + + } + return { mode, precisionPerEachBlocks }; +} + +void TAtrac3BitStreamWriter::EncodeSpecs(const vector<TScaledBlock>& scaledBlocks, NBitStream::TBitStream* bitStream, + const uint16_t bitsUsed) +{ + int mt[MaxSpecs]; + auto allocation = CreateAllocation(scaledBlocks, bitsUsed, mt); + const vector<uint32_t>& precisionPerEachBlocks = allocation.second; const uint32_t numBlocks = precisionPerEachBlocks.size(); //number of blocks to save - int mt[MAX_SPECS]; - const auto consumption = CalcSpecsBitsConsumption(scaledBlocks, precisionPerEachBlocks, mt); - const uint32_t codingMode = consumption.first;//0 - VLC, 1 - CLC + const uint32_t codingMode = allocation.first;//0 - VLC, 1 - CLC + assert(numBlocks <= 32); bitStream->Write(numBlocks-1, 5); bitStream->Write(codingMode, 1); @@ -122,53 +199,234 @@ void TAtrac3BitStreamWriter::EncodeSpecs(const vector<TScaledBlock>& scaledBlock } } -void TAtrac3BitStreamWriter::WriteSoundUnit(const TAtrac3Data::SubbandInfo& subbandInfo, const vector<TScaledBlock>& scaledBlocks) { +uint8_t TAtrac3BitStreamWriter::GroupTonalComponents(const std::vector<TTonalComponent>& tonalComponents, + TTonalComponentsSubGroup groups[64]) +{ + for (const TTonalComponent& tc : tonalComponents) { + assert(tc.ScaledBlock.Values.size() < 8); + assert(tc.ScaledBlock.Values.size() > 0); + assert(tc.QuantIdx >1); + assert(tc.QuantIdx <8); + groups[tc.QuantIdx * 8 + tc.ScaledBlock.Values.size()].SubGroupPtr.push_back(&tc); + } + uint8_t tcsgn = 0; + //for each group + for (uint8_t i = 0; i < 64; ++i) { + uint8_t start_pos; + uint8_t cur_pos = 0; + //scan tonal components + while (cur_pos < groups[i].SubGroupPtr.size()) { + start_pos = cur_pos; + ++tcsgn; + groups[i].SubGroupMap.push_back(cur_pos); + uint8_t groupLimiter = 0; + //allow not grather than 8 components in one subgroup limited by 64 specs + do { + ++cur_pos; + if (cur_pos == groups[i].SubGroupPtr.size()) + break; + if (groups[i].SubGroupPtr[cur_pos]->ValPtr->Pos - (groups[i].SubGroupPtr[start_pos]->ValPtr->Pos & ~63) < 64) { + ++groupLimiter; + } else { + groupLimiter = 0; + start_pos = cur_pos; + } + } while (groupLimiter < 7); + } + } + return tcsgn; +} + +uint16_t TAtrac3BitStreamWriter::EncodeTonalComponents(const std::vector<TTonalComponent>& tonalComponents, + NBitStream::TBitStream* bitStream, uint8_t numQmfBand) +{ + const uint16_t bitsUsed = bitStream->GetSizeInBits(); + //group tonal components with same quantizer and len + TTonalComponentsSubGroup groups[64]; + const uint8_t tcsgn = GroupTonalComponents(tonalComponents, groups); + + assert(tcsgn < 32); + bitStream->Write(tcsgn, 5); + if (tcsgn == 0) { + for (int i = 0; i < 64; ++i) + assert(groups[i].SubGroupPtr.size() == 0); + return 5; //wrote 0 but 5 bits for tcsgn + } + //Coding mode: + // 0 - All are VLC + // 1 - All are CLC + // 2 - Error + // 3 - Own mode for each component + + //TODO: implement switch for best coding mode. Now VLC for all + bitStream->Write(0, 2); + + uint8_t tcgnCheck = 0; + //for each group of equal quantiser and len + for (uint8_t i = 0; i < 64; ++i) { + const TTonalComponentsSubGroup& curGroup = groups[i]; + if (curGroup.SubGroupPtr.size() == 0) { + assert(curGroup.SubGroupMap.size() == 0); + continue; + } + assert(curGroup.SubGroupMap.size()); + for (uint8_t subgroup = 0; subgroup < curGroup.SubGroupMap.size(); ++subgroup) { + const uint8_t subGroupStartPos = curGroup.SubGroupMap[subgroup]; + const uint8_t subGroupEndPos = (subgroup < curGroup.SubGroupMap.size() - 1) ? + curGroup.SubGroupMap[subgroup+1] : curGroup.SubGroupPtr.size(); + assert(subGroupEndPos > subGroupStartPos); + //number of coded values are same in group + const uint8_t codedValues = curGroup.SubGroupPtr[0]->ScaledBlock.Values.size(); + + //Number of tonal component for each 64spec block. Used to set qmf band flags and simplify band encoding loop + uint8_t bandFlags[16]; + memset(bandFlags, 0, 16 * sizeof(uint8_t)); + assert(numQmfBand <= 4); + for (uint8_t j = subGroupStartPos; j < subGroupEndPos; ++j) { + //assert num of coded values are same in group + assert(codedValues == curGroup.SubGroupPtr[j]->ScaledBlock.Values.size()); + uint8_t specBlock = (curGroup.SubGroupPtr[j]->ValPtr->Pos) >> 6; + assert((specBlock >> 2) < numQmfBand); + bandFlags[specBlock]++; + } + + assert(numQmfBand == 4); + + tcgnCheck++; + + for (uint8_t j = 0; j < numQmfBand; ++j) { + bitStream->Write((bool)(*(uint32_t*)&bandFlags[j<<2]), 1); + } + //write number of coded values for components in current group + assert(codedValues > 0); + bitStream->Write(codedValues - 1, 3); + //write quant index + assert((i >> 3) > 1); + assert((i >> 3) < 8); + assert(i); + bitStream->Write(i >> 3, 3); + uint8_t lastPos = subGroupStartPos; + uint8_t checkPos = 0; + for (uint16_t j = 0; j < 16; ++j) { + if (!(*(uint32_t*)&bandFlags[j & 0xC])) { //discard two bits + continue; + } + + const uint8_t codedComponents = bandFlags[j]; + assert(codedComponents < 8); + bitStream->Write(codedComponents, 3); + uint8_t k = lastPos; + for (; k < lastPos + codedComponents; ++k) { + assert(curGroup.SubGroupPtr[k]->ValPtr->Pos >= j * 64); + uint16_t relPos = curGroup.SubGroupPtr[k]->ValPtr->Pos - j * 64; + assert(curGroup.SubGroupPtr[k]->ScaledBlock.ScaleFactorIndex < 64); + bitStream->Write(curGroup.SubGroupPtr[k]->ScaledBlock.ScaleFactorIndex, 6); + + assert(relPos < 64); + + bitStream->Write(relPos, 6); + + assert(curGroup.SubGroupPtr[k]->ScaledBlock.Values.size() < 8); + int mantisas[256]; + const TFloat mul = MaxQuant[std::min((uint32_t)(i>>3), (uint32_t)7)]; + assert(codedValues == curGroup.SubGroupPtr[k]->ScaledBlock.Values.size()); + for (uint32_t z = 0; z < curGroup.SubGroupPtr[k]->ScaledBlock.Values.size(); ++z) { + mantisas[z] = round(curGroup.SubGroupPtr[k]->ScaledBlock.Values[z] * mul); + } + //VLCEnc + + assert(i); + VLCEnc(i>>3, mantisas, curGroup.SubGroupPtr[k]->ScaledBlock.Values.size(), bitStream); + + + } + lastPos = k; + checkPos = lastPos; + bool shouldBreakCurrentGroup = true; + for (uint16_t k = j+1; k < 16; ++k) { + if (bandFlags[k]) { + shouldBreakCurrentGroup = false; + } + } + } + + assert(subGroupEndPos == checkPos); + } + } + assert(tcgnCheck == tcsgn); + return bitStream->GetSizeInBits() - bitsUsed; +} + +vector<uint32_t> TAtrac3BitStreamWriter::CalcBitsAllocation(const std::vector<TScaledBlock>& scaledBlocks, + const uint32_t bfuNum, + const TFloat spread, + const TFloat shift) +{ + vector<uint32_t> bitsPerEachBlock(bfuNum); + for (int i = 0; i < bitsPerEachBlock.size(); ++i) { + const uint32_t fix = FixedBitAllocTable[i]; + int tmp = spread * ( (TFloat)scaledBlocks[i].ScaleFactorIndex/3.2) + (1.0 - spread) * fix - shift; + if (tmp > 7) { + bitsPerEachBlock[i] = 7; + } else if (tmp < 0) { + bitsPerEachBlock[i] = 0; + } else { + bitsPerEachBlock[i] = tmp; + } + } + return bitsPerEachBlock; +} + + +void TAtrac3BitStreamWriter::WriteSoundUnit(const TAtrac3Data::SubbandInfo& subbandInfo, + const std::vector<TTonalComponent>& tonalComponents, + const vector<TScaledBlock>& scaledBlocks) +{ NBitStream::TBitStream bitStream; if (Params.Js) { //TODO } else { bitStream.Write(0x28, 6); //0x28 - id } - const uint32_t numQmfBand = subbandInfo.GetQmfNum(); + const uint8_t numQmfBand = subbandInfo.GetQmfNum(); bitStream.Write(numQmfBand - 1, 2); //write gain info for (uint32_t band = 0; band < numQmfBand; ++band) { const vector<TAtrac3Data::SubbandInfo::TGainPoint>& GainPoints = subbandInfo.GetGainPoints(band); + assert(GainPoints.size() < TAtrac3Data::SubbandInfo::MaxGainPointsNum); bitStream.Write(GainPoints.size(), 3); + int s = 0; for (const TAtrac3Data::SubbandInfo::TGainPoint& point : GainPoints) { bitStream.Write(point.Level, 4); bitStream.Write(point.Location, 5); + s++; + assert(s < 8); } } - - //tonal components - bitStream.Write(0, 5); //disabled - - vector<uint32_t> precisionPerEachBlocks(27,1); - for (int i = 0; i < 2; i++) { - //precisionPerEachBlocks[i] = 4; - } - + const uint16_t bitsUsedByGainInfo = bitStream.GetSizeInBits() - 8; + const uint16_t bitsUsedByTonal = EncodeTonalComponents(tonalComponents, &bitStream, numQmfBand); //spec - EncodeSpecs(scaledBlocks, precisionPerEachBlocks, &bitStream); + EncodeSpecs(scaledBlocks, &bitStream, bitsUsedByTonal + bitsUsedByGainInfo); if (!Container) abort(); if (OutBuffer.empty()) { std::vector<char> channel = bitStream.GetBytes(); - //std::cout << channel.size() << std::endl; assert(channel.size() <= Params.FrameSz/2); channel.resize(Params.FrameSz/2); OutBuffer.insert(OutBuffer.end(), channel.begin(), channel.end()); } else { std::vector<char> channel = bitStream.GetBytes(); - channel.resize(Params.FrameSz/2); - //std::cout << channel.size() << std::endl; + assert(channel.size() <= Params.FrameSz/2); + channel.resize(Params.FrameSz/2); OutBuffer.insert(OutBuffer.end(), channel.begin(), channel.end()); Container->WriteFrame(OutBuffer); OutBuffer.clear(); } } + +} // namespace NAtrac3 +} // namespace NAtracDEnc diff --git a/src/atrac/atrac3_bitstream.h b/src/atrac/atrac3_bitstream.h index 60f1e4a..225d98c 100644 --- a/src/atrac/atrac3_bitstream.h +++ b/src/atrac/atrac3_bitstream.h @@ -8,16 +8,53 @@ #include <vector> #include <utility> -static const uint32_t MAXSPECPERBLOCK = 128; +namespace NAtracDEnc { +namespace NAtrac3 { + +struct TTonalComponent { + TTonalComponent(const TAtrac3Data::TTonalVal* valPtr, uint8_t quantIdx, const TScaledBlock& scaledBlock) + : ValPtr(valPtr) + , QuantIdx(quantIdx) + , ScaledBlock(scaledBlock) + {} + const TAtrac3Data::TTonalVal* ValPtr = nullptr; + uint8_t QuantIdx = 0; + TScaledBlock ScaledBlock; +}; class TAtrac3BitStreamWriter : public virtual TAtrac3Data { + struct TTonalComponentsSubGroup { + std::vector<uint8_t> SubGroupMap; + std::vector<const TTonalComponent*> SubGroupPtr; + }; TOma* Container; const TContainerParams Params; std::vector<char> OutBuffer; - uint32_t CLCEnc(const uint32_t selector, const int mantissas[MAXSPECPERBLOCK], const uint32_t blockSize, NBitStream::TBitStream* bitStream); - uint32_t VLCEnc(const uint32_t selector, const int mantissas[MAXSPECPERBLOCK], const uint32_t blockSize, NBitStream::TBitStream* bitStream); - std::pair<uint8_t, uint32_t> CalcSpecsBitsConsumption(const std::vector<NAtracDEnc::TScaledBlock>& scaledBlocks, const std::vector<uint32_t>& precisionPerEachBlocks, int* mantisas); - void EncodeSpecs(const std::vector<NAtracDEnc::TScaledBlock>& scaledBlocks, const std::vector<uint32_t>& bitsPerEachBlock, NBitStream::TBitStream* bitStream); + + uint32_t CLCEnc(const uint32_t selector, const int mantissas[MaxSpecsPerBlock], + const uint32_t blockSize, NBitStream::TBitStream* bitStream); + + uint32_t VLCEnc(const uint32_t selector, const int mantissas[MaxSpecsPerBlock], + const uint32_t blockSize, NBitStream::TBitStream* bitStream); + + std::vector<uint32_t> CalcBitsAllocation(const std::vector<TScaledBlock>& scaledBlocks, + uint32_t bfuNum, TFloat spread, TFloat shift); + + std::pair<uint8_t, std::vector<uint32_t>> CreateAllocation(const std::vector<TScaledBlock>& scaledBlocks, + uint16_t bitsUsed, int mt[MaxSpecs]); + + std::pair<uint8_t, uint32_t> CalcSpecsBitsConsumption(const std::vector<TScaledBlock>& scaledBlocks, + const std::vector<uint32_t>& precisionPerEachBlocks, + int* mantisas); + + void EncodeSpecs(const std::vector<TScaledBlock>& scaledBlocks, NBitStream::TBitStream* bitStream, + uint16_t bitsUsed); + + uint8_t GroupTonalComponents(const std::vector<TTonalComponent>& tonalComponents, + TTonalComponentsSubGroup groups[64]); + + uint16_t EncodeTonalComponents(const std::vector<TTonalComponent>& tonalComponents, + NBitStream::TBitStream* bitStream, uint8_t numQmfBand); public: TAtrac3BitStreamWriter(TOma* container, const TContainerParams& params) //no mono mode for atrac3 : Container(container) @@ -25,5 +62,10 @@ public: { } - void WriteSoundUnit(const TAtrac3Data::SubbandInfo& subbandInfo, const std::vector<NAtracDEnc::TScaledBlock>& scaledBlocks); + void WriteSoundUnit(const TAtrac3Data::SubbandInfo& subbandInfo, + const std::vector<TTonalComponent>& tonalComponents, + const std::vector<TScaledBlock>& scaledBlocks); }; + +} // namespace NAtrac3 +} // namespace NAtracDEnc diff --git a/src/atrac/atrac3_qmf.h b/src/atrac/atrac3_qmf.h index bcd0475..f0ef805 100644 --- a/src/atrac/atrac3_qmf.h +++ b/src/atrac/atrac3_qmf.h @@ -2,22 +2,26 @@ #include <vector> #include "../qmf/qmf.h" +namespace NAtracDEnc { + template<class TIn> class Atrac3SplitFilterBank { const static int nInSamples = 1024; TQmf<TIn, nInSamples> Qmf1; TQmf<TIn, nInSamples / 2> Qmf2; TQmf<TIn, nInSamples / 2> Qmf3; - std::vector<double> Buf1; - std::vector<double> Buf2; + std::vector<TFloat> Buf1; + std::vector<TFloat> Buf2; public: Atrac3SplitFilterBank() { Buf1.resize(nInSamples); Buf2.resize(nInSamples); } - void Split(TIn* pcm, double* subs[4]) { + void Split(TIn* pcm, TFloat* subs[4]) { Qmf1.Split(pcm, Buf1.data(), Buf2.data()); Qmf2.Split(Buf1.data(), subs[0], subs[1]); Qmf3.Split(Buf2.data(), subs[3], subs[2]); } }; + +} //namespace NAtracDEnc diff --git a/src/atrac/atrac_psy_common.cpp b/src/atrac/atrac_psy_common.cpp new file mode 100644 index 0000000..44f973c --- /dev/null +++ b/src/atrac/atrac_psy_common.cpp @@ -0,0 +1,26 @@ +#include "atrac_psy_common.h" + +namespace NAtracDEnc { + +//returns 1 for tone-like, 0 - noise-like +TFloat AnalizeScaleFactorSpread(const std::vector<TScaledBlock>& scaledBlocks) { + TFloat s = 0.0; + for (int i = 0; i < scaledBlocks.size(); ++i) { + s += scaledBlocks[i].ScaleFactorIndex; + } + s /= scaledBlocks.size(); + TFloat sigma = 0.0; + TFloat t = 0.0; + for (int i = 0; i < scaledBlocks.size(); ++i) { + t = (scaledBlocks[i].ScaleFactorIndex - s); + t *= t; + sigma += t; + } + sigma /= scaledBlocks.size(); + sigma = sqrt(sigma); + if (sigma > 14.0) + sigma = 14.0; + return sigma/14.0; +} + +} //namespace NAtracDEnc diff --git a/src/atrac/atrac_psy_common.h b/src/atrac/atrac_psy_common.h new file mode 100644 index 0000000..4c580a4 --- /dev/null +++ b/src/atrac/atrac_psy_common.h @@ -0,0 +1,8 @@ +#pragma once +#include "atrac_scale.h" + +namespace NAtracDEnc { + +double AnalizeScaleFactorSpread(const std::vector<TScaledBlock>& scaledBlocks); + +} //namespace NAtracDEnc diff --git a/src/atrac/atrac_scale.cpp b/src/atrac/atrac_scale.cpp index 92d2645..a03bc13 100644 --- a/src/atrac/atrac_scale.cpp +++ b/src/atrac/atrac_scale.cpp @@ -4,47 +4,65 @@ #include <cmath> #include <iostream> #include <algorithm> + namespace NAtracDEnc { + using std::vector; using std::map; -using namespace std; +using std::cerr; +using std::endl; + +using std::abs; + static const uint32_t MAX_SCALE = 65536; template<class TBaseData> -vector<TScaledBlock> TScaler<TBaseData>::Scale(const vector<double>& specs, const TBlockSize& blockSize) { +TScaledBlock TScaler<TBaseData>::Scale(const TFloat* in, uint16_t len) { + TFloat maxAbsSpec = 0; + for (uint16_t i = 0; i < len; ++i) { + const TFloat absSpec = abs(in[i]); + if (absSpec > maxAbsSpec) { + if (absSpec > MAX_SCALE) { + cerr << "Scale error: absSpec > MAX_SCALE, val: " << absSpec << endl; + maxAbsSpec = MAX_SCALE; + } else { + maxAbsSpec = absSpec; + } + } + } + const map<TFloat, uint8_t>::const_iterator scaleIter = ScaleIndex.lower_bound(maxAbsSpec); + const TFloat scaleFactor = scaleIter->first; + const uint8_t scaleFactorIndex = scaleIter->second; + TScaledBlock res(scaleFactorIndex); + for (uint16_t i = 0; i < len; ++i) { + const TFloat scaledValue = in[i] / scaleFactor; + if (scaledValue > 1.0) { + cerr << "got "<< scaledValue << " it is wrong scalling" << endl; + } + res.Values.push_back(scaledValue); + } + return res; +} + +template<class TBaseData> +vector<TScaledBlock> TScaler<TBaseData>::ScaleFrame(const vector<TFloat>& specs, const TBlockSize& blockSize) { vector<TScaledBlock> scaledBlocks; for (uint8_t bandNum = 0; bandNum < this->NumQMF; ++bandNum) { const bool shortWinMode = !!blockSize.LogCount[bandNum]; for (uint8_t blockNum = this->BlocksPerBand[bandNum]; blockNum < this->BlocksPerBand[bandNum + 1]; ++blockNum) { - const uint16_t specNumStart = shortWinMode ? TBaseData::SpecsStartShort[blockNum] : TBaseData::SpecsStartLong[blockNum]; - const uint16_t specNumEnd = specNumStart + this->SpecsPerBlock[blockNum]; - double maxAbsSpec = 0; - for (uint16_t curSpec = specNumStart; curSpec < specNumEnd; ++curSpec) { - const double absSpec = abs(specs[curSpec]); - if (absSpec > maxAbsSpec) { - if (absSpec > MAX_SCALE) { - cerr << "got " << absSpec << " value - overflow" << endl; - maxAbsSpec = MAX_SCALE; - } else { - maxAbsSpec = absSpec; - } - } - } - const map<double, uint8_t>::const_iterator scaleIter = ScaleIndex.lower_bound(maxAbsSpec); - const double scaleFactor = scaleIter->first; - const uint8_t scaleFactorIndex = scaleIter->second; - scaledBlocks.push_back(TScaledBlock(scaleFactorIndex)); - for (uint16_t specNum = specNumStart; specNum < specNumEnd; ++specNum) { - const double scaledValue = specs[specNum] / scaleFactor; - if (scaledValue > 1.0) - cerr << "got "<< scaledValue << " value - wrong scalling" << endl; - scaledBlocks.back().Values.push_back(scaledValue); - } + const uint16_t specNumStart = shortWinMode ? TBaseData::SpecsStartShort[blockNum] : + TBaseData::SpecsStartLong[blockNum]; + scaledBlocks.emplace_back(Scale(&specs[specNumStart], this->SpecsPerBlock[blockNum])); } } return scaledBlocks; } -template class TScaler<TAtrac1Data>; -template class TScaler<TAtrac3Data>; -} + +template +class TScaler<NAtrac1::TAtrac1Data>; + +template +class TScaler<NAtrac3::TAtrac3Data>; + +} //namespace NAtracDEnc diff --git a/src/atrac/atrac_scale.h b/src/atrac/atrac_scale.h index dd437a2..499fac2 100644 --- a/src/atrac/atrac_scale.h +++ b/src/atrac/atrac_scale.h @@ -4,24 +4,60 @@ #include <cstdint> #include "atrac1.h" +#include "../config.h" + namespace NAtracDEnc { struct TScaledBlock { TScaledBlock(uint8_t sfi) : ScaleFactorIndex(sfi) {} - const uint8_t ScaleFactorIndex = 0; - std::vector<double> Values; + /* const */ uint8_t ScaleFactorIndex = 0; + std::vector<TFloat> Values; }; +class TBlockSize; + template <class TBaseData> class TScaler : public TBaseData { - std::map<double, uint8_t>ScaleIndex; + std::map<TFloat, uint8_t>ScaleIndex; public: TScaler() { for (int i = 0; i < 64; i++) { ScaleIndex[TBaseData::ScaleTable[i]] = i; } } - std::vector<TScaledBlock> Scale(const std::vector<double>& specs, const TBlockSize& blockSize); + TScaledBlock Scale(const TFloat* in, uint16_t len); + std::vector<TScaledBlock> ScaleFrame(const std::vector<TFloat>& specs, const TBlockSize& blockSize); +}; + +class TBlockSize { + static std::array<int, 4> Parse(NBitStream::TBitStream* stream) { + //ATRAC1 - 3 subbands, ATRAC3 - 4 subbands. + //TODO: rewrite + std::array<int, 4> tmp; + tmp[0] = 2 - stream->Read(2); + tmp[1] = 2 - stream->Read(2); + tmp[2] = 3 - stream->Read(2); + stream->Read(2); //skip unused 2 bits + return tmp; + } + static std::array<int, 4> Create(bool lowShort, bool midShort, bool hiShort) { + std::array<int, 4> tmp; + tmp[0] = lowShort ? 2 : 0; + tmp[1] = midShort ? 2 : 0; + tmp[2] = hiShort ? 3 : 0; + return tmp; + } +public: + TBlockSize(NBitStream::TBitStream* stream) + : LogCount(Parse(stream)) + {} + TBlockSize(bool lowShort, bool midShort, bool hiShort) + : LogCount(Create(lowShort, midShort, hiShort)) + {} + TBlockSize() + : LogCount({{0, 0, 0, 0}}) + {} + const std::array<int, 4> LogCount; }; -} +} //namespace NAtracDEnc |