aboutsummaryrefslogtreecommitdiffstats
path: root/src/atrac
diff options
context:
space:
mode:
authorDaniil Cherednik <dan.cherednik@gmail.com>2016-06-19 02:58:23 +0300
committerDaniil Cherednik <dan.cherednik@gmail.com>2016-06-19 03:31:55 +0300
commit1151d5831f19a9f24dd0c545a4968606712a62d2 (patch)
treec978c1b9a3fc86fef531dd412fe6b7668b7c0567 /src/atrac
parent8d65a0bd0774e03b3d10354e15f2f3361a2ce26a (diff)
downloadatracdenc-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.cpp13
-rw-r--r--src/atrac/atrac1.h73
-rw-r--r--src/atrac/atrac1_bitalloc.cpp75
-rw-r--r--src/atrac/atrac1_bitalloc.h11
-rw-r--r--src/atrac/atrac1_dequantiser.cpp22
-rw-r--r--src/atrac/atrac1_dequantiser.h8
-rw-r--r--src/atrac/atrac1_qmf.h24
-rw-r--r--src/atrac/atrac3.cpp7
-rw-r--r--src/atrac/atrac3.h46
-rw-r--r--src/atrac/atrac3_bitstream.cpp308
-rw-r--r--src/atrac/atrac3_bitstream.h54
-rw-r--r--src/atrac/atrac3_qmf.h10
-rw-r--r--src/atrac/atrac_psy_common.cpp26
-rw-r--r--src/atrac/atrac_psy_common.h8
-rw-r--r--src/atrac/atrac_scale.cpp76
-rw-r--r--src/atrac/atrac_scale.h46
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