diff options
author | Daniil Cherednik <dan.cherednik@gmail.com> | 2016-03-13 09:49:33 +0300 |
---|---|---|
committer | Daniil Cherednik <dan.cherednik@gmail.com> | 2016-07-17 20:26:30 +0300 |
commit | 59818683fe2930ea4a7f898f43f47db94f437cc9 (patch) | |
tree | 03b6522e3a2e9926d2de4faabad6a700b35b90fd /src/atrac | |
parent | b4df8a7c2dd12eea27c8cc52bd52a1bb8c00943f (diff) | |
download | atracdenc-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.cpp | 23 | ||||
-rw-r--r-- | src/atrac/atrac3.h | 189 | ||||
-rw-r--r-- | src/atrac/atrac3_bitstream.cpp | 143 | ||||
-rw-r--r-- | src/atrac/atrac3_bitstream.h | 27 | ||||
-rw-r--r-- | src/atrac/atrac3_qmf.h | 23 | ||||
-rw-r--r-- | src/atrac/atrac_scale.cpp | 4 |
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>; } |