aboutsummaryrefslogtreecommitdiffstats
path: root/src/atrac
diff options
context:
space:
mode:
authorDaniil Cherednik <dan.cherednik@gmail.com>2016-03-13 09:49:33 +0300
committerDaniil Cherednik <dan.cherednik@gmail.com>2016-07-17 20:26:30 +0300
commit59818683fe2930ea4a7f898f43f47db94f437cc9 (patch)
tree03b6522e3a2e9926d2de4faabad6a700b35b90fd /src/atrac
parentb4df8a7c2dd12eea27c8cc52bd52a1bb8c00943f (diff)
downloadatracdenc-59818683fe2930ea4a7f898f43f47db94f437cc9.tar.gz
Initial implementation of atrac3 stream (CLC and VLC)
- no psy, gc, tonal component encoding, js
Diffstat (limited to 'src/atrac')
-rw-r--r--src/atrac/atrac3.cpp23
-rw-r--r--src/atrac/atrac3.h189
-rw-r--r--src/atrac/atrac3_bitstream.cpp143
-rw-r--r--src/atrac/atrac3_bitstream.h27
-rw-r--r--src/atrac/atrac3_qmf.h23
-rw-r--r--src/atrac/atrac_scale.cpp4
6 files changed, 408 insertions, 1 deletions
diff --git a/src/atrac/atrac3.cpp b/src/atrac/atrac3.cpp
new file mode 100644
index 0000000..54bf497
--- /dev/null
+++ b/src/atrac/atrac3.cpp
@@ -0,0 +1,23 @@
+#include "atrac3.h"
+#include <algorithm>
+constexpr uint32_t TAtrac3Data::BlockSizeTab[33];
+constexpr uint32_t TAtrac3Data::ClcLengthTab[8];
+constexpr double TAtrac3Data::MaxQuant[8];
+constexpr uint32_t TAtrac3Data::BlocksPerBand[4 + 1];
+constexpr uint32_t TAtrac3Data::SpecsPerBlock[33];
+constexpr TAtrac3Data::THuffEntry TAtrac3Data::HuffTable1[HuffTable1Sz];
+constexpr TAtrac3Data::THuffEntry TAtrac3Data::HuffTable2[HuffTable2Sz];
+constexpr TAtrac3Data::THuffEntry TAtrac3Data::HuffTable3[HuffTable3Sz];
+constexpr TAtrac3Data::THuffEntry TAtrac3Data::HuffTable5[HuffTable5Sz];
+constexpr TAtrac3Data::THuffEntry TAtrac3Data::HuffTable6[HuffTable6Sz];
+constexpr TAtrac3Data::THuffEntry TAtrac3Data::HuffTable7[HuffTable7Sz];
+constexpr TAtrac3Data::THuffTablePair TAtrac3Data::HuffTables[7];
+
+constexpr TContainerParams TAtrac3Data::ContainerParams[8];
+double TAtrac3Data::EncodeWindow[256] = {0};
+double TAtrac3Data::ScaleTable[64] = {0};
+
+const TContainerParams* TAtrac3Data::GetContainerParamsForBitrate(uint32_t bitrate) {
+ std::cout << bitrate << std::endl;
+ return std::lower_bound(ContainerParams, ContainerParams+8, bitrate);
+}
diff --git a/src/atrac/atrac3.h b/src/atrac/atrac3.h
new file mode 100644
index 0000000..01c8ae0
--- /dev/null
+++ b/src/atrac/atrac3.h
@@ -0,0 +1,189 @@
+#pragma once
+#include <math.h>
+#include <cstdint>
+#include <vector>
+#include <cassert>
+#include <iostream>
+
+
+struct TContainerParams {
+ const uint32_t Bitrate;
+ const uint16_t FrameSz;
+ const bool Js;
+};
+
+inline bool operator< (const TContainerParams& x, const TContainerParams& y)
+{
+ return x.Bitrate < y.Bitrate;
+}
+inline bool operator> (const TContainerParams& x, const TContainerParams& y)
+{
+ return x.Bitrate > y.Bitrate;
+}
+inline bool operator< (const TContainerParams& x, const unsigned int y)
+{
+ return x.Bitrate < y;
+}
+inline bool operator> (const TContainerParams& x, const unsigned int y)
+{
+ return x.Bitrate > y;
+}
+
+class TAtrac3Data {
+protected:
+ static double ScaleTable[64];
+ static double EncodeWindow[256];
+
+ static const uint32_t NumSamples=1024;
+ static const uint32_t frameSz = 152;
+ static constexpr double MaxQuant[8] = {
+ 0.0, 1.5, 2.5, 3.5,
+ 4.5, 7.5, 15.5, 31.5
+ };
+ static constexpr uint32_t BlockSizeTab[33] = {
+ 0, 8, 16, 24, 32, 40, 48, 56,
+ 64, 80, 96, 112, 128, 144, 160, 176,
+ 192, 224, 256, 288, 320, 352, 384, 416,
+ 448, 480, 512, 576, 640, 704, 768, 896,
+ 1024
+ };
+ static constexpr uint32_t const * const SpecsStartShort = &BlockSizeTab[0];
+
+ 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 constexpr uint32_t BlocksPerBand[NumQMF + 1] = {0, 18, 26, 30, 32};
+ static constexpr uint32_t SpecsPerBlock[33] = {
+ 8, 8, 8, 8, 8, 8, 8, 8,
+ 16, 16, 16, 16, 16, 16, 16, 16,
+ 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 64, 64, 64, 64, 128, 128,
+ 128
+ };
+ struct THuffEntry {
+ const uint8_t Code;
+ const uint8_t Bits;
+ };
+ static constexpr uint8_t HuffTable1Sz = 9;
+ static constexpr THuffEntry HuffTable1[HuffTable1Sz] = {
+ { 0x0, 1 },
+ { 0x4, 3 }, { 0x5, 3 },
+ { 0xC, 4 }, { 0xD, 4 },
+ { 0x1C, 5 }, { 0x1D, 5 }, { 0x1E, 5 }, { 0x1F, 5 }
+ };
+ static constexpr uint8_t HuffTable2Sz = 5;
+ static constexpr THuffEntry HuffTable2[HuffTable2Sz] = {
+ { 0x0, 1 },
+ { 0x4, 3 }, { 0x5, 3 }, { 0x6, 3 }, { 0x7, 3 }
+ };
+ static constexpr uint8_t HuffTable3Sz = 7;
+ static constexpr THuffEntry HuffTable3[HuffTable3Sz] = {
+ { 0x0, 1 },
+ { 0x4, 3}, { 0x5, 3 },
+ { 0xC, 4 }, { 0xD, 4 }, { 0xE, 4 }, { 0xF, 4 }
+ };
+ static constexpr uint8_t HuffTable5Sz = 15;
+ static constexpr THuffEntry HuffTable5[HuffTable5Sz] = {
+ { 0x0, 2 },
+ { 0x2, 3 }, { 0x3, 3 },
+ { 0x8, 4 }, { 0x9, 4 }, { 0xA, 4 }, { 0xB, 4 }, //{ 0xC, 4 }, { 0xD, 4 },
+ { 0x1C, 5 }, { 0x1D, 5 },
+ { 0x3C, 6 }, { 0x3D, 6 }, { 0x3E, 6 }, { 0x3F, 6},
+ { 0xC, 4 }, { 0xD, 4 } //TODO: is it right table???
+ };
+ static constexpr uint8_t HuffTable6Sz = 31;
+ static constexpr THuffEntry HuffTable6[HuffTable6Sz] = {
+ { 0x0, 3 },
+ { 0x2, 4 }, { 0x3, 4 }, { 0x4, 4 }, { 0x5, 4 }, { 0x6, 4 }, { 0x7, 4 }, //{ 0x8, 4 }, { 0x9, 4 },
+ { 0x14, 5 }, { 0x15, 5 }, { 0x16, 5 }, { 0x17, 5 }, { 0x18, 5 }, { 0x19, 5 },
+ { 0x34, 6 }, { 0x35, 6 }, { 0x36, 6 }, { 0x37, 6 }, { 0x38, 6 }, { 0x39, 6 }, { 0x3A, 6 }, { 0x3B, 6 },
+ { 0x78, 7 }, { 0x79, 7 }, { 0x7A, 7 }, { 0x7B, 7 }, { 0x7C, 7 }, { 0x7D, 7 }, { 0x7E, 7 }, { 0x7F, 7 },
+ { 0x8, 4 }, { 0x9, 4 } //TODO: is it right table???
+ };
+ static constexpr uint8_t HuffTable7Sz = 63;
+ 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 },
+ { 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 },
+ { 0x2, 4 }, { 0x3, 4 } //TODO: is it right table???
+ };
+
+ struct THuffTablePair {
+ const THuffEntry* Table;
+ const uint32_t Sz;
+ };
+
+ static constexpr THuffTablePair HuffTables[7] {
+ { HuffTable1, HuffTable1Sz },
+ { HuffTable2, HuffTable2Sz },
+ { HuffTable3, HuffTable3Sz },
+ { HuffTable1, HuffTable1Sz },
+ { HuffTable5, HuffTable5Sz },
+ { HuffTable6, HuffTable6Sz },
+ { HuffTable7, HuffTable7Sz }
+ };
+public:
+ TAtrac3Data() {
+ if (ScaleTable[0] == 0) {
+ for (uint32_t i = 0; i < 64; i++) {
+ ScaleTable[i] = pow(2.0, (double)(i - 15.0) / 3.0);
+ }
+ }
+ for (int i = 0; i < 256; i++) {
+ EncodeWindow[i] = (sin(((i + 0.5) / 256.0 - 0.5) * M_PI) + 1.0) * 0.5;
+ }
+ }
+ static uint32_t MantissaToCLcIdx(int32_t mantissa) {
+ assert(mantissa > -3 && mantissa < 2);
+ const uint32_t mantissa_clc_rtab[4] = { 2, 3, 0, 1};
+ return mantissa_clc_rtab[mantissa + 2];
+ }
+ static uint32_t MantissasToVlcIndex(int32_t a, int32_t b) {
+ assert(a > -2 && a < 2);
+ assert(b > -2 && b < 2);
+ const uint32_t mantissas_vlc_rtab[9] = { 8, 4, 7, 2, 0, 1, 6, 3, 5 };
+ const uint8_t idx = 3 * (a + 1) + (b + 1);
+ return mantissas_vlc_rtab[idx];
+ }
+ static constexpr TContainerParams ContainerParams[8] = {
+ { 66150, 192, true },
+ { 93713, 272, true },
+ { 104738, 304, false },
+ { 132300, 384, false },
+ { 146081, 424, false },
+ { 176400, 512, false },
+ { 264600, 768, false },
+ { 352800, 1024, false }
+ };
+ static const TContainerParams* GetContainerParamsForBitrate(uint32_t bitrate);
+};
+
+class TAtrac3SubbandInfo {
+public:
+ struct TGainPoint {
+ const uint32_t Level;
+ const uint32_t Location;
+ };
+private:
+ std::vector<std::vector<TGainPoint>> Info;
+public:
+ TAtrac3SubbandInfo()
+ {
+ Info.resize(4);
+ }
+ uint32_t GetQmfNum() const {
+ return Info.size();
+ }
+ const std::vector<TGainPoint>& GetGainPoints(uint32_t i) const {
+ assert(Info[i].size() == 0);
+ return Info[i];
+ }
+};
+
diff --git a/src/atrac/atrac3_bitstream.cpp b/src/atrac/atrac3_bitstream.cpp
new file mode 100644
index 0000000..3612afb
--- /dev/null
+++ b/src/atrac/atrac3_bitstream.cpp
@@ -0,0 +1,143 @@
+#include "atrac3_bitstream.h"
+#include "../bitstream/bitstream.h"
+#include <cassert>
+#include <algorithm>
+#include <iostream>
+#include <vector>
+#include <cstdlib>
+
+using NAtracDEnc::TScaledBlock;
+using std::vector;
+
+void TAtrac3BitStreamWriter::CLCEnc(const uint32_t selector, const int mantissas[MAXSPECPERBLOCK], const uint32_t blockSize, NBitStream::TBitStream* bitStream) {
+ uint32_t numBits = ClcLengthTab[selector];
+ if (selector > 1) {
+ for (uint32_t i = 0; i < blockSize; ++i) {
+ bitStream->Write(NBitStream::MakeSign(mantissas[i], numBits), numBits);
+ }
+ } else {
+ for (uint32_t i = 0; i < blockSize / 2; ++i) {
+ uint32_t code = MantissaToCLcIdx(mantissas[i * 2]) << 2;
+ code |= MantissaToCLcIdx(mantissas[i * 2 + 1]);
+ assert(numBits == 4);
+ bitStream->Write(code, numBits);
+ }
+ }
+}
+
+void TAtrac3BitStreamWriter::VLCEnc(const uint32_t selector, const int mantissas[MAXSPECPERBLOCK], const uint32_t blockSize, NBitStream::TBitStream* bitStream) {
+ const THuffEntry* huffTable = HuffTables[selector - 1].Table;
+ const uint8_t tableSz = HuffTables[selector - 1].Sz;
+ if (selector > 1) {
+ for (uint32_t i = 0; i < blockSize; ++i) {
+ int m = mantissas[i];
+ uint32_t huffS = (m < 0) ? (((uint32_t)(-m)) << 1) | 1 : ((uint32_t)m) << 1;
+ if (huffS)
+ huffS -= 1;
+ assert(huffS < 256);
+ assert(huffS < tableSz);
+ std::cout << "m: " << m << "huff: " << huffS << std::endl;
+ bitStream->Write(huffTable[huffS].Code, huffTable[huffS].Bits);
+ }
+ } else {
+ assert(tableSz == 9);
+ for (uint32_t i = 0; i < blockSize / 2; ++i) {
+ const int ma = mantissas[i * 2];
+ const int mb = mantissas[i * 2 + 1];
+ const uint32_t huffS = MantissasToVlcIndex(ma, mb);
+ bitStream->Write(huffTable[huffS].Code, huffTable[huffS].Bits);
+ }
+ }
+}
+void TAtrac3BitStreamWriter::EncodeSpecs(const vector<TScaledBlock>& scaledBlocks, const vector<uint32_t>& precisionPerEachBlocks, NBitStream::TBitStream* bitStream) {
+ const uint32_t numBlocks = precisionPerEachBlocks.size(); //number of blocks to save
+ const uint32_t codingMode = 0;//1; //0 - VLC, 1 - CLC
+ int mantisas[MAXSPECPERBLOCK];
+ assert(numBlocks <= 32);
+ bitStream->Write(numBlocks-1, 5);
+ bitStream->Write(codingMode, 1);
+
+ for (uint32_t i = 0; i < numBlocks; ++i) {
+ uint32_t val = precisionPerEachBlocks[i]; //coding table used (VLC) or number of bits used (CLC)
+ bitStream->Write(val, 3);
+ }
+ for (uint32_t i = 0; i < numBlocks; ++i) {
+ if (precisionPerEachBlocks[i] == 0)
+ continue;
+ bitStream->Write(scaledBlocks[i].ScaleFactorIndex, 6);
+ }
+ for (uint32_t i = 0; i < numBlocks; ++i) {
+ if (precisionPerEachBlocks[i] == 0)
+ continue;
+
+ 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)];
+
+ for (uint32_t j = 0; first < last; first++, j++) {
+ mantisas[j] = round(scaledBlocks[i].Values[j] * mul);
+ }
+
+ if (codingMode == 1) {
+ CLCEnc(precisionPerEachBlocks[i], mantisas, blockSize, bitStream);
+ } else {
+ VLCEnc(precisionPerEachBlocks[i], mantisas, blockSize, bitStream);
+ }
+ }
+
+
+}
+
+void TAtrac3BitStreamWriter::WriteSoundUnit(const TAtrac3SubbandInfo& subbandInfo, const vector<TScaledBlock>& scaledBlocks) {
+ NBitStream::TBitStream bitStream;
+ if (Params.Js) {
+ //TODO
+ } else {
+ bitStream.Write(0x28, 6); //0x28 - id
+ }
+ const uint32_t numQmfBand = subbandInfo.GetQmfNum();
+ bitStream.Write(numQmfBand - 1, 2);
+
+ //write gain info
+ for (uint32_t band = 0; band < numQmfBand; ++band) {
+ const vector<TAtrac3SubbandInfo::TGainPoint>& GainPoints = subbandInfo.GetGainPoints(band);
+ bitStream.Write(GainPoints.size(), 3);
+ assert(GainPoints.size() == 0);
+ for (const TAtrac3SubbandInfo::TGainPoint& point : GainPoints) {
+ abort();
+ bitStream.Write(point.Level, 4);
+ bitStream.Write(point.Location, 5);
+ }
+ }
+
+ //tonal components
+ bitStream.Write(0, 5); //disabled
+
+ vector<uint32_t> precisionPerEachBlocks(27,1);
+ for (int i = 0; i < 2; i++) {
+ //precisionPerEachBlocks[i] = 4;
+ }
+
+ //spec
+ EncodeSpecs(scaledBlocks, precisionPerEachBlocks, &bitStream);
+
+ 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);
+ OutBuffer.insert(OutBuffer.end(), channel.begin(), channel.end());
+ Container->WriteFrame(OutBuffer);
+ OutBuffer.clear();
+ }
+
+}
diff --git a/src/atrac/atrac3_bitstream.h b/src/atrac/atrac3_bitstream.h
new file mode 100644
index 0000000..8a63d01
--- /dev/null
+++ b/src/atrac/atrac3_bitstream.h
@@ -0,0 +1,27 @@
+#pragma once
+#include "atrac3.h"
+#include "atrac1.h"
+#include "../aea.h"
+#include "../oma.h"
+#include "../atrac/atrac1.h"
+#include "atrac_scale.h"
+#include <vector>
+
+static const uint32_t MAXSPECPERBLOCK = 128;
+
+class TAtrac3BitStreamWriter : public virtual TAtrac3Data {
+ TOma* Container;
+ const TContainerParams Params;
+ std::vector<char> OutBuffer;
+ void CLCEnc(const uint32_t selector, const int mantissas[MAXSPECPERBLOCK], const uint32_t blockSize, NBitStream::TBitStream* bitStream);
+ void VLCEnc(const uint32_t selector, const int mantissas[MAXSPECPERBLOCK], const uint32_t blockSize, NBitStream::TBitStream* bitStream);
+ void EncodeSpecs(const std::vector<NAtracDEnc::TScaledBlock>& scaledBlocks, const std::vector<uint32_t>& bitsPerEachBlock, NBitStream::TBitStream* bitStream);
+public:
+ TAtrac3BitStreamWriter(TOma* container, const TContainerParams& params) //no mono mode for atrac3
+ : Container(container)
+ , Params(params)
+ {
+
+ }
+ void WriteSoundUnit(const TAtrac3SubbandInfo& subbandInfo, const std::vector<NAtracDEnc::TScaledBlock>& scaledBlocks);
+};
diff --git a/src/atrac/atrac3_qmf.h b/src/atrac/atrac3_qmf.h
new file mode 100644
index 0000000..bcd0475
--- /dev/null
+++ b/src/atrac/atrac3_qmf.h
@@ -0,0 +1,23 @@
+#pragma once
+#include <vector>
+#include "../qmf/qmf.h"
+
+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;
+public:
+ Atrac3SplitFilterBank() {
+ Buf1.resize(nInSamples);
+ Buf2.resize(nInSamples);
+ }
+ void Split(TIn* pcm, double* 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]);
+ }
+};
diff --git a/src/atrac/atrac_scale.cpp b/src/atrac/atrac_scale.cpp
index 1e24cb5..92d2645 100644
--- a/src/atrac/atrac_scale.cpp
+++ b/src/atrac/atrac_scale.cpp
@@ -1,5 +1,6 @@
#include "atrac_scale.h"
#include "atrac1.h"
+#include "atrac3.h"
#include <cmath>
#include <iostream>
#include <algorithm>
@@ -16,7 +17,7 @@ vector<TScaledBlock> TScaler<TBaseData>::Scale(const vector<double>& specs, cons
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 ? this->SpecsStartShort[blockNum] : this->SpecsStartLong[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) {
@@ -45,4 +46,5 @@ vector<TScaledBlock> TScaler<TBaseData>::Scale(const vector<double>& specs, cons
return scaledBlocks;
}
template class TScaler<TAtrac1Data>;
+template class TScaler<TAtrac3Data>;
}