aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorDaniil Cherednik <dan.cherednik@gmail.com>2025-05-31 22:39:38 +0200
committerDaniil Cherednik <dan.cherednik@gmail.com>2025-05-31 22:39:38 +0200
commit1c7f2f821fb965af468cdf2a14df3ff75cc1c352 (patch)
tree1bc92237122b75c67afc326af207cf3cc9eb3d6c /src
parent272af27a3d148bd13e8f15640e53ca70c64ccb9b (diff)
parent6dfc60e9d4791c3385908c61ad75c4a0093ea1eb (diff)
downloadatracdenc-1c7f2f821fb965af468cdf2a14df3ff75cc1c352.tar.gz
Merge branch 'at3plus-dev'
It looks like we are able to encode ATRAC3PLUS compatible bitstream so we can merge at3p development branch in to the main branch. Current limitation for AT3P mode: - Only 352 Kbps (proper bit allocation and some psychoacoustic must be implemented) - GHA sometime works with error (but huge bitrate hide it) - No VLC, VQ, delta encoding - No noise substitution - No gain control - No window shape switching
Diffstat (limited to 'src')
-rw-r--r--src/CMakeLists.txt35
-rw-r--r--src/atrac/at3p/at3p.cpp257
-rw-r--r--src/atrac/at3p/at3p_bitstream.cpp624
-rw-r--r--src/atrac/at3p/at3p_bitstream.h59
-rw-r--r--src/atrac/at3p/at3p_bitstream_impl.h149
-rw-r--r--src/atrac/at3p/at3p_bitstream_ut.cpp139
-rw-r--r--src/atrac/at3p/at3p_gha.cpp859
-rw-r--r--src/atrac/at3p/at3p_gha.h78
-rw-r--r--src/atrac/at3p/at3p_gha_ut.cpp787
-rw-r--r--src/atrac/at3p/at3p_mdct.cpp104
-rw-r--r--src/atrac/at3p/at3p_mdct.h50
-rw-r--r--src/atrac/at3p/at3p_mdct_ut.cpp106
-rw-r--r--src/atrac/at3p/at3p_tables.cpp125
-rw-r--r--src/atrac/at3p/at3p_tables.h79
-rw-r--r--src/atrac/at3p/ff/atrac3plus.h165
-rw-r--r--src/atrac/at3p/ff/atrac3plus_data.h1672
-rw-r--r--src/atrac/at3p/ff/atrac3plusdsp.c204
-rw-r--r--src/atrac/at3p/ghasend_tool.cpp90
-rw-r--r--src/atrac/atrac3plus_pqf/ut/ipqf_ut.cpp14
-rw-r--r--src/atrac/atrac_scale.cpp4
-rw-r--r--src/atrac1denc.cpp4
-rw-r--r--src/atrac1denc.h5
-rw-r--r--src/atrac3denc.cpp1
-rw-r--r--src/atrac3p.h55
-rw-r--r--src/lib/bs_encode/encode.cpp184
-rw-r--r--src/lib/bs_encode/encode.h71
-rw-r--r--src/lib/bs_encode/encode_ut.cpp178
-rw-r--r--src/lib/fft/kissfft_impl/kiss_fft.h1
-rw-r--r--src/lib/fft/kissfft_impl/tools/kiss_fftr.c153
-rw-r--r--src/lib/fft/kissfft_impl/tools/kiss_fftr.h54
m---------src/lib/libgha0
-rw-r--r--src/main.cpp82
-rw-r--r--src/oma.cpp6
-rw-r--r--src/pcmengin.h36
-rw-r--r--src/util.h5
-rw-r--r--src/wav.cpp4
-rw-r--r--src/wav.h9
37 files changed, 6420 insertions, 28 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 57a5e41..17f35b3 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -1,10 +1,10 @@
CMAKE_MINIMUM_REQUIRED(VERSION 3.1...3.26)
-set (CMAKE_CXX_STANDARD 11)
+set (CMAKE_CXX_STANDARD 14)
set (CMAKE_C_STANDARD 11)
#add_definitions( "-Wall -O2 -g -Rpass-analysis=loop-vectorize" )
-#set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -fsanitize=address -fno-omit-frame-pointer")
+set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -fsanitize=address -fno-omit-frame-pointer")
if(NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE "Release" CACHE STRING "Choose Release or Debug" FORCE)
@@ -59,11 +59,19 @@ include_directories(
"."
"lib"
"lib/liboma/include"
+ "lib/fft/kissfft_impl"
)
-set(SOURCE_FFT_LIB lib/fft/kissfft_impl/kiss_fft.c)
+set(SOURCE_FFT_LIB
+ lib/fft/kissfft_impl/kiss_fft.c
+ lib/fft/kissfft_impl/tools/kiss_fftr.c
+)
+
+set_source_files_properties(${SOURCE_FFT_LIB} PROPERTIES COMPILE_FLAGS -Dkiss_fft_scalar=float)
+add_library(fft_impl STATIC ${SOURCE_FFT_LIB})
-set_source_files_properties(lib/fft/kissfft_impl/kiss_fft.c PROPERTIES COMPILE_FLAGS -Dkiss_fft_scalar=float)
+set(GHA_FFT_LIB fft_impl)
+add_subdirectory(lib/libgha)
set(SOURCE_OMA_LIB lib/liboma/src/liboma.c)
set(SOURCE_BITSTREAM_LIB lib/bitstream/bitstream.cpp)
@@ -84,11 +92,17 @@ set(SOURCE_ATRACDENC_IMPL
atrac3denc.cpp
atrac/atrac3.cpp
atrac/atrac3_bitstream.cpp
+ atrac/atrac3plus_pqf/atrac3plus_pqf.c
+ atrac/at3p/ff/atrac3plusdsp.c
+ atrac/at3p/at3p.cpp
+ atrac/at3p/at3p_bitstream.cpp
+ atrac/at3p/at3p_gha.cpp
+ atrac/at3p/at3p_mdct.cpp
+ atrac/at3p/at3p_tables.cpp
lib/mdct/mdct.cpp
+ lib/bs_encode/encode.cpp
)
-add_library(fft_impl STATIC ${SOURCE_FFT_LIB})
-
add_library(pcm_io STATIC ${SOURCE_PCM_IO_LIB})
if (NOT WIN32)
target_link_libraries(pcm_io ${SNDFILE_LIBRARIES})
@@ -97,7 +111,7 @@ endif()
add_library(oma STATIC ${SOURCE_OMA_LIB})
add_library(bitstream STATIC ${SOURCE_BITSTREAM_LIB})
add_library(atracdenc_impl STATIC ${SOURCE_ATRACDENC_IMPL})
-target_link_libraries(atracdenc_impl fft_impl pcm_io oma bitstream ${SNDFILE_LIBRARIES})
+target_link_libraries(atracdenc_impl fft_impl pcm_io oma bitstream ${SNDFILE_LIBRARIES} gha)
set(SOURCE_EXE
main.cpp
help.cpp
@@ -105,3 +119,10 @@ set(SOURCE_EXE
add_executable(atracdenc ${SOURCE_EXE})
target_link_libraries(atracdenc pcm_io oma atracdenc_impl ${SNDFILE_LIBRARIES})
install(TARGETS atracdenc)
+
+#DEVTOOL
+set(GHASENDTOOL_EXE
+ atrac/at3p/ghasend_tool.cpp
+)
+add_executable(ghasendtool ${GHASENDTOOL_EXE})
+target_link_libraries(ghasendtool pcm_io oma atracdenc_impl ${SNDFILE_LIBRARIES})
diff --git a/src/atrac/at3p/at3p.cpp b/src/atrac/at3p/at3p.cpp
new file mode 100644
index 0000000..c48c21c
--- /dev/null
+++ b/src/atrac/at3p/at3p.cpp
@@ -0,0 +1,257 @@
+/*
+ * This file is part of AtracDEnc.
+ *
+ * AtracDEnc is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * AtracDEnc is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with AtracDEnc; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <atrac3p.h>
+
+#include <atrac/atrac3plus_pqf/atrac3plus_pqf.h>
+
+#include "at3p_bitstream.h"
+#include "at3p_gha.h"
+#include "at3p_mdct.h"
+#include "at3p_tables.h"
+#include <atrac/atrac_scale.h>
+
+#include <cassert>
+#include <vector>
+#include <unordered_map>
+
+using std::vector;
+
+namespace NAtracDEnc {
+
+class TAt3PEnc::TImpl {
+public:
+ TImpl(ICompressedOutput* out, int channels, TSettings settings)
+ : BitStream(out, 2048)
+ , ChannelCtx(channels)
+ , GhaProcessor(MakeGhaProcessor0(channels == 2))
+ , Settings(settings)
+ {
+ delay.NumToneBands = 0;
+ }
+
+ TPCMEngine::EProcessResult EncodeFrame(const float* data, int channels);
+private:
+ struct TChannelCtx {
+ TChannelCtx()
+ : PqfCtx(at3plus_pqf_create_a_ctx())
+ , Specs(TAt3PEnc::NumSamples)
+ {}
+
+ ~TChannelCtx() {
+ at3plus_pqf_free_a_ctx(PqfCtx);
+ }
+
+ at3plus_pqf_a_ctx_t PqfCtx;
+
+ float* NextBuf = Buf1;
+ float* CurBuf = nullptr;
+ float Buf1[TAt3PEnc::NumSamples];
+ float Buf2[TAt3PEnc::NumSamples];
+ float PrevBuf[TAt3PEnc::NumSamples];
+ TAt3pMDCT::THistBuf MdctBuf;
+ std::vector<float> Specs;
+ };
+
+ TAt3pMDCT Mdct;
+ TScaler<NAt3p::TScaleTable> Scaler;
+ TAt3PBitStream BitStream;
+ vector<TChannelCtx> ChannelCtx;
+ std::unique_ptr<IGhaProcessor> GhaProcessor;
+ TAt3PGhaData delay;
+ const TSettings Settings;
+};
+
+TPCMEngine::EProcessResult TAt3PEnc::TImpl::
+EncodeFrame(const float* data, int channels)
+{
+ int needMore = 0;
+ for (int ch = 0; ch < channels; ch++) {
+ float src[TAt3PEnc::NumSamples];
+ for (size_t i = 0; i < NumSamples; ++i) {
+ src[i] = data[i * channels + ch];
+ }
+
+ at3plus_pqf_do_analyse(ChannelCtx[ch].PqfCtx, src, ChannelCtx[ch].NextBuf);
+ if (ChannelCtx[ch].CurBuf == nullptr) {
+ assert(ChannelCtx[ch].NextBuf == ChannelCtx[ch].Buf1);
+ ChannelCtx[ch].CurBuf = ChannelCtx[ch].Buf2;
+ std::swap(ChannelCtx[ch].NextBuf, ChannelCtx[ch].CurBuf);
+ needMore++;
+ }
+ }
+
+ if (needMore == channels) {
+ return TPCMEngine::EProcessResult::LOOK_AHEAD;
+ }
+
+ assert(needMore == 0);
+
+ float* b1Prev = ChannelCtx[0].PrevBuf;
+ const float* b1Cur = ChannelCtx[0].CurBuf;
+ const float* b1Next = ChannelCtx[0].NextBuf;
+ float* b2Prev = (channels == 2) ? ChannelCtx[1].PrevBuf : nullptr;
+ const float* b2Cur = (channels == 2) ? ChannelCtx[1].CurBuf : nullptr;
+ const float* b2Next = (channels == 2) ? ChannelCtx[1].NextBuf : nullptr;
+
+
+ const TAt3PGhaData* p = nullptr;
+ if (delay.NumToneBands) {
+ p = &delay;
+ }
+
+ const TAt3PGhaData* tonalBlock = GhaProcessor->DoAnalize({b1Cur, b1Next}, {b2Cur, b2Next}, b1Prev, b2Prev);
+
+ std::vector<std::vector<TScaledBlock>> scaledBlocks;
+ for (int ch = 0; ch < channels; ch++) {
+ float* x = (ch == 0) ? b1Prev : b2Prev;
+ auto& c = ChannelCtx[ch];
+ TAt3pMDCT::TPcmBandsData p;
+ float tmp[2048];
+ //TODO: scale window
+ if (Settings.UseGha & TSettings::GHA_WRITE_RESIUDAL) {
+ for (size_t i = 0; i < 2048; i++) {
+ //TODO: find why we need to add the 0.5db
+ tmp[i] = x[i] / (32768.0 / 1.122018);
+ }
+ } else {
+ for (size_t i = 0; i < 2048; i++) {
+ tmp[i] = 0.0;
+ }
+ }
+ for (size_t b = 0; b < 16; b++) {
+ p[b] = tmp + b * 128;
+ }
+ Mdct.Do(c.Specs.data(), p, c.MdctBuf);
+
+ const auto& block = Scaler.ScaleFrame(c.Specs, NAt3p::TScaleTable::TBlockSizeMod());
+ scaledBlocks.push_back(block);
+ }
+
+ BitStream.WriteFrame(channels, p, scaledBlocks);
+
+ for (int ch = 0; ch < channels; ch++) {
+ if (Settings.UseGha & TSettings::GHA_PASS_INPUT) {
+ memcpy(ChannelCtx[ch].PrevBuf, ChannelCtx[ch].CurBuf, sizeof(float) * TAt3PEnc::NumSamples);
+ } else {
+ memset(ChannelCtx[ch].PrevBuf, 0, sizeof(float) * TAt3PEnc::NumSamples);
+ }
+ std::swap(ChannelCtx[ch].NextBuf, ChannelCtx[ch].CurBuf);
+ }
+ if (tonalBlock && (Settings.UseGha & TSettings::GHA_WRITE_TONAL)) {
+ delay = *tonalBlock;
+ } else {
+ delay.NumToneBands = 0;
+ }
+
+ return TPCMEngine::EProcessResult::PROCESSED;
+}
+
+TAt3PEnc::TAt3PEnc(TCompressedOutputPtr&& out, int channels, TSettings settings)
+ : Out(std::move(out))
+ , Channels(channels)
+ , Impl(new TImpl(Out.get(), Channels, settings))
+{
+}
+
+TPCMEngine::TProcessLambda TAt3PEnc::GetLambda() {
+ return [this](float* data, const TPCMEngine::ProcessMeta&) {
+ return Impl->EncodeFrame(data, Channels);
+ };
+}
+
+static void SetGha(const std::string& str, TAt3PEnc::TSettings& settings) {
+ int mask = std::stoi(str);
+ if (mask > 7 || mask < 0) {
+ throw std::runtime_error("invalud value of GHA processing mask");
+ }
+
+ if (mask & TAt3PEnc::TSettings::GHA_PASS_INPUT)
+ std::cerr << "GHA_PASS_INPUT" << std::endl;
+ if (mask & TAt3PEnc::TSettings::GHA_WRITE_RESIUDAL)
+ std::cerr << "GHA_WRITE_RESIUDAL" << std::endl;
+ if (mask & TAt3PEnc::TSettings::GHA_WRITE_TONAL)
+ std::cerr << "GHA_WRITE_TONAL" << std::endl;
+
+ settings.UseGha = mask;
+}
+
+
+
+void TAt3PEnc::ParseAdvancedOpt(const char* opt, TSettings& settings) {
+ typedef void (*processFn)(const std::string& str, TSettings& settings);
+ static std::unordered_map<std::string, processFn> keys {
+ {"ghadbg", &SetGha}
+ };
+
+ if (opt == nullptr)
+ return;
+
+ const char* start = opt;
+ bool vState = false; //false - key state, true - value state
+ processFn handler = nullptr;
+
+ while (opt) {
+ if (!vState) {
+ if (*opt == ',') {
+ throw std::runtime_error("unexpected \",\" just after key.");
+// if (opt - start > 0) {
+// }
+// opt++;
+// start = opt;
+ } else if (*opt == '=') {
+ auto it = keys.find(std::string(start, opt - start));
+ if (it == keys.end()) {
+ throw std::runtime_error(std::string("unexpected advanced option \"")
+ + std::string(start, opt - start));
+ }
+ handler = it->second;
+ vState = true;
+ opt++;
+ start = opt;
+ } else if (!*opt) {
+ throw std::runtime_error("unexpected end of key token");
+// if (opt - start > 0) {
+// }
+// opt = nullptr;
+ } else {
+ opt++;
+ }
+ } else {
+ if (*opt == ',') {
+ if (opt - start > 0) {
+ handler(std::string(start, opt - start), settings);
+ }
+ opt++;
+ start = opt;
+ vState = false;
+ } else if (*opt == '=') {
+ throw std::runtime_error("unexpected \"=\" inside value token.");
+ } else if (!*opt) {
+ if (opt - start > 0) {
+ handler(std::string(start, opt - start), settings);
+ }
+ opt = nullptr;
+ } else {
+ opt++;
+ }
+ }
+ }
+}
+
+}
diff --git a/src/atrac/at3p/at3p_bitstream.cpp b/src/atrac/at3p/at3p_bitstream.cpp
new file mode 100644
index 0000000..f95018b
--- /dev/null
+++ b/src/atrac/at3p/at3p_bitstream.cpp
@@ -0,0 +1,624 @@
+/*
+ * This file is part of AtracDEnc.
+ *
+ * AtracDEnc is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * AtracDEnc is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with AtracDEnc; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "at3p_bitstream_impl.h"
+#include "at3p_bitstream.h"
+#include "at3p_gha.h"
+#include "at3p_tables.h"
+#include <env.h>
+#include <util.h>
+
+#include "ff/atrac3plus_data.h"
+
+#include <iostream>
+#include <limits>
+#include <memory>
+
+namespace NAtracDEnc {
+
+using namespace NAt3p;
+using std::vector;
+using std::make_pair;
+using std::pair;
+
+static THuffTables HuffTabs;
+
+TTonePackResult CreateFreqBitPack(const TAt3PGhaData::TWaveParam* const param, int len)
+{
+ const int MaxBits = 10;
+
+ int bits[2] = {MaxBits, MaxBits};
+
+ std::vector<TTonePackResult::TEntry> res[2];
+ res[0].reserve(len);
+ res[1].reserve(len);
+
+ // try ascending order
+ {
+ auto& t = res[0];
+ uint16_t prevFreqIndex = param->FreqIndex & 1023;
+ t.emplace_back(TTonePackResult::TEntry{prevFreqIndex, MaxBits});
+
+ for (int i = 1; i < len; i++) {
+ uint16_t curFreqIndex = param[i].FreqIndex & 1023;
+ if (prevFreqIndex < 512) {
+ t.emplace_back(TTonePackResult::TEntry{curFreqIndex, MaxBits});
+ bits[0] += MaxBits;
+ } else {
+ uint16_t b = GetFirstSetBit(1023 - prevFreqIndex) + 1;
+ uint16_t code = curFreqIndex - (1024 - (1 << b));
+ t.emplace_back(TTonePackResult::TEntry{code, b});
+ bits[0] += b;
+ }
+ prevFreqIndex = curFreqIndex;
+ }
+ }
+
+ // try descending order
+ if (len > 1) {
+ auto& t = res[1];
+ uint16_t prevFreqIndex = param[len - 1].FreqIndex & 1023;
+ t.emplace_back(TTonePackResult::TEntry{prevFreqIndex, MaxBits});
+
+ for (int i = len - 2; i >= 0; i--) {
+ uint16_t curFreqIndex = param[i].FreqIndex & 1023;
+ uint16_t b = GetFirstSetBit(prevFreqIndex) + 1;
+ t.emplace_back(TTonePackResult::TEntry{curFreqIndex, b});
+ bits[1] += b;
+ prevFreqIndex = curFreqIndex;
+ }
+
+ }
+
+ if (len == 1 || bits[0] < bits[1]) {
+ return {res[0], bits[0], ETonePackOrder::ASC};
+ } else {
+ return {res[1], bits[1], ETonePackOrder::DESC};
+ }
+}
+
+uint32_t TDumper::GetConsumption() const noexcept
+{
+ return std::accumulate(Buf.begin(), Buf.end(), 0,
+ [](uint32_t acc, const std::pair<uint16_t, uint8_t>& x) noexcept -> uint32_t { return acc + x.second; });
+}
+
+IBitStreamPartEncoder::EStatus TConfigure::Encode(void* frameData, TBitAllocHandler&)
+{
+ TSpecFrame* frame = TSpecFrame::Cast(frameData);
+
+ frame->WordLen.resize(frame->NumQuantUnits);
+
+ for (size_t i = 0; i < frame->WordLen.size(); i++) {
+ static uint8_t allocTable[32] = {
+ 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 6, 6, 6, 6, 6, 6, 6,
+ 6, 6, 5, 5, 4, 3, 2, 1
+ };
+ frame->WordLen[i].first = allocTable[i];
+ frame->WordLen[i].second = allocTable[i];
+ }
+
+ frame->SfIdx.resize(frame->NumQuantUnits);
+
+ for (size_t i = 0; i < frame->SfIdx.size(); i++) {
+ frame->SfIdx[i].first = frame->Chs[0].ScaledBlocks.at(i).ScaleFactorIndex;
+ if (frame->Chs.size() > 1)
+ frame->SfIdx[i].second = frame->Chs[1].ScaledBlocks.at(i).ScaleFactorIndex;
+ }
+
+ frame->SpecTabIdx.resize(frame->NumQuantUnits);
+
+ Insert(frame->NumQuantUnits - 1, 5);
+ Insert(0, 1); //mute flag
+
+ frame->AllocatedBits = GetConsumption();
+
+ return EStatus::Ok;
+}
+
+IBitStreamPartEncoder::EStatus TWordLenEncoder::Encode(void* frameData, TBitAllocHandler&) {
+ auto specFrame = TSpecFrame::Cast(frameData);
+
+ ASSERT(specFrame->WordLen.size() > specFrame->NumQuantUnits);
+ for (size_t ch = 0; ch < specFrame->Chs.size(); ch++) {
+
+ Insert(0, 2); // 0 - constant number of bits
+
+ if (ch == 0) {
+ for (size_t i = 0; i < specFrame->NumQuantUnits; i++) {
+ Insert(specFrame->WordLen[i].first, 3);
+ }
+ } else {
+ for (size_t i = 0; i < specFrame->NumQuantUnits; i++) {
+ Insert(specFrame->WordLen[i].second, 3);
+ }
+ }
+ }
+
+ return EStatus::Ok;
+}
+
+IBitStreamPartEncoder::EStatus TSfIdxEncoder::Encode(void* frameData, TBitAllocHandler&) {
+ auto specFrame = TSpecFrame::Cast(frameData);
+
+ if (specFrame->SfIdx.empty()) {
+ return EStatus::Ok;
+ }
+
+ for (size_t ch = 0; ch < specFrame->Chs.size(); ch++) {
+
+ Insert(0, 2); // 0 - constant number of bits
+
+ if (ch == 0) {
+ for (size_t i = 0; i < specFrame->NumQuantUnits; i++) {
+ Insert(specFrame->SfIdx[i].first, 6);
+ }
+ } else {
+ for (size_t i = 0; i < specFrame->NumQuantUnits; i++) {
+ Insert(specFrame->SfIdx[i].second, 6);
+ }
+ }
+ }
+
+ return EStatus::Ok;
+}
+
+void TQuantUnitsEncoder::EncodeCodeTab(bool useFullTable, size_t channels,
+ size_t numQuantUnits, const std::vector<std::pair<uint8_t, uint8_t>>& specTabIdx,
+ std::vector<std::pair<uint16_t, uint8_t>>& data)
+{
+ data.emplace_back(useFullTable, 1); // use full table
+
+ for (size_t ch = 0; ch < channels; ch++) {
+
+ data.emplace_back(0, 1); // table type
+
+ data.emplace_back(0, 2); // 0 - constant number of bits
+
+ data.emplace_back(0, 1); // num_coded_vals equal to used_quant_units
+
+ if (ch == 0) {
+ for (size_t i = 0; i < numQuantUnits; i++) {
+ data.emplace_back(specTabIdx[i].first, useFullTable + 2);
+ }
+ } else {
+ for (size_t i = 0; i < numQuantUnits; i++) {
+ data.emplace_back(specTabIdx[i].second, useFullTable + 2);
+ }
+ }
+ }
+}
+
+void TQuantUnitsEncoder::EncodeQuSpectra(const int* qspec, const size_t num_spec, const size_t idx,
+ std::vector<std::pair<uint16_t, uint8_t>>& data) {
+ const Atrac3pSpecCodeTab *tab = &atrac3p_spectra_tabs[idx];
+ const std::array<TVlcElement, 256>& vlcTab = HuffTabs.VlcSpecs[idx];
+
+ size_t groupSize = tab->group_size;
+ size_t numCoeffs = tab->num_coeffs;
+ size_t bitsCoeff = tab->bits;
+ bool isSigned = tab->is_signed;
+
+ for (size_t pos = 0; pos < num_spec;) {
+ if (groupSize != 1) {
+ // TODO: Acording to FFmpeg it should be possible
+ // to skip group, if all rest of coeffs is zero
+ // but this should be checked with real AT3P decoder
+ data.emplace_back(1, 1);
+ }
+
+ for (size_t j = 0; j < groupSize; j++) {
+ uint32_t val = 0;
+ int8_t signs[4] = {0};
+ for (size_t i = 0; i < numCoeffs; i++) {
+ int16_t t = qspec[pos++];
+#ifndef NDEBUG
+ {
+ uint16_t x = std::abs(t);
+ x >>= (uint16_t)(bitsCoeff - (int)isSigned);
+ ASSERT(x == 0);
+ }
+#endif
+ if (!isSigned && t != 0) {
+ signs[i] = t > 0 ? 1 : -1;
+ if (t < 0)
+ t = -t;
+ } else {
+ t = t & ((1u << (bitsCoeff)) - 1);
+ }
+ t <<= (bitsCoeff * i);
+ val |= t;
+ }
+
+ ASSERT(val > 255);
+
+ const TVlcElement& el = vlcTab.at(val);
+
+ data.emplace_back(el.Code, el.Len);
+ for (size_t i = 0; i < 4; i++) {
+ if (signs[i] != 0) {
+ if (signs[i] > 0) {
+ data.emplace_back(0, 1);
+ } else {
+ data.emplace_back(1, 1);
+ }
+ }
+ }
+ }
+ }
+}
+
+size_t TQuantUnitsEncoder::TUnit::MakeKey(size_t ch, size_t qu, size_t worlen) {
+ ASSERT(qu < 32);
+ ASSERT(worlen < 8);
+ return (ch << 8) | (qu << 3) | worlen;
+}
+
+TQuantUnitsEncoder::TUnit::TUnit(size_t qu, size_t wordlen)
+ : Wordlen(wordlen)
+ , Multiplier(1.0f / atrac3p_mant_tab[wordlen])
+{
+ Mantisas.resize(TScaleTable::SpecsPerBlock[qu]);
+}
+
+size_t TQuantUnitsEncoder::TUnit::GetOrCompute(const float* val, std::vector<std::pair<uint16_t, uint8_t>>& res)
+{
+ QuantMantisas(val, 0, Mantisas.size(), Multiplier, false, Mantisas.data());
+
+ std::vector<std::pair<uint16_t, uint8_t>> tmp;
+
+ size_t bestTab = 0;
+ size_t consumed = std::numeric_limits<size_t>::max();
+
+ for (size_t i = 0, tabIndex = Wordlen - 1; i < 8; i++, tabIndex += 7) {
+
+ EncodeQuSpectra(Mantisas.data(), Mantisas.size(), tabIndex, tmp);
+
+ size_t t = std::accumulate(tmp.begin(), tmp.end(), 0,
+ [](size_t acc, const std::pair<uint8_t, uint16_t>& x) noexcept -> size_t
+ { return acc + x.second; });
+
+ if (t < consumed) {
+ consumed = t;
+ ConsumedBits = t;
+ bestTab = i;
+ res.clear();
+ res.swap(tmp);
+ tmp.clear();
+ } else {
+ tmp.clear();
+ }
+ }
+ return bestTab;
+}
+
+IBitStreamPartEncoder::EStatus TQuantUnitsEncoder::Encode(void* frameData, TBitAllocHandler&)
+{
+ auto specFrame = TSpecFrame::Cast(frameData);
+ std::vector<
+ std::vector<std::pair<uint16_t, uint8_t>>> data;
+ for (size_t ch = 0; ch < specFrame->Chs.size(); ch++) {
+ auto& chData = specFrame->Chs.at(ch);
+ auto scaledBlocks = chData.ScaledBlocks;
+
+ for (size_t qu = 0; qu < specFrame->NumQuantUnits; qu++) {
+ size_t len = (ch == 0) ?
+ specFrame->WordLen.at(qu).first :
+ specFrame->WordLen.at(qu).second;
+
+ size_t key = TUnit::MakeKey(ch, qu, len);
+
+ TUnit* unit;
+ // try_emplace
+ auto it = UnitBuffers.find(key);
+ if (it == UnitBuffers.end()) {
+ unit = &(UnitBuffers.emplace(key, TUnit(qu, len)).first->second);
+ } else {
+ unit = &it->second;
+ }
+
+ const float* values = scaledBlocks.at(qu).Values.data();
+
+ data.push_back(std::vector<std::pair<uint16_t, uint8_t>>());
+ auto tabIdx = unit->GetOrCompute(values, data.back());
+
+ if (ch == 0) {
+ specFrame->SpecTabIdx[qu].first = tabIdx;
+ } else {
+ specFrame->SpecTabIdx[qu].second = tabIdx;
+ }
+ }
+ if (true /*frame.NumUsedQuantUnits > 2*/) {
+ size_t numPwrSpec = atrac3p_subband_to_num_powgrps[atrac3p_qu_to_subband[specFrame->NumQuantUnits - 1]];
+ data.push_back(std::vector<std::pair<uint16_t, uint8_t>>());
+ auto& t = data.back();
+ for (size_t i = 0; i < numPwrSpec; i++) {
+ t.emplace_back(15, 4);
+ }
+ }
+ }
+
+ {
+ std::vector<std::pair<uint16_t, uint8_t>> tabIdxData;
+ EncodeCodeTab(true, specFrame->Chs.size(), specFrame->NumQuantUnits, specFrame->SpecTabIdx, tabIdxData);
+ for (size_t i = 0; i < tabIdxData.size(); i++) {
+ Insert(tabIdxData[i].first, tabIdxData[i].second);
+ }
+ }
+
+ for (const auto& x : data) {
+ for (size_t i = 0; i < x.size(); i++) {
+ Insert(x[i].first, x[i].second);
+ }
+ }
+
+ return EStatus::Ok;
+}
+
+static std::vector<IBitStreamPartEncoder::TPtr> CreateEncParts()
+{
+ vector<IBitStreamPartEncoder::TPtr> parts;
+ parts.emplace_back(new TConfigure());
+ parts.emplace_back(new TWordLenEncoder());
+ parts.emplace_back(new TSfIdxEncoder());
+ parts.emplace_back(new TQuantUnitsEncoder());
+ parts.emplace_back(new TTonalComponentEncoder());
+
+ return parts;
+}
+
+TAt3PBitStream::TAt3PBitStream(ICompressedOutput* container, uint16_t frameSz)
+ : Container(container)
+ , Encoder(CreateEncParts())
+ , FrameSzToAllocBits((uint32_t)frameSz * 8 - 3) //Size of frame in bits for allocation. 3 bits is start bit and channel configuration
+ , FrameSz(frameSz)
+{
+ NEnv::SetRoundFloat();
+}
+
+void TTonalComponentEncoder::WriteSubbandFlags(const bool* flags, size_t numFlags)
+{
+
+ size_t sum = 0;
+ for (size_t i = 0; i < numFlags; i++) {
+ sum += (uint32_t)flags[i];
+ }
+
+ if (sum == 0) {
+ Insert(0, 1);
+ } else if (sum == numFlags) {
+ Insert(1, 1);
+ Insert(0, 1);
+ } else {
+ Insert(1, 1);
+ Insert(1, 1);
+ for (size_t i = 0; i < numFlags; i++) {
+ Insert(flags[i], 1);
+ }
+ }
+}
+
+void TTonalComponentEncoder::WriteTonalBlock(size_t channels, const TAt3PGhaData* tonalBlock)
+{
+ //GHA amplidude mode 1
+ Insert(1, 1);
+
+ //Num tone bands
+ const TVlcElement& tbHuff = HuffTabs.NumToneBands[tonalBlock->NumToneBands - 1];
+ Insert(tbHuff.Code, tbHuff.Len);
+
+ if (channels == 2) {
+ WriteSubbandFlags(tonalBlock->ToneSharing, tonalBlock->NumToneBands);
+ WriteSubbandFlags(&tonalBlock->SecondIsLeader, 1);
+ Insert(0, 1);
+ }
+
+ for (size_t ch = 0; ch < channels; ch++) {
+ if (ch) {
+ // each channel has own envelope
+ Insert(0, 1);
+ }
+ // Envelope data
+ for (int i = 0; i < tonalBlock->NumToneBands; i++) {
+ if (ch && tonalBlock->ToneSharing[i]) {
+ continue;
+ }
+
+ const auto envelope = tonalBlock->GetEnvelope(ch, i);
+
+ if (envelope.first != TAt3PGhaData::EMPTY_POINT) {
+ // start point present
+ Insert(1, 1);
+ Insert(envelope.first, 5);
+ } else {
+ Insert(0, 1);
+ }
+
+ if (envelope.second != TAt3PGhaData::EMPTY_POINT) {
+ // stop point present
+ Insert(1, 1);
+ Insert(envelope.second, 5);
+ } else {
+ Insert(0, 1);
+ }
+ }
+
+ // Num waves
+ int mode = 0; //TODO: Calc mode
+ Insert(mode, ch + 1);
+ for (int i = 0; i < tonalBlock->NumToneBands; i++) {
+ if (ch && tonalBlock->ToneSharing[i]) {
+ continue;
+ }
+ Insert(tonalBlock->GetNumWaves(ch, i), 4);
+ }
+ // Tones freq
+ if (ch) {
+ // 0 - independed
+ // 1 - delta to leader
+ Insert(0, 1);
+ }
+
+ for (int i = 0; i < tonalBlock->NumToneBands; i++) {
+ if (ch && tonalBlock->ToneSharing[i]) {
+ continue;
+ }
+
+ auto numWaves = tonalBlock->GetNumWaves(ch, i);
+ if (numWaves == 0) {
+ continue;
+ }
+
+ const auto w = tonalBlock->GetWaves(ch, i);
+ const auto pkt = CreateFreqBitPack(w.first, w.second);
+
+ if (numWaves > 1) {
+ Insert(static_cast<bool>(pkt.Order), 1);
+ }
+
+ for (const auto& d : pkt.Data) {
+ Insert(d.Code, d.Bits);
+ }
+ }
+
+ // Amplitude
+ mode = 0; //TODO: Calc mode
+ Insert(mode, ch + 1);
+
+ for (int i = 0; i < tonalBlock->NumToneBands; i++) {
+ if (ch && tonalBlock->ToneSharing[i]) {
+ continue;
+ }
+
+ auto numWaves = tonalBlock->GetNumWaves(ch, i);
+ if (numWaves == 0) {
+ continue;
+ }
+
+ const auto w = tonalBlock->GetWaves(ch, i);
+ for (size_t j = 0; j < numWaves; j++) {
+ Insert(w.first[j].AmpSf, 6);
+ }
+ }
+
+ // Phase
+ for (int i = 0; i < tonalBlock->NumToneBands; i++) {
+ if (ch && tonalBlock->ToneSharing[i]) {
+ continue;
+ }
+
+ auto numWaves = tonalBlock->GetNumWaves(ch, i);
+ if (numWaves == 0) {
+ continue;
+ }
+
+ const auto w = tonalBlock->GetWaves(ch, i);
+ for (size_t j = 0; j < w.second; j++) {
+ Insert(w.first[j].PhaseIndex, 5);
+ }
+ }
+ }
+}
+
+IBitStreamPartEncoder::EStatus TTonalComponentEncoder::CheckFrameDone(TSpecFrame* frame, TBitAllocHandler& ba) noexcept
+{
+ uint32_t totalConsumption = BitsUsed + ba.GetCurGlobalConsumption();
+
+ if (totalConsumption > frame->SizeBits) {
+ if (frame->NumQuantUnits == 32) {
+ frame->NumQuantUnits = 28;
+ } else {
+ frame->NumQuantUnits--;
+ }
+ return EStatus::Repeat;
+ }
+ return EStatus::Ok;
+}
+
+IBitStreamPartEncoder::EStatus TTonalComponentEncoder::Encode(void* frameData, TBitAllocHandler& ba)
+{
+ auto specFrame = TSpecFrame::Cast(frameData);
+ auto tonalBlock = specFrame->TonalBlock;
+
+ // Check tonal component already encoded
+ if (BitsUsed != 0) {
+ if (tonalBlock && tonalBlock->NumToneBands > specFrame->NumQuantUnits) {
+ std::cerr << "TODO" << std::endl;
+ abort();
+ }
+ return CheckFrameDone(specFrame, ba);
+ }
+
+ const size_t chNum = specFrame->Chs.size();
+
+ if (chNum == 2) {
+ Insert(0, 2); //swap_channels and negate_coeffs
+ }
+
+ for (size_t ch = 0; ch < chNum; ch++) {
+ Insert(0, 1); // window shape
+ }
+
+ for (size_t ch = 0; ch < chNum; ch++) {
+ Insert(0, 1); //gain comp
+ }
+
+ if (tonalBlock && tonalBlock->NumToneBands) {
+ Insert(1, 1);
+ WriteTonalBlock(chNum, tonalBlock);
+ } else {
+ Insert(0, 1);
+ }
+
+ Insert(0, 1); // no noise info
+ // Terminator
+ Insert(3, 2);
+
+ BitsUsed = GetConsumption();
+
+ return CheckFrameDone(specFrame, ba);
+}
+
+void TAt3PBitStream::WriteFrame(int channels, const TAt3PGhaData* tonalBlock, const std::vector<std::vector<TScaledBlock>>& scaledBlocks)
+{
+ NBitStream::TBitStream bitStream;
+ // First bit must be zero
+ bitStream.Write(0, 1);
+ // Channel block type
+ // 0 - MONO block
+ // 1 - STEREO block
+ // 2 - Nobody know
+ bitStream.Write(channels - 1, 2);
+
+ const uint32_t initialNumQuantUnits = 32;
+
+ TSpecFrame frame(FrameSzToAllocBits, initialNumQuantUnits, channels, tonalBlock, scaledBlocks);
+
+ Encoder.Do(&frame, bitStream);
+
+ std::vector<char> buf = bitStream.GetBytes();
+
+ ASSERT(bitStream.GetSizeInBits() > FrameSz * 8);
+
+ buf.resize(FrameSz);
+ Container->WriteFrame(buf);
+}
+
+}
diff --git a/src/atrac/at3p/at3p_bitstream.h b/src/atrac/at3p/at3p_bitstream.h
new file mode 100644
index 0000000..25edd1e
--- /dev/null
+++ b/src/atrac/at3p/at3p_bitstream.h
@@ -0,0 +1,59 @@
+/*
+ * This file is part of AtracDEnc.
+ *
+ * AtracDEnc is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * AtracDEnc is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with AtracDEnc; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#pragma once
+
+#include "compressed_io.h"
+#include "at3p_gha.h"
+#include <lib/bs_encode/encode.h>
+
+namespace NAtracDEnc {
+
+struct TScaledBlock;
+
+struct TAt3PGhaData;
+
+enum class ETonePackOrder : bool {
+ ASC = false,
+ DESC = true
+};
+
+struct TTonePackResult {
+ struct TEntry {
+ uint16_t Code;
+ uint16_t Bits;
+ };
+ std::vector<TEntry> Data;
+ int UsedBits;
+ ETonePackOrder Order;
+};
+
+TTonePackResult CreateFreqBitPack(const TAt3PGhaData::TWaveParam* param, int len);
+
+class TAt3PBitStream {
+public:
+ TAt3PBitStream(ICompressedOutput* container, uint16_t frameSz);
+ void WriteFrame(int channels, const TAt3PGhaData* tonalData, const std::vector<std::vector<TScaledBlock>>& scaledBlocks);
+private:
+ ICompressedOutput* Container;
+ TBitStreamEncoder Encoder;
+ const uint32_t FrameSzToAllocBits;
+ const uint16_t FrameSz;
+};
+
+}
diff --git a/src/atrac/at3p/at3p_bitstream_impl.h b/src/atrac/at3p/at3p_bitstream_impl.h
new file mode 100644
index 0000000..91b2df2
--- /dev/null
+++ b/src/atrac/at3p/at3p_bitstream_impl.h
@@ -0,0 +1,149 @@
+#pragma once
+
+/*
+ * This file is part of AtracDEnc.
+ *
+ * AtracDEnc is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * AtracDEnc is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with AtracDEnc; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "atrac/at3p/at3p_gha.h"
+#include <lib/bitstream/bitstream.h>
+#include <lib/bs_encode/encode.h>
+#include <atrac/atrac_scale.h>
+#include <vector>
+
+namespace NAtracDEnc {
+
+struct TSpecFrame {
+ TSpecFrame(uint32_t sz, uint32_t numQuantUnits, size_t channels,
+ const TAt3PGhaData* tonalBlock,
+ const std::vector<std::vector<TScaledBlock>>& scaledBlocks)
+ : SizeBits(sz)
+ , NumQuantUnits(numQuantUnits)
+ , TonalBlock(tonalBlock)
+ , AllocatedBits(0)
+ {
+ Chs.reserve(channels);
+ for (size_t i = 0; i < channels; i++) {
+ Chs.emplace_back(TChannel(scaledBlocks[i]));
+ }
+ }
+
+ const uint32_t SizeBits;
+ uint32_t NumQuantUnits;
+ const TAt3PGhaData* TonalBlock;
+ std::vector<std::pair<uint8_t, uint8_t>> WordLen;
+ std::vector<std::pair<uint8_t, uint8_t>> SfIdx;
+ std::vector<std::pair<uint8_t, uint8_t>> SpecTabIdx;
+
+ struct TChannel {
+ TChannel(const std::vector<TScaledBlock>& scaledBlock)
+ : ScaledBlocks(scaledBlock)
+ {}
+ const std::vector<TScaledBlock>& ScaledBlocks;
+ };
+
+ std::vector<TChannel> Chs;
+ size_t AllocatedBits;
+ static TSpecFrame* Cast(void* p) { return reinterpret_cast<TSpecFrame*>(p); }
+};
+
+class TDumper : public IBitStreamPartEncoder {
+public:
+ void Dump(NBitStream::TBitStream& bs) override {
+ for (const auto& pair : Buf) {
+ bs.Write(pair.first, pair.second);
+ }
+ Buf.clear();
+ }
+ void Reset() noexcept override {
+ Buf.clear();
+ }
+ uint32_t GetConsumption() const noexcept override;
+protected:
+
+ // value, nbits
+ void Insert(uint16_t value, uint8_t nbits) { Buf.emplace_back(std::make_pair(value, nbits)); }
+ std::vector<std::pair<uint16_t, uint8_t>> Buf;
+};
+
+class TConfigure : public TDumper {
+public:
+ TConfigure() = default;
+ EStatus Encode(void* frameData, TBitAllocHandler& ba) override;
+};
+
+class TWordLenEncoder : public TDumper {
+public:
+ TWordLenEncoder() = default;
+ EStatus Encode(void* frameData, TBitAllocHandler& ba) override;
+private:
+};
+
+class TSfIdxEncoder : public TDumper {
+public:
+ TSfIdxEncoder() = default;
+ EStatus Encode(void* frameData, TBitAllocHandler& ba) override;
+private:
+};
+
+class TQuantUnitsEncoder : public TDumper {
+public:
+ TQuantUnitsEncoder() = default;
+ EStatus Encode(void* frameData, TBitAllocHandler& ba) override;
+ static void EncodeQuSpectra(const int* qspec, const size_t num_spec, const size_t idx,
+ std::vector<std::pair<uint16_t, uint8_t>>& data);
+ static void EncodeCodeTab(bool useFullTable, size_t channels,
+ size_t numQuantUnits, const std::vector<std::pair<uint8_t, uint8_t>>& specTabIdx,
+ std::vector<std::pair<uint16_t, uint8_t>>& data);
+
+private:
+ class TUnit {
+ public:
+ static size_t MakeKey(size_t ch, size_t qu, size_t worlen);
+ TUnit(size_t qu, size_t wordlen);
+ size_t GetOrCompute(const float* val, std::vector<std::pair<uint16_t, uint8_t>>& res);
+ const std::vector<int>& GetMantisas() const { return Mantisas; }
+
+ private:
+ uint32_t Wordlen;
+ float Multiplier;
+ uint16_t ConsumedBits; // Number of bits consumed by QuSpectr
+
+ std::vector<int> Mantisas;
+ };
+ // The key is <ch_id, unit_id, wordlen>
+ // will be used to cache unit encoding result duting bit allocation
+ std::map<size_t, TUnit> UnitBuffers;
+};
+
+class TTonalComponentEncoder : public TDumper {
+public:
+ TTonalComponentEncoder() = default;
+ EStatus Encode(void* frameData, TBitAllocHandler& ba) override;
+ //TODO: find the common way
+ void Dump(NBitStream::TBitStream& bs) override {
+ TDumper::Dump(bs);
+ BitsUsed = 0;
+ }
+private:
+ EStatus CheckFrameDone(TSpecFrame* frame, TBitAllocHandler& ba) noexcept;
+ void WriteTonalBlock(size_t channels, const TAt3PGhaData* tonalBlock);
+ void WriteSubbandFlags(const bool* flags, size_t numFlags);
+ size_t BitsUsed = 0;
+};
+
+
+}
diff --git a/src/atrac/at3p/at3p_bitstream_ut.cpp b/src/atrac/at3p/at3p_bitstream_ut.cpp
new file mode 100644
index 0000000..a4d7bd7
--- /dev/null
+++ b/src/atrac/at3p/at3p_bitstream_ut.cpp
@@ -0,0 +1,139 @@
+#include "at3p_bitstream.h"
+#include "at3p_bitstream_impl.h"
+#include <gtest/gtest.h>
+#include <cmath>
+
+using namespace NAtracDEnc;
+
+TEST(AT3PBitstream, ToneFreqBitPack__1) {
+ std::vector<TAt3PGhaData::TWaveParam> params;
+
+ params.push_back(TAt3PGhaData::TWaveParam{1, 0, 0, 0});
+
+ auto r = CreateFreqBitPack(params.data(), params.size());
+ EXPECT_EQ(r.UsedBits, 10);
+ EXPECT_EQ(r.Order, ETonePackOrder::ASC);
+ EXPECT_EQ(r.Data.size(), 1);
+ EXPECT_EQ(r.Data[0].Code, 1);
+ EXPECT_EQ(r.Data[0].Bits, 10);
+}
+
+TEST(AT3PBitstream, ToneFreqBitPack__512_1020_1023) {
+ std::vector<TAt3PGhaData::TWaveParam> params;
+
+ params.push_back(TAt3PGhaData::TWaveParam{512, 0, 0, 0});
+ params.push_back(TAt3PGhaData::TWaveParam{1020, 0, 0, 0});
+ params.push_back(TAt3PGhaData::TWaveParam{1023, 0, 0, 0});
+
+ auto r = CreateFreqBitPack(params.data(), params.size());
+ EXPECT_EQ(r.UsedBits, 21);
+ EXPECT_EQ(r.Order, ETonePackOrder::ASC);
+ EXPECT_EQ(r.Data.size(), 3);
+ EXPECT_EQ(r.Data[0].Code, 512);
+ EXPECT_EQ(r.Data[0].Bits, 10);
+ EXPECT_EQ(r.Data[1].Code, 508);
+ EXPECT_EQ(r.Data[1].Bits, 9);
+ EXPECT_EQ(r.Data[2].Code, 3);
+ EXPECT_EQ(r.Data[2].Bits, 2);
+}
+
+TEST(AT3PBitstream, ToneFreqBitPack__1_2_3) {
+ std::vector<TAt3PGhaData::TWaveParam> params;
+
+ params.push_back(TAt3PGhaData::TWaveParam{1, 0, 0, 0});
+ params.push_back(TAt3PGhaData::TWaveParam{2, 0, 0, 0});
+ params.push_back(TAt3PGhaData::TWaveParam{3, 0, 0, 0});
+
+ auto r = CreateFreqBitPack(params.data(), params.size());
+ EXPECT_EQ(r.UsedBits, 14);
+ EXPECT_EQ(r.Order, ETonePackOrder::DESC);
+ EXPECT_EQ(r.Data.size(), 3);
+ EXPECT_EQ(r.Data[0].Code, 3);
+ EXPECT_EQ(r.Data[0].Bits, 10);
+ EXPECT_EQ(r.Data[1].Code, 2);
+ EXPECT_EQ(r.Data[1].Bits, 2);
+ EXPECT_EQ(r.Data[2].Code, 1);
+ EXPECT_EQ(r.Data[2].Bits, 2);
+}
+
+TEST(AT3PBitstream, ToneFreqBitPack__1_2_3_1020_1021_1022) {
+ std::vector<TAt3PGhaData::TWaveParam> params;
+
+ params.push_back(TAt3PGhaData::TWaveParam{1, 0, 0, 0});
+ params.push_back(TAt3PGhaData::TWaveParam{2, 0, 0, 0});
+ params.push_back(TAt3PGhaData::TWaveParam{3, 0, 0, 0});
+ params.push_back(TAt3PGhaData::TWaveParam{1020, 0, 0, 0});
+ params.push_back(TAt3PGhaData::TWaveParam{1021, 0, 0, 0});
+ params.push_back(TAt3PGhaData::TWaveParam{1022, 0, 0, 0});
+
+ auto r = CreateFreqBitPack(params.data(), params.size());
+ EXPECT_EQ(r.UsedBits, 44);
+ EXPECT_EQ(r.Order, ETonePackOrder::DESC);
+ EXPECT_EQ(r.Data.size(), 6);
+ EXPECT_EQ(r.Data[0].Code, 1022);
+ EXPECT_EQ(r.Data[0].Bits, 10);
+ EXPECT_EQ(r.Data[1].Code, 1021);
+ EXPECT_EQ(r.Data[1].Bits, 10);
+ EXPECT_EQ(r.Data[2].Code, 1020);
+ EXPECT_EQ(r.Data[2].Bits, 10);
+ EXPECT_EQ(r.Data[3].Code, 3);
+ EXPECT_EQ(r.Data[3].Bits, 10);
+ EXPECT_EQ(r.Data[4].Code, 2);
+ EXPECT_EQ(r.Data[4].Bits, 2);
+ EXPECT_EQ(r.Data[5].Code, 1);
+ EXPECT_EQ(r.Data[5].Bits, 2);
+}
+
+TEST(AT3PBitstream, ToneFreqBitPack__1_2_1020_1021_1022) {
+ std::vector<TAt3PGhaData::TWaveParam> params;
+
+ params.push_back(TAt3PGhaData::TWaveParam{1, 0, 0, 0});
+ params.push_back(TAt3PGhaData::TWaveParam{2, 0, 0, 0});
+ params.push_back(TAt3PGhaData::TWaveParam{1020, 0, 0, 0});
+ params.push_back(TAt3PGhaData::TWaveParam{1021, 0, 0, 0});
+ params.push_back(TAt3PGhaData::TWaveParam{1022, 0, 0, 0});
+
+ auto r = CreateFreqBitPack(params.data(), params.size());
+ EXPECT_EQ(r.UsedBits, 34);
+ EXPECT_EQ(r.Order, ETonePackOrder::ASC);
+ EXPECT_EQ(r.Data.size(), 5);
+ EXPECT_EQ(r.Data[0].Code, 1);
+ EXPECT_EQ(r.Data[0].Bits, 10);
+ EXPECT_EQ(r.Data[1].Code, 2);
+ EXPECT_EQ(r.Data[1].Bits, 10);
+ EXPECT_EQ(r.Data[2].Code, 1020);
+ EXPECT_EQ(r.Data[2].Bits, 10);
+ EXPECT_EQ(r.Data[3].Code, 1);
+ EXPECT_EQ(r.Data[3].Bits, 2);
+ EXPECT_EQ(r.Data[4].Code, 2);
+ EXPECT_EQ(r.Data[4].Bits, 2);
+}
+
+void FillFrameData(TSpecFrame& frame) {
+ frame.NumQuantUnits = 6;
+
+ for (size_t i = 0; i < frame.NumQuantUnits; i++) {
+ frame.WordLen.push_back({6, 6});
+ }
+}
+
+TEST(AT3PBitstream, Wordlen) {
+ std::vector<IBitStreamPartEncoder::TPtr> encoders;
+
+ encoders.emplace_back(new TWordLenEncoder());
+
+ NBitStream::TBitStream bs;
+ TBitStreamEncoder encoder(std::move(encoders));
+
+ std::vector<std::vector<TScaledBlock>> scaledBlocks;
+ scaledBlocks.resize(2);
+
+ TSpecFrame frame(444, 28, 2, nullptr, scaledBlocks);
+
+ FillFrameData(frame);
+
+ encoder.Do(&frame, bs);
+
+ EXPECT_EQ(bs.GetSizeInBits(), 40);
+}
+
diff --git a/src/atrac/at3p/at3p_gha.cpp b/src/atrac/at3p/at3p_gha.cpp
new file mode 100644
index 0000000..70905b5
--- /dev/null
+++ b/src/atrac/at3p/at3p_gha.cpp
@@ -0,0 +1,859 @@
+/*
+ * This file is part of AtracDEnc.
+ *
+ * AtracDEnc is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * AtracDEnc is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with AtracDEnc; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "at3p_gha.h"
+#include "ff/atrac3plus.h"
+
+#include <assert.h>
+#include <atrac/atrac_psy_common.h>
+#include <libgha/include/libgha.h>
+
+#include <memory>
+
+#include <algorithm>
+#include <cstring>
+#include <cmath>
+#include <iostream>
+#include <map>
+#include <vector>
+
+using std::map;
+using std::vector;
+using std::isnan;
+using std::pair;
+using std::max;
+using std::min;
+
+namespace NAtracDEnc {
+
+namespace {
+
+uint32_t GhaFreqToIndex(float f, uint32_t sb)
+{
+ return static_cast<uint32_t>(lrintf(1024.0f * (f / M_PI)) & 1023) | (sb << 10);
+}
+
+uint32_t GhaPhaseToIndex(float p)
+{
+ return static_cast<uint32_t>(lrintf(32.0 * ((p) / (2 * M_PI))) & 31);
+}
+
+uint32_t PhaseIndexToOffset(uint32_t ind)
+{
+ return (ind & 0x1F) << 6;
+}
+
+class TGhaProcessor : public IGhaProcessor {
+ // Number of subbands to process;
+ // No need to process all subbands.
+ static constexpr size_t SUBBANDS = 8;
+ static constexpr size_t SAMPLES_PER_SUBBAND = 128;
+ static constexpr size_t LOOK_AHEAD = 64;
+ static constexpr size_t GHA_SUBBAND_BUF_SZ = SAMPLES_PER_SUBBAND + LOOK_AHEAD;
+ static constexpr size_t CHANNEL_BUF_SZ = SUBBANDS * GHA_SUBBAND_BUF_SZ;
+
+ using TGhaInfoMap = map<uint32_t, struct gha_info>;
+ using TWavesChannel = TAt3PGhaData::TWavesChannel;
+ using TAmpSfTab = std::array<float, 64>;
+
+ struct TChannelData {
+ const float* SrcBuf;
+ const float* SrcBufNext;
+ float Buf[CHANNEL_BUF_SZ];
+ pair<uint32_t, uint32_t> Envelopes[SUBBANDS] = {{TAt3PGhaData::INIT,TAt3PGhaData::INIT}};
+ bool Gapless[SUBBANDS] = {false};
+ uint8_t SubbandDone[SUBBANDS] = {0};
+ TGhaInfoMap GhaInfos;
+ float MaxToneMagnitude[SUBBANDS] = {0}; // Max magnitude of sine in the band. Used to stop processing when next extracted sine become significant less then max one
+ float LastResuidalEnergy[SUBBANDS] = {0}; // Resuidal energy on the last round for subband. It is the second criteria to stop processing, we expect resuidal becaming less on the each round
+ uint16_t LastAddedFreqIdx[SUBBANDS];
+
+ void MarkSubbandDone(size_t sb) {
+ SubbandDone[sb] = 16;
+ }
+
+ bool IsSubbandDone(size_t sb) const {
+ return SubbandDone[sb] == 16;
+ }
+ };
+
+ struct TChannelGhaCbCtx {
+ TChannelGhaCbCtx(TChannelData* data, size_t sb)
+ : Data(data)
+ , Sb(sb)
+ {}
+ TChannelData* Data;
+ size_t Sb;
+
+ enum class EAdjustStatus {
+ Error,
+ Ok,
+ Repeat
+ } AdjustStatus;
+ size_t FrameSz = 0;
+ };
+
+public:
+ TGhaProcessor(bool stereo)
+ : LibGhaCtx(gha_create_ctx(128))
+ , Stereo(stereo)
+ {
+ gha_set_max_magnitude(LibGhaCtx, 32768);
+ gha_set_upsample(LibGhaCtx, 1);
+
+ if (!StaticInited) {
+ ff_atrac3p_init_dsp_static();
+
+ FillSubbandAth(&SubbandAth[0]);
+
+ AmpSfTab = CreateAmpSfTab();
+ for (int i = 0; i < 2048; i++) {
+ SineTab[i] = sin(2 * M_PI * i / 2048);
+ }
+
+ StaticInited = true;
+ }
+
+ for (size_t ch = 0; ch < 2; ch++) {
+ ChUnit.channels[ch].tones_info = &ChUnit.channels[ch].tones_info_hist[0][0];
+ ChUnit.channels[ch].tones_info_prev = &ChUnit.channels[ch].tones_info_hist[1][0];
+ }
+
+ ChUnit.waves_info = &ChUnit.wave_synth_hist[0];
+ ChUnit.waves_info_prev = &ChUnit.wave_synth_hist[1];
+ ChUnit.waves_info->tones_present = false;
+ ChUnit.waves_info_prev->tones_present = false;
+ }
+
+ ~TGhaProcessor()
+ {
+ gha_free_ctx(LibGhaCtx);
+ }
+
+ const TAt3PGhaData* DoAnalize(TBufPtr b1, TBufPtr b2, float *w1, float *w2) override;
+
+private:
+ void ApplyFilter(const TAt3PGhaData*, float *b1, float *b2);
+ static void FillSubbandAth(float* out);
+ static TAmpSfTab CreateAmpSfTab();
+ static void CheckResuidalAndApply(float* resuidal, size_t size, void* self) noexcept;
+ static void GenWaves(const TAt3PGhaData::TWaveParam* param, size_t numWaves, size_t reg_offset, float* out, size_t outLimit);
+
+ void AdjustEnvelope(pair<uint32_t, uint32_t>& envelope, const pair<uint32_t, uint32_t>& src, uint32_t history);
+ uint32_t FillFolowerRes(const TGhaInfoMap& lGha, const TChannelData* src, TGhaInfoMap::const_iterator& it, uint32_t leaderSb);
+
+ uint32_t AmplitudeToSf(float amp) const;
+ bool CheckNextFrame(const float* nextSrc, const vector<gha_info>& ghaInfos) const;
+
+ bool DoRound(TChannelData& data, size_t& totalTones) const;
+ bool PsyPreCheck(size_t sb, const struct gha_info& gha, const TChannelData& data) const;
+ void FillResultBuf(const vector<TChannelData>& data);
+
+ gha_ctx_t LibGhaCtx;
+ TAt3PGhaData ResultBuf;
+ TAt3PGhaData ResultBufHistory;
+
+ const bool Stereo;
+
+ static float SubbandAth[SUBBANDS];
+ static float SineTab[2048];
+ static bool StaticInited;
+ static TAmpSfTab AmpSfTab;
+
+ Atrac3pChanUnitCtx ChUnit;
+};
+
+bool TGhaProcessor::StaticInited = false;
+float TGhaProcessor::SubbandAth[SUBBANDS];
+float TGhaProcessor::SineTab[2048];
+TGhaProcessor::TAmpSfTab TGhaProcessor::AmpSfTab;
+
+void TGhaProcessor::FillSubbandAth(float* out)
+{
+ const auto ath = CalcATH(16 * 1024, 44100);
+ #pragma GCC nounroll
+ for (size_t sb = 0; sb < SUBBANDS; sb++) {
+ float m = 999.;
+ for (size_t f = sb * 1024, i = 0; i < 1024; f++, i++) {
+ m = fmin(m, ath[f]);
+ }
+ //m += 26; //Some gap to not encode too much
+ out[sb] = pow(10, 0.1 * (m + 90)); //adjust to 0db level = 32768, convert to power
+ }
+}
+
+TGhaProcessor::TAmpSfTab TGhaProcessor::CreateAmpSfTab()
+{
+ TAmpSfTab AmpSfTab;
+ for (int i = 0; i < (int)AmpSfTab.size(); i++) {
+ AmpSfTab[i] = exp2f((i - 3) / 4.0f);
+ }
+ return AmpSfTab;
+}
+
+void TGhaProcessor::GenWaves(const TAt3PGhaData::TWaveParam* param, size_t numWaves, size_t reg_offset, float* out, size_t outLimit)
+{
+ for (size_t w = 0; w < numWaves; w++, param++) {
+ //std::cerr << "GenWaves : " << w << " FreqIndex: " << param->FreqIndex << " phaseIndex: " << param->PhaseIndex << " ampSf " << param->AmpSf << std::endl;
+ auto amp = AmpSfTab[param->AmpSf];
+ auto inc = param->FreqIndex;
+ auto pos = ((int)PhaseIndexToOffset(param->PhaseIndex) + ((int)reg_offset ^ 128) * inc) & 2047;
+
+ for (size_t i = 0; i < outLimit; i++) {
+ //std::cerr << "inc: " << inc << " pos: " << pos << std::endl;
+ out[i] += SineTab[pos] * amp;
+ pos = (pos + inc) & 2047;
+ }
+ }
+}
+
+void TGhaProcessor::CheckResuidalAndApply(float* resuidal, size_t size, void* d) noexcept
+{
+ TChannelGhaCbCtx* ctx = (TChannelGhaCbCtx*)(d);
+ const float* srcBuf = ctx->Data->SrcBuf + (ctx->Sb * SAMPLES_PER_SUBBAND);
+ //std::cerr << "TGhaProcessor::CheckResuidal " << srcBuf[0] << " " << srcBuf[1] << " " << srcBuf[2] << " " << srcBuf[3] << std::endl;
+
+ float resuidalEnergy = 0;
+
+ uint32_t start = 0;
+ uint32_t curStart = 0;
+ uint32_t count = 0;
+ uint32_t len = 0;
+ bool found = false;
+
+ if (size != SAMPLES_PER_SUBBAND)
+ abort();
+
+ for (size_t i = 0; i < SAMPLES_PER_SUBBAND; i += 4) {
+ float energyIn = 0.0;
+ float energyOut = 0.0;
+ for (size_t j = 0; j < 4; j++) {
+ energyIn += srcBuf[i + j] * srcBuf[i + j];
+ energyOut += resuidal[i + j] * resuidal[i + j];
+ }
+
+ energyIn = sqrt(energyIn/4);
+ energyOut = sqrt(energyOut/4);
+ resuidalEnergy += energyOut;
+
+ if (energyIn / energyOut < 1) {
+ count = 0;
+ found = false;
+ curStart = i + 4;
+ } else {
+ count++;
+ if (count > len) {
+ len = count;
+ if (!found) {
+ start = curStart;
+ found = true;
+ }
+ }
+ }
+
+ // std::cerr << " " << i << " rms : " << energyIn << " " << energyOut << "\t\t\t" << ((energyOut < energyIn) ? "+" : "-") << std::endl;
+ }
+
+ const auto sb = ctx->Sb;
+ // Do not encode too short frame
+ if (len < 4) {
+ ctx->AdjustStatus = TChannelGhaCbCtx::EAdjustStatus::Error;
+ return;
+ }
+
+ const uint32_t end = start + len * 4;
+
+ if (ctx->AdjustStatus != TChannelGhaCbCtx::EAdjustStatus::Repeat && end != SAMPLES_PER_SUBBAND) {
+ ctx->FrameSz = end;
+ ctx->AdjustStatus = TChannelGhaCbCtx::EAdjustStatus::Repeat;
+ return;
+ }
+
+ const float threshold = 1.05; //TODO: tune it
+ if (static_cast<bool>(ctx->Data->LastResuidalEnergy[sb]) == false) {
+ ctx->Data->LastResuidalEnergy[sb] = resuidalEnergy;
+ } else if (ctx->Data->LastResuidalEnergy[sb] < resuidalEnergy * threshold) {
+ ctx->AdjustStatus = TChannelGhaCbCtx::EAdjustStatus::Error;
+ return;
+ } else {
+ ctx->Data->LastResuidalEnergy[sb] = resuidalEnergy;
+ }
+
+ auto& envelope = ctx->Data->Envelopes[sb];
+ envelope.first = start;
+
+ if (envelope.second == TAt3PGhaData::EMPTY_POINT && end != SAMPLES_PER_SUBBAND) {
+ ctx->AdjustStatus = TChannelGhaCbCtx::EAdjustStatus::Error;
+ return;
+ }
+
+ envelope.second = end;
+
+ ctx->AdjustStatus = TChannelGhaCbCtx::EAdjustStatus::Ok;
+
+ float* b = &ctx->Data->Buf[sb * GHA_SUBBAND_BUF_SZ];
+
+ memcpy(b, resuidal, sizeof(float) * SAMPLES_PER_SUBBAND);
+}
+
+void TGhaProcessor::ApplyFilter(const TAt3PGhaData* d, float* b1, float* b2)
+{
+ for (size_t ch_num = 0; ch_num < 2; ch_num++)
+ memset(ChUnit.channels[ch_num].tones_info, 0,
+ sizeof(*ChUnit.channels[ch_num].tones_info) * ATRAC3P_SUBBANDS);
+
+ if (d) {
+ memset(ChUnit.waves_info->waves, 0, sizeof(ChUnit.waves_info->waves));
+ ChUnit.waves_info->num_tone_bands = d->NumToneBands;
+ ChUnit.waves_info->tones_present = true;
+ ChUnit.waves_info->amplitude_mode = 1;
+ ChUnit.waves_info->tones_index = 0;
+ } else {
+ ChUnit.waves_info->tones_present = false;
+ }
+
+ if (d) {
+ for (size_t ch = 0; ch <= (size_t)Stereo; ch++) {
+ for (int i = 0; i < ChUnit.waves_info->num_tone_bands; i++) {
+ if (ch && d->ToneSharing[i]) {
+ continue;
+ }
+
+ ChUnit.channels[ch].tones_info[i].num_wavs = d->GetNumWaves(ch, i);
+
+ const auto envelope = d->GetEnvelope(ch, i);
+ if (envelope.first != TAt3PGhaData::EMPTY_POINT) {
+ // start point present
+ ChUnit.channels[ch].tones_info[i].pend_env.has_start_point = true;
+ ChUnit.channels[ch].tones_info[i].pend_env.start_pos = envelope.first;
+ } else {
+ ChUnit.channels[ch].tones_info[i].pend_env.has_start_point = false;
+ ChUnit.channels[ch].tones_info[i].pend_env.start_pos = -1;
+ }
+
+ if (envelope.second != TAt3PGhaData::EMPTY_POINT) {
+ // stop point present
+ ChUnit.channels[ch].tones_info[i].pend_env.has_stop_point = true;
+ ChUnit.channels[ch].tones_info[i].pend_env.stop_pos = envelope.second;
+ } else {
+ ChUnit.channels[ch].tones_info[i].pend_env.has_stop_point = false;
+ ChUnit.channels[ch].tones_info[i].pend_env.stop_pos = 32;
+ }
+ }
+
+ for (int sb = 0; sb < ChUnit.waves_info->num_tone_bands; sb++) {
+ if (d->GetNumWaves(ch, sb)) {
+ if (ChUnit.waves_info->tones_index + ChUnit.channels[ch].tones_info[sb].num_wavs > 48) {
+ std::cerr << "too many tones: " << ChUnit.waves_info->tones_index + ChUnit.channels[ch].tones_info[sb].num_wavs << std::endl;
+ abort();
+ }
+ ChUnit.channels[ch].tones_info[sb].start_index = ChUnit.waves_info->tones_index;
+ ChUnit.waves_info->tones_index += ChUnit.channels[ch].tones_info[sb].num_wavs;
+ }
+ }
+
+ Atrac3pWaveParam *iwav;
+ for (int sb = 0; sb < ChUnit.waves_info->num_tone_bands; sb++) {
+ if (d->GetNumWaves(ch, sb)) {
+ iwav = &ChUnit.waves_info->waves[ChUnit.channels[ch].tones_info[sb].start_index];
+ auto w = d->GetWaves(ch, sb);
+ ChUnit.channels[ch].tones_info[sb].num_wavs = w.second;
+ for (size_t j = 0; j < w.second; j++) {
+ iwav[j].freq_index = w.first[j].FreqIndex;
+ iwav[j].amp_index = w.first[j].AmpIndex;
+ iwav[j].amp_sf = w.first[j].AmpSf;
+ iwav[j].phase_index = w.first[j].PhaseIndex;
+ }
+ }
+ }
+ }
+
+ if (Stereo) {
+ for (int i = 0; i < ChUnit.waves_info->num_tone_bands; i++) {
+ if (d->ToneSharing[i]) {
+ ChUnit.channels[1].tones_info[i] = ChUnit.channels[0].tones_info[i];
+ }
+
+ if (d->SecondIsLeader) {
+ std::swap(ChUnit.channels[0].tones_info[i],
+ ChUnit.channels[1].tones_info[i]);
+ }
+ }
+ }
+ }
+
+ for (size_t ch = 0; ch <= (size_t)Stereo; ch++) {
+ float* x = (ch == 0) ? b1 : b2;
+ if (ChUnit.waves_info->tones_present ||
+ ChUnit.waves_info_prev->tones_present) {
+ for (size_t sb = 0; sb < SUBBANDS; sb++) {
+ if (ChUnit.channels[ch].tones_info[sb].num_wavs ||
+ ChUnit.channels[ch].tones_info_prev[sb].num_wavs) {
+
+ ff_atrac3p_generate_tones(&ChUnit, ch, sb,
+ (x + sb * 128));
+ }
+ }
+ }
+ }
+
+ for (size_t ch = 0; ch <= (size_t)Stereo; ch++) {
+ std::swap(ChUnit.channels[ch].tones_info, ChUnit.channels[ch].tones_info_prev);
+ }
+
+ std::swap(ChUnit.waves_info, ChUnit.waves_info_prev);
+}
+
+const TAt3PGhaData* TGhaProcessor::DoAnalize(TBufPtr b1, TBufPtr b2, float* w1, float* w2)
+{
+ vector<TChannelData> data((size_t)Stereo + 1);
+ bool progress[2] = {false};
+
+ for (size_t ch = 0; ch < data.size(); ch++) {
+ const float* bCur = (ch == 0) ? b1[0] : b2[0];
+ const float* bNext = (ch == 0) ? b1[1] : b2[1];
+ data[ch].SrcBuf = bCur;
+ data[ch].SrcBufNext = bNext;
+
+ for (size_t sb = 0; sb < SUBBANDS; sb++, bCur += SAMPLES_PER_SUBBAND, bNext += SAMPLES_PER_SUBBAND) {
+ constexpr auto copyCurSz = sizeof(float) * SAMPLES_PER_SUBBAND;
+ constexpr auto copyNextSz = sizeof(float) * LOOK_AHEAD;
+ memcpy(&data[ch].Buf[0] + sb * GHA_SUBBAND_BUF_SZ , bCur, copyCurSz);
+ memcpy(&data[ch].Buf[0] + sb * GHA_SUBBAND_BUF_SZ + SAMPLES_PER_SUBBAND, bNext, copyNextSz);
+ }
+ //for (int i = 0; i < SAMPLES_PER_SUBBAND + LOOK_AHEAD; i++) {
+ //std::cerr << i << " " << data[0].Buf[i] << std::endl;
+ //}
+ }
+
+ size_t totalTones = 0;
+ do {
+ for (size_t ch = 0; ch < data.size(); ch++) {
+ progress[ch] = DoRound(data[ch], totalTones);
+ }
+ } while ((progress[0] || progress[1]) && totalTones < 48);
+
+ if (totalTones == 0) {
+ ApplyFilter(nullptr, w1, w2);
+ return nullptr;
+ }
+
+ FillResultBuf(data);
+
+ ResultBufHistory = ResultBuf;
+
+ ApplyFilter(&ResultBuf, w1, w2);
+
+ return &ResultBuf;
+}
+
+bool TGhaProcessor::CheckNextFrame(const float* nextSrc, const vector<gha_info>& ghaInfos) const
+{
+ vector<TAt3PGhaData::TWaveParam> t;
+ t.reserve(ghaInfos.size());
+ for (const auto& x : ghaInfos) {
+ t.emplace_back(TAt3PGhaData::TWaveParam
+ {
+ // TODO: do not do it twice
+ GhaFreqToIndex(x.frequency, 0),
+ AmplitudeToSf(x.magnitude),
+ 1,
+ GhaPhaseToIndex(x.phase)
+ }
+ );
+ }
+
+ float buf[LOOK_AHEAD] = {0.0};
+
+ GenWaves(t.data(), t.size(), 0, buf, LOOK_AHEAD);
+
+ float energyBefore = 0.0;
+ float energyAfter = 0.0;
+
+ for (size_t i = 0; i < LOOK_AHEAD; i++) {
+ energyBefore += nextSrc[i] * nextSrc[i];
+ float t = nextSrc[i] - buf[i];
+ energyAfter += t * t;
+ //std::cerr << buf[i] << " === " << nextSrc[i] << std::endl;
+ }
+
+ // std::cerr << "ENERGY: before: " << energyBefore << " after: " << energyAfter << std::endl;
+
+ return energyAfter < energyBefore;
+}
+
+bool TGhaProcessor::DoRound(TChannelData& data, size_t& totalTones) const
+{
+ bool progress = false;
+ for (size_t sb = 0; sb < SUBBANDS; sb++) {
+ if (data.IsSubbandDone(sb)) {
+ continue;
+ }
+
+ if (totalTones >= 48) {
+ return false;
+ }
+
+ const float* srcB = data.SrcBuf + (sb * SAMPLES_PER_SUBBAND);
+ {
+ auto cit = data.GhaInfos.lower_bound(sb << 10);
+ vector<gha_info> tmp;
+ for(auto it = cit; it != data.GhaInfos.end() && it->first < (sb + 1) << 10; it++) {
+ // std::cerr << sb << " before: freq: " << it->second.frequency << " magn: " << it->second.magnitude << std::endl;
+ tmp.push_back(it->second);
+ }
+ if (tmp.size() > 0) {
+ TChannelGhaCbCtx ctx(&data, sb);
+ do {
+ int ar = gha_adjust_info(srcB, tmp.data(), tmp.size(), LibGhaCtx, CheckResuidalAndApply, &ctx, ctx.FrameSz);
+ if (ar < 0) {
+ ctx.AdjustStatus = TChannelGhaCbCtx::EAdjustStatus::Error;
+ };
+ } while (ctx.AdjustStatus == TChannelGhaCbCtx::EAdjustStatus::Repeat);
+
+ if (ctx.AdjustStatus == TChannelGhaCbCtx::EAdjustStatus::Ok) {
+ std::sort(tmp.begin(), tmp.end(), [](const gha_info& a, const gha_info& b) {return a.frequency < b.frequency;});
+
+ bool dupFound = false;
+ {
+ auto idx1 = GhaFreqToIndex(tmp[0].frequency, sb);
+ for (size_t i = 1; i < tmp.size(); i++) {
+ auto idx2 = GhaFreqToIndex(tmp[i].frequency, sb);
+ if (idx2 == idx1) {
+ dupFound = true;
+ break;
+ } else {
+ idx1 = idx2;
+ }
+ }
+ }
+
+ if (!dupFound) {
+ // check is this tone set ok for the next one
+ if (data.Envelopes[sb].second == SAMPLES_PER_SUBBAND || data.Envelopes[sb].second == TAt3PGhaData::EMPTY_POINT) {
+ bool cont = CheckNextFrame(data.SrcBufNext + SAMPLES_PER_SUBBAND * sb, tmp);
+
+ if (data.Gapless[sb] == true && cont == false) {
+ data.GhaInfos.erase(data.LastAddedFreqIdx[sb]);
+ totalTones--;
+ data.MarkSubbandDone(sb);
+ continue;
+ } else if (data.Envelopes[sb].second == SAMPLES_PER_SUBBAND && cont == true) {
+ data.Envelopes[sb].second = TAt3PGhaData::EMPTY_POINT;
+ data.Gapless[sb] = true;
+ }
+ }
+
+ auto it = cit;
+ for (size_t i = 0; i < tmp.size(); i++) {
+ // std::cerr << sb << " after: freq: " << tmp[i].frequency << " magn: " << tmp[i].magnitude << std::endl;
+ it = data.GhaInfos.erase(it);
+ }
+ for (const auto& x : tmp) {
+ data.MaxToneMagnitude[sb] = std::max(data.MaxToneMagnitude[sb], x.magnitude);
+ const auto newIndex = GhaFreqToIndex(x.frequency, sb);
+ data.GhaInfos.insert({newIndex, x});
+ }
+ } else {
+ std::cerr << "jackpot! same freq index after adjust call, sb: " << sb << " " << std::endl;
+ data.GhaInfos.erase(data.LastAddedFreqIdx[sb]);
+ totalTones--;
+ data.MarkSubbandDone(sb);
+ continue;
+ }
+ } else {
+ data.GhaInfos.erase(data.LastAddedFreqIdx[sb]);
+ totalTones--;
+ data.MarkSubbandDone(sb);
+ continue;
+ }
+ }
+ }
+
+ float* b = &data.Buf[sb * GHA_SUBBAND_BUF_SZ];
+ struct gha_info res;
+
+ gha_analyze_one(b, &res, LibGhaCtx);
+
+ auto freqIndex = GhaFreqToIndex(res.frequency, sb);
+ if (PsyPreCheck(sb, res, data) == false) {
+ data.MarkSubbandDone(sb);
+ } else {
+ if (data.SubbandDone[sb] == 0) {
+ bool ins = data.GhaInfos.insert({freqIndex, res}).second;
+ data.LastAddedFreqIdx[sb] = freqIndex;
+ assert(ins);
+ } else {
+ const auto it = data.GhaInfos.lower_bound(freqIndex);
+ const size_t minFreqDistanse = 20; // Now we unable to handle tones with close frequency
+ if (it != data.GhaInfos.end()) {
+ if (it->first == freqIndex) {
+ data.MarkSubbandDone(sb);
+ continue;
+ }
+
+ if (it->first - freqIndex < minFreqDistanse) {
+ data.MarkSubbandDone(sb);
+ continue;
+ }
+ }
+ if (it != data.GhaInfos.begin()) {
+ auto prev = it;
+ prev--;
+ if (freqIndex - prev->first < minFreqDistanse) {
+ data.MarkSubbandDone(sb);
+ continue;
+ }
+ }
+ if (data.SubbandDone[sb] == 15) {
+ data.MarkSubbandDone(sb);
+ continue;
+ }
+ data.GhaInfos.insert(it, {freqIndex, res});
+ data.LastAddedFreqIdx[sb] = freqIndex;
+ }
+
+ data.SubbandDone[sb]++;
+ totalTones++;
+ progress = true;
+ }
+
+ }
+ return progress;
+}
+
+bool TGhaProcessor::PsyPreCheck(size_t sb, const struct gha_info& gha, const TChannelData& data) const
+{
+ if (isnan(gha.magnitude)) {
+ return false;
+ }
+
+ //std::cerr << "sb: " << sb << " " << gha.magnitude << " ath: " << SubbandAth[sb] << " max: " << data.MaxToneMagnitude[sb] << std::endl;
+ // TODO: improve it
+ // Just to start. Actualy we need to consider spectral leakage during MDCT
+ if ((gha.magnitude * gha.magnitude) > SubbandAth[sb]) {
+ // Stop processing for sb if next extracted tone 23db less then maximal one
+ // TODO: tune
+ if (gha.magnitude > data.MaxToneMagnitude[sb] / 10) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+void TGhaProcessor::AdjustEnvelope(pair<uint32_t, uint32_t>& envelope, const pair<uint32_t, uint32_t>& src, uint32_t history)
+{
+ if (src.first == 0 && history == TAt3PGhaData::EMPTY_POINT) {
+ envelope.first = TAt3PGhaData::EMPTY_POINT;
+ } else {
+ if (src.first == TAt3PGhaData::EMPTY_POINT) {
+ abort(); //impossible right now
+ envelope.first = TAt3PGhaData::EMPTY_POINT;
+ } else {
+ envelope.first = src.first / 4;
+ }
+ }
+ if (src.second == TAt3PGhaData::EMPTY_POINT) {
+ envelope.second = src.second;
+ } else {
+ if (src.second == 0)
+ abort();
+ envelope.second = (src.second - 1) / 4;
+ if (envelope.second >= 32)
+ abort();
+ }
+}
+
+void TGhaProcessor::FillResultBuf(const vector<TChannelData>& data)
+{
+ uint32_t usedContiguousSb[2] = {0, 0};
+ uint32_t numTones[2] = {0, 0};
+
+ // TODO: This can be improved. Bitstream allows to set leader/folower flag for each band.
+ for (size_t ch = 0; ch < data.size(); ch++) {
+ int cur = -1;
+ for (const auto& info : data[ch].GhaInfos) {
+ int sb = info.first >> 10;
+ if (sb == cur + 1) {
+ usedContiguousSb[ch]++;
+ numTones[ch]++;
+ cur = sb;
+ } else if (sb == cur) {
+ numTones[ch]++;
+ continue;
+ } else {
+ break;
+ }
+ }
+ }
+
+ bool leader = usedContiguousSb[1] > usedContiguousSb[0];
+
+ std::vector<TWavesChannel> history;
+ history.reserve(data.size());
+
+ history.push_back(ResultBuf.Waves[0]);
+
+ ResultBuf.SecondIsLeader = leader;
+ ResultBuf.NumToneBands = usedContiguousSb[leader];
+
+ TGhaInfoMap::const_iterator leaderStartIt;
+ TGhaInfoMap::const_iterator folowerIt;
+ if (data.size() == 2) {
+ TWavesChannel& fWaves = ResultBuf.Waves[1];
+
+ history.push_back(fWaves);
+
+ fWaves.WaveParams.clear();
+ fWaves.WaveSbInfos.clear();
+ // Yes, see bitstream code
+ fWaves.WaveSbInfos.resize(usedContiguousSb[leader]);
+ folowerIt = data[!leader].GhaInfos.begin();
+ leaderStartIt = data[leader].GhaInfos.begin();
+ }
+
+ const auto& ghaInfos = data[leader].GhaInfos;
+ TWavesChannel& waves = ResultBuf.Waves[0];
+ waves.WaveParams.clear();
+ waves.WaveSbInfos.clear();
+ waves.WaveSbInfos.resize(usedContiguousSb[leader]);
+ auto it = ghaInfos.begin();
+ uint32_t prevSb = 0;
+ uint32_t index = 0;
+
+ if (usedContiguousSb[leader] == 0) {
+ return;
+ }
+
+ while (it != ghaInfos.end()) {
+ const auto sb = ((it->first) >> 10);
+ if (sb >= usedContiguousSb[leader]) {
+ break;
+ }
+
+ const auto freqIndex = it->first & 1023;
+ const auto phaseIndex = GhaPhaseToIndex(it->second.phase);
+ const auto ampSf = AmplitudeToSf(it->second.magnitude);
+
+ waves.WaveSbInfos[sb].WaveNums++;
+ if (sb != prevSb) {
+ uint32_t histStop = TAt3PGhaData::INIT;
+ if (ResultBufHistory.Waves[0].WaveSbInfos.size() > prevSb) {
+ histStop = ResultBufHistory.Waves[0].WaveSbInfos[prevSb].Envelope.second;
+ }
+ AdjustEnvelope(waves.WaveSbInfos[prevSb].Envelope, data[leader].Envelopes[prevSb], histStop);
+
+ // update index sb -> wave position index
+ waves.WaveSbInfos[sb].WaveIndex = index;
+
+ // process folower if present
+ if (data.size() == 2) {
+ FillFolowerRes(data[leader].GhaInfos, &data[!leader], folowerIt, prevSb);
+ leaderStartIt = it;
+ }
+
+ prevSb = sb;
+ }
+ waves.WaveParams.push_back(TAt3PGhaData::TWaveParam{freqIndex, ampSf, 1, phaseIndex});
+ it++;
+ index++;
+ }
+
+ uint32_t histStop = (uint32_t)-2;
+ if (ResultBufHistory.Waves[0].WaveSbInfos.size() > prevSb) {
+ histStop = ResultBufHistory.Waves[0].WaveSbInfos[prevSb].Envelope.second;
+ }
+
+ TGhaProcessor::AdjustEnvelope(waves.WaveSbInfos[prevSb].Envelope, data[leader].Envelopes[prevSb], histStop);
+
+ if (data.size() == 2) {
+ FillFolowerRes(data[leader].GhaInfos, &data[!leader], folowerIt, prevSb);
+ }
+}
+
+uint32_t TGhaProcessor::FillFolowerRes(const TGhaInfoMap& lGhaInfos, const TChannelData* src, TGhaInfoMap::const_iterator& it, const uint32_t curSb)
+{
+ uint32_t histStop = (uint32_t)-2;
+ if (ResultBufHistory.Waves[1].WaveSbInfos.size() > curSb) {
+ histStop = ResultBufHistory.Waves[1].WaveSbInfos[curSb].Envelope.second;
+ }
+
+ const TGhaInfoMap& fGhaInfos = src->GhaInfos;
+
+ TWavesChannel& waves = ResultBuf.Waves[1];
+
+ uint32_t folowerSbMode = 0; // 0 - no tones, 1 - sharing band, 2 - own tones set
+ uint32_t nextSb = 0;
+ uint32_t added = 0;
+
+ while (it != fGhaInfos.end()) {
+ uint32_t sb = ((it->first) >> 10);
+ if (sb > curSb) {
+ nextSb = sb;
+ break;
+ }
+
+ // search same indedx in the leader and set coresponding bit
+ folowerSbMode |= uint8_t(lGhaInfos.find(it->first) == lGhaInfos.end()) + 1u;
+
+ const auto freqIndex = it->first & 1023;
+ const auto phaseIndex = GhaPhaseToIndex(it->second.phase);
+ const auto ampSf = AmplitudeToSf(it->second.magnitude);
+
+ waves.WaveParams.push_back(TAt3PGhaData::TWaveParam{freqIndex, ampSf, 1, phaseIndex});
+
+ it++;
+ added++;
+ }
+
+ switch (folowerSbMode) {
+ case 0:
+ ResultBuf.ToneSharing[curSb] = false;
+ waves.WaveSbInfos[curSb].WaveNums = 0;
+ break;
+ case 1:
+ ResultBuf.ToneSharing[curSb] = true;
+ waves.WaveParams.resize(waves.WaveParams.size() - added);
+ break;
+ default:
+ ResultBuf.ToneSharing[curSb] = false;
+ waves.WaveSbInfos[curSb].WaveIndex = waves.WaveParams.size() - added;
+ waves.WaveSbInfos[curSb].WaveNums = added;
+ AdjustEnvelope(waves.WaveSbInfos[curSb].Envelope, src->Envelopes[curSb], histStop);
+ }
+ return nextSb;
+}
+
+uint32_t TGhaProcessor::AmplitudeToSf(float amp) const
+{
+ auto it = std::upper_bound(AmpSfTab.begin(), AmpSfTab.end(), amp);
+ if (it != AmpSfTab.begin()) {
+ it--;
+ }
+ return it - AmpSfTab.begin();
+}
+
+} // namespace
+
+std::unique_ptr<IGhaProcessor> MakeGhaProcessor0(bool stereo)
+{
+ return std::unique_ptr<TGhaProcessor>(new TGhaProcessor(stereo));
+}
+
+} // namespace NAtracDEnc
diff --git a/src/atrac/at3p/at3p_gha.h b/src/atrac/at3p/at3p_gha.h
new file mode 100644
index 0000000..702f593
--- /dev/null
+++ b/src/atrac/at3p/at3p_gha.h
@@ -0,0 +1,78 @@
+/*
+ * This file is part of AtracDEnc.
+ *
+ * AtracDEnc is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * AtracDEnc is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with AtracDEnc; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#pragma once
+
+#include <config.h>
+
+#include <array>
+#include <memory>
+#include <vector>
+
+namespace NAtracDEnc {
+
+struct TAt3PGhaData {
+ static constexpr uint32_t EMPTY_POINT = static_cast<uint32_t>(-1);
+ static constexpr uint32_t INIT = static_cast<uint32_t>(-2);
+ struct TWaveParam {
+ uint32_t FreqIndex;
+ uint32_t AmpSf;
+ uint32_t AmpIndex;
+ uint32_t PhaseIndex;
+ };
+ struct TWaveSbInfo {
+ size_t WaveIndex;
+ size_t WaveNums;
+ std::pair<uint32_t, uint32_t> Envelope = {EMPTY_POINT, EMPTY_POINT};
+ };
+ struct TWavesChannel {
+ std::vector<TWaveSbInfo> WaveSbInfos;
+ std::vector<TWaveParam> WaveParams;
+ };
+ std::array<TWavesChannel, 2> Waves;
+
+ uint8_t NumToneBands;
+
+ bool ToneSharing[16];
+ bool SecondIsLeader;
+
+ size_t GetNumWaves(size_t ch, size_t sb) const {
+ return Waves[ch].WaveSbInfos.at(sb).WaveNums;
+ }
+
+ std::pair<uint32_t, uint32_t> GetEnvelope(size_t ch, size_t sb) const {
+ return Waves[ch].WaveSbInfos.at(sb).Envelope;
+ }
+
+ std::pair<const TWaveParam*, size_t> GetWaves(size_t ch, size_t sb) const {
+ const auto& sbInfo = Waves[ch].WaveSbInfos.at(sb);
+ return { &Waves[ch].WaveParams[sbInfo.WaveIndex], sbInfo.WaveNums };
+ }
+};
+
+class IGhaProcessor {
+public:
+ using TBufPtr = std::array<const float*, 2>;
+ virtual ~IGhaProcessor() {}
+ virtual const TAt3PGhaData* DoAnalize(TBufPtr b1, TBufPtr b2, float* w1, float* w2) = 0;
+};
+
+std::unique_ptr<IGhaProcessor> MakeGhaProcessor0(bool stereo);
+
+} // namespace NAtracDEnc
+
diff --git a/src/atrac/at3p/at3p_gha_ut.cpp b/src/atrac/at3p/at3p_gha_ut.cpp
new file mode 100644
index 0000000..a3cacec
--- /dev/null
+++ b/src/atrac/at3p/at3p_gha_ut.cpp
@@ -0,0 +1,787 @@
+#include "at3p_bitstream.h"
+#include "at3p_gha.h"
+#include "oma.h"
+#include "util.h"
+#include <gtest/gtest.h>
+#include <cmath>
+#include <vector>
+#include <cstdlib>
+
+using std::vector;
+
+using namespace NAtracDEnc;
+
+struct TTestParam {
+ float freq;
+ float phase;
+ uint16_t amplitude;
+ uint16_t start;
+ uint16_t end;
+};
+
+static void atde_noinline Gen(const TTestParam& p, vector<float>& out)
+{
+ float freq = p.freq / (44100.0 / 16.0);
+ float a = p.amplitude;
+ int end = p.end;
+ int j = 0;
+ for (int i = p.start; i < end; i++, j++) {
+ out[i] += sin(freq * (float)j * 2.0 * M_PI + p.phase) * a;
+ }
+}
+
+static TAt3PGhaData DoAnalize(IGhaProcessor* p, IGhaProcessor::TBufPtr b1, IGhaProcessor::TBufPtr b2) {
+ float w1[2048] = {0};
+ float w2[2048] = {0};
+ return *p->DoAnalize(b1, b2, w1, w2);
+}
+
+static const TAt3PGhaData atde_noinline GenAndRunGha(vector<TTestParam> p1, vector<TTestParam> p2)
+{
+ vector<float> buf1(2048 * 2);
+
+ for (const auto& p : p1) {
+ Gen(p, buf1);
+ }
+
+ vector<float> buf2;
+
+ if (!p2.empty()) {
+ buf2.resize(2048 * 2);
+
+ for (const auto& p : p2) {
+ Gen(p, buf2);
+ }
+ }
+
+ auto processor = MakeGhaProcessor0(!p2.empty());
+ const float* b1 = buf1.data();
+ const float* b2 = buf2.empty() ? nullptr : buf2.data();
+
+ return DoAnalize(processor.get(), {b1, b1 + 2048}, {b2, b2 + 2048});
+}
+
+static class TDumper {
+public:
+ TDumper()
+ : PathPrefix(std::getenv("GHA_UT_DUMP_DIR"))
+ {}
+
+ void Dump(const TAt3PGhaData* gha, size_t channels, size_t len) {
+ if (!PathPrefix) {
+ return;
+ }
+
+ std::string path = PathPrefix;
+ path += "/";
+ path += ::testing::UnitTest::GetInstance()->current_test_info()->name();
+ path += ".oma";
+
+ std::unique_ptr<TOma> out(new TOma(path,
+ "test",
+ channels,
+ 1, OMAC_ID_ATRAC3PLUS,
+ 2048,
+ false));
+
+ TAt3PBitStream bs(out.get(), 2048);
+
+ for (size_t i = 0; i < len; i++) {
+ // bs.WriteFrame(channels, gha + i);
+ }
+ }
+private:
+ const char* PathPrefix;
+} Dumper;
+
+
+// Single channel simple cases
+
+TEST(AT3PGHA, 689hz0625__full_frame_mono) {
+ auto res = GenAndRunGha({{689.0625f, 0, 32768, 0, 128}}, {});
+ EXPECT_EQ(res.NumToneBands, 1);
+ EXPECT_EQ(res.Waves[0].WaveParams.size(), 1);
+ EXPECT_EQ(res.Waves[0].WaveSbInfos.size(), 1);
+ EXPECT_EQ(res.GetNumWaves(0, 0), 1);
+ EXPECT_EQ(res.GetWaves(0, 0).second, 1);
+ EXPECT_EQ(res.GetWaves(0, 0).first->FreqIndex, 512);
+ EXPECT_EQ(res.GetWaves(0, 0).first->AmpSf, 63);
+ //EXPECT_EQ(res.GetWaves(0, 0).first->PhaseIndex, 0);
+ Dumper.Dump(&res, 1, 1);
+}
+
+TEST(AT3PGHA, 0__full_frame_mono) {
+ auto res = GenAndRunGha({{0.0f, M_PI/2, 32768, 0, 128}}, {});
+ EXPECT_EQ(res.NumToneBands, 1);
+ EXPECT_EQ(res.Waves[0].WaveParams.size(), 1);
+ EXPECT_EQ(res.Waves[0].WaveSbInfos.size(), 1);
+ EXPECT_EQ(res.GetNumWaves(0, 0), 1);
+ EXPECT_EQ(res.GetWaves(0, 0).second, 1);
+ EXPECT_EQ(res.GetWaves(0, 0).first->FreqIndex, 0);
+ EXPECT_EQ(res.GetWaves(0, 0).first->AmpSf, 63);
+ //EXPECT_EQ(res.GetWaves(0, 0).first->PhaseIndex, 0);
+ Dumper.Dump(&res, 1, 1);
+}
+
+
+TEST(AT3PGHA, 689hz0625__partial_frame_mono) {
+ auto res = GenAndRunGha({{689.0625f, 0, 32768, 32, 128}}, {});
+ EXPECT_EQ(res.NumToneBands, 1);
+ EXPECT_EQ(res.Waves[0].WaveParams.size(), 1);
+ EXPECT_EQ(res.Waves[0].WaveSbInfos.size(), 1);
+ EXPECT_EQ(res.GetNumWaves(0, 0), 1);
+ EXPECT_EQ(res.GetWaves(0, 0).second, 1);
+ EXPECT_EQ(res.GetWaves(0, 0).first->FreqIndex, 512);
+}
+
+TEST(AT3PGHA, 689hz0625_900hz__full_frame_mono) {
+ auto res = GenAndRunGha({{689.0625f, 0, 16384, 0, 128}, {900.0, 0, 8192, 0, 128}}, {});
+ EXPECT_EQ(res.NumToneBands, 1);
+ EXPECT_EQ(res.Waves[0].WaveParams.size(), 2);
+ EXPECT_EQ(res.Waves[0].WaveSbInfos.size(), 1);
+ EXPECT_EQ(res.GetNumWaves(0, 0), 2);
+ EXPECT_EQ(res.GetWaves(0, 0).second, 2);
+ EXPECT_EQ(res.GetWaves(0, 0).first[0].FreqIndex, 512);
+ EXPECT_EQ(res.GetWaves(0, 0).first[1].FreqIndex, 669);
+ Dumper.Dump(&res, 1, 1);
+}
+
+TEST(AT3PGHA, 400hz_800hz__full_frame_mono) {
+ auto res = GenAndRunGha({{400.0, 0, 16384, 0, 128}, {800.0, 0, 4096, 0, 128}}, {});
+ EXPECT_EQ(res.NumToneBands, 1);
+ EXPECT_EQ(res.Waves[0].WaveParams.size(), 2);
+ EXPECT_EQ(res.Waves[0].WaveSbInfos.size(), 1);
+ EXPECT_EQ(res.GetNumWaves(0, 0), 2);
+ EXPECT_EQ(res.GetWaves(0, 0).second, 2);
+ EXPECT_EQ(res.GetWaves(0, 0).first[0].FreqIndex, 297);
+ EXPECT_EQ(res.GetWaves(0, 0).first[1].FreqIndex, 594);
+ Dumper.Dump(&res, 1, 1);
+}
+
+TEST(AT3PGHA, 689hz0625_2067hz1875__full_frame_mono) {
+ auto res = GenAndRunGha({{689.0625f, 0, 16384, 0, 128}, {689.0625f, 0, 16384, 128, 256}}, {});
+ EXPECT_EQ(res.NumToneBands, 2);
+ EXPECT_EQ(res.Waves[0].WaveParams.size(), 2);
+ EXPECT_EQ(res.Waves[0].WaveSbInfos.size(), 2);
+ EXPECT_EQ(res.GetNumWaves(0, 0), 1);
+ EXPECT_EQ(res.GetNumWaves(0, 1), 1);
+ EXPECT_EQ(res.GetWaves(0, 0).second, 1);
+ EXPECT_EQ(res.GetWaves(0, 0).first[0].FreqIndex, 512);
+ EXPECT_EQ(res.GetWaves(0, 0).first->AmpSf, 59);
+ EXPECT_EQ(res.GetWaves(0, 1).second, 1);
+ EXPECT_EQ(res.GetWaves(0, 1).first[0].FreqIndex, 512);
+ EXPECT_EQ(res.GetWaves(0, 1).first->AmpSf, 59);
+ Dumper.Dump(&res, 1, 1);
+}
+
+TEST(AT3PGHA, 689hz0625_4823hz4375__full_frame_mono) {
+ auto res = GenAndRunGha({{689.0625f, 0, 32768, 0, 128}, {689.0625f, 0, 16384, 256, 384}}, {});
+ EXPECT_EQ(res.NumToneBands, 1);
+ EXPECT_EQ(res.Waves[0].WaveParams.size(), 1);
+ EXPECT_EQ(res.Waves[0].WaveSbInfos.size(), 1);
+ EXPECT_EQ(res.GetNumWaves(0, 0), 1);
+ EXPECT_EQ(res.GetWaves(0, 0).second, 1);
+ EXPECT_EQ(res.GetWaves(0, 0).first->FreqIndex, 512);
+ Dumper.Dump(&res, 1, 1);
+}
+
+// Two channels simple cases
+
+TEST(AT3PGHA, 689hz0625__full_frame_stereo_shared) {
+ auto res = GenAndRunGha({{689.0625f, 0, 32768, 0, 128}}, {{689.0625f, 0, 32768, 0, 128}});
+ EXPECT_EQ(res.NumToneBands, 1);
+ EXPECT_EQ(res.Waves[0].WaveParams.size(), 1);
+ EXPECT_EQ(res.Waves[0].WaveSbInfos.size(), 1);
+ EXPECT_EQ(res.GetNumWaves(0, 0), 1);
+ EXPECT_EQ(res.GetWaves(0, 0).second, 1);
+ EXPECT_EQ(res.GetWaves(0, 0).first->FreqIndex, 512);
+
+ EXPECT_EQ(res.ToneSharing[0], true);
+ EXPECT_EQ(res.Waves[1].WaveParams.size(), 0);
+ Dumper.Dump(&res, 2, 1);
+}
+
+TEST(AT3PGHA, 689hz0625__full_frame_stereo_own) {
+ auto res = GenAndRunGha({{689.0625f, 0, 32768, 0, 128}}, {{1000.0625f, 0, 32768, 0, 128}});
+ EXPECT_EQ(res.NumToneBands, 1);
+ EXPECT_EQ(res.Waves[0].WaveParams.size(), 1);
+ EXPECT_EQ(res.Waves[0].WaveSbInfos.size(), 1);
+ EXPECT_EQ(res.GetNumWaves(0, 0), 1);
+ EXPECT_EQ(res.GetWaves(0, 0).second, 1);
+ EXPECT_EQ(res.GetWaves(0, 0).first->FreqIndex, 512);
+
+ EXPECT_EQ(res.ToneSharing[0], false);
+
+ EXPECT_EQ(res.Waves[1].WaveParams.size(), 1);
+ EXPECT_EQ(res.Waves[1].WaveSbInfos.size(), 1);
+ EXPECT_EQ(res.GetNumWaves(1, 0), 1);
+ EXPECT_EQ(res.GetWaves(1, 0).second, 1);
+ EXPECT_EQ(res.GetWaves(1, 0).first->FreqIndex, 743);
+
+ Dumper.Dump(&res, 2, 1);
+}
+
+TEST(AT3PGHA, 689hz0625__full_frame_stereo_multiple_second) {
+ auto res = GenAndRunGha({{689.0625f, 0, 32768, 0, 128}}, {{689.0625f, 0, 16384, 0, 128}, {900.0, 0, 8192, 0, 128}});
+ EXPECT_EQ(res.NumToneBands, 1);
+ EXPECT_EQ(res.Waves[0].WaveParams.size(), 1);
+ EXPECT_EQ(res.Waves[0].WaveSbInfos.size(), 1);
+ EXPECT_EQ(res.GetNumWaves(0, 0), 1);
+ EXPECT_EQ(res.GetWaves(0, 0).second, 1);
+ EXPECT_EQ(res.GetWaves(0, 0).first->FreqIndex, 512);
+
+ EXPECT_EQ(res.ToneSharing[0], false);
+ EXPECT_EQ(res.Waves[1].WaveParams.size(), 2);
+ EXPECT_EQ(res.Waves[1].WaveSbInfos.size(), 1);
+ EXPECT_EQ(res.GetNumWaves(1, 0), 2);
+ EXPECT_EQ(res.GetWaves(1, 0).second, 2);
+ EXPECT_EQ(res.GetWaves(1, 0).first[0].FreqIndex, 512);
+ EXPECT_EQ(res.GetWaves(1, 0).first[1].FreqIndex, 669);
+ Dumper.Dump(&res, 2, 1);
+}
+
+TEST(AT3PGHA, 689hz0625_2067hz1875__full_frame_stereo_first_is_leader) {
+ auto res = GenAndRunGha({{689.0625f, 0, 32768, 0, 128}, {689.0625f, 0, 16384, 128, 256}},
+ {{689.0625f, 0, 32768, 0, 128}});
+ EXPECT_EQ(res.NumToneBands, 2);
+ EXPECT_EQ(res.Waves[0].WaveParams.size(), 2);
+ EXPECT_EQ(res.Waves[0].WaveSbInfos.size(), 2);
+ EXPECT_EQ(res.GetNumWaves(0, 0), 1);
+ EXPECT_EQ(res.GetNumWaves(0, 1), 1);
+ EXPECT_EQ(res.GetWaves(0, 0).second, 1);
+ EXPECT_EQ(res.GetWaves(0, 0).first[0].FreqIndex, 512);
+ EXPECT_EQ(res.GetWaves(0, 1).second, 1);
+ EXPECT_EQ(res.GetWaves(0, 1).first[0].FreqIndex, 512);
+
+ EXPECT_EQ(res.ToneSharing[0], true);
+ EXPECT_EQ(res.ToneSharing[1], false);
+
+ EXPECT_EQ(res.Waves[1].WaveParams.size(), 0); // sb0 sharing, sb1 zerro
+ EXPECT_EQ(res.Waves[1].WaveSbInfos.size(), 2);
+ EXPECT_EQ(res.GetNumWaves(1, 1), 0);
+ Dumper.Dump(&res, 2, 1);
+}
+
+TEST(AT3PGHA, 689hz0625_2067hz1875__full_frame_stereo_second_is_leader) {
+ auto res = GenAndRunGha({{689.0625f, 0, 32768, 0, 128}},
+ {{689.0625f, 0, 32768, 0, 128}, {689.0625f, 0, 16384, 128, 256}});
+ EXPECT_EQ(res.NumToneBands, 2);
+ EXPECT_EQ(res.Waves[0].WaveParams.size(), 2);
+ EXPECT_EQ(res.Waves[0].WaveSbInfos.size(), 2);
+ EXPECT_EQ(res.GetNumWaves(0, 0), 1);
+ EXPECT_EQ(res.GetNumWaves(0, 1), 1);
+ EXPECT_EQ(res.GetWaves(0, 0).second, 1);
+ EXPECT_EQ(res.GetWaves(0, 0).first[0].FreqIndex, 512);
+ EXPECT_EQ(res.GetWaves(0, 1).second, 1);
+ EXPECT_EQ(res.GetWaves(0, 1).first[0].FreqIndex, 512);
+
+ EXPECT_EQ(res.ToneSharing[0], true);
+ EXPECT_EQ(res.ToneSharing[1], false);
+
+ EXPECT_EQ(res.Waves[1].WaveParams.size(), 0);
+ EXPECT_EQ(res.Waves[1].WaveSbInfos.size(), 2);
+ EXPECT_EQ(res.GetNumWaves(1, 1), 0);
+
+ Dumper.Dump(&res, 2, 1);
+}
+
+TEST(AT3PGHA, 689hz0625_2067hz1875_3445hz3125__full_frame_stereo_sharing_0_2) {
+ auto res = GenAndRunGha({{689.0625f, 0, 32768, 0, 128}, {689.0625f, 0, 32768, 128, 256}, {689.0625f, 0, 16384, 256, 384}},
+ {{689.0625f, 0, 32768, 0, 128}, {689.0625f, 0, 16384, 256, 384}});
+ EXPECT_EQ(res.NumToneBands, 3);
+ EXPECT_EQ(res.Waves[0].WaveParams.size(), 3);
+ EXPECT_EQ(res.Waves[0].WaveSbInfos.size(), 3);
+ EXPECT_EQ(res.GetNumWaves(0, 0), 1);
+ EXPECT_EQ(res.GetNumWaves(0, 1), 1);
+ EXPECT_EQ(res.GetNumWaves(0, 2), 1);
+ EXPECT_EQ(res.GetWaves(0, 0).second, 1);
+ EXPECT_EQ(res.GetWaves(0, 0).first[0].FreqIndex, 512);
+ EXPECT_EQ(res.GetWaves(0, 1).second, 1);
+ EXPECT_EQ(res.GetWaves(0, 1).first[0].FreqIndex, 512);
+ EXPECT_EQ(res.GetWaves(0, 2).second, 1);
+ EXPECT_EQ(res.GetWaves(0, 2).first[0].FreqIndex, 512);
+
+ EXPECT_EQ(res.ToneSharing[0], true);
+ EXPECT_EQ(res.ToneSharing[1], false);
+ EXPECT_EQ(res.ToneSharing[2], true);
+ EXPECT_EQ(res.Waves[1].WaveParams.size(), 0);
+ EXPECT_EQ(res.GetNumWaves(1, 1), 0);
+ Dumper.Dump(&res, 2, 1);
+}
+
+TEST(AT3PGHA, 689hz0625_2067hz1875_3445hz3125__full_frame_stereo_folower_sharing_2) {
+ auto res = GenAndRunGha({{689.0625f, 0, 32768, 0, 128}, {689.0625f, 0, 32768, 128, 256}, {689.0625f, 0, 16384, 256, 384}},
+ {{689.0625f, 0, 16384, 256, 384}});
+ EXPECT_EQ(res.NumToneBands, 3);
+ EXPECT_EQ(res.Waves[0].WaveParams.size(), 3);
+ EXPECT_EQ(res.Waves[0].WaveSbInfos.size(), 3);
+ EXPECT_EQ(res.GetNumWaves(0, 0), 1);
+ EXPECT_EQ(res.GetNumWaves(0, 1), 1);
+ EXPECT_EQ(res.GetNumWaves(0, 2), 1);
+ EXPECT_EQ(res.GetWaves(0, 0).second, 1);
+ EXPECT_EQ(res.GetWaves(0, 0).first[0].FreqIndex, 512);
+ EXPECT_EQ(res.GetWaves(0, 1).second, 1);
+ EXPECT_EQ(res.GetWaves(0, 1).first[0].FreqIndex, 512);
+ EXPECT_EQ(res.GetWaves(0, 2).second, 1);
+ EXPECT_EQ(res.GetWaves(0, 2).first[0].FreqIndex, 512);
+
+ EXPECT_EQ(res.ToneSharing[0], false);
+ EXPECT_EQ(res.ToneSharing[1], false);
+ EXPECT_EQ(res.ToneSharing[2], true);
+ EXPECT_EQ(res.Waves[1].WaveParams.size(), 0);
+ EXPECT_EQ(res.GetNumWaves(1, 0), 0);
+ EXPECT_EQ(res.GetNumWaves(1, 1), 0);
+ Dumper.Dump(&res, 2, 1);
+}
+
+TEST(AT3PGHA, 689hz0625_2067hz1875_3445hz3125__full_frame_stereo_folower_sharing_1) {
+ auto res = GenAndRunGha({{689.0625f, 0, 32768, 0, 128}, {689.0625f, 0, 32768, 128, 256}, {689.0625f, 0, 16384, 256, 384}},
+ {{689.0625f, 0, 16384, 128, 256}});
+ EXPECT_EQ(res.NumToneBands, 3);
+ EXPECT_EQ(res.Waves[0].WaveParams.size(), 3);
+ EXPECT_EQ(res.Waves[0].WaveSbInfos.size(), 3);
+ EXPECT_EQ(res.GetNumWaves(0, 0), 1);
+ EXPECT_EQ(res.GetNumWaves(0, 1), 1);
+ EXPECT_EQ(res.GetNumWaves(0, 2), 1);
+ EXPECT_EQ(res.GetWaves(0, 0).second, 1);
+ EXPECT_EQ(res.GetWaves(0, 0).first[0].FreqIndex, 512);
+ EXPECT_EQ(res.GetWaves(0, 1).second, 1);
+ EXPECT_EQ(res.GetWaves(0, 1).first[0].FreqIndex, 512);
+ EXPECT_EQ(res.GetWaves(0, 2).second, 1);
+ EXPECT_EQ(res.GetWaves(0, 2).first[0].FreqIndex, 512);
+
+ EXPECT_EQ(res.ToneSharing[0], false);
+ EXPECT_EQ(res.ToneSharing[1], true);
+ EXPECT_EQ(res.ToneSharing[2], false);
+ EXPECT_EQ(res.Waves[1].WaveParams.size(), 0);
+ EXPECT_EQ(res.GetNumWaves(1, 0), 0);
+ EXPECT_EQ(res.GetNumWaves(1, 2), 0);
+ Dumper.Dump(&res, 2, 1);
+}
+
+/*
+TEST(AT3PGHA, max_tones_multiple_bands_full_frame_stereo) {
+ auto res = GenAndRunGha({
+ {60.0f, 8192, 0, 128}, {120.0f, 8192, 0, 128}, {180.0f, 4096, 0, 128}, {240.0f, 2048, 0, 128},
+ {60.0f, 8192, 128, 256}, {120.0f, 8192, 128, 256}, {180.0f, 4096, 128, 256}, {240.0f, 2048, 128, 256},
+ {60.0f, 8192, 256, 384}, {120.0f, 8192, 256, 384}, {180.0f, 4096, 256, 384}, {240.0f, 2048, 256, 384},
+ {60.0f, 8192, 384, 512}, {120.0f, 8192, 384, 512}, {180.0f, 4096, 384, 512}, {240.0f, 2048, 384, 512},
+ {60.0f, 8192, 512, 640}, {120.0f, 8192, 512, 640}, {180.0f, 4096, 512, 640}, {240.0f, 2048, 512, 640},
+ {60.0f, 8192, 640, 768}, {120.0f, 8192, 640, 768}, {180.0f, 4096, 640, 768}, {240.0f, 2048, 640, 768},
+ {60.0f, 8192, 768, 896}, {120.0f, 8192, 768, 896}, {180.0f, 4096, 768, 896}, {240.0f, 2048, 768, 896},
+ }, {
+ {60.0f, 8192, 0, 128}, {120.0f, 8192, 0, 128}, {180.0f, 4096, 0, 128}, {240.0f, 2048, 0, 128},
+ {60.0f, 8192, 128, 256}, {120.0f, 8192, 128, 256}, {180.0f, 4096, 128, 256}, {240.0f, 2048, 128, 256},
+ {60.0f, 8192, 256, 384}, {120.0f, 8192, 256, 384}, {180.0f, 4096, 256, 384}, {240.0f, 2048, 256, 384},
+ {60.0f, 8192, 384, 512}, {120.0f, 8192, 384, 512}, {180.0f, 4096, 384, 512}, {240.0f, 2048, 384, 512},
+ {60.0f, 8192, 512, 640}, {120.0f, 8192, 512, 640}, {180.0f, 4096, 512, 640}, {240.0f, 2048, 512, 640},
+ {60.0f, 8192, 640, 768}, {120.0f, 8192, 640, 768}, {180.0f, 4096, 640, 768}, {240.0f, 2048, 640, 768},
+ {60.0f, 8192, 768, 896}, {120.0f, 8192, 768, 896}, {180.0f, 4096, 768, 896}, {240.0f, 2048, 768, 896},
+ });
+ EXPECT_EQ(res.NumToneBands, 7);
+ EXPECT_EQ(res.Waves[0].WaveParams.size(), 28);
+ EXPECT_EQ(res.Waves[0].WaveSbInfos.size(), 7);
+ EXPECT_EQ(res.GetNumWaves(0, 0), 4);
+ EXPECT_EQ(res.GetNumWaves(0, 1), 4);
+ EXPECT_EQ(res.GetNumWaves(0, 2), 4);
+ EXPECT_EQ(res.GetNumWaves(0, 3), 4);
+ EXPECT_EQ(res.GetNumWaves(0, 4), 4);
+ EXPECT_EQ(res.GetNumWaves(0, 5), 4);
+ EXPECT_EQ(res.GetNumWaves(0, 6), 4);
+ EXPECT_EQ(res.GetWaves(0, 0).second, 4);
+ EXPECT_EQ(res.GetWaves(0, 0).first[0].FreqIndex, 45);
+ EXPECT_EQ(res.GetWaves(0, 0).first[1].FreqIndex, 89);
+ EXPECT_EQ(res.GetWaves(0, 0).first[2].FreqIndex, 134);
+ EXPECT_EQ(res.GetWaves(0, 0).first[3].FreqIndex, 178);
+
+ EXPECT_EQ(res.GetWaves(0, 1).first[0].FreqIndex, 45);
+ EXPECT_EQ(res.GetWaves(0, 1).first[1].FreqIndex, 89);
+ EXPECT_EQ(res.GetWaves(0, 1).first[2].FreqIndex, 134);
+ EXPECT_EQ(res.GetWaves(0, 1).first[3].FreqIndex, 178);
+
+ EXPECT_EQ(res.GetWaves(0, 2).first[0].FreqIndex, 45);
+ EXPECT_EQ(res.GetWaves(0, 2).first[1].FreqIndex, 89);
+ EXPECT_EQ(res.GetWaves(0, 2).first[2].FreqIndex, 134);
+ EXPECT_EQ(res.GetWaves(0, 2).first[3].FreqIndex, 178);
+
+ EXPECT_EQ(res.GetWaves(0, 3).first[0].FreqIndex, 45);
+ EXPECT_EQ(res.GetWaves(0, 3).first[1].FreqIndex, 89);
+ EXPECT_EQ(res.GetWaves(0, 3).first[2].FreqIndex, 134);
+ EXPECT_EQ(res.GetWaves(0, 3).first[3].FreqIndex, 178);
+
+ EXPECT_EQ(res.GetWaves(0, 4).first[0].FreqIndex, 45);
+ EXPECT_EQ(res.GetWaves(0, 4).first[1].FreqIndex, 89);
+ EXPECT_EQ(res.GetWaves(0, 4).first[2].FreqIndex, 134);
+ EXPECT_EQ(res.GetWaves(0, 4).first[3].FreqIndex, 178);
+
+ EXPECT_EQ(res.GetWaves(0, 5).first[0].FreqIndex, 45);
+ EXPECT_EQ(res.GetWaves(0, 5).first[1].FreqIndex, 89);
+ EXPECT_EQ(res.GetWaves(0, 5).first[2].FreqIndex, 134);
+ EXPECT_EQ(res.GetWaves(0, 5).first[3].FreqIndex, 178);
+
+ EXPECT_EQ(res.GetWaves(0, 6).first[0].FreqIndex, 45);
+ EXPECT_EQ(res.GetWaves(0, 6).first[1].FreqIndex, 89);
+ EXPECT_EQ(res.GetWaves(0, 6).first[2].FreqIndex, 134);
+ EXPECT_EQ(res.GetWaves(0, 6).first[3].FreqIndex, 178);
+
+ EXPECT_EQ(res.Waves[1].WaveParams.size(), 21);
+ EXPECT_EQ(res.Waves[1].WaveSbInfos.size(), 7);
+ EXPECT_EQ(res.GetNumWaves(1, 0), 3);
+ EXPECT_EQ(res.GetNumWaves(1, 1), 3);
+ EXPECT_EQ(res.GetNumWaves(1, 2), 3);
+ EXPECT_EQ(res.GetNumWaves(1, 3), 3);
+ EXPECT_EQ(res.GetNumWaves(1, 4), 3);
+ EXPECT_EQ(res.GetNumWaves(1, 5), 3);
+ EXPECT_EQ(res.GetNumWaves(1, 6), 3);
+ EXPECT_EQ(res.GetWaves(1, 0).second, 3);
+ EXPECT_EQ(res.GetWaves(1, 0).first[0].FreqIndex, 45);
+ EXPECT_EQ(res.GetWaves(1, 0).first[1].FreqIndex, 89);
+ EXPECT_EQ(res.GetWaves(1, 0).first[2].FreqIndex, 134);
+
+ EXPECT_EQ(res.GetWaves(1, 1).first[0].FreqIndex, 45);
+ EXPECT_EQ(res.GetWaves(1, 1).first[1].FreqIndex, 89);
+ EXPECT_EQ(res.GetWaves(1, 1).first[2].FreqIndex, 134);
+
+ EXPECT_EQ(res.GetWaves(1, 2).first[0].FreqIndex, 45);
+ EXPECT_EQ(res.GetWaves(1, 2).first[1].FreqIndex, 89);
+ EXPECT_EQ(res.GetWaves(1, 2).first[2].FreqIndex, 134);
+
+ EXPECT_EQ(res.GetWaves(1, 3).first[0].FreqIndex, 45);
+ EXPECT_EQ(res.GetWaves(1, 3).first[1].FreqIndex, 89);
+ EXPECT_EQ(res.GetWaves(1, 3).first[2].FreqIndex, 134);
+
+ EXPECT_EQ(res.GetWaves(1, 4).first[0].FreqIndex, 45);
+ EXPECT_EQ(res.GetWaves(1, 4).first[1].FreqIndex, 89);
+ EXPECT_EQ(res.GetWaves(1, 4).first[2].FreqIndex, 134);
+
+ EXPECT_EQ(res.GetWaves(1, 5).first[0].FreqIndex, 45);
+ EXPECT_EQ(res.GetWaves(1, 5).first[1].FreqIndex, 89);
+ EXPECT_EQ(res.GetWaves(1, 5).first[2].FreqIndex, 134);
+
+ EXPECT_EQ(res.GetWaves(1, 6).first[0].FreqIndex, 45);
+ EXPECT_EQ(res.GetWaves(1, 6).first[1].FreqIndex, 89);
+ EXPECT_EQ(res.GetWaves(1, 6).first[2].FreqIndex, 134);
+ Dumper.Dump(&res, 2, 1);
+}
+
+*/
+
+TEST(AT3PGHA, 100hz__two_frames_mono) {
+ vector<float> buf(2048 * 2);
+
+ Gen({100.0f, 0, 32768, 0, 256}, buf);
+
+ memcpy(&buf[2048], &buf[128], sizeof(float) * 128);
+ memset(&buf[128], 0, sizeof(float) * 128);
+
+ std::vector<TAt3PGhaData> resBuf;
+ auto processor = MakeGhaProcessor0(false);
+
+ {
+ const auto res = DoAnalize(processor.get(), {&buf[0], &buf[2048]}, {nullptr, nullptr});
+
+ EXPECT_EQ(res.NumToneBands, 1);
+ EXPECT_EQ(res.Waves[0].WaveParams.size(), 1);
+ EXPECT_EQ(res.Waves[0].WaveSbInfos.size(), 1);
+ EXPECT_EQ(res.GetNumWaves(0, 0), 1);
+ EXPECT_EQ(res.GetWaves(0, 0).second, 1);
+ EXPECT_EQ(res.GetWaves(0, 0).first->FreqIndex, 74);
+ EXPECT_EQ(res.GetWaves(0, 0).first->AmpSf, 62);
+ EXPECT_EQ(res.GetWaves(0, 0).first->PhaseIndex, 0);
+
+ resBuf.push_back(res);
+ }
+
+ {
+ memset(&buf[0], 0, sizeof(float) * 128);
+ const auto res = DoAnalize(processor.get(), {&buf[2048], &buf[0]}, {nullptr, nullptr});
+
+ EXPECT_EQ(res.NumToneBands, 1);
+ EXPECT_EQ(res.Waves[0].WaveParams.size(), 1);
+ EXPECT_EQ(res.Waves[0].WaveSbInfos.size(), 1);
+ EXPECT_EQ(res.GetNumWaves(0, 0), 1);
+ EXPECT_EQ(res.GetWaves(0, 0).second, 1);
+ EXPECT_EQ(res.GetWaves(0, 0).first->FreqIndex, 74);
+ EXPECT_EQ(res.GetWaves(0, 0).first->AmpSf, 62);
+ EXPECT_EQ(res.GetWaves(0, 0).first->PhaseIndex, 21);
+
+ resBuf.push_back(res);
+ }
+ Dumper.Dump(resBuf.data(), 1, 2);
+}
+
+TEST(AT3PGHA, 100hz_than_500hz_than_100hz__3_frames_mono) {
+ vector<float> buf(2048 * 2);
+
+ Gen({100.0f, 0, 32768, 0, 128}, buf);
+ Gen({500.0f, 0, 32768, 128, 256}, buf);
+
+ memcpy(&buf[2048], &buf[128], sizeof(float) * 128);
+ memset(&buf[128], 0, sizeof(float) * 128);
+
+ std::vector<TAt3PGhaData> resBuf;
+ auto processor = MakeGhaProcessor0(false);
+
+ {
+ const auto res = DoAnalize(processor.get(), {&buf[0], &buf[2048]}, {nullptr, nullptr});
+
+ EXPECT_EQ(res.NumToneBands, 1);
+ EXPECT_EQ(res.Waves[0].WaveParams.size(), 1);
+ EXPECT_EQ(res.Waves[0].WaveSbInfos.size(), 1);
+ EXPECT_EQ(res.GetNumWaves(0, 0), 1);
+ EXPECT_EQ(res.GetWaves(0, 0).second, 1);
+ EXPECT_EQ(res.GetWaves(0, 0).first->FreqIndex, 74);
+ EXPECT_EQ(res.GetWaves(0, 0).first->AmpSf, 62);
+ EXPECT_EQ(res.GetWaves(0, 0).first->PhaseIndex, 0);
+
+ resBuf.push_back(res);
+ }
+
+ {
+ memset(&buf[0], 0, sizeof(float) * 128);
+ Gen({100.0f, 0, 32768, 0, 128}, buf);
+ const auto res = DoAnalize(processor.get(), {&buf[2048], &buf[0]}, {nullptr, nullptr});
+
+ EXPECT_EQ(res.NumToneBands, 1);
+ EXPECT_EQ(res.Waves[0].WaveParams.size(), 1);
+ EXPECT_EQ(res.Waves[0].WaveSbInfos.size(), 1);
+ EXPECT_EQ(res.GetNumWaves(0, 0), 1);
+ EXPECT_EQ(res.GetWaves(0, 0).second, 1);
+ EXPECT_EQ(res.GetWaves(0, 0).first->FreqIndex, 372);
+ EXPECT_EQ(res.GetWaves(0, 0).first->AmpSf, 62);
+ EXPECT_EQ(res.GetWaves(0, 0).first->PhaseIndex, 0);
+
+ resBuf.push_back(res);
+ }
+ {
+ memset(&buf[2048], 0, sizeof(float) * 128);
+ const auto res = DoAnalize(processor.get(), {&buf[0], &buf[2048]}, {nullptr, nullptr});
+
+ EXPECT_EQ(res.NumToneBands, 1);
+ EXPECT_EQ(res.Waves[0].WaveParams.size(), 1);
+ EXPECT_EQ(res.Waves[0].WaveSbInfos.size(), 1);
+ EXPECT_EQ(res.GetNumWaves(0, 0), 1);
+ EXPECT_EQ(res.GetWaves(0, 0).second, 1);
+ EXPECT_EQ(res.GetWaves(0, 0).first->FreqIndex, 74);
+ EXPECT_EQ(res.GetWaves(0, 0).first->AmpSf, 62);
+ EXPECT_EQ(res.GetWaves(0, 0).first->PhaseIndex, 0);
+
+ resBuf.push_back(res);
+ }
+
+ Dumper.Dump(resBuf.data(), 1, 3);
+}
+
+TEST(AT3PGHA, 100hz__phase_two_frames_mono) {
+ vector<float> buf(2048 * 2);
+
+ Gen({100.0f, M_PI * 0.25, 32768, 0, 256}, buf);
+
+ memcpy(&buf[2048], &buf[128], sizeof(float) * 128);
+ memset(&buf[128], 0, sizeof(float) * 128);
+
+ auto processor = MakeGhaProcessor0(false);
+ const auto res = DoAnalize(processor.get(), {&buf[0], &buf[2048]}, {nullptr, nullptr});
+
+ EXPECT_EQ(res.NumToneBands, 1);
+ EXPECT_EQ(res.Waves[0].WaveParams.size(), 1);
+ EXPECT_EQ(res.Waves[0].WaveSbInfos.size(), 1);
+ EXPECT_EQ(res.GetNumWaves(0, 0), 1);
+ EXPECT_EQ(res.GetWaves(0, 0).second, 1);
+ EXPECT_EQ(res.GetWaves(0, 0).first->FreqIndex, 74);
+ EXPECT_EQ(res.GetWaves(0, 0).first->AmpSf, 62);
+ EXPECT_EQ(res.GetWaves(0, 0).first->PhaseIndex, 4);
+}
+
+TEST(AT3PGHA, 689hz0625__two_frames_mono) {
+ vector<float> buf(2048 * 2);
+
+ Gen({689.0625f, 0, 32768, 0, 256}, buf);
+
+ memcpy(&buf[2048], &buf[128], sizeof(float) * 128);
+ memset(&buf[128], 0, sizeof(float) * 128);
+
+ auto processor = MakeGhaProcessor0(false);
+ const auto res = DoAnalize(processor.get(), {&buf[0], &buf[2048]}, {nullptr, nullptr});
+
+ EXPECT_EQ(res.NumToneBands, 1);
+ EXPECT_EQ(res.Waves[0].WaveParams.size(), 1);
+ EXPECT_EQ(res.Waves[0].WaveSbInfos.size(), 1);
+ EXPECT_EQ(res.GetNumWaves(0, 0), 1);
+ EXPECT_EQ(res.GetWaves(0, 0).second, 1);
+ EXPECT_EQ(res.GetWaves(0, 0).first->FreqIndex, 512);
+ EXPECT_EQ(res.GetWaves(0, 0).first->AmpSf, 63);
+}
+
+TEST(AT3PGHA, 689hz0625_1000hz__two_frames_mono) {
+ vector<float> buf(2048 * 2);
+
+ Gen({689.0625f, 0, 16384, 0, 256}, buf);
+ Gen({1000.0f, 0, 16384, 0, 256}, buf);
+
+ memcpy(&buf[2048], &buf[128], sizeof(float) * 128);
+ memset(&buf[128], 0, sizeof(float) * 128);
+
+ auto processor = MakeGhaProcessor0(false);
+ const auto res = DoAnalize(processor.get(), {&buf[0], &buf[2048]}, {nullptr, nullptr});
+
+ EXPECT_EQ(res.NumToneBands, 1);
+ EXPECT_EQ(res.Waves[0].WaveParams.size(), 2);
+ EXPECT_EQ(res.Waves[0].WaveSbInfos.size(), 1);
+ EXPECT_EQ(res.GetNumWaves(0, 0), 2);
+ EXPECT_EQ(res.GetWaves(0, 0).second, 2);
+ EXPECT_EQ(res.GetWaves(0, 0).first[0].FreqIndex, 512);
+ EXPECT_EQ(res.GetWaves(0, 0).first[0].AmpSf, 58);
+ EXPECT_EQ(res.GetWaves(0, 0).first[1].FreqIndex, 743);
+ EXPECT_EQ(res.GetWaves(0, 0).first[1].AmpSf, 58);
+}
+
+TEST(AT3PGHA, 500hz_1000hz__two_frames_mono) {
+ vector<float> buf(2048 * 2);
+
+ Gen({500.0f, 0, 16384, 0, 256}, buf);
+ Gen({1000.0f, 0, 2048, 0, 256}, buf);
+
+ memcpy(&buf[2048], &buf[128], sizeof(float) * 128);
+ memset(&buf[128], 0, sizeof(float) * 128);
+
+ auto processor = MakeGhaProcessor0(false);
+ const auto res = DoAnalize(processor.get(), {&buf[0], &buf[2048]}, {nullptr, nullptr});
+
+ EXPECT_EQ(res.NumToneBands, 1);
+ EXPECT_EQ(res.Waves[0].WaveParams.size(), 2);
+ EXPECT_EQ(res.Waves[0].WaveSbInfos.size(), 1);
+ EXPECT_EQ(res.GetNumWaves(0, 0), 2);
+ EXPECT_EQ(res.GetWaves(0, 0).second, 2);
+ EXPECT_EQ(res.GetWaves(0, 0).first[0].FreqIndex, 372);
+ EXPECT_EQ(res.GetWaves(0, 0).first[0].AmpSf, 58);
+ EXPECT_EQ(res.GetWaves(0, 0).first[1].FreqIndex, 743);
+ EXPECT_EQ(res.GetWaves(0, 0).first[1].AmpSf, 46);
+}
+
+TEST(AT3PGHA, 500hz_1000hz__phase_two_frames_mono) {
+ vector<float> buf(2048 * 2);
+
+ Gen({500.0f, M_PI * 0.5, 16384, 0, 256}, buf);
+ Gen({1000.0f, M_PI * 0.25, 2048, 0, 256}, buf);
+
+ memcpy(&buf[2048], &buf[128], sizeof(float) * 128);
+ memset(&buf[128], 0, sizeof(float) * 128);
+
+ auto processor = MakeGhaProcessor0(false);
+ const auto res = DoAnalize(processor.get(), {&buf[0], &buf[2048]}, {nullptr, nullptr});
+
+ EXPECT_EQ(res.NumToneBands, 1);
+ EXPECT_EQ(res.Waves[0].WaveParams.size(), 2);
+ EXPECT_EQ(res.Waves[0].WaveSbInfos.size(), 1);
+ EXPECT_EQ(res.GetNumWaves(0, 0), 2);
+ EXPECT_EQ(res.GetWaves(0, 0).second, 2);
+ EXPECT_EQ(res.GetWaves(0, 0).first[0].FreqIndex, 372);
+ EXPECT_EQ(res.GetWaves(0, 0).first[0].AmpSf, 59);
+ EXPECT_EQ(res.GetWaves(0, 0).first[1].FreqIndex, 743);
+ EXPECT_EQ(res.GetWaves(0, 0).first[1].AmpSf, 46);
+ Dumper.Dump(&res, 1, 1);
+}
+
+TEST(AT3PGHA, 250hz_500hz_1000hz__two_frames_mono) {
+ vector<float> buf(2048 * 2);
+
+ Gen({250.0f, 0, 16384, 0, 256}, buf);
+ Gen({500.0f, 0, 4096, 0, 256}, buf);
+ Gen({1000.0f, 0, 2048, 0, 256}, buf);
+
+ memcpy(&buf[2048], &buf[128], sizeof(float) * 128);
+ memset(&buf[128], 0, sizeof(float) * 128);
+
+ auto processor = MakeGhaProcessor0(false);
+ const auto res = DoAnalize(processor.get(), {&buf[0], &buf[2048]}, {nullptr, nullptr});
+
+ EXPECT_EQ(res.NumToneBands, 1);
+ EXPECT_EQ(res.Waves[0].WaveParams.size(), 3);
+ EXPECT_EQ(res.Waves[0].WaveSbInfos.size(), 1);
+ EXPECT_EQ(res.GetNumWaves(0, 0), 3);
+ EXPECT_EQ(res.GetWaves(0, 0).second, 3);
+ EXPECT_EQ(res.GetWaves(0, 0).first[0].FreqIndex, 186);
+ EXPECT_EQ(res.GetWaves(0, 0).first[0].AmpSf, 58);
+ EXPECT_EQ(res.GetWaves(0, 0).first[1].FreqIndex, 372);
+ EXPECT_EQ(res.GetWaves(0, 0).first[1].AmpSf, 50);
+ EXPECT_EQ(res.GetWaves(0, 0).first[2].FreqIndex, 743);
+ EXPECT_EQ(res.GetWaves(0, 0).first[2].AmpSf, 46);
+}
+
+TEST(AT3PGHA, 250hz_500hz_1000hz_1200hz__two_frames_mono) {
+ vector<float> buf(2048 * 2);
+
+ Gen({250.0f, 0, 16384, 0, 256}, buf);
+ Gen({500.0f, 0, 8000, 0, 256}, buf);
+ Gen({1000.0f, 0, 4096, 0, 256}, buf);
+ Gen({1200.0f, 0, 2048, 0, 256}, buf);
+
+ memcpy(&buf[2048], &buf[128], sizeof(float) * 128);
+ memset(&buf[128], 0, sizeof(float) * 128);
+
+ auto processor = MakeGhaProcessor0(false);
+ const auto res = DoAnalize(processor.get(), {&buf[0], &buf[2048]}, {nullptr, nullptr});
+
+ EXPECT_EQ(res.NumToneBands, 1);
+ EXPECT_EQ(res.Waves[0].WaveParams.size(), 4);
+ EXPECT_EQ(res.Waves[0].WaveSbInfos.size(), 1);
+ EXPECT_EQ(res.GetNumWaves(0, 0), 4);
+ EXPECT_EQ(res.GetWaves(0, 0).second, 4);
+ EXPECT_EQ(res.GetWaves(0, 0).first[0].FreqIndex, 186);
+ EXPECT_EQ(res.GetWaves(0, 0).first[0].AmpSf, 58);
+ EXPECT_EQ(res.GetWaves(0, 0).first[1].FreqIndex, 372);
+ EXPECT_EQ(res.GetWaves(0, 0).first[1].AmpSf, 54);
+ EXPECT_EQ(res.GetWaves(0, 0).first[2].FreqIndex, 743);
+ EXPECT_EQ(res.GetWaves(0, 0).first[2].AmpSf, 50);
+ EXPECT_EQ(res.GetWaves(0, 0).first[3].FreqIndex, 892);
+ EXPECT_EQ(res.GetWaves(0, 0).first[3].AmpSf, 46);
+}
+
+void CheckReduction(float f, uint32_t expFreqIndex){
+ vector<float> buf(2048 * 3);
+ Gen({f, 0, 16384, 0, 384}, buf);
+
+ memcpy(&buf[2048], &buf[128], sizeof(float) * 128);
+ memcpy(&buf[4096], &buf[256], sizeof(float) * 128);
+ memset(&buf[128], 0, sizeof(float) * 256);
+
+ auto processor = MakeGhaProcessor0(false);
+ float w1[2048] = {0};
+ float w2[2048] = {0};
+ {
+ const auto res = processor->DoAnalize({&buf[0], &buf[2048]}, {nullptr, nullptr}, w1, w2);
+ EXPECT_EQ(res->NumToneBands, 1);
+ EXPECT_EQ(res->Waves[0].WaveParams.size(), 1);
+ EXPECT_EQ(res->GetWaves(0, 0).first[0].FreqIndex, expFreqIndex);
+ }
+ {
+ memcpy(&w1[0], &buf[0], sizeof(float) * 2048);
+ const auto res = processor->DoAnalize({&buf[2048], &buf[4096]}, {nullptr, nullptr}, w1, w2);
+ EXPECT_EQ(res->NumToneBands, 1);
+ EXPECT_EQ(res->Waves[0].WaveParams.size(), 1);
+ EXPECT_EQ(res->GetWaves(0, 0).first[0].FreqIndex, expFreqIndex);
+ double e1 = 0;
+ double e2 = 0;
+ for (size_t i = 0; i < 128; i++) {
+ e1 += w1[i] * w1[i];
+ e2 += buf[i] * buf[i];
+ }
+ std::cerr << 5 * log(e2/e1) << std::endl;
+ float reduction = 5 * log(e2/e1);
+ EXPECT_GE(reduction, 50);
+ }
+
+}
+
+TEST(AT3PGHA, 269hz166_long_frame_mono) {
+ CheckReduction(269.166, 200);
+}
+
+TEST(AT3PGHA, 999hz948_long_frame_mono) {
+ CheckReduction(999.948, 743);
+}
+
+TEST(AT3PGHA, 1345hz826_long_frame_mono) {
+ CheckReduction(1345.826, 1000);
+}
diff --git a/src/atrac/at3p/at3p_mdct.cpp b/src/atrac/at3p/at3p_mdct.cpp
new file mode 100644
index 0000000..b92e87b
--- /dev/null
+++ b/src/atrac/at3p/at3p_mdct.cpp
@@ -0,0 +1,104 @@
+/*
+ * This file is part of AtracDEnc.
+ *
+ * AtracDEnc is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * AtracDEnc is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with AtracDEnc; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "at3p_mdct.h"
+#include "util.h"
+
+#include <array>
+
+#include <iostream>
+#include <vector>
+
+using std::vector;
+
+namespace NAtracDEnc {
+
+static std::array<float, 128> SineWin;
+
+static void InitSineWin() {
+ if (SineWin[SineWin.size() - 1] == 0.0) {
+ for (size_t i = 0; i < SineWin.size(); i++) {
+ SineWin[i] = 2.0 * sinf((i + 0.5) * (M_PI / (2.0 * SineWin.size())));
+ }
+ }
+}
+
+TAt3pMDCT::TAt3pMDCT()
+{
+ InitSineWin();
+}
+
+void TAt3pMDCT::Do(float specs[2048], const TPcmBandsData& bands, THistBuf& work)
+{
+ for (size_t b = 0; b < 16; b++) {
+ const float* srcBuff = bands[b];
+ float* const curSpec = &specs[b*128];
+
+ std::array<float, 256>& tmp = work[b];
+
+ for (size_t i = 0; i < 128; i++) {
+ tmp[128 + i] = SineWin[127 - i] * srcBuff[i];
+ }
+
+ const vector<float>& sp = Mdct(tmp.data());
+
+ memcpy(curSpec, sp.data(), 128 * sizeof(float));
+
+ if (b & 1) {
+ SwapArray(curSpec, 128);
+ }
+
+ for (size_t i = 0; i < 128; i++) {
+ tmp[i] = SineWin[i] * srcBuff[i];
+ }
+ }
+}
+
+TAt3pMIDCT::TAt3pMIDCT()
+{
+ InitSineWin();
+}
+
+void TAt3pMIDCT::Do(float specs[2048], TPcmBandsData& bands, THistBuf& work)
+{
+ for (size_t b = 0; b < 16; b++) {
+ float* dstBuff = bands[b];
+ float* const curSpec = &specs[b*128];
+
+ std::array<float, 128>& tmp = work[b];
+
+ if (b & 1) {
+ SwapArray(curSpec, 128);
+ }
+
+ vector<float> inv = Midct(curSpec);
+
+ for (int j = 0; j < 128; ++j) {
+ inv[j] *= SineWin[j];
+ inv[255 - j] *= SineWin[j];
+ }
+
+ for (uint32_t j = 0; j < 128; ++j) {
+ dstBuff[j] = inv[j] + tmp[j];
+ }
+
+ memcpy(tmp.data(), &inv[128], sizeof(float)*128);
+ }
+}
+
+};
diff --git a/src/atrac/at3p/at3p_mdct.h b/src/atrac/at3p/at3p_mdct.h
new file mode 100644
index 0000000..de67245
--- /dev/null
+++ b/src/atrac/at3p/at3p_mdct.h
@@ -0,0 +1,50 @@
+/*
+ * This file is part of AtracDEnc.
+ *
+ * AtracDEnc is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * AtracDEnc is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with AtracDEnc; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#pragma once
+
+#include <array>
+#include <config.h>
+
+#include "lib/mdct/mdct.h"
+
+namespace NAtracDEnc {
+
+class TAt3pMDCT {
+public:
+ TAt3pMDCT();
+ using THistBuf = std::array<std::array<float, 256>, 16>;
+ using TPcmBandsData = std::array<const float*, 16>;
+
+ void Do(float specs[2048], const TPcmBandsData& bands, THistBuf& work);
+private:
+ NMDCT::TMDCT<256> Mdct;
+};
+
+class TAt3pMIDCT {
+public:
+ TAt3pMIDCT();
+ using THistBuf = std::array<std::array<float, 128>, 16>;
+ using TPcmBandsData = std::array<float*, 16>;
+
+ void Do(float specs[2048], TPcmBandsData& bands, THistBuf& work);
+private:
+ NMDCT::TMIDCT<256> Midct;
+};
+
+}
diff --git a/src/atrac/at3p/at3p_mdct_ut.cpp b/src/atrac/at3p/at3p_mdct_ut.cpp
new file mode 100644
index 0000000..c74eb47
--- /dev/null
+++ b/src/atrac/at3p/at3p_mdct_ut.cpp
@@ -0,0 +1,106 @@
+/*
+ * This file is part of AtracDEnc.
+ *
+ * AtracDEnc is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * AtracDEnc is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with AtracDEnc; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "at3p_mdct.h"
+#include <gtest/gtest.h>
+
+#include <vector>
+#include <cmath>
+
+using namespace NAtracDEnc;
+
+TEST(TAtpMDCT, ZeroOneBlock) {
+ std::array<float, 2048> specs;
+ static std::array<float, 2048> zero;
+
+ {
+ TAt3pMDCT mdct;
+
+ static TAt3pMDCT::THistBuf buff;
+
+ TAt3pMDCT::TPcmBandsData pcm;
+ for (size_t i = 0; i < pcm.size(); i++) {
+ pcm[i] = &zero[i * 128];
+ }
+
+ mdct.Do(specs.data(), pcm, buff);
+
+ for(auto s: specs)
+ EXPECT_NEAR(s, 0.0, 0.0000000001);
+ }
+
+ {
+ TAt3pMIDCT midct;
+
+ TAt3pMIDCT::TPcmBandsData pcm;
+ static TAt3pMIDCT::THistBuf buff;
+ for (size_t i = 0; i < pcm.size(); i++) {
+ pcm[i] = &zero[i * 128];
+ }
+
+ midct.Do(specs.data(), pcm, buff);
+
+ for(size_t i = 0; i < zero.size(); ++i)
+ EXPECT_NEAR(zero[i], 0.0, 0.0000000001);
+ }
+}
+
+
+TEST(TAtpMDCT, DC) {
+ std::array<float, 4096> specs;
+ std::array<float, 2048> dc;
+
+ for (size_t i = 0; i < dc.size(); i++) {
+ dc[i] = 1.0;
+ }
+
+ {
+ TAt3pMDCT mdct;
+
+ static TAt3pMDCT::THistBuf buff;
+
+ TAt3pMDCT::TPcmBandsData pcm;
+ for (size_t i = 0; i < pcm.size(); i++) {
+ pcm[i] = &dc[i * 128];
+ }
+
+ mdct.Do(specs.data(), pcm, buff);
+ mdct.Do(specs.data() + 2048, pcm, buff);
+ }
+
+ {
+ TAt3pMIDCT midct;
+
+ std::array<float, 2048> result;
+
+ TAt3pMIDCT::TPcmBandsData pcm;
+
+ static TAt3pMIDCT::THistBuf buff;
+
+ for (size_t i = 0; i < pcm.size(); i++) {
+ pcm[i] = &result[i * 128];
+ }
+
+ midct.Do(specs.data(), pcm, buff);
+ midct.Do(specs.data() + 2048, pcm, buff);
+
+ for(size_t i = 0; i < result.size(); ++i) {
+ EXPECT_NEAR(result[i], dc[i], 0.000001);
+ }
+ }
+}
diff --git a/src/atrac/at3p/at3p_tables.cpp b/src/atrac/at3p/at3p_tables.cpp
new file mode 100644
index 0000000..fee3417
--- /dev/null
+++ b/src/atrac/at3p/at3p_tables.cpp
@@ -0,0 +1,125 @@
+/*
+ * This file is part of AtracDEnc.
+ *
+ * AtracDEnc is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * AtracDEnc is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with AtracDEnc; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "util.h"
+#include "at3p_tables.h"
+#include "ff/atrac3plus_data.h"
+
+#include <iostream>
+#include <sstream>
+
+namespace NAtracDEnc {
+namespace NAt3p {
+
+static struct TInvMantTab {
+public:
+ TInvMantTab() {
+ Data[0] = 0.0; //unused (for zero lenght on the decoder)
+ for (size_t i = 1; i < 8; i++) {
+ Data[i] = 1.0 / atrac3p_mant_tab[i];
+ }
+ }
+ float Data[8];
+} InvMantTab_;
+
+float InvMantTab(size_t i) { return InvMantTab_.Data[i]; }
+
+static struct TScaleTableInitializer {
+public:
+ TScaleTableInitializer() {
+ const std::array<float, 64> src = {
+ 0.027852058, 0.0350914, 0.044212341, 0.055704117,
+ 0.0701828, 0.088424683, 0.11140823, 0.1403656,
+ 0.17684937, 0.22281647, 0.2807312, 0.35369873,
+ 0.44563293, 0.5614624, 0.70739746, 0.89126587,
+ 1.1229248, 1.4147949, 1.7825317, 2.2458496,
+ 2.8295898, 3.5650635, 4.4916992, 5.6591797,
+ 7.130127, 8.9833984, 11.318359, 14.260254,
+ 17.966797, 22.636719, 28.520508, 35.933594,
+ 45.273438, 57.041016, 71.867188, 90.546875,
+ 114.08203, 143.73438, 181.09375, 228.16406,
+ 287.46875, 362.1875, 456.32812, 574.9375,
+ 724.375, 912.65625, 1149.875, 1448.75,
+ 1825.3125, 2299.75, 2897.5, 3650.625,
+ 4599.5, 5795.0, 7301.25, 9199.0,
+ 11590.0, 14602.5, 18398.0, 23180.0,
+ 29205.0, 36796.0, 46360.0, 58410.0
+ };
+
+ for (size_t i = 0; i < src.size(); i++) {
+ TScaleTable::ScaleTable[i] = src[i] / src.back();
+ }
+ }
+} ScaleTableInitializer_;
+
+float TScaleTable::ScaleTable[64];
+constexpr uint32_t TScaleTable::BlocksPerBand[NumQMF + 1];
+constexpr uint32_t TScaleTable::SpecsPerBlock[MaxBfus];
+constexpr uint32_t TScaleTable::BlockSizeTab[MaxBfus + 1];
+
+static uint16_t atde_noinline GenHuffmanEncTable(const uint8_t *cb, const uint8_t *xlat, uint16_t outLen, TVlcElement* const out)
+{
+ uint16_t index = 0;
+ uint16_t code = 0;
+ for (int b = 1; b <= 12; b++) {
+ for (int i = *cb++; i > 0; i--) {
+ uint8_t val = xlat[index];
+ if (val >= outLen) {
+ std::stringstream ss;
+ ss << "encoded value out of range, invalid haffman table, got: " << (int)val << " table len: " << (int)outLen;
+ throw std::runtime_error(ss.str());
+ }
+ TVlcElement* cur = out + val;
+ cur->Code = code;
+ cur->Len = b;
+ index++;
+ code++;
+ }
+ code <<= 1;
+ }
+ return index;
+}
+
+template<typename T>
+uint16_t GenHuffmanEncTable(const uint8_t *cb, const uint8_t *xlat, T& out)
+{
+ return GenHuffmanEncTable(cb, xlat, out.size(), out.data());
+}
+
+THuffTables::THuffTables()
+{
+ GenHuffmanEncTable(&atrac3p_tone_cbs[0][0], &atrac3p_tone_xlats[0], NumToneBands);
+
+ for (size_t i = 0; i < VlcSpecs.size(); i++) {
+ for (size_t j = 0; j < VlcSpecs[i].size(); j++) {
+ VlcSpecs[i][j].Code = 0;
+ VlcSpecs[i][j].Len = 0;
+ }
+ }
+
+ for (int i = 0, x = 0; i < 112; i++) {
+ if (atrac3p_spectra_cbs[i][0] >= 0) {
+ x += GenHuffmanEncTable((uint8_t*)&atrac3p_spectra_cbs[i][0], &atrac3p_spectra_xlats[x], VlcSpecs[i]);
+ } else {
+ VlcSpecs[i] = VlcSpecs[-atrac3p_spectra_cbs[i][0]];
+ }
+ }
+}
+
+} // namespace NAt3p
+} // namespace NAtracDEnc
diff --git a/src/atrac/at3p/at3p_tables.h b/src/atrac/at3p/at3p_tables.h
new file mode 100644
index 0000000..0840273
--- /dev/null
+++ b/src/atrac/at3p/at3p_tables.h
@@ -0,0 +1,79 @@
+/*
+ * This file is part of AtracDEnc.
+ *
+ * AtracDEnc is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * AtracDEnc is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with AtracDEnc; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#pragma once
+
+#include <array>
+#include <cstdint>
+#include <cstddef>
+
+namespace NAtracDEnc {
+
+namespace NAt3p {
+
+float InvMantTab(size_t i);
+
+struct TVlcElement {
+ int16_t Code;
+ int16_t Len;
+};
+
+struct THuffTables {
+ THuffTables();
+ std::array<TVlcElement, 16> NumToneBands;
+ std::array<std::array<TVlcElement, 256>, 112> VlcSpecs;
+};
+
+struct TScaleTable {
+
+ class TBlockSizeMod {
+ public:
+ constexpr bool ShortWin(uint8_t) const noexcept {
+ return false;
+ }
+ };
+
+ static constexpr uint32_t MaxBfus = 32;
+ static constexpr uint32_t NumQMF = 16;
+ static float ScaleTable[64];
+
+ static constexpr uint32_t BlocksPerBand[NumQMF + 1] =
+ {
+ 0, 8, 12, 16, 18, 20, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32
+ };
+ static constexpr uint32_t SpecsPerBlock[MaxBfus] = {
+ 16, 16, 16, 16, 16, 16, 16, 16,
+ 32, 32, 32, 32, 32, 32, 32, 32,
+ 64, 64, 64, 64, 64, 64, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128
+ };
+ static constexpr uint32_t BlockSizeTab[MaxBfus + 1] = {
+ 0, 16, 32, 48, 64, 80, 96, 112,
+ 128, 160, 192, 224, 256, 288, 320, 352,
+ 384, 448, 512, 576, 640, 704, 768, 896,
+ 1024, 1152, 1280, 1408, 1536, 1664, 1792, 1920,
+ 2048
+ };
+ static constexpr uint32_t const * const SpecsStartShort = &BlockSizeTab[0];
+
+ static constexpr uint32_t const * const SpecsStartLong = &BlockSizeTab[0];
+};
+
+}
+
+} // namespace NAtracDEnc
diff --git a/src/atrac/at3p/ff/atrac3plus.h b/src/atrac/at3p/ff/atrac3plus.h
new file mode 100644
index 0000000..3aeb110
--- /dev/null
+++ b/src/atrac/at3p/ff/atrac3plus.h
@@ -0,0 +1,165 @@
+/*
+ * ATRAC3+ compatible decoder
+ *
+ * Copyright (c) 2010-2013 Maxim Poliakovski
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * @file
+ * Global structures, constants and data for ATRAC3+ decoder.
+ */
+
+#ifndef AVCODEC_ATRAC3PLUS_H
+#define AVCODEC_ATRAC3PLUS_H
+
+#include <stdint.h>
+
+/** Global unit sizes */
+#define ATRAC3P_SUBBANDS 16 ///< number of PQF subbands
+#define ATRAC3P_SUBBAND_SAMPLES 128 ///< number of samples per subband
+#define ATRAC3P_FRAME_SAMPLES (ATRAC3P_SUBBAND_SAMPLES * ATRAC3P_SUBBANDS)
+
+#define ATRAC3P_PQF_FIR_LEN 12 ///< length of the prototype FIR of the PQF
+
+/** Global constants */
+#define ATRAC3P_POWER_COMP_OFF 15 ///< disable power compensation
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif /* __cplusplus */
+
+/** ATRAC3+ channel unit types */
+enum Atrac3pChannelUnitTypes {
+ CH_UNIT_MONO = 0, ///< unit containing one coded channel
+ CH_UNIT_STEREO = 1, ///< unit containing two jointly-coded channels
+ CH_UNIT_EXTENSION = 2, ///< unit containing extension information
+ CH_UNIT_TERMINATOR = 3 ///< unit sequence terminator
+};
+
+/** Amplitude envelope of a group of sine waves */
+typedef struct Atrac3pWaveEnvelope {
+ int has_start_point; ///< indicates start point within the GHA window
+ int has_stop_point; ///< indicates stop point within the GHA window
+ int start_pos; ///< start position expressed in n*4 samples
+ int stop_pos; ///< stop position expressed in n*4 samples
+} Atrac3pWaveEnvelope;
+
+/** Parameters of a group of sine waves */
+typedef struct Atrac3pWavesData {
+ Atrac3pWaveEnvelope pend_env; ///< pending envelope from the previous frame
+ Atrac3pWaveEnvelope curr_env; ///< group envelope from the current frame
+ int num_wavs; ///< number of sine waves in the group
+ int start_index; ///< start index into global tones table for that subband
+} Atrac3pWavesData;
+
+/** Parameters of a single sine wave */
+typedef struct Atrac3pWaveParam {
+ int freq_index; ///< wave frequency index
+ int amp_sf; ///< quantized amplitude scale factor
+ int amp_index; ///< quantized amplitude index
+ int phase_index; ///< quantized phase index
+} Atrac3pWaveParam;
+
+/** Sound channel parameters */
+typedef struct Atrac3pChanParams {
+ //int ch_num;
+ //int num_coded_vals; ///< number of transmitted quant unit values
+ //int fill_mode;
+ //int split_point;
+ //int table_type; ///< table type: 0 - tone?, 1- noise?
+ //int qu_wordlen[32]; ///< array of word lengths for each quant unit
+ //int qu_sf_idx[32]; ///< array of scale factor indexes for each quant unit
+ //int qu_tab_idx[32]; ///< array of code table indexes for each quant unit
+ //int16_t spectrum[2048]; ///< decoded IMDCT spectrum
+ //uint8_t power_levs[5]; ///< power compensation levels
+
+ /* imdct window shape history (2 frames) for overlapping. */
+ //uint8_t wnd_shape_hist[2][ATRAC3P_SUBBANDS]; ///< IMDCT window shape, 0=sine/1=steep
+ //uint8_t *wnd_shape; ///< IMDCT window shape for current frame
+ //uint8_t *wnd_shape_prev; ///< IMDCT window shape for previous frame
+
+ //int num_gain_subbands; ///< number of subbands with gain control data
+
+ /* tones data history (2 frames) for overlapping. */
+ Atrac3pWavesData tones_info_hist[2][ATRAC3P_SUBBANDS];
+ Atrac3pWavesData *tones_info;
+ Atrac3pWavesData *tones_info_prev;
+} Atrac3pChanParams;
+
+/* Per-unit sine wave parameters */
+typedef struct Atrac3pWaveSynthParams {
+ int tones_present; ///< 1 - tones info present
+ int amplitude_mode; ///< 1 - low range, 0 - high range
+ int num_tone_bands; ///< number of PQF bands with tones
+ //uint8_t tone_sharing[ATRAC3P_SUBBANDS]; ///< 1 - subband-wise tone sharing flags
+ //uint8_t tone_master[ATRAC3P_SUBBANDS]; ///< 1 - subband-wise tone channel swapping
+ uint8_t invert_phase[ATRAC3P_SUBBANDS]; ///< 1 - subband-wise phase inversion
+ int tones_index; ///< total sum of tones in this unit
+ Atrac3pWaveParam waves[48];
+} Atrac3pWaveSynthParams;
+
+/** Channel unit parameters */
+typedef struct Atrac3pChanUnitCtx {
+ /* channel unit variables */
+ //int unit_type; ///< unit type (mono/stereo)
+ //int num_quant_units;
+ //int num_subbands;
+ //int used_quant_units; ///< number of quant units with coded spectrum
+ //int num_coded_subbands; ///< number of subbands with coded spectrum
+ //int mute_flag; ///< mute flag
+ //int use_full_table; ///< 1 - full table list, 0 - restricted one
+ //int noise_present; ///< 1 - global noise info present
+ //int noise_level_index; ///< global noise level index
+ //int noise_table_index; ///< global noise RNG table index
+ //uint8_t swap_channels[ATRAC3P_SUBBANDS]; ///< 1 - perform subband-wise channel swapping
+ //uint8_t negate_coeffs[ATRAC3P_SUBBANDS]; ///< 1 - subband-wise IMDCT coefficients negation
+ Atrac3pChanParams channels[2];
+
+ /* Variables related to GHA tones */
+ Atrac3pWaveSynthParams wave_synth_hist[2]; ///< waves synth history for two frames
+ Atrac3pWaveSynthParams *waves_info;
+ Atrac3pWaveSynthParams *waves_info_prev;
+
+ //Atrac3pIPQFChannelCtx ipqf_ctx[2];
+ //DECLARE_ALIGNED(32, float, prev_buf)[2][ATRAC3P_FRAME_SAMPLES]; ///< overlapping buffer
+} Atrac3pChanUnitCtx;
+
+/**
+ * Initialize sine waves synthesizer and ff_sine_* tables.
+ */
+void ff_atrac3p_init_dsp_static(void);
+
+/**
+ * Synthesize sine waves for a particular subband.
+ *
+ * @param[in] ch_unit pointer to the channel unit context
+ * @param[in] fdsp pointer to float DSP context
+ * @param[in] ch_num which channel to process
+ * @param[in] sb which subband to process
+ * @param[out] out receives processed data
+ */
+void ff_atrac3p_generate_tones(Atrac3pChanUnitCtx *ch_unit,
+ int ch_num, int sb, float *out);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* AVCODEC_ATRAC3PLUS_H */
diff --git a/src/atrac/at3p/ff/atrac3plus_data.h b/src/atrac/at3p/ff/atrac3plus_data.h
new file mode 100644
index 0000000..3e64292
--- /dev/null
+++ b/src/atrac/at3p/ff/atrac3plus_data.h
@@ -0,0 +1,1672 @@
+/*
+ * ATRAC3+ compatible decoder
+ *
+ * Copyright (c) 2010-2013 Maxim Poliakovski
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef AVCODEC_ATRAC3PLUS_DATA_H
+#define AVCODEC_ATRAC3PLUS_DATA_H
+
+#include <stddef.h>
+#include <stdint.h>
+
+/* Mantissa table. */
+/* pow(10, x * log10(2) + 0.05) / 2 / ([1,2,3,5,7,15,31] + 0.5) */
+static const float atrac3p_mant_tab[8] = {
+ 0.0,
+ 0.74801636,
+ 0.44882202,
+ 0.32058716,
+ 0.20400238,
+ 0.1496048,
+ 0.07239151,
+ 0.035619736
+};
+
+/** VLC tables for wordlen */
+static const uint8_t atrac3p_wl_cbs[][12] = {
+ { 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 1, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 1, 0, 2, 3, 2, 0, 0, 0, 0, 0, 0, 0 },
+ { 1, 0, 2, 3, 2, 0, 0, 0, 0, 0, 0, 0 },
+};
+
+/** VLC tables for code table indexes */
+static const uint8_t atrac3p_ct_cbs[][12] = {
+ { 1, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 5, 2, 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 5, 2, 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 1, 0, 1, 6, 0, 0, 0, 0, 0, 0, 0, 0 },
+};
+/* Symbols for wordlen interleaved with symbols for code table */
+static const uint8_t atrac3p_wl_ct_xlats[] = {
+ /* wordlen table 1 - 3 entries */
+ 0, 1, 7,
+ /* code table 1 - 4 entries */
+ 0, 1, 2, 3,
+ /* wordlen table 2 - 5 entries */
+ 0, 1, 2, 6, 7,
+ /* code table 2 - 8 entries */
+ 0, 1, 2, 3, 4, 5, 6, 7,
+ /* wordlen table 3 - 8 entries */
+ 0, 1, 7, 2, 5, 6, 3, 4,
+ /* code table 3 - 8 entries */
+ 0, 1, 2, 3, 6, 7, 4, 5,
+ /* wordlen table 4 - 8 entries */
+ 0, 1, 7, 2, 3, 6, 4, 5,
+ /* code table 4 - 8 entries */
+ 0, 1, 2, 3, 4, 5, 6, 7,
+};
+
+/** VLC tables for scale factor indexes */
+static const uint8_t atrac3p_sf_cbs[][12] = {
+ { 0, 1, 4, 2, 0, 0, 0, 7, 50, 0, 0, 0 },
+ { 0, 1, 4, 2, 0, 0, 0, 7, 50, 0, 0, 0 },
+ { 1, 0, 2, 0, 4, 0, 2, 1, 54, 0, 0, 0 },
+ { 0, 1, 4, 0, 4, 0, 3, 0, 52, 0, 0, 0 },
+ { 0, 1, 4, 2, 0, 8, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 4, 2, 0, 8, 0, 0, 0, 0, 0, 0 },
+ { 1, 0, 2, 2, 2, 0, 8, 0, 0, 0, 0, 0 },
+ { 0, 1, 4, 2, 2, 2, 4, 0, 0, 0, 0, 0 },
+};
+
+static const uint8_t atrac3p_sf_xlats[] = {
+ /* Scale factor index 1 - 64 entries */
+ 0, 1, 61, 62, 63, 2, 60, 3, 4, 5, 6, 57, 58, 59, 7, 8,
+ 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
+ 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
+ 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56,
+ /* Scale factor index 2 - 64 entries */
+ 0, 1, 2, 62, 63, 3, 61, 4, 5, 6, 57, 58, 59, 60, 7, 8,
+ 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
+ 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
+ 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56,
+ /* Scale factor index 3 - 64 entries */
+ 0, 1, 63, 2, 3, 61, 62, 4, 60, 59, 5, 6, 7, 8, 9, 10,
+ 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26,
+ 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42,
+ 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58,
+ /* Scale factor index 4 - 64 entries */
+ 0, 1, 2, 62, 63, 3, 4, 60, 61, 5, 58, 59, 6, 7, 8, 9,
+ 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,
+ 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41,
+ 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57,
+ /* Scale factor index 5 - 15 entries */
+ 0, 1, 13, 14, 15, 2, 12, 3, 4, 5, 6, 7, 9, 10, 11,
+ /* Scale factor index 6 - 15 entries */
+ 0, 1, 2, 14, 15, 3, 13, 4, 5, 6, 7, 9, 10, 11, 12,
+ /* Scale factor index 7 - 15 entries */
+ 0, 1, 15, 2, 14, 3, 13, 4, 5, 6, 7, 9, 10, 11, 12,
+ /* Scale factor index 8 - 15 entries */
+ 0, 1, 2, 14, 15, 3, 13, 4, 12, 5, 11, 6, 7, 9, 10,
+};
+
+/* weights for quantized word lengths */
+static const int8_t atrac3p_wl_weights[6][32] = {
+ { 5, 5, 4, 4, 3, 3, 2, 2, 1, 1, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 5, 5, 5, 4, 4, 4, 3, 3, 3, 2, 2, 2, 1, 1, 1, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 6, 5, 5, 5, 4, 4, 4, 4, 3, 3, 3, 3, 2, 2, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0 },
+ { 5, 5, 4, 4, 3, 3, 2, 2, 1, 1, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 5, 5, 5, 4, 4, 4, 3, 3, 3, 2, 2, 2, 1, 1, 1, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 6, 5, 5, 5, 5, 5, 5, 5, 3, 3, 3, 3, 2, 2, 1, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
+};
+
+/* weights for quantized scale factors
+ * sf_weights[i] = i / (tab_idx + 1)
+ * where tab_idx = [1,2] */
+static const int8_t atrac3p_sf_weights[2][32] = {
+ { 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7,
+ 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 14, 14, 15, 15 },
+ { 0, 0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 5,
+ 5, 5, 6, 6, 6, 7, 7, 7, 8, 8, 8, 9, 9, 9, 10, 10 }
+};
+
+/** Ungroup table for word length segments.
+ * Numbers in this table tell which coeff belongs to which segment. */
+static const uint8_t atrac3p_qu_num_to_seg[32] = {
+ 0, 0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 5,
+ 5, 5, 6, 6, 6, 7, 7, 7, 8, 8, 8, 9, 9, 9, 9, 9
+};
+
+/** Map quant unit number to subband number */
+static const uint8_t atrac3p_qu_to_subband[32] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2,
+ 3, 3, 4, 4, 5, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15
+};
+
+/** Map subband number to number of power compensation groups */
+static const int atrac3p_subband_to_num_powgrps[16] = {
+ 1, 2, 2, 3, 3, 3, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5
+};
+
+/** 3D base shape tables. The values are grouped together as follows:
+ * [num_start_values = 8][num_shape_tables = 16][num_seg_coeffs = 9]
+ * For each of the 8 start values there are 16 different shapes each
+ * 9 coefficients long. */
+static const int8_t atrac3p_wl_shapes[8][16][9] = {
+ { { 0, 0, 0, 0, 0, 0, 0, -2, -1 },
+ { 0, 0, 0, 0, 0, 0, 0, -5, -1 },
+ { 0, 0, 0, -7, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, -7, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, -5, 0, 0 },
+ { 0, 0, 0, 0, -5, 0, 0, 0, 0 },
+ { -7, -7, 0, 0, 0, 0, 0, 0, 0 },
+ { 0, -7, 0, 0, 0, 0, 0, 0, 0 },
+ { -2, -2, -5, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, -2, -5, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, -2, -5, 0, 0 },
+ { 0, 0, 0, -5, 0, 0, 0, 0, 0 },
+ { 0, -2, -7, -2, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, -2, -5, 0, 0, 0 },
+ { 0, 0, 0, -5, -5, 0, 0, 0, 0 },
+ { 0, 0, 0, -5, -2, 0, 0, 0, 0 } },
+ { { -1, -5, -3, -2, -1, -1, 0, 0, 0 },
+ { -2, -5, -3, -3, -2, -1, -1, 0, 0 },
+ { 0, -1, -1, -1, 0, 0, 0, 0, 0 },
+ { -1, -3, 0, 0, 0, 0, 0, 0, 0 },
+ { -1, -2, 0, 0, 0, 0, 0, 0, 0 },
+ { -1, -3, -1, 0, 0, 0, 0, 1, 1 },
+ { -1, -5, -3, -3, -2, -1, 0, 0, 0 },
+ { -1, -1, -4, -2, -2, -1, -1, 0, 0 },
+ { -1, -1, -3, -2, -3, -1, -1, -1, 0 },
+ { -1, -4, -2, -3, -1, 0, 0, 0, 0 },
+ { 0, -1, -2, -2, -1, -1, 0, 0, 0 },
+ { 0, -2, -1, 0, 0, 0, 0, 0, 0 },
+ { -1, -1, 0, 0, 0, 0, 0, 0, 0 },
+ { -1, -1, -3, -2, -2, -1, -1, -1, 0 },
+ { 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0, -1, -3, -2, -2, -1, -1, -1, 0 }, },
+ { { -1, -2, 0, 1, 1, 1, 1, 1, 1 },
+ { 0, -1, 1, 1, 1, 1, 1, 1, 1 },
+ { 0, -2, 1, 1, 1, 1, 1, 1, 1 },
+ { 0, -2, 0, 1, 1, 1, 1, 1, 1 },
+ { -1, -1, 0, 1, 1, 1, 1, 1, 1 },
+ { 0, 0, -1, 0, 1, 1, 1, 1, 1 },
+ { -1, -1, 1, 1, 1, 1, 1, 1, 1 },
+ { 0, 0, -1, 1, 1, 1, 1, 1, 1 },
+ { 0, -1, 0, 1, 1, 1, 1, 1, 1 },
+ { -1, -1, -1, 1, 1, 1, 1, 1, 1 },
+ { 0, 0, 0, 0, 1, 1, 1, 1, 1 },
+ { 0, 0, 0, 1, 1, 1, 1, 1, 1 },
+ { 0, -1, -1, 1, 1, 1, 1, 1, 1 },
+ { 0, 1, 0, 1, 1, 1, 1, 1, 1 },
+ { 0, -3, -2, 1, 1, 1, 1, 2, 2 },
+ { -3, -5, -3, 2, 2, 2, 2, 2, 2 }, },
+ { { -1, -2, 0, 2, 2, 2, 2, 2, 2 },
+ { -1, -2, 0, 1, 2, 2, 2, 2, 2 },
+ { 0, -2, 0, 2, 2, 2, 2, 2, 2 },
+ { -1, 0, 1, 2, 2, 2, 2, 2, 2 },
+ { 0, 0, 1, 2, 2, 2, 2, 2, 2 },
+ { 0, -2, 0, 1, 2, 2, 2, 2, 2 },
+ { 0, -1, 1, 2, 2, 2, 2, 2, 2 },
+ { -1, -1, 0, 2, 2, 2, 2, 2, 2 },
+ { -1, -1, 0, 1, 2, 2, 2, 2, 2 },
+ { -1, -2, -1, 2, 2, 2, 2, 2, 2 },
+ { 0, -1, 0, 2, 2, 2, 2, 2, 2 },
+ { 1, 1, 0, 1, 2, 2, 2, 2, 2 },
+ { 0, 1, 2, 2, 2, 2, 2, 2, 2 },
+ { 1, 0, 0, 1, 2, 2, 2, 2, 2 },
+ { 0, 0, 0, 1, 2, 2, 2, 2, 2 },
+ { -1, -1, -1, 1, 2, 2, 2, 2, 2 }, },
+ { { 0, 1, 2, 3, 3, 3, 3, 3, 3 },
+ { 1, 1, 2, 3, 3, 3, 3, 3, 3 },
+ { -1, 0, 1, 2, 3, 3, 3, 3, 3 },
+ { 0, 0, 2, 3, 3, 3, 3, 3, 3 },
+ { -1, 0, 1, 3, 3, 3, 3, 3, 3 },
+ { 0, 0, 1, 3, 3, 3, 3, 3, 3 },
+ { 1, 2, 3, 3, 3, 3, 3, 3, 3 },
+ { 1, 2, 2, 3, 3, 3, 3, 3, 3 },
+ { 0, 1, 1, 3, 3, 3, 3, 3, 3 },
+ { 0, 0, 1, 2, 3, 3, 3, 3, 3 },
+ { -1, 1, 2, 3, 3, 3, 3, 3, 3 },
+ { -1, 0, 2, 3, 3, 3, 3, 3, 3 },
+ { 2, 2, 3, 3, 3, 3, 3, 3, 3 },
+ { 1, 1, 3, 3, 3, 3, 3, 3, 3 },
+ { 0, 2, 3, 3, 3, 3, 3, 3, 3 },
+ { 0, 1, 1, 2, 3, 3, 3, 3, 3 }, },
+ { { 0, 1, 2, 3, 4, 4, 4, 4, 4 },
+ { 1, 2, 3, 4, 4, 4, 4, 4, 4 },
+ { 0, 0, 2, 3, 4, 4, 4, 4, 4 },
+ { 1, 1, 2, 4, 4, 4, 4, 4, 4 },
+ { 0, 1, 2, 4, 4, 4, 4, 4, 4 },
+ { -1, 0, 1, 3, 4, 4, 4, 4, 4 },
+ { 0, 0, 1, 3, 4, 4, 4, 4, 4 },
+ { 1, 1, 2, 3, 4, 4, 4, 4, 4 },
+ { 0, 1, 1, 3, 4, 4, 4, 4, 4 },
+ { 2, 2, 3, 4, 4, 4, 4, 4, 4 },
+ { 1, 1, 3, 4, 4, 4, 4, 4, 4 },
+ { 1, 2, 2, 4, 4, 4, 4, 4, 4 },
+ { -1, 0, 2, 3, 4, 4, 4, 4, 4 },
+ { 0, 1, 3, 4, 4, 4, 4, 4, 4 },
+ { 1, 2, 2, 3, 4, 4, 4, 4, 4 },
+ { 0, 2, 3, 4, 4, 4, 4, 4, 4 }, },
+ { { 1, 2, 3, 4, 5, 5, 5, 5, 5 },
+ { 0, 1, 2, 3, 4, 5, 5, 5, 5 },
+ { 0, 1, 2, 3, 5, 5, 5, 5, 5 },
+ { 1, 1, 3, 4, 5, 5, 5, 5, 5 },
+ { 1, 1, 2, 4, 5, 5, 5, 5, 5 },
+ { 1, 2, 2, 4, 5, 5, 5, 5, 5 },
+ { 1, 1, 2, 3, 5, 5, 5, 5, 5 },
+ { 2, 2, 3, 4, 5, 5, 5, 5, 5 },
+ { 0, 1, 2, 4, 5, 5, 5, 5, 5 },
+ { 2, 2, 3, 5, 5, 5, 5, 5, 5 },
+ { 1, 2, 3, 5, 5, 5, 5, 5, 5 },
+ { 0, 1, 3, 4, 5, 5, 5, 5, 5 },
+ { 1, 2, 2, 3, 5, 5, 5, 5, 5 },
+ { 2, 3, 4, 5, 5, 5, 5, 5, 5 },
+ { 0, 2, 3, 4, 5, 5, 5, 5, 5 },
+ { 1, 1, 1, 3, 4, 5, 5, 5, 5 }, },
+ { { 1, 2, 3, 4, 5, 5, 5, 6, 6 },
+ { 1, 2, 3, 4, 5, 6, 6, 6, 6 },
+ { 2, 3, 4, 5, 6, 6, 6, 6, 6 },
+ { 1, 2, 3, 4, 6, 6, 6, 6, 6 },
+ { 2, 2, 3, 4, 5, 5, 5, 6, 6 },
+ { 1, 2, 3, 4, 5, 5, 6, 6, 6 },
+ { 2, 2, 3, 4, 6, 6, 6, 6, 6 },
+ { 2, 2, 3, 4, 5, 6, 6, 6, 6 },
+ { 2, 2, 4, 5, 6, 6, 6, 6, 6 },
+ { 2, 2, 3, 5, 6, 6, 6, 6, 6 },
+ { 1, 2, 3, 5, 6, 6, 6, 6, 6 },
+ { 2, 3, 3, 5, 6, 6, 6, 6, 6 },
+ { 1, 2, 4, 5, 6, 6, 6, 6, 6 },
+ { 2, 2, 3, 4, 5, 5, 6, 6, 6 },
+ { 2, 3, 3, 4, 6, 6, 6, 6, 6 },
+ { 1, 3, 4, 5, 6, 6, 6, 6, 6 } }
+};
+
+/** 2D base shape tables for scale factor coding.
+ * The values are grouped together as follows:
+ * [num_shape_tables = 64][num_seg_coeffs = 9] */
+static const int8_t atrac3p_sf_shapes[64][9] = {
+ { -3, -2, -1, 0, 3, 5, 6, 8, 40 },
+ { -3, -2, 0, 1, 7, 9, 11, 13, 20 },
+ { -1, 0, 0, 1, 6, 8, 10, 13, 41 },
+ { 0, 0, 0, 2, 5, 5, 6, 8, 14 },
+ { 0, 0, 0, 2, 6, 7, 8, 11, 47 },
+ { 0, 0, 1, 2, 5, 7, 8, 10, 32 },
+ { 0, 0, 1, 3, 8, 10, 12, 14, 47 },
+ { 0, 0, 2, 4, 9, 10, 12, 14, 40 },
+ { 0, 0, 3, 5, 9, 10, 12, 14, 22 },
+ { 0, 1, 3, 5, 10, 14, 18, 22, 31 },
+ { 0, 2, 5, 6, 10, 10, 10, 12, 46 },
+ { 0, 2, 5, 7, 12, 14, 15, 18, 44 },
+ { 1, 1, 4, 5, 7, 7, 8, 9, 15 },
+ { 1, 2, 2, 2, 4, 5, 7, 9, 26 },
+ { 1, 2, 2, 3, 6, 7, 7, 8, 47 },
+ { 1, 2, 2, 3, 6, 8, 10, 13, 22 },
+ { 1, 3, 4, 7, 13, 17, 21, 24, 41 },
+ { 1, 4, 0, 4, 10, 12, 13, 14, 17 },
+ { 2, 3, 3, 3, 6, 8, 10, 13, 48 },
+ { 2, 3, 3, 4, 9, 12, 14, 17, 47 },
+ { 2, 3, 3, 5, 10, 12, 14, 17, 25 },
+ { 2, 3, 5, 7, 8, 9, 9, 9, 13 },
+ { 2, 3, 5, 9, 16, 21, 25, 28, 33 },
+ { 2, 4, 5, 8, 12, 14, 17, 19, 26 },
+ { 2, 4, 6, 8, 12, 13, 13, 15, 20 },
+ { 2, 4, 7, 12, 20, 26, 30, 32, 35 },
+ { 3, 3, 5, 6, 12, 14, 16, 19, 34 },
+ { 3, 4, 4, 5, 7, 9, 10, 11, 48 },
+ { 3, 4, 5, 6, 8, 9, 10, 11, 16 },
+ { 3, 5, 5, 5, 7, 9, 10, 13, 35 },
+ { 3, 5, 5, 7, 10, 12, 13, 15, 49 },
+ { 3, 5, 7, 7, 8, 7, 9, 12, 21 },
+ { 3, 5, 7, 8, 12, 14, 15, 15, 24 },
+ { 3, 5, 7, 10, 16, 21, 24, 27, 44 },
+ { 3, 5, 8, 14, 21, 26, 28, 29, 42 },
+ { 3, 6, 10, 13, 18, 19, 20, 22, 27 },
+ { 3, 6, 11, 16, 24, 27, 28, 29, 31 },
+ { 4, 5, 4, 3, 4, 6, 8, 11, 18 },
+ { 4, 6, 5, 6, 9, 10, 12, 14, 20 },
+ { 4, 6, 7, 6, 6, 6, 7, 8, 46 },
+ { 4, 6, 7, 9, 13, 16, 18, 20, 48 },
+ { 4, 6, 7, 9, 14, 17, 20, 23, 31 },
+ { 4, 6, 9, 11, 14, 15, 15, 17, 21 },
+ { 4, 8, 13, 20, 27, 32, 35, 36, 38 },
+ { 5, 6, 6, 4, 5, 6, 7, 6, 6 },
+ { 5, 7, 7, 8, 9, 9, 10, 12, 49 },
+ { 5, 8, 9, 9, 10, 11, 12, 13, 42 },
+ { 5, 8, 10, 12, 15, 16, 17, 19, 42 },
+ { 5, 8, 12, 17, 26, 31, 32, 33, 44 },
+ { 5, 9, 13, 16, 20, 22, 23, 23, 35 },
+ { 6, 8, 8, 7, 6, 5, 6, 8, 15 },
+ { 6, 8, 8, 8, 9, 10, 12, 16, 24 },
+ { 6, 8, 8, 9, 10, 10, 11, 11, 13 },
+ { 6, 8, 10, 13, 19, 21, 24, 26, 32 },
+ { 6, 9, 10, 11, 13, 13, 14, 16, 49 },
+ { 7, 9, 9, 10, 13, 14, 16, 19, 27 },
+ { 7, 10, 12, 13, 16, 16, 17, 17, 27 },
+ { 7, 10, 12, 14, 17, 19, 20, 22, 48 },
+ { 8, 9, 10, 9, 10, 11, 11, 11, 19 },
+ { 8, 11, 12, 12, 13, 13, 13, 13, 17 },
+ { 8, 11, 13, 14, 16, 17, 19, 20, 27 },
+ { 8, 12, 17, 22, 26, 28, 29, 30, 33 },
+ { 10, 14, 16, 19, 21, 22, 22, 24, 28 },
+ { 10, 15, 17, 18, 21, 22, 23, 25, 43 }
+};
+
+static const uint8_t atrac3p_ct_restricted_to_full[2][7][4] = {
+ { { 0, 5, 4, 1 },
+ { 0, 1, 2, 3 },
+ { 3, 0, 4, 2 },
+ { 4, 0, 1, 2 },
+ { 1, 0, 4, 3 },
+ { 3, 0, 2, 1 },
+ { 0, 3, 1, 2 } },
+ { { 4, 0, 1, 2 },
+ { 0, 3, 2, 1 },
+ { 0, 1, 2, 3 },
+ { 0, 1, 2, 4 },
+ { 0, 1, 2, 3 },
+ { 1, 4, 2, 0 },
+ { 0, 1, 2, 3 } }
+};
+
+/** Tables for spectrum coding */
+
+/* If the first entry of a subtable is negative, it means
+ * that another VLC is to be reused. */
+static const int8_t atrac3p_spectra_cbs[][12] = {
+ { 1, 0, 0, 1, 7, 0, 19, 5, 13, 21, 6, 8 },
+ { 0, 1, 0, 4, 11, 0, 1, 29, 6, 20, 7, 2 },
+ { 0, 0, 1, 8, 0, 13, 18, 7, 2, 0, 0, 0 },
+ { 0, 2, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 1, 3, 5, 8, 12, 23, 72, 68, 31, 2 },
+ { 0, 1, 3, 2, 6, 4, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 2, 2, 2, 6, 14, 21, 13, 2, 0, 0 },
+ { 1, 0, 0, 0, 8, 1, 18, 9, 22, 10, 12, 0 },
+ { 0, 0, 0, 0, 16, 11, 32, 19, 1, 2, 0, 0 },
+ { 1, 0, 0, 4, 2, 2, 9, 15, 12, 4, 0, 0 },
+ { 0, 1, 0, 4, 3, 5, 16, 28, 34, 26, 4, 0 },
+ { 0, 0, 0, 0, 9, 12, 16, 44, 98, 42, 4, 0 },
+ { 0, 1, 1, 2, 2, 5, 7, 21, 54, 85, 62, 16 },
+ { 0, 0, 3, 2, 5, 7, 17, 23, 6, 0, 0, 0 },
+ { 1, 0, 0, 2, 6, 0, 7, 21, 15, 17, 8, 4 },
+ { 0, 1, 4, 0, 4, 3, 8, 3, 2, 0, 0, 0 },
+ { 0, 0, 5, 0, 4, 6, 10, 16, 8, 0, 0, 0 },
+ { 0, 3, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 5, 2, 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 3, 4, 12, 15, 34, 83, 75, 30, 0 },
+ { 0, 0, 0, 3, 14, 10, 20, 16, 0, 0, 0, 0 },
+ { 1, 0, 3, 1, 0, 4, 0, 0, 0, 0, 0, 0 },
+ { 1, 0, 0, 2, 2, 6, 12, 18, 19, 15, 6, 0 },
+ { 0, 0, 1, 1, 13, 1, 14, 28, 33, 81, 32, 52 },
+ { 1, 1, 1, 1, 2, 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 0, 2, 3, 6, 19, 9, 75, 110, 0, 0 },
+ { 0, 0, 1, 3, 5, 5, 13, 27, 69, 96, 35, 2 },
+ { 0, 0, 0, 7, 6, 8, 22, 20, 0, 0, 0, 0 },
+ { 1, 0, 0, 6, 2, 0, 0, 0, 19, 9, 24, 20 },
+ { 0, 0, 1, 2, 13, 1, 31, 13, 16, 4, 0, 0 },
+ { 0, 2, 3, 2, 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 5, 4, 12, 17, 47, 24, 12, 0, 0 },
+ { 0, 2, 2, 4, 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 1, 16, 31, 36, static_cast<int8_t>(172), 0, 0, 0 },
+ { 0, 0, 0, 5, 12, 9, 12, 15, 10, 0, 0, 0 },
+ { 0, 1, 0, 6, 2, 6, 18, 4, 26, 6, 12, 0 },
+ { 1, 0, 2, 2, 0, 4, 3, 8, 3, 2, 0, 0 },
+ { 0, 2, 3, 2, 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 4, 7, 12, 19, 21, 58, 0, 0, 0 },
+ { 1, 1, 1, 0, 3, 2, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 1, 8, 6, 8, 8, 0, 0, 0, 0, 0 },
+ { 0, 0, 1, 5, 7, 8, 16, 22, 4, 0, 0, 0 },
+ { 0, 1, 0, 8, 0, 1, 16, 10, 29, 12, 4, 0 },
+ { 0, 0, 5, 2, 2, 9, 5, 2, 0, 0, 0, 0 },
+ { 0, 0, 1, 1, 10, 4, 16, 29, 46, 75, 74, 0 },
+ { 0, 0, 0, 1, 7, 12, 36, 63, 2, 0, 0, 0 },
+ { 0, 3, 0, 1, 3, 4, 4, 0, 0, 0, 0, 0 },
+ { 0, 1, 2, 2, 6, 8, 6, 3, 1, 2, 0, 0 },
+ { 0, 1, 1, 3, 4, 6, 13, 25, 10, 0, 0, 0 },
+ { 1, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 0, 4, 8, 3, 8, 24, 17, 12, 4, 0 },
+ { 0, 1, 1, 5, 2, 8, 7, 13, 8, 4, 0, 0 },
+ { 1, 0, 0, 4, 0, 4, 5, 9, 30, 45, 21, 2 },
+ { 0, 1, 3, 3, 4, 4, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 1, 3, 4, 8, 10, 36, 60, 78, 48, 8 },
+ { -6 },
+ { 1, 0, 0, 2, 6, 0, 11, 13, 12, 24, 4, 8 },
+ { 1, 0, 0, 4, 0, 8, 4, 9, 19, 13, 13, 10 },
+ { 1, 0, 0, 4, 0, 5, 12, 13, 14, 0, 0, 0 },
+ { 0, 1, 0, 4, 4, 5, 9, 30, 45, 21, 2, 0 },
+ { 0, 0, 1, 4, 4, 4, 12, 30, 73, 75, 22, 0 },
+ { -5 },
+ { 0, 0, 3, 2, 4, 8, 23, 13, 10, 0, 0, 0 },
+ { -14 },
+ { 0, 0, 1, 3, 12, 0, 30, 9, 18, 8, 0, 0 },
+ { -9 },
+ { 1, 0, 0, 4, 0, 3, 5, 16, 28, 34, 26, 4 },
+ { -11 },
+ { 0, 0, 0, 4, 4, 9, 13, 37, 76, 72, 39, 2 },
+ { -6 },
+ { -28 },
+ { -22 },
+ { -2 },
+ { -31 },
+ { -60 },
+ { 0, 0, 2, 2, 4, 5, 11, 26, 67, 78, 51, 10 },
+ { -6 },
+ { -35 },
+ { 0, 1, 0, 4, 6, 7, 10, 22, 11, 16, 4, 0 },
+ { 0, 1, 0, 0, 4, 11, 8, 28, 92, 97, 13, 2 },
+ { -59 },
+ { 1, 0, 0, 0, 4, 6, 6, 14, 42, 63, 59, 30 },
+ { -75 },
+ { 1, 0, 2, 0, 2, 2, 6, 17, 14, 13, 6, 0 },
+ { 1, 0, 0, 1, 7, 0, 20, 4, 10, 24, 2, 12 },
+ { 1, 0, 1, 3, 2, 3, 7, 4, 4, 0, 0, 0 },
+ { 0, 1, 1, 3, 4, 9, 15, 12, 4, 0, 0, 0 },
+ { -66 },
+ { -32 },
+ { -12 },
+ { 0, 1, 1, 3, 4, 6, 14, 22, 12, 0, 0, 0 },
+ { -42 },
+ { 1, 0, 1, 3, 2, 3, 7, 4, 4, 0, 0, 0 },
+ { 1, 1, 1, 0, 4, 0, 0, 0, 0, 0, 0, 0 },
+ { -17 },
+ { -39 },
+ { 1, 0, 2, 0, 2, 4, 11, 9, 2, 0, 0, 0 },
+ { -62 },
+ { -28 },
+ { 1, 0, 0, 2, 3, 5, 12, 14, 18, 15, 9, 2 },
+ { 1, 1, 1, 0, 4, 0, 0, 0, 0, 0, 0, 0 },
+ { 1, 1, 1, 1, 2, 0, 0, 0, 0, 0, 0, 0 },
+ { 1, 0, 0, 2, 2, 2, 6, 12, 34, 92, 54, 20 },
+ { 1, 0, 0, 3, 0, 3, 3, 10, 40, 85, 61, 50 },
+ { 0, 1, 2, 1, 4, 7, 10, 26, 12, 0, 0, 0 },
+ { 1, 0, 0, 1, 7, 0, 19, 5, 13, 23, 0, 12 },
+ { -78 },
+ { 1, 0, 0, 0, 1, 4, 9, 4, 103, 110, 24, 0 },
+ { 1, 0, 2, 2, 2, 4, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 4, 0, 0, 0, 8, 11, 24, 53, 64, 60 },
+ { -47 },
+ { 0, 1, 0, 4, 6, 10, 12, 7, 15, 4, 4, 0 },
+};
+
+static const uint8_t atrac3p_spectra_xlats[] = {
+ /* Table set A, code table 0, wordlen 1 - 81 entries */
+ 0x00, 0x03, 0x40, 0xC0, 0x10, 0x30, 0x04, 0x0C, 0x01, 0x50, 0xD0, 0x70,
+ 0xF0, 0xC4, 0x14, 0x34, 0x4C, 0x1C, 0x3C, 0x41, 0xC1, 0x31, 0x05, 0x0D,
+ 0xC3, 0x13, 0x07, 0x0F, 0x44, 0xCC, 0x11, 0x43, 0x33, 0x54, 0x74, 0xDC,
+ 0xFC, 0x71, 0x15, 0x4D, 0xCD, 0x1D, 0xD3, 0xC7, 0x37, 0x3F, 0xD4, 0xF4,
+ 0x5C, 0x7C, 0x51, 0xD1, 0xF1, 0x45, 0xC5, 0x35, 0xDD, 0x3D, 0x53, 0x73,
+ 0xF3, 0x47, 0x17, 0x77, 0x4F, 0xCF, 0x1F, 0x55, 0xF5, 0x7D, 0xD7, 0x5F,
+ 0xFF, 0xD5, 0x75, 0x5D, 0xFD, 0x57, 0xF7, 0xDF, 0x7F,
+ /* Table set A, code table 0, wordlen 2 - 81 entries */
+ 0x00, 0x40, 0x10, 0x04, 0x01, 0x50, 0x44, 0x14, 0x54, 0x41, 0x11, 0x51,
+ 0x05, 0x45, 0x15, 0x55, 0x90, 0x80, 0x20, 0x60, 0x84, 0x94, 0x24, 0x64,
+ 0x08, 0x48, 0x18, 0x58, 0x81, 0x91, 0x21, 0x85, 0x95, 0x65, 0x09, 0x49,
+ 0x19, 0x59, 0x02, 0x42, 0x12, 0x52, 0x06, 0x46, 0x16, 0x56, 0x88, 0x61,
+ 0x25, 0x29, 0x69, 0x5A, 0xA0, 0xA4, 0x98, 0x28, 0x68, 0xA1, 0xA5, 0x89,
+ 0x99, 0xA9, 0x82, 0x92, 0x22, 0x62, 0x96, 0x26, 0x66, 0x0A, 0x4A, 0x1A,
+ 0xA8, 0x86, 0xA6, 0x8A, 0x9A, 0x2A, 0x6A, 0xA2, 0xAA,
+ /* Table set A, code table 0, wordlen 3 - 49 entries */
+ 0x00, 0x08, 0x38, 0x01, 0x09, 0x39, 0x07, 0x0F, 0x3F, 0x10, 0x30, 0x11,
+ 0x31, 0x02, 0x0A, 0x3A, 0x05, 0x06, 0x0E, 0x3E, 0x17, 0x37, 0x18, 0x28,
+ 0x19, 0x29, 0x2A, 0x32, 0x03, 0x0B, 0x33, 0x3B, 0x0D, 0x15, 0x3D, 0x16,
+ 0x1E, 0x36, 0x1F, 0x2F, 0x12, 0x1A, 0x13, 0x2B, 0x1D, 0x35, 0x2E, 0x1B,
+ 0x2D,
+ /* Table set A, code table 0, wordlen 4 - 6 entries */
+ 0x01, 0x02, 0x00, 0x03, 0x04, 0x05,
+ /* Table set A, code table 0, wordlen 5 - 225 entries */
+ 0x00, 0x10, 0xF0, 0x01, 0x11, 0xF1, 0x0F, 0x1F, 0xFF, 0x20, 0xE0, 0xE1,
+ 0x02, 0xF2, 0x0E, 0x1E, 0x2F, 0x30, 0xD0, 0x21, 0x12, 0x22, 0xE2, 0x03,
+ 0x0D, 0x2E, 0xEE, 0xFE, 0xEF, 0x40, 0xC0, 0x31, 0xC1, 0xD1, 0x32, 0xD2,
+ 0x13, 0x23, 0xE3, 0xF3, 0x04, 0xF4, 0x0C, 0x1C, 0x1D, 0x2D, 0xED, 0xFD,
+ 0x3E, 0xDE, 0x3F, 0xDF, 0x50, 0x60, 0x70, 0x90, 0xA0, 0xB0, 0x41, 0x51,
+ 0x61, 0x71, 0x91, 0xA1, 0xB1, 0x42, 0x62, 0x92, 0xA2, 0xC2, 0x33, 0xC3,
+ 0xD3, 0x14, 0x24, 0x34, 0xD4, 0xE4, 0x05, 0x15, 0xF5, 0x06, 0x16, 0x26,
+ 0xE6, 0xF6, 0x07, 0x17, 0xE7, 0xF7, 0x09, 0x19, 0x29, 0xF9, 0x0A, 0x1A,
+ 0x2A, 0xEA, 0xFA, 0x0B, 0x1B, 0xFB, 0x2C, 0x3C, 0xDC, 0xEC, 0xFC, 0x3D,
+ 0x4D, 0xCD, 0xDD, 0x4E, 0x6E, 0x7E, 0xAE, 0xCE, 0x4F, 0x5F, 0x6F, 0x7F,
+ 0x9F, 0xAF, 0xBF, 0xCF, 0x52, 0x72, 0xB2, 0x43, 0x53, 0x63, 0x73, 0x93,
+ 0xA3, 0xB3, 0x44, 0x64, 0x74, 0x94, 0xA4, 0xB4, 0xC4, 0x25, 0x35, 0xA5,
+ 0xC5, 0xD5, 0xE5, 0x36, 0x46, 0xB6, 0xC6, 0xD6, 0x27, 0x37, 0x47, 0xB7,
+ 0xC7, 0xD7, 0x39, 0x49, 0x59, 0xC9, 0xD9, 0xE9, 0x3A, 0x4A, 0x5A, 0xCA,
+ 0xDA, 0x2B, 0x3B, 0x4B, 0x6B, 0x7B, 0xDB, 0xEB, 0x4C, 0x5C, 0x6C, 0x7C,
+ 0x9C, 0xAC, 0xCC, 0x5D, 0x6D, 0x7D, 0x9D, 0xAD, 0xBD, 0x5E, 0x9E, 0xBE,
+ 0x54, 0x45, 0x55, 0x65, 0x75, 0x95, 0xB5, 0x56, 0x66, 0x76, 0x96, 0xA6,
+ 0x57, 0x67, 0x97, 0xA7, 0x69, 0x79, 0xA9, 0xB9, 0x6A, 0x7A, 0x9A, 0xAA,
+ 0xBA, 0x5B, 0x9B, 0xAB, 0xBB, 0xCB, 0xBC, 0x77, 0x99,
+ /* Table set A, code table 0, wordlen 6 - 16 entries */
+ 0x01, 0x00, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0D, 0x0E,
+ 0x0A, 0x0B, 0x0C, 0x0F,
+ /* Table set A, code table 0, wordlen 7 - 63 entries */
+ 0x00, 0x01, 0x3F, 0x02, 0x3E, 0x03, 0x3D, 0x04, 0x05, 0x06, 0x3A, 0x3B,
+ 0x3C, 0x07, 0x08, 0x09, 0x0A, 0x1A, 0x1B, 0x1C, 0x24, 0x25, 0x26, 0x36,
+ 0x37, 0x38, 0x39, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x19, 0x1D, 0x1E,
+ 0x1F, 0x21, 0x22, 0x23, 0x27, 0x2F, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35,
+ 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x29, 0x2A, 0x2B, 0x2C, 0x2D,
+ 0x2E, 0x18, 0x28,
+ /* Table set A, code table 1, wordlen 1 - 81 entries */
+ 0x00, 0x40, 0xC0, 0x10, 0x30, 0x04, 0x0C, 0x01, 0x03, 0xD0, 0x50, 0x70,
+ 0xF0, 0xC4, 0x34, 0x4C, 0xCC, 0x1C, 0x41, 0xC1, 0x31, 0x05, 0x0D, 0x43,
+ 0xC3, 0x13, 0x07, 0x0F, 0x44, 0x14, 0x74, 0xDC, 0x3C, 0x11, 0x1D, 0x33,
+ 0x37, 0x54, 0xD4, 0xF4, 0x5C, 0x7C, 0xFC, 0xD1, 0x71, 0xF1, 0x15, 0x35,
+ 0x4D, 0xCD, 0xDD, 0x3D, 0xD3, 0x73, 0x47, 0xC7, 0x17, 0x77, 0x3F, 0x51,
+ 0x45, 0xC5, 0x55, 0x53, 0xF3, 0x4F, 0xCF, 0x1F, 0xFF, 0xD5, 0x75, 0xF5,
+ 0x5D, 0x7D, 0xFD, 0x57, 0xD7, 0xF7, 0x5F, 0xDF, 0x7F,
+ /* Table set A, code table 1, wordlen 2 - 81 entries */
+ 0x00, 0x40, 0x10, 0x50, 0x04, 0x44, 0x14, 0x54, 0x01, 0x41, 0x11, 0x51,
+ 0x05, 0x45, 0x15, 0x55, 0x90, 0x94, 0x58, 0x91, 0x95, 0x19, 0x59, 0x06,
+ 0x46, 0x16, 0x56, 0x80, 0x60, 0x84, 0x24, 0x64, 0xA4, 0x08, 0x48, 0x18,
+ 0x68, 0x81, 0x21, 0x61, 0xA1, 0x85, 0x25, 0x65, 0xA5, 0x09, 0x49, 0x99,
+ 0x69, 0xA9, 0x02, 0x42, 0x12, 0x52, 0x96, 0x26, 0x66, 0x1A, 0x5A, 0x20,
+ 0xA0, 0x88, 0x98, 0x28, 0xA8, 0x89, 0x29, 0x82, 0x92, 0x22, 0x62, 0x86,
+ 0xA6, 0x0A, 0x4A, 0x9A, 0x6A, 0xAA, 0xA2, 0x8A, 0x2A,
+ /* Table set A, code table 1, wordlen 3 - 49 entries */
+ 0x00, 0x08, 0x38, 0x01, 0x07, 0x39, 0x0F, 0x09, 0x3F, 0x10, 0x30, 0x31,
+ 0x02, 0x3A, 0x06, 0x0E, 0x3E, 0x17, 0x18, 0x28, 0x11, 0x29, 0x0A, 0x32,
+ 0x03, 0x0B, 0x3B, 0x05, 0x0D, 0x3D, 0x16, 0x1F, 0x37, 0x19, 0x12, 0x1A,
+ 0x2A, 0x13, 0x33, 0x15, 0x35, 0x1E, 0x2E, 0x36, 0x2F, 0x1B, 0x2B, 0x1D,
+ 0x2D,
+ /* Table set A, code table 1, wordlen 4 - 121 entries */
+ 0x00, 0x10, 0xF0, 0x01, 0x0F, 0xF1, 0x1F, 0xFF, 0x20, 0xE0, 0x11, 0x02,
+ 0x0E, 0x30, 0x50, 0xB0, 0xD0, 0x21, 0xE1, 0x12, 0xF2, 0x03, 0x05, 0x0B,
+ 0x0D, 0x1E, 0xFE, 0x2F, 0xEF, 0x40, 0xC0, 0x31, 0x51, 0xB1, 0xC1, 0xD1,
+ 0x22, 0x52, 0xE2, 0x13, 0xF3, 0x04, 0x15, 0xF5, 0x1B, 0xEB, 0xFB, 0x0C,
+ 0x1D, 0xFD, 0x2E, 0x5E, 0xEE, 0x3F, 0x5F, 0xBF, 0xDF, 0x41, 0x32, 0x42,
+ 0xB2, 0xD2, 0x23, 0x53, 0xB3, 0xE3, 0x14, 0x24, 0xE4, 0xF4, 0x25, 0x35,
+ 0xD5, 0xE5, 0x2B, 0x3B, 0xDB, 0x1C, 0x2C, 0xBC, 0xEC, 0xFC, 0x2D, 0xBD,
+ 0xED, 0x3E, 0x4E, 0xBE, 0xDE, 0x4F, 0xCF, 0xC2, 0x33, 0x43, 0xC3, 0xD3,
+ 0x34, 0x44, 0x54, 0xB4, 0xD4, 0x45, 0x55, 0xC5, 0x4B, 0xCB, 0x3C, 0x4C,
+ 0x5C, 0xCC, 0xDC, 0x3D, 0x4D, 0x5D, 0xCD, 0xDD, 0xCE, 0xC4, 0xB5, 0x5B,
+ 0xBB,
+ /* Table set A, code table 1, wordlen 5 - 225 entries */
+ 0x00, 0x10, 0xF0, 0x01, 0x11, 0xF1, 0x0F, 0x1F, 0xFF, 0x20, 0xE0, 0x21,
+ 0xE1, 0x02, 0x12, 0xF2, 0x0E, 0x1E, 0xFE, 0x2F, 0xEF, 0x30, 0xD0, 0x31,
+ 0xD1, 0x22, 0xE2, 0x03, 0x13, 0xF3, 0x0D, 0x1D, 0xFD, 0x2E, 0xEE, 0x3F,
+ 0xDF, 0x40, 0x60, 0x70, 0x90, 0xA0, 0xC0, 0x41, 0xC1, 0x32, 0x42, 0xC2,
+ 0xD2, 0x23, 0x33, 0xD3, 0xE3, 0x04, 0x14, 0x24, 0xE4, 0xF4, 0x06, 0x16,
+ 0xF6, 0x07, 0x09, 0x0A, 0x1A, 0xFA, 0x0C, 0x1C, 0x2C, 0xEC, 0xFC, 0x2D,
+ 0x3D, 0xDD, 0xED, 0x3E, 0x4E, 0xCE, 0xDE, 0x4F, 0xCF, 0x50, 0xB0, 0x51,
+ 0x61, 0x71, 0x91, 0xA1, 0xB1, 0x52, 0x62, 0x72, 0x92, 0xA2, 0xB2, 0x43,
+ 0x53, 0x63, 0x73, 0x93, 0xA3, 0xC3, 0x34, 0x44, 0x64, 0xA4, 0xC4, 0xD4,
+ 0x05, 0x15, 0x25, 0x35, 0xD5, 0xE5, 0xF5, 0x26, 0x36, 0x46, 0xC6, 0xD6,
+ 0xE6, 0x17, 0x27, 0x37, 0xC7, 0xD7, 0xE7, 0xF7, 0x19, 0x29, 0x39, 0xC9,
+ 0xD9, 0xE9, 0xF9, 0x2A, 0x3A, 0x4A, 0x5A, 0xCA, 0xDA, 0xEA, 0x0B, 0x1B,
+ 0x2B, 0x3B, 0xCB, 0xDB, 0xEB, 0xFB, 0x3C, 0x4C, 0x6C, 0x7C, 0x9C, 0xAC,
+ 0xBC, 0xCC, 0xDC, 0x4D, 0x5D, 0x6D, 0x7D, 0x9D, 0xAD, 0xBD, 0xCD, 0x5E,
+ 0x6E, 0x7E, 0x9E, 0xAE, 0xBE, 0x5F, 0x6F, 0x7F, 0x9F, 0xAF, 0xBF, 0xB3,
+ 0x54, 0x74, 0x94, 0xB4, 0x45, 0x55, 0x65, 0x75, 0x95, 0xA5, 0xB5, 0xC5,
+ 0x56, 0x66, 0x76, 0x96, 0xA6, 0xB6, 0x47, 0x57, 0x67, 0xA7, 0xB7, 0x49,
+ 0x59, 0x69, 0xA9, 0xB9, 0x6A, 0x7A, 0x9A, 0xAA, 0xBA, 0x4B, 0x5B, 0x6B,
+ 0x7B, 0x9B, 0xAB, 0xBB, 0x5C, 0x77, 0x97, 0x79, 0x99,
+ /* Table set A, code table 1, wordlen 6 - 256 entries */
+ 0x00, 0x01, 0x10, 0x11, 0x21, 0x12, 0x20, 0x31, 0x02, 0x22, 0x13, 0x30,
+ 0x41, 0x32, 0x03, 0x23, 0x14, 0x24, 0x40, 0x51, 0x61, 0xD1, 0xE1, 0x42,
+ 0x52, 0xD2, 0x33, 0x43, 0xD3, 0x04, 0x34, 0x05, 0x15, 0x25, 0x16, 0x1D,
+ 0x2D, 0x1E, 0x2E, 0x50, 0x60, 0xD0, 0xE0, 0xF0, 0x71, 0x81, 0xF1, 0x62,
+ 0x72, 0xE2, 0xF2, 0x53, 0x63, 0xE3, 0xF3, 0x44, 0x54, 0xD4, 0xE4, 0xF4,
+ 0x35, 0x45, 0x55, 0xD5, 0xE5, 0xF5, 0x06, 0x26, 0x36, 0xD6, 0x07, 0x17,
+ 0x27, 0x37, 0xD7, 0x18, 0x28, 0x1C, 0x0D, 0x3D, 0x4D, 0x5D, 0x6D, 0x8D,
+ 0x0E, 0x3E, 0x4E, 0x5E, 0x0F, 0x1F, 0x2F, 0x3F, 0x5F, 0x70, 0x80, 0x90,
+ 0xC0, 0x91, 0xA1, 0xB1, 0xC1, 0x82, 0x92, 0xA2, 0xC2, 0x73, 0x83, 0x93,
+ 0xA3, 0xC3, 0x64, 0x74, 0x84, 0x94, 0xA4, 0xC4, 0x65, 0x75, 0x85, 0x46,
+ 0x56, 0x66, 0xC6, 0xE6, 0xF6, 0x47, 0x57, 0xE7, 0xF7, 0x08, 0x38, 0x48,
+ 0x58, 0x68, 0xD8, 0xE8, 0xF8, 0x09, 0x19, 0x29, 0x39, 0x59, 0xD9, 0xE9,
+ 0xF9, 0x1A, 0x2A, 0x3A, 0xDA, 0xEA, 0xFA, 0x1B, 0x2B, 0xDB, 0xEB, 0xFB,
+ 0x0C, 0x2C, 0x3C, 0xDC, 0xEC, 0x7D, 0x9D, 0xAD, 0xBD, 0xCD, 0x6E, 0x7E,
+ 0x8E, 0x9E, 0xAE, 0xBE, 0xCE, 0x4F, 0x6F, 0x7F, 0x8F, 0xAF, 0xA0, 0xB2,
+ 0xB3, 0xB4, 0x95, 0xA5, 0xB5, 0xC5, 0x76, 0x86, 0x96, 0xA6, 0xB6, 0x67,
+ 0x77, 0x87, 0x97, 0xC7, 0x78, 0x88, 0x98, 0xC8, 0x49, 0x69, 0x79, 0x89,
+ 0x99, 0xC9, 0x0A, 0x4A, 0x5A, 0x6A, 0x7A, 0xCA, 0x0B, 0x3B, 0x4B, 0x5B,
+ 0x6B, 0xCB, 0x4C, 0x5C, 0x6C, 0x7C, 0x8C, 0x9C, 0xAC, 0xBC, 0xCC, 0xFC,
+ 0xDD, 0xED, 0xFD, 0xDE, 0xEE, 0xFE, 0x9F, 0xBF, 0xCF, 0xDF, 0xEF, 0xFF,
+ 0xB0, 0xA7, 0xB7, 0xA8, 0xB8, 0xA9, 0xB9, 0x8A, 0x9A, 0xAA, 0xBA, 0x7B,
+ 0x8B, 0x9B, 0xAB, 0xBB,
+ /* Table set A, code table 1, wordlen 7 - 63 entries */
+ 0x00, 0x01, 0x3F, 0x02, 0x3E, 0x03, 0x04, 0x3B, 0x3C, 0x3D, 0x05, 0x06,
+ 0x07, 0x08, 0x38, 0x39, 0x3A, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x1A,
+ 0x1B, 0x24, 0x25, 0x26, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x0F, 0x10,
+ 0x11, 0x12, 0x13, 0x14, 0x15, 0x19, 0x1C, 0x1D, 0x1E, 0x1F, 0x21, 0x22,
+ 0x23, 0x27, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30, 0x31, 0x16, 0x17, 0x18,
+ 0x28, 0x29, 0x2A,
+ /* Table set A, code table 2, wordlen 1 - 81 entries */
+ 0x00, 0x40, 0xC0, 0x10, 0x30, 0x04, 0x0C, 0x01, 0x03, 0xD0, 0x70, 0x34,
+ 0x1C, 0x0D, 0x13, 0x07, 0x50, 0xF0, 0x44, 0xC4, 0x14, 0x74, 0x4C, 0xCC,
+ 0xDC, 0x3C, 0x41, 0xC1, 0x11, 0x31, 0x05, 0x1D, 0x43, 0xC3, 0x33, 0x37,
+ 0x0F, 0x54, 0xF4, 0xFC, 0xD1, 0x71, 0x15, 0x4D, 0xCD, 0xDD, 0xD3, 0x73,
+ 0x47, 0xC7, 0x77, 0x3F, 0xD4, 0x5C, 0x7C, 0x51, 0xF1, 0x45, 0xC5, 0x55,
+ 0x35, 0x3D, 0x53, 0xF3, 0x17, 0x4F, 0xCF, 0x1F, 0xFF, 0x75, 0xF5, 0x5D,
+ 0x7D, 0xD7, 0xF7, 0x5F, 0xDF, 0xD5, 0xFD, 0x57, 0x7F,
+ /* Table set A, code table 2, wordlen 2 - 25 entries */
+ 0x00, 0x08, 0x38, 0x01, 0x07, 0x09, 0x39, 0x0F, 0x3F, 0x10, 0x02, 0x06,
+ 0x30, 0x11, 0x31, 0x0A, 0x3A, 0x0E, 0x17, 0x37, 0x32, 0x16, 0x3E, 0x12,
+ 0x36,
+ /* Table set A, code table 2, wordlen 3 - 49 entries */
+ 0x00, 0x08, 0x38, 0x01, 0x07, 0x09, 0x39, 0x0F, 0x3F, 0x10, 0x30, 0x02,
+ 0x3A, 0x06, 0x0E, 0x18, 0x28, 0x11, 0x31, 0x0A, 0x03, 0x05, 0x3E, 0x17,
+ 0x37, 0x19, 0x29, 0x12, 0x2A, 0x32, 0x0B, 0x33, 0x3B, 0x0D, 0x15, 0x3D,
+ 0x16, 0x1E, 0x36, 0x1F, 0x2F, 0x1A, 0x13, 0x1B, 0x2B, 0x1D, 0x2D, 0x35,
+ 0x2E,
+ /* Table set A, code table 2, wordlen 4 - 6 entries */
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05,
+ /* Table set A, code table 2, wordlen 5 - 8 entries */
+ 0x01, 0x00, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ /* Table set A, code table 2, wordlen 6 - 256 entries */
+ 0x00, 0x01, 0x11, 0x10, 0x21, 0x12, 0x22, 0x20, 0x30, 0x31, 0x41, 0x02,
+ 0x32, 0x03, 0x13, 0x23, 0x33, 0x14, 0x24, 0x40, 0x51, 0x61, 0x42, 0x52,
+ 0x43, 0x53, 0x04, 0x34, 0x44, 0x15, 0x25, 0x35, 0x16, 0x26, 0x50, 0x60,
+ 0x71, 0x81, 0xD1, 0x62, 0x72, 0x82, 0xD2, 0x63, 0x73, 0xD3, 0x54, 0x64,
+ 0x05, 0x45, 0x55, 0x65, 0x06, 0x36, 0x46, 0x56, 0x17, 0x27, 0x37, 0x47,
+ 0x18, 0x28, 0x38, 0x19, 0x1D, 0x2D, 0x3D, 0x1E, 0x70, 0x80, 0x90, 0xD0,
+ 0xE0, 0x91, 0xA1, 0xB1, 0xC1, 0xE1, 0xF1, 0x92, 0xA2, 0xC2, 0xE2, 0xF2,
+ 0x83, 0x93, 0xA3, 0xC3, 0xE3, 0xF3, 0x74, 0x84, 0x94, 0xA4, 0xC4, 0xD4,
+ 0xE4, 0xF4, 0x75, 0x85, 0x95, 0xD5, 0xE5, 0x66, 0x76, 0x86, 0xD6, 0xE6,
+ 0x07, 0x57, 0x67, 0x77, 0xD7, 0x08, 0x48, 0x58, 0x68, 0xD8, 0x09, 0x29,
+ 0x39, 0x49, 0x59, 0x69, 0x1A, 0x2A, 0x3A, 0x4A, 0x1B, 0x2B, 0x1C, 0x2C,
+ 0x3C, 0x4C, 0x0D, 0x4D, 0x5D, 0x6D, 0x7D, 0x8D, 0x0E, 0x2E, 0x3E, 0x4E,
+ 0x5E, 0x6E, 0x1F, 0x2F, 0x3F, 0x4F, 0x5F, 0xA0, 0xB0, 0xC0, 0xF0, 0xB2,
+ 0xB3, 0xB4, 0xA5, 0xB5, 0xC5, 0xF5, 0x96, 0xA6, 0xB6, 0xC6, 0xF6, 0x87,
+ 0x97, 0xA7, 0xB7, 0xC7, 0xE7, 0xF7, 0x78, 0x88, 0x98, 0xA8, 0xC8, 0xE8,
+ 0xF8, 0x79, 0x89, 0x99, 0xC9, 0xD9, 0xE9, 0xF9, 0x0A, 0x5A, 0x6A, 0x7A,
+ 0x8A, 0xDA, 0xEA, 0xFA, 0x0B, 0x3B, 0x4B, 0x5B, 0x6B, 0x7B, 0x8B, 0xDB,
+ 0x0C, 0x5C, 0x6C, 0x7C, 0x8C, 0x9C, 0xDC, 0x9D, 0xAD, 0xBD, 0xCD, 0x7E,
+ 0x8E, 0x9E, 0xAE, 0xBE, 0x0F, 0x6F, 0x7F, 0x8F, 0x9F, 0xAF, 0xB8, 0xA9,
+ 0xB9, 0x9A, 0xAA, 0xBA, 0xCA, 0x9B, 0xAB, 0xBB, 0xCB, 0xEB, 0xFB, 0xAC,
+ 0xBC, 0xCC, 0xEC, 0xFC, 0xDD, 0xED, 0xFD, 0xCE, 0xDE, 0xEE, 0xFE, 0xBF,
+ 0xCF, 0xDF, 0xEF, 0xFF,
+ /* Table set A, code table 2, wordlen 7 - 63 entries */
+ 0x00, 0x02, 0x03, 0x01, 0x05, 0x06, 0x07, 0x09, 0x36, 0x37, 0x38, 0x3A,
+ 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, 0x04, 0x08, 0x0A, 0x0B, 0x0C, 0x0E, 0x31,
+ 0x34, 0x35, 0x39, 0x0D, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x16, 0x17, 0x19,
+ 0x1A, 0x1E, 0x27, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30, 0x32, 0x33, 0x14,
+ 0x15, 0x18, 0x1B, 0x1C, 0x1D, 0x1F, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26,
+ 0x28, 0x29, 0x2A,
+ /* Table set A, code table 3, wordlen 1 - 9 entries */
+ 0x00, 0x04, 0x0C, 0x01, 0x03, 0x05, 0x0D, 0x07, 0x0F,
+ /* Table set A, code table 3, wordlen 2 - 81 entries */
+ 0x00, 0x40, 0x01, 0x10, 0x04, 0x80, 0x50, 0x20, 0x14, 0x05, 0x02, 0x90,
+ 0x60, 0x44, 0x54, 0x24, 0x08, 0x18, 0x41, 0x11, 0x15, 0x09, 0x06, 0xA0,
+ 0x84, 0x94, 0x64, 0xA4, 0x48, 0x58, 0x28, 0x51, 0x21, 0x45, 0x55, 0x25,
+ 0x19, 0x12, 0x16, 0x0A, 0x1A, 0x68, 0xA8, 0x81, 0x91, 0x61, 0xA1, 0x85,
+ 0x95, 0x65, 0xA5, 0x49, 0x59, 0x29, 0x69, 0x42, 0x52, 0x46, 0x56, 0x2A,
+ 0x88, 0x98, 0x89, 0x99, 0xA9, 0x82, 0x92, 0x22, 0x62, 0x86, 0x26, 0x66,
+ 0x4A, 0x5A, 0x6A, 0xA2, 0x96, 0xA6, 0x8A, 0x9A, 0xAA,
+ /* Table set A, code table 3, wordlen 3 - 256 entries */
+ 0x00, 0x10, 0x40, 0x50, 0x04, 0x44, 0x14, 0x54, 0x01, 0x41, 0x11, 0x51,
+ 0x05, 0x45, 0x15, 0x55, 0x90, 0x20, 0x94, 0x64, 0x18, 0x21, 0x95, 0x19,
+ 0x69, 0x02, 0x52, 0x06, 0x46, 0x16, 0x80, 0x60, 0x84, 0xD4, 0x24, 0x08,
+ 0x48, 0x58, 0x68, 0x81, 0x91, 0x61, 0x85, 0x25, 0x65, 0xA5, 0x09, 0x49,
+ 0x59, 0x29, 0x42, 0x12, 0x56, 0x96, 0xA6, 0x0A, 0x17, 0x1B, 0xD0, 0xC4,
+ 0x74, 0xF4, 0x88, 0xC8, 0x28, 0xA1, 0x71, 0xC5, 0xD5, 0x75, 0x99, 0xB9,
+ 0x4D, 0x1D, 0x2D, 0x6D, 0x22, 0x62, 0x66, 0x4A, 0x1A, 0x9A, 0x6A, 0x8E,
+ 0x5E, 0x43, 0x23, 0x07, 0x47, 0x57, 0x6B, 0xC0, 0xA0, 0xE0, 0x70, 0xB0,
+ 0xA4, 0xE4, 0x34, 0xB4, 0x98, 0xD8, 0xA8, 0x38, 0x78, 0x0C, 0x4C, 0x1C,
+ 0x5C, 0x9C, 0x6C, 0x7C, 0xC1, 0xD1, 0xE1, 0x31, 0xE5, 0x35, 0xB5, 0xF5,
+ 0x89, 0xA9, 0x79, 0xF9, 0x0D, 0xCD, 0x9D, 0xDD, 0xAD, 0x3D, 0x7D, 0x82,
+ 0xC2, 0x92, 0xD2, 0xE2, 0x72, 0xF2, 0x86, 0xD6, 0xE6, 0x76, 0xB6, 0x8A,
+ 0x5A, 0xDA, 0xEA, 0xFA, 0x4E, 0x1E, 0x9E, 0xEE, 0x03, 0x13, 0x53, 0x97,
+ 0xB7, 0x0B, 0x4B, 0x8B, 0x5B, 0x9B, 0xEB, 0x7B, 0x0F, 0x4F, 0x1F, 0x5F,
+ 0x9F, 0x2F, 0x3F, 0xBF, 0xE8, 0xB8, 0xF8, 0x8C, 0x2C, 0x3C, 0xFC, 0xB1,
+ 0xC9, 0xD9, 0xE9, 0x39, 0x5D, 0xED, 0xBD, 0xA2, 0x32, 0x26, 0x36, 0x2A,
+ 0xAA, 0xBA, 0x0E, 0x2E, 0x6E, 0x83, 0xC3, 0x93, 0x63, 0xB3, 0xA7, 0x37,
+ 0x30, 0xF0, 0xCC, 0xDC, 0xAC, 0xEC, 0xBC, 0xF1, 0x8D, 0xFD, 0xB2, 0xC6,
+ 0xF6, 0xCA, 0x3A, 0x7A, 0xCE, 0xDE, 0xAE, 0x3E, 0x7E, 0xBE, 0xFE, 0xD3,
+ 0xA3, 0xE3, 0x33, 0x73, 0xF3, 0x87, 0xC7, 0xD7, 0x27, 0x67, 0xE7, 0x77,
+ 0xF7, 0xCB, 0xDB, 0x2B, 0xAB, 0x3B, 0xBB, 0xFB, 0x8F, 0xCF, 0xDF, 0x6F,
+ 0xAF, 0xEF, 0x7F, 0xFF,
+ /* Table set A, code table 3, wordlen 4 - 6 entries */
+ 0x01, 0x00, 0x02, 0x03, 0x04, 0x05,
+ /* Table set A, code table 3, wordlen 5 - 225 entries */
+ 0x00, 0xF0, 0x0F, 0x10, 0x01, 0xFF, 0x20, 0xE0, 0x11, 0xF1, 0x0E, 0x1F,
+ 0x30, 0x40, 0xD0, 0x21, 0xE1, 0x02, 0x12, 0x22, 0xE2, 0xF2, 0x03, 0x13,
+ 0x1E, 0x2E, 0x3E, 0xEE, 0xFE, 0x2F, 0xEF, 0xD2, 0x43, 0xF3, 0x04, 0x0D,
+ 0x2D, 0x3D, 0x3F, 0xDF, 0x50, 0x60, 0x70, 0x90, 0xB0, 0x31, 0x41, 0x91,
+ 0xA1, 0xC1, 0xD1, 0x42, 0xA2, 0xC2, 0x23, 0x33, 0xE3, 0x24, 0x34, 0xB4,
+ 0xD4, 0xF4, 0x05, 0x15, 0x45, 0xE5, 0x16, 0x36, 0x56, 0xA6, 0xC6, 0xD6,
+ 0xF6, 0x57, 0xC7, 0xF7, 0x09, 0x29, 0x49, 0x59, 0x69, 0xF9, 0x0A, 0x2A,
+ 0x3A, 0x4A, 0xDA, 0xEA, 0xFA, 0x0B, 0x2B, 0xAB, 0xEB, 0xFB, 0x0C, 0x1C,
+ 0x2C, 0x3C, 0x4C, 0x5C, 0xCC, 0xDC, 0xFC, 0x1D, 0x4D, 0x6D, 0xBD, 0xCD,
+ 0xED, 0xFD, 0x4E, 0x6E, 0xCE, 0xDE, 0x7F, 0xA0, 0xC0, 0x51, 0x61, 0x71,
+ 0xB1, 0x32, 0x52, 0x62, 0x72, 0x92, 0xB2, 0x53, 0x63, 0x73, 0x93, 0xA3,
+ 0xB3, 0xC3, 0xD3, 0x14, 0x44, 0x54, 0x64, 0x74, 0x94, 0xA4, 0xC4, 0xE4,
+ 0x25, 0x35, 0x55, 0x65, 0x75, 0x95, 0xA5, 0xB5, 0xC5, 0xD5, 0xF5, 0x06,
+ 0x26, 0x46, 0x66, 0x76, 0x96, 0xB6, 0xE6, 0x07, 0x17, 0x27, 0x37, 0x47,
+ 0x67, 0x77, 0x97, 0xA7, 0xB7, 0xD7, 0xE7, 0x19, 0x39, 0x79, 0x99, 0xA9,
+ 0xB9, 0xC9, 0xD9, 0xE9, 0x1A, 0x5A, 0x6A, 0x7A, 0x9A, 0xAA, 0xBA, 0xCA,
+ 0x1B, 0x3B, 0x4B, 0x5B, 0x6B, 0x7B, 0x9B, 0xBB, 0xCB, 0xDB, 0x6C, 0x7C,
+ 0x9C, 0xAC, 0xBC, 0xEC, 0x5D, 0x7D, 0x9D, 0xAD, 0xDD, 0x5E, 0x7E, 0x9E,
+ 0xAE, 0xBE, 0x4F, 0x5F, 0x6F, 0x9F, 0xAF, 0xBF, 0xCF,
+ /* Table set A, code table 3, wordlen 6 - 256 entries */
+ 0x00, 0x10, 0x01, 0x11, 0x20, 0x21, 0x02, 0x12, 0x22, 0x31, 0x41, 0x32,
+ 0x13, 0x23, 0x30, 0x40, 0x51, 0x42, 0x03, 0x33, 0x43, 0x04, 0x14, 0x24,
+ 0x34, 0x15, 0x25, 0x50, 0x61, 0x71, 0xD1, 0x52, 0x62, 0x72, 0xD2, 0x53,
+ 0x63, 0xD3, 0x44, 0x54, 0x64, 0x05, 0x35, 0x45, 0x55, 0x16, 0x26, 0x36,
+ 0x46, 0x17, 0x27, 0x1D, 0x2D, 0x3D, 0x60, 0x70, 0xD0, 0x81, 0x91, 0xA1,
+ 0xC1, 0xE1, 0xF1, 0x82, 0x92, 0xC2, 0xE2, 0xF2, 0x73, 0x83, 0xE3, 0xF3,
+ 0x74, 0x84, 0xC4, 0xD4, 0xE4, 0xF4, 0x65, 0x75, 0x85, 0xD5, 0xE5, 0x06,
+ 0x56, 0x66, 0xD6, 0xE6, 0x07, 0x37, 0x47, 0x57, 0x67, 0xD7, 0xE7, 0x18,
+ 0x28, 0x38, 0x48, 0x58, 0xD8, 0x19, 0x29, 0x2A, 0x1C, 0x2C, 0x0D, 0x4D,
+ 0x5D, 0x6D, 0x7D, 0x8D, 0x9D, 0x1E, 0x2E, 0x3E, 0x4E, 0x5E, 0x6E, 0x7E,
+ 0x1F, 0x2F, 0x3F, 0x80, 0x90, 0xA0, 0xC0, 0xE0, 0xF0, 0xB1, 0xA2, 0xB2,
+ 0x93, 0xA3, 0xB3, 0xC3, 0x94, 0xA4, 0xB4, 0x95, 0xA5, 0xB5, 0xC5, 0xF5,
+ 0x76, 0x86, 0x96, 0xA6, 0xC6, 0xF6, 0x77, 0x87, 0x97, 0xA7, 0xC7, 0xF7,
+ 0x08, 0x68, 0x78, 0x88, 0x98, 0xC8, 0xE8, 0xF8, 0x09, 0x39, 0x49, 0x59,
+ 0x69, 0x79, 0x89, 0xD9, 0xE9, 0xF9, 0x0A, 0x1A, 0x3A, 0x4A, 0x5A, 0x6A,
+ 0xDA, 0xEA, 0xFA, 0x1B, 0x2B, 0x3B, 0x4B, 0x5B, 0xDB, 0xEB, 0xFB, 0x0C,
+ 0x3C, 0x4C, 0x5C, 0x6C, 0x7C, 0x8C, 0x9C, 0xDC, 0xEC, 0xAD, 0xBD, 0xCD,
+ 0xDD, 0xED, 0x0E, 0x8E, 0x9E, 0xAE, 0xBE, 0x0F, 0x4F, 0x5F, 0x6F, 0x7F,
+ 0x8F, 0x9F, 0xAF, 0xB0, 0xB6, 0xB7, 0xA8, 0xB8, 0x99, 0xA9, 0xB9, 0xC9,
+ 0x7A, 0x8A, 0x9A, 0xAA, 0xBA, 0xCA, 0x0B, 0x6B, 0x7B, 0x8B, 0x9B, 0xCB,
+ 0xAC, 0xBC, 0xCC, 0xFC, 0xFD, 0xCE, 0xDE, 0xEE, 0xFE, 0xBF, 0xCF, 0xDF,
+ 0xEF, 0xFF, 0xAB, 0xBB,
+ /* Table set A, code table 3, wordlen 7 - 63 entries */
+ 0x00, 0x01, 0x02, 0x03, 0x3D, 0x3E, 0x3F, 0x04, 0x05, 0x06, 0x3A, 0x3B,
+ 0x3C, 0x07, 0x08, 0x09, 0x0A, 0x36, 0x37, 0x38, 0x39, 0x0B, 0x0C, 0x0D,
+ 0x0E, 0x0F, 0x10, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x23, 0x24, 0x25,
+ 0x26, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x11, 0x12, 0x13, 0x14, 0x15,
+ 0x16, 0x17, 0x18, 0x1F, 0x21, 0x22, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C,
+ 0x2D, 0x2E, 0x2F,
+ /* Table set A, code table 4, wordlen 1 - 81 entries */
+ 0x00, 0x40, 0xC0, 0x10, 0x30, 0x04, 0x0C, 0x01, 0x03, 0x50, 0xD0, 0x70,
+ 0xF0, 0xC4, 0x34, 0x4C, 0xCC, 0x1C, 0x41, 0xC1, 0x31, 0x05, 0x0D, 0x43,
+ 0xC3, 0x13, 0x07, 0x0F, 0x44, 0x14, 0x74, 0xDC, 0x3C, 0x11, 0x1D, 0x33,
+ 0x37, 0x54, 0xD4, 0xF4, 0x5C, 0x7C, 0xFC, 0xD1, 0x71, 0xF1, 0xC5, 0x15,
+ 0x35, 0x4D, 0xCD, 0xDD, 0x3D, 0xD3, 0x73, 0x47, 0xC7, 0x17, 0x77, 0x1F,
+ 0x3F, 0x51, 0x45, 0x55, 0xD5, 0x75, 0xF5, 0x5D, 0x7D, 0xFD, 0x53, 0xF3,
+ 0x57, 0xD7, 0xF7, 0x4F, 0xCF, 0x5F, 0xDF, 0x7F, 0xFF,
+ /* Table set A, code table 4, wordlen 2 - 81 entries */
+ 0x00, 0x40, 0x01, 0x10, 0x50, 0x04, 0x44, 0x14, 0x54, 0x41, 0x11, 0x51,
+ 0x05, 0x45, 0x15, 0x55, 0x59, 0x80, 0x90, 0x20, 0x60, 0x84, 0x94, 0x24,
+ 0x64, 0x08, 0x48, 0x18, 0x58, 0x81, 0x91, 0x21, 0x61, 0x85, 0x95, 0x25,
+ 0x65, 0x09, 0x49, 0x19, 0x02, 0x42, 0x12, 0x52, 0x06, 0x46, 0x16, 0x56,
+ 0xA0, 0xA4, 0x68, 0xA1, 0xA5, 0x99, 0x29, 0x69, 0x96, 0x66, 0x4A, 0x1A,
+ 0x5A, 0x88, 0x98, 0x28, 0x89, 0xA9, 0x82, 0x92, 0x22, 0x62, 0x86, 0x26,
+ 0xA6, 0x0A, 0x9A, 0x2A, 0x6A, 0xA8, 0xA2, 0x8A, 0xAA,
+ /* Table set A, code table 4, wordlen 3 - 7 entries */
+ 0x00, 0x07, 0x01, 0x02, 0x06, 0x03, 0x05,
+ /* Table set A, code table 4, wordlen 4 - 121 entries */
+ 0x00, 0x10, 0xF0, 0x01, 0x0F, 0x11, 0xF1, 0x1F, 0xFF, 0x20, 0xE0, 0x21,
+ 0xE1, 0x02, 0x12, 0xF2, 0x0E, 0x1E, 0xFE, 0x2F, 0xEF, 0x30, 0x50, 0xD0,
+ 0xD1, 0x22, 0xE2, 0x03, 0x13, 0xF3, 0x0D, 0x1D, 0x2D, 0xFD, 0x2E, 0xEE,
+ 0x3F, 0xDF, 0x40, 0xB0, 0xC0, 0x31, 0x41, 0x51, 0xB1, 0xC1, 0x32, 0xB2,
+ 0xC2, 0xD2, 0x23, 0xB3, 0xD3, 0xE3, 0x04, 0x14, 0xE4, 0xF4, 0x05, 0x15,
+ 0xD5, 0xE5, 0xF5, 0x0B, 0x1B, 0x2B, 0x3B, 0xEB, 0xFB, 0x0C, 0x1C, 0x2C,
+ 0xFC, 0x3D, 0x5D, 0xED, 0x3E, 0x4E, 0x5E, 0xBE, 0xDE, 0x4F, 0x5F, 0xBF,
+ 0xCF, 0x42, 0x52, 0x33, 0x53, 0xC3, 0x24, 0xB4, 0xD4, 0x25, 0x35, 0xC5,
+ 0x4B, 0xCB, 0xDB, 0x3C, 0x4C, 0x5C, 0xDC, 0xEC, 0x4D, 0xBD, 0xCD, 0xDD,
+ 0xCE, 0x43, 0x34, 0x44, 0x54, 0xC4, 0x45, 0x55, 0xB5, 0x5B, 0xBB, 0xBC,
+ 0xCC,
+ /* Table set A, code table 4, wordlen 5 - 8 entries */
+ 0x01, 0x02, 0x00, 0x03, 0x04, 0x05, 0x06, 0x07,
+ /* Table set A, code table 4, wordlen 6 - 256 entries */
+ 0x02, 0x00, 0x30, 0x21, 0x31, 0x41, 0x61, 0x12, 0x22, 0x42, 0x62, 0x43,
+ 0x53, 0x24, 0x45, 0x26, 0x27, 0x10, 0x40, 0xB0, 0x01, 0x11, 0x81, 0x32,
+ 0x52, 0x72, 0x92, 0x03, 0x13, 0x33, 0x63, 0x14, 0x34, 0x54, 0x64, 0x74,
+ 0x05, 0x15, 0x25, 0x35, 0x55, 0x65, 0x06, 0x46, 0x56, 0x57, 0x67, 0x88,
+ 0x20, 0x51, 0x91, 0xD1, 0xF2, 0x23, 0x83, 0x93, 0x04, 0x44, 0x84, 0x94,
+ 0x75, 0x85, 0xC5, 0x36, 0x66, 0x96, 0xB6, 0x07, 0x37, 0x97, 0x08, 0x28,
+ 0x38, 0x48, 0x68, 0x09, 0x69, 0x79, 0x0A, 0x2A, 0x1B, 0x9B, 0x2C, 0x4D,
+ 0x50, 0x60, 0x70, 0x80, 0x90, 0xA0, 0xC0, 0xD0, 0xE0, 0xF0, 0x71, 0xA1,
+ 0xB1, 0xC1, 0xE1, 0xF1, 0x82, 0xA2, 0xB2, 0xC2, 0xD2, 0xE2, 0x73, 0xA3,
+ 0xB3, 0xC3, 0xD3, 0xE3, 0xF3, 0xA4, 0xB4, 0xC4, 0xD4, 0xE4, 0xF4, 0x95,
+ 0xA5, 0xB5, 0xD5, 0xE5, 0xF5, 0x16, 0x76, 0x86, 0xA6, 0xC6, 0xD6, 0xE6,
+ 0xF6, 0x17, 0x47, 0x77, 0x87, 0xA7, 0xB7, 0xC7, 0xD7, 0xE7, 0xF7, 0x18,
+ 0x58, 0x78, 0x98, 0xA8, 0xB8, 0xC8, 0xD8, 0xE8, 0xF8, 0x19, 0x29, 0x39,
+ 0x49, 0x59, 0x89, 0x99, 0xA9, 0xB9, 0xC9, 0xD9, 0xE9, 0xF9, 0x1A, 0x3A,
+ 0x4A, 0x5A, 0x6A, 0x7A, 0x8A, 0x9A, 0xAA, 0xBA, 0xCA, 0xDA, 0xEA, 0xFA,
+ 0x0B, 0x2B, 0x3B, 0x4B, 0x5B, 0x6B, 0x7B, 0x8B, 0xAB, 0xBB, 0xCB, 0xDB,
+ 0xEB, 0xFB, 0x0C, 0x1C, 0x3C, 0x4C, 0x5C, 0x6C, 0x7C, 0x8C, 0x9C, 0xAC,
+ 0xBC, 0xCC, 0xDC, 0xEC, 0xFC, 0x0D, 0x1D, 0x2D, 0x3D, 0x5D, 0x6D, 0x7D,
+ 0x8D, 0x9D, 0xAD, 0xBD, 0xCD, 0xDD, 0xED, 0xFD, 0x0E, 0x1E, 0x2E, 0x3E,
+ 0x4E, 0x5E, 0x6E, 0x7E, 0x8E, 0x9E, 0xAE, 0xBE, 0xCE, 0xDE, 0xEE, 0xFE,
+ 0x0F, 0x1F, 0x2F, 0x3F, 0x4F, 0x5F, 0x6F, 0x7F, 0x8F, 0x9F, 0xAF, 0xBF,
+ 0xCF, 0xDF, 0xEF, 0xFF,
+ /* Table set A, code table 4, wordlen 7 - 63 entries */
+ 0x00, 0x01, 0x02, 0x3E, 0x3F, 0x03, 0x04, 0x05, 0x06, 0x08, 0x36, 0x38,
+ 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x07, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E,
+ 0x35, 0x37, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x24, 0x25, 0x27,
+ 0x2A, 0x34, 0x16, 0x19, 0x1C, 0x23, 0x26, 0x28, 0x29, 0x2B, 0x2D, 0x2E,
+ 0x2F, 0x30, 0x31, 0x32, 0x33, 0x17, 0x18, 0x1A, 0x1B, 0x1D, 0x1E, 0x1F,
+ 0x21, 0x22, 0x2C,
+ /* Table set A, code table 5, wordlen 1 - 81 entries */
+ 0x00, 0x40, 0xC0, 0x30, 0x04, 0x01, 0x03, 0x10, 0x0C, 0xD0, 0x70, 0x34,
+ 0x1C, 0x0D, 0x07, 0x50, 0xF0, 0x44, 0xC4, 0x14, 0x4C, 0xCC, 0x3C, 0x41,
+ 0xC1, 0x11, 0x31, 0x05, 0x43, 0xC3, 0x13, 0x33, 0x0F, 0x74, 0xDC, 0x1D,
+ 0x37, 0x54, 0xD4, 0xF4, 0x5C, 0x7C, 0xFC, 0xD1, 0x71, 0xF1, 0xC5, 0x15,
+ 0x35, 0x4D, 0xCD, 0xDD, 0x3D, 0x53, 0xD3, 0x73, 0x47, 0xC7, 0x17, 0x77,
+ 0x4F, 0x1F, 0x3F, 0x51, 0x45, 0x55, 0xF3, 0xCF, 0xFF, 0xD5, 0x75, 0xF5,
+ 0x5D, 0x7D, 0xFD, 0x57, 0xD7, 0xF7, 0x5F, 0xDF, 0x7F,
+ /* Table set A, code table 5, wordlen 2 - 25 entries */
+ 0x00, 0x08, 0x38, 0x01, 0x07, 0x09, 0x39, 0x0F, 0x3F, 0x10, 0x02, 0x06,
+ 0x30, 0x11, 0x31, 0x0A, 0x3A, 0x0E, 0x17, 0x37, 0x32, 0x16, 0x3E, 0x12,
+ 0x36,
+ /* Table set A, code table 5, wordlen 3 - 7 entries */
+ 0x00, 0x01, 0x02, 0x06, 0x07, 0x03, 0x05,
+ /* Table set A, code table 5, wordlen 4 - 121 entries */
+ 0x00, 0x01, 0x0F, 0x1F, 0x10, 0xE0, 0xF0, 0x11, 0xF1, 0x2F, 0xFF, 0x20,
+ 0x21, 0xE1, 0x02, 0x12, 0xF2, 0x03, 0xF3, 0x0E, 0x2E, 0xFE, 0x3F, 0x30,
+ 0x40, 0xD0, 0xC1, 0xD1, 0x22, 0xC2, 0x33, 0xE3, 0x0C, 0xCC, 0x0D, 0x1D,
+ 0x2D, 0xFD, 0x1E, 0x3E, 0x5E, 0xEF, 0xC0, 0x52, 0xB2, 0xD2, 0x43, 0xC3,
+ 0xD3, 0x24, 0x45, 0xF5, 0x4B, 0x5B, 0xFB, 0x1C, 0x3D, 0xBD, 0xDD, 0xEE,
+ 0xBF, 0xCF, 0xDF, 0x50, 0xB0, 0x31, 0x41, 0x51, 0xB1, 0x32, 0x42, 0xE2,
+ 0x13, 0x23, 0x53, 0xB3, 0x04, 0x14, 0x34, 0x44, 0x54, 0xB4, 0xC4, 0xD4,
+ 0xE4, 0xF4, 0x05, 0x15, 0x25, 0x35, 0x55, 0xB5, 0xC5, 0xD5, 0xE5, 0x0B,
+ 0x1B, 0x2B, 0x3B, 0xBB, 0xCB, 0xDB, 0xEB, 0x2C, 0x3C, 0x4C, 0x5C, 0xBC,
+ 0xDC, 0xEC, 0xFC, 0x4D, 0x5D, 0xCD, 0xED, 0x4E, 0xBE, 0xCE, 0xDE, 0x4F,
+ 0x5F,
+ /* Table set A, code table 5, wordlen 5 - 8 entries */
+ 0x00, 0x01, 0x02, 0x03, 0x06, 0x07, 0x04, 0x05,
+ /* Table set A, code table 5, wordlen 6 - 31 entries */
+ 0x04, 0x00, 0x01, 0x02, 0x03, 0x1C, 0x1D, 0x1E, 0x1F, 0x05, 0x06, 0x07,
+ 0x18, 0x19, 0x1B, 0x08, 0x09, 0x0E, 0x13, 0x15, 0x16, 0x17, 0x1A, 0x0A,
+ 0x0B, 0x0C, 0x0D, 0x0F, 0x11, 0x12, 0x14,
+ /* Table set A, code table 5, wordlen 7 - 63 entries */
+ 0x00, 0x01, 0x02, 0x3D, 0x3E, 0x3F, 0x03, 0x04, 0x05, 0x06, 0x3A, 0x3B,
+ 0x3C, 0x07, 0x08, 0x09, 0x0A, 0x36, 0x37, 0x38, 0x39, 0x0B, 0x0C, 0x0D,
+ 0x0E, 0x0F, 0x1A, 0x1B, 0x1C, 0x24, 0x25, 0x26, 0x31, 0x32, 0x33, 0x34,
+ 0x35, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x17, 0x18, 0x19, 0x1D, 0x1E,
+ 0x1F, 0x21, 0x22, 0x23, 0x27, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30, 0x16,
+ 0x28, 0x29, 0x2A,
+ /* Table set A, code table 6, wordlen 1 - 81 entries */
+ 0x00, 0x40, 0xC0, 0x10, 0x30, 0x04, 0x0C, 0x01, 0x03, 0x70, 0x50, 0xD0,
+ 0xF0, 0x44, 0xC4, 0x14, 0x34, 0x4C, 0x1C, 0x3C, 0x31, 0x05, 0x0D, 0x13,
+ 0x07, 0x0F, 0x74, 0xCC, 0xDC, 0xFC, 0x41, 0xC1, 0x11, 0x43, 0xC3, 0x33,
+ 0x54, 0xD4, 0xF4, 0x5C, 0x7C, 0x51, 0xD1, 0x71, 0xF1, 0x45, 0xC5, 0x15,
+ 0x35, 0x4D, 0xCD, 0x1D, 0x3D, 0x53, 0xD3, 0x73, 0xF3, 0x47, 0xC7, 0x17,
+ 0x37, 0x4F, 0xCF, 0x1F, 0x3F, 0x55, 0xD5, 0x75, 0xF5, 0x5D, 0xDD, 0xFD,
+ 0x57, 0xD7, 0x77, 0xF7, 0xFF, 0x7D, 0x5F, 0xDF, 0x7F,
+ /* Table set A, code table 6, wordlen 2 - 25 entries */
+ 0x00, 0x08, 0x38, 0x01, 0x07, 0x39, 0x0F, 0x09, 0x3F, 0x10, 0x30, 0x31,
+ 0x02, 0x3A, 0x06, 0x0E, 0x17, 0x37, 0x11, 0x0A, 0x32, 0x16, 0x3E, 0x12,
+ 0x36,
+ /* Table set A, code table 6, wordlen 3 - 256 entries */
+ 0x00, 0x40, 0x10, 0x50, 0x04, 0x44, 0x14, 0x01, 0x41, 0x05, 0x45, 0x55,
+ 0x54, 0x11, 0x51, 0x15, 0x80, 0x90, 0x60, 0x24, 0x64, 0xA4, 0x48, 0x61,
+ 0x95, 0x25, 0xA5, 0x02, 0x42, 0x52, 0x16, 0x56, 0x20, 0x84, 0x94, 0x18,
+ 0x58, 0x81, 0x91, 0x85, 0x65, 0x09, 0x49, 0x19, 0x59, 0x99, 0x29, 0x69,
+ 0x79, 0x5D, 0x12, 0x62, 0x06, 0x46, 0x86, 0x66, 0x1A, 0x5A, 0x6A, 0x47,
+ 0x17, 0xC0, 0xA0, 0xE0, 0xC4, 0xD4, 0x74, 0x08, 0x78, 0x0C, 0x4C, 0x1C,
+ 0x5C, 0xD1, 0x21, 0xE1, 0x71, 0xC5, 0xE5, 0x75, 0xB5, 0x89, 0xBD, 0x92,
+ 0x22, 0x96, 0xA6, 0x36, 0x0A, 0x4A, 0x8A, 0x9A, 0x2A, 0x7A, 0xDE, 0x6E,
+ 0x43, 0x13, 0x53, 0x23, 0x07, 0x77, 0x4B, 0x1B, 0x9B, 0x6B, 0x2F, 0xD0,
+ 0x30, 0x70, 0xE4, 0x34, 0xF4, 0xC8, 0x98, 0x28, 0x68, 0xA8, 0xE8, 0x38,
+ 0xB8, 0xF8, 0x9C, 0x2C, 0x6C, 0x7C, 0xA1, 0xB1, 0xD5, 0x35, 0xC9, 0xD9,
+ 0xA9, 0xE9, 0x39, 0xB9, 0xF9, 0xCD, 0x1D, 0x2D, 0xAD, 0x7D, 0xC2, 0xD2,
+ 0xA2, 0xB2, 0xF2, 0xC6, 0x26, 0x76, 0xB6, 0xDA, 0xAA, 0xEA, 0x3A, 0xFA,
+ 0x0E, 0x4E, 0x2E, 0x7E, 0xBE, 0xFE, 0x03, 0x83, 0x63, 0xA3, 0xB3, 0x87,
+ 0x57, 0x97, 0xD7, 0x27, 0x0B, 0x8B, 0x5B, 0x2B, 0xAB, 0xCF, 0x1F, 0x9F,
+ 0x7F, 0xBF, 0xB0, 0xF0, 0xB4, 0x88, 0xD8, 0x8C, 0xCC, 0xDC, 0xAC, 0xEC,
+ 0x3C, 0xBC, 0xFC, 0xC1, 0x31, 0xF1, 0xF5, 0x0D, 0x4D, 0x8D, 0x9D, 0xDD,
+ 0x6D, 0xED, 0x3D, 0xFD, 0x82, 0xE2, 0x32, 0x72, 0xD6, 0xE6, 0xF6, 0xCA,
+ 0xBA, 0x8E, 0xCE, 0x1E, 0x5E, 0x9E, 0xAE, 0xEE, 0x3E, 0xC3, 0x93, 0xD3,
+ 0xE3, 0x33, 0x73, 0xF3, 0xC7, 0x67, 0xA7, 0xE7, 0x37, 0xB7, 0xF7, 0xCB,
+ 0xDB, 0xEB, 0x3B, 0x7B, 0xBB, 0xFB, 0x0F, 0x4F, 0x8F, 0x5F, 0xDF, 0x6F,
+ 0xAF, 0xEF, 0x3F, 0xFF,
+ /* Table set A, code table 6, wordlen 4 - 121 entries */
+ 0x00, 0x10, 0x20, 0xE0, 0xF0, 0x02, 0x0E, 0xEF, 0x30, 0x01, 0x11, 0x21,
+ 0x31, 0xF1, 0x12, 0xF2, 0x1E, 0xEE, 0xDF, 0xFF, 0x40, 0xC0, 0xD0, 0xD1,
+ 0xE1, 0x22, 0x32, 0x42, 0xD2, 0xE2, 0x03, 0x13, 0x23, 0xB3, 0xC3, 0xE3,
+ 0xF3, 0xE4, 0x05, 0xF5, 0x2B, 0x0C, 0xFC, 0x1D, 0x2D, 0xBD, 0xDD, 0xFD,
+ 0x2E, 0x4E, 0xDE, 0xFE, 0x0F, 0x1F, 0x2F, 0x3F, 0x50, 0xB0, 0x41, 0x51,
+ 0xB1, 0xC1, 0x52, 0xB2, 0xC2, 0x33, 0x43, 0x53, 0xD3, 0x04, 0x14, 0x24,
+ 0x34, 0x44, 0x54, 0xB4, 0xC4, 0xD4, 0xF4, 0x15, 0x25, 0x35, 0x45, 0x55,
+ 0xB5, 0xC5, 0xD5, 0xE5, 0x0B, 0x1B, 0x3B, 0x4B, 0x5B, 0xBB, 0xCB, 0xDB,
+ 0xEB, 0xFB, 0x1C, 0x2C, 0x3C, 0x4C, 0x5C, 0xBC, 0xCC, 0xDC, 0xEC, 0x0D,
+ 0x3D, 0x4D, 0x5D, 0xCD, 0xED, 0x3E, 0x5E, 0xBE, 0xCE, 0x4F, 0xCF, 0x5F,
+ 0xBF,
+ /* Table set A, code table 6, wordlen 5 - 15 entries */
+ 0x00, 0x01, 0x0F, 0x0E, 0x02, 0x03, 0x0D, 0x04, 0x06, 0x0A, 0x0C, 0x05,
+ 0x07, 0x09, 0x0B,
+ /* Table set A, code table 6, wordlen 6 - 31 entries */
+ 0x00, 0x01, 0x1F, 0x02, 0x1E, 0x03, 0x04, 0x0F, 0x11, 0x1C, 0x1D, 0x05,
+ 0x06, 0x07, 0x08, 0x18, 0x19, 0x1A, 0x1B, 0x09, 0x0A, 0x0B, 0x15, 0x16,
+ 0x17, 0x0C, 0x13, 0x14, 0x0D, 0x0E, 0x12,
+ /* Table set A, code table 6, wordlen 7 - 63 entries */
+ 0x00, 0x01, 0x02, 0x3E, 0x3F, 0x03, 0x04, 0x3C, 0x3D, 0x05, 0x06, 0x07,
+ 0x39, 0x3A, 0x3B, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x1A, 0x26, 0x34,
+ 0x35, 0x36, 0x37, 0x38, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x19, 0x1B,
+ 0x1C, 0x1D, 0x1E, 0x1F, 0x21, 0x22, 0x23, 0x24, 0x25, 0x27, 0x2D, 0x2E,
+ 0x2F, 0x30, 0x31, 0x32, 0x33, 0x14, 0x15, 0x16, 0x17, 0x18, 0x28, 0x29,
+ 0x2A, 0x2B, 0x2C,
+ /* Table set A, code table 7, wordlen 1 - 4 entries */
+ 0x00, 0x01, 0x02, 0x03,
+ /* Table set A, code table 7, wordlen 2 - 81 entries */
+ 0x00, 0x40, 0x10, 0x04, 0x01, 0x50, 0x44, 0x14, 0x54, 0x41, 0x11, 0x05,
+ 0x15, 0x51, 0x45, 0x55, 0x80, 0x90, 0x20, 0x64, 0x08, 0x19, 0x02, 0x06,
+ 0x60, 0x84, 0x94, 0x24, 0x48, 0x18, 0x58, 0x81, 0x91, 0x21, 0x61, 0x85,
+ 0x95, 0x25, 0x65, 0x09, 0x49, 0x59, 0x42, 0x12, 0x52, 0x46, 0x16, 0x56,
+ 0xA0, 0xA4, 0x98, 0x28, 0x68, 0xA1, 0xA5, 0x99, 0x29, 0x69, 0x96, 0x26,
+ 0x66, 0x0A, 0x4A, 0x1A, 0x5A, 0x88, 0xA8, 0x89, 0xA9, 0x82, 0x92, 0x22,
+ 0x62, 0x86, 0xA6, 0x2A, 0x6A, 0xA2, 0x8A, 0x9A, 0xAA,
+ /* Table set A, code table 7, wordlen 3 - 49 entries */
+ 0x00, 0x08, 0x38, 0x01, 0x39, 0x07, 0x0F, 0x09, 0x3F, 0x10, 0x30, 0x31,
+ 0x02, 0x3A, 0x06, 0x0E, 0x17, 0x11, 0x0A, 0x32, 0x0D, 0x16, 0x3E, 0x37,
+ 0x18, 0x28, 0x19, 0x29, 0x12, 0x2A, 0x03, 0x3B, 0x05, 0x15, 0x1E, 0x1F,
+ 0x2F, 0x1A, 0x0B, 0x2B, 0x33, 0x35, 0x3D, 0x2E, 0x36, 0x13, 0x1B, 0x1D,
+ 0x2D,
+ /* Table set A, code table 7, wordlen 4 - 121 entries */
+ 0x00, 0x10, 0xF0, 0x01, 0x0F, 0x11, 0xF1, 0x1F, 0xFF, 0x20, 0xE0, 0x02,
+ 0xF2, 0x0E, 0x21, 0xE1, 0x12, 0xE2, 0x1E, 0x2E, 0xFE, 0x2F, 0xEF, 0x30,
+ 0x50, 0xB0, 0xC0, 0xD0, 0x31, 0xB1, 0xD1, 0x22, 0xD2, 0x03, 0x13, 0xE3,
+ 0xF3, 0xF4, 0x05, 0xE5, 0xF5, 0x0B, 0x1B, 0x0C, 0x0D, 0x1D, 0x2D, 0xFD,
+ 0x3E, 0xEE, 0x3F, 0x5F, 0xDF, 0x40, 0x41, 0x51, 0xC1, 0x32, 0x42, 0x52,
+ 0xB2, 0xC2, 0x23, 0x33, 0xB3, 0xC3, 0xD3, 0x04, 0x14, 0x24, 0xD4, 0xE4,
+ 0x15, 0x25, 0xC5, 0xD5, 0x2B, 0x3B, 0xEB, 0xFB, 0x1C, 0x2C, 0x3C, 0x5C,
+ 0xEC, 0xFC, 0x3D, 0x5D, 0xDD, 0xED, 0x4E, 0x5E, 0xBE, 0xCE, 0xDE, 0x4F,
+ 0xBF, 0xCF, 0x43, 0x53, 0x34, 0x54, 0xB4, 0xC4, 0x35, 0x45, 0x55, 0xB5,
+ 0x4B, 0x5B, 0xCB, 0xDB, 0x4C, 0xBC, 0xCC, 0xDC, 0x4D, 0xBD, 0xCD, 0x44,
+ 0xBB,
+ /* Table set A, code table 7, wordlen 5 - 15 entries */
+ 0x00, 0x01, 0x0E, 0x0F, 0x02, 0x03, 0x0D, 0x04, 0x06, 0x0A, 0x0C, 0x05,
+ 0x07, 0x09, 0x0B,
+ /* Table set A, code table 7, wordlen 6 - 256 entries */
+ 0x00, 0x10, 0x01, 0x11, 0x20, 0x21, 0x02, 0x12, 0x30, 0x31, 0x41, 0x22,
+ 0x03, 0x13, 0x23, 0x14, 0x40, 0x51, 0x61, 0x32, 0x42, 0x33, 0x04, 0x24,
+ 0x15, 0x16, 0x50, 0x60, 0xD0, 0x71, 0x81, 0xD1, 0xE1, 0xF1, 0x52, 0x62,
+ 0x72, 0xD2, 0x43, 0x53, 0x63, 0xD3, 0x34, 0x44, 0x54, 0x05, 0x25, 0x35,
+ 0x45, 0x06, 0x26, 0x36, 0x17, 0x27, 0x18, 0x0D, 0x1D, 0x2D, 0x3D, 0x1E,
+ 0x2E, 0x1F, 0x70, 0x80, 0xE0, 0xF0, 0x91, 0xA1, 0xC1, 0x82, 0x92, 0xC2,
+ 0xE2, 0xF2, 0x73, 0x83, 0x93, 0xE3, 0xF3, 0x64, 0x74, 0x84, 0xD4, 0xE4,
+ 0xF4, 0x55, 0x65, 0xD5, 0xE5, 0xF5, 0x46, 0x56, 0x66, 0xD6, 0x07, 0x37,
+ 0x47, 0x57, 0x08, 0x28, 0x38, 0x48, 0x19, 0x29, 0x39, 0x1A, 0x2A, 0x1B,
+ 0x1C, 0x2C, 0x3C, 0x4D, 0x5D, 0x6D, 0x0E, 0x3E, 0x4E, 0x5E, 0x0F, 0x2F,
+ 0x3F, 0x4F, 0x90, 0xA0, 0xB0, 0xC0, 0xB1, 0xA2, 0xB2, 0xA3, 0xB3, 0xC3,
+ 0x94, 0xA4, 0xB4, 0xC4, 0x75, 0x85, 0x95, 0xA5, 0xC5, 0x76, 0x86, 0x96,
+ 0xE6, 0xF6, 0x67, 0x77, 0x87, 0xD7, 0xE7, 0xF7, 0x58, 0x68, 0x78, 0x88,
+ 0xD8, 0xE8, 0xF8, 0x09, 0x49, 0x59, 0x69, 0xD9, 0xE9, 0xF9, 0x0A, 0x3A,
+ 0x4A, 0x5A, 0xDA, 0xEA, 0x0B, 0x2B, 0x3B, 0x4B, 0xDB, 0x0C, 0x4C, 0x5C,
+ 0x6C, 0xDC, 0x7D, 0x8D, 0x9D, 0xAD, 0xBD, 0xCD, 0x6E, 0x7E, 0x8E, 0x9E,
+ 0xAE, 0xBE, 0x5F, 0x6F, 0x7F, 0x8F, 0x9F, 0xAF, 0xB5, 0xA6, 0xB6, 0xC6,
+ 0x97, 0xA7, 0xC7, 0x98, 0xA8, 0xB8, 0xC8, 0x79, 0x89, 0x99, 0xA9, 0xB9,
+ 0xC9, 0x6A, 0x7A, 0x8A, 0x9A, 0xAA, 0xCA, 0xFA, 0x5B, 0x6B, 0x7B, 0x8B,
+ 0xCB, 0xEB, 0xFB, 0x7C, 0x8C, 0x9C, 0xAC, 0xBC, 0xEC, 0xFC, 0xDD, 0xED,
+ 0xFD, 0xCE, 0xDE, 0xEE, 0xFE, 0xBF, 0xCF, 0xDF, 0xB7, 0xBA, 0x9B, 0xAB,
+ 0xBB, 0xCC, 0xEF, 0xFF,
+ /* Table set B, code table 0, wordlen 1 - 81 entries */
+ 0x00, 0x01, 0x03, 0x40, 0xC0, 0x10, 0x30, 0x04, 0x0C, 0x50, 0xD0, 0x70,
+ 0xF0, 0x34, 0x1C, 0x05, 0x0D, 0x13, 0x07, 0x0F, 0x44, 0xC4, 0x14, 0x4C,
+ 0xCC, 0x3C, 0x41, 0xC1, 0x11, 0x31, 0x43, 0xC3, 0x33, 0x54, 0x74, 0xDC,
+ 0xFC, 0x71, 0x15, 0x4D, 0x1D, 0xD3, 0xC7, 0x37, 0x3F, 0xD4, 0xF4, 0x5C,
+ 0x7C, 0x51, 0xD1, 0xF1, 0x45, 0xC5, 0x55, 0x35, 0xCD, 0xDD, 0x3D, 0x53,
+ 0x73, 0xF3, 0x47, 0x17, 0x77, 0x4F, 0xCF, 0x1F, 0xFF, 0xF5, 0x7D, 0xD7,
+ 0x5F, 0xD5, 0x75, 0x5D, 0xFD, 0x57, 0xF7, 0xDF, 0x7F,
+ /* Table set B, code table 0, wordlen 2 - 81 entries */
+ 0x00, 0x40, 0x10, 0x04, 0x01, 0x50, 0x44, 0x14, 0x54, 0x41, 0x11, 0x05,
+ 0x15, 0x80, 0x51, 0x45, 0x55, 0x90, 0x20, 0x60, 0x24, 0x08, 0x18, 0x09,
+ 0x02, 0x06, 0x84, 0x94, 0x64, 0x48, 0x58, 0x81, 0x91, 0x21, 0x61, 0x95,
+ 0x25, 0x65, 0x19, 0x59, 0x42, 0x12, 0x46, 0x16, 0x56, 0xA0, 0xA4, 0x28,
+ 0x68, 0x85, 0xA5, 0x49, 0x29, 0x69, 0x52, 0x0A, 0x1A, 0x5A, 0x88, 0x98,
+ 0xA1, 0x89, 0x99, 0xA9, 0x22, 0x62, 0x96, 0x26, 0x66, 0x4A, 0x6A, 0xA8,
+ 0x82, 0x92, 0xA2, 0x86, 0xA6, 0x8A, 0x9A, 0x2A, 0xAA,
+ /* Table set B, code table 0, wordlen 3 - 49 entries */
+ 0x00, 0x08, 0x38, 0x01, 0x07, 0x30, 0x09, 0x39, 0x0F, 0x3F, 0x10, 0x18,
+ 0x28, 0x31, 0x02, 0x3A, 0x03, 0x05, 0x06, 0x0E, 0x17, 0x37, 0x11, 0x19,
+ 0x29, 0x0A, 0x32, 0x0B, 0x3B, 0x0D, 0x15, 0x3D, 0x3E, 0x1F, 0x2F, 0x12,
+ 0x1A, 0x2A, 0x13, 0x1B, 0x2B, 0x33, 0x1D, 0x2D, 0x35, 0x16, 0x1E, 0x2E,
+ 0x36,
+ /* Table set B, code table 0, wordlen 4 - 121 entries */
+ 0x00, 0x10, 0xF0, 0x01, 0x0F, 0x11, 0xF1, 0x1F, 0xFF, 0x20, 0xE0, 0x02,
+ 0xF2, 0x0E, 0x21, 0xE1, 0x12, 0xE2, 0x1E, 0x2E, 0xFE, 0x2F, 0xEF, 0x30,
+ 0x50, 0xB0, 0xC0, 0xD0, 0x31, 0xB1, 0xD1, 0x22, 0xD2, 0x03, 0x13, 0xE3,
+ 0xF3, 0xF4, 0x05, 0xE5, 0xF5, 0x0B, 0x1B, 0x0C, 0x0D, 0x1D, 0x2D, 0xFD,
+ 0x3E, 0xEE, 0x3F, 0x5F, 0xDF, 0x40, 0x41, 0x51, 0xC1, 0x32, 0x42, 0x52,
+ 0xB2, 0xC2, 0x23, 0x33, 0xB3, 0xC3, 0xD3, 0x04, 0x14, 0x24, 0xD4, 0xE4,
+ 0x15, 0x25, 0xC5, 0xD5, 0x2B, 0x3B, 0xEB, 0xFB, 0x1C, 0x2C, 0x3C, 0x5C,
+ 0xEC, 0xFC, 0x3D, 0x5D, 0xDD, 0xED, 0x4E, 0x5E, 0xBE, 0xCE, 0xDE, 0x4F,
+ 0xBF, 0xCF, 0x43, 0x53, 0x34, 0x54, 0xB4, 0xC4, 0x35, 0x45, 0x55, 0xB5,
+ 0x4B, 0x5B, 0xCB, 0xDB, 0x4C, 0xBC, 0xCC, 0xDC, 0x4D, 0xBD, 0xCD, 0x44,
+ 0xBB,
+ /* Table set B, code table 0, wordlen 5 - 225 entries */
+ 0x00, 0x10, 0xF0, 0x01, 0x0F, 0x11, 0xF1, 0x1F, 0xFF, 0x20, 0xE0, 0x02,
+ 0x0E, 0x30, 0xD0, 0x21, 0xE1, 0x12, 0xF2, 0x03, 0x0D, 0x1E, 0xFE, 0x2F,
+ 0xEF, 0x40, 0x60, 0x70, 0x90, 0xA0, 0xC0, 0x31, 0xD1, 0x22, 0x32, 0xD2,
+ 0xE2, 0x13, 0x23, 0xE3, 0xF3, 0x04, 0x06, 0x07, 0x09, 0x0A, 0x0C, 0x1D,
+ 0x2D, 0xFD, 0x2E, 0x3E, 0xEE, 0x3F, 0xDF, 0x50, 0xB0, 0x41, 0x51, 0x61,
+ 0x71, 0x91, 0xA1, 0xB1, 0xC1, 0x42, 0x62, 0x72, 0x92, 0xA2, 0xC2, 0x33,
+ 0x93, 0xA3, 0xD3, 0x14, 0x24, 0xE4, 0xF4, 0x05, 0x15, 0xF5, 0x16, 0x26,
+ 0xD6, 0xE6, 0xF6, 0x17, 0x27, 0xD7, 0xE7, 0xF7, 0x19, 0x29, 0x39, 0xE9,
+ 0xF9, 0x1A, 0x2A, 0xEA, 0xFA, 0x0B, 0x1B, 0xFB, 0x1C, 0x2C, 0xEC, 0xFC,
+ 0x3D, 0x7D, 0x9D, 0xDD, 0xED, 0x4E, 0x6E, 0x7E, 0x9E, 0xAE, 0xCE, 0xDE,
+ 0x4F, 0x5F, 0x6F, 0x7F, 0x9F, 0xAF, 0xBF, 0xCF, 0x52, 0xB2, 0x43, 0x53,
+ 0x63, 0x73, 0xB3, 0xC3, 0x34, 0x44, 0x64, 0x74, 0x94, 0xA4, 0xB4, 0xC4,
+ 0xD4, 0x25, 0x35, 0x65, 0x75, 0x95, 0xA5, 0xD5, 0xE5, 0x36, 0x46, 0x56,
+ 0x66, 0xA6, 0xB6, 0xC6, 0x37, 0x47, 0x57, 0xB7, 0xC7, 0x49, 0x59, 0x69,
+ 0xB9, 0xC9, 0xD9, 0x3A, 0x4A, 0x5A, 0x6A, 0xAA, 0xBA, 0xCA, 0xDA, 0x2B,
+ 0x3B, 0x6B, 0x7B, 0x9B, 0xAB, 0xDB, 0xEB, 0x3C, 0x4C, 0x6C, 0x7C, 0x9C,
+ 0xAC, 0xCC, 0xDC, 0x4D, 0x5D, 0x6D, 0xAD, 0xBD, 0xCD, 0x5E, 0xBE, 0x54,
+ 0x45, 0x55, 0xB5, 0xC5, 0x76, 0x96, 0x67, 0x77, 0x97, 0xA7, 0x79, 0x99,
+ 0xA9, 0x7A, 0x9A, 0x4B, 0x5B, 0xBB, 0xCB, 0x5C, 0xBC,
+ /* Table set B, code table 0, wordlen 7 - 63 entries */
+ 0x00, 0x01, 0x3F, 0x02, 0x3E, 0x03, 0x04, 0x3C, 0x3D, 0x05, 0x06, 0x07,
+ 0x08, 0x38, 0x39, 0x3A, 0x3B, 0x09, 0x0A, 0x0B, 0x0C, 0x19, 0x1A, 0x1B,
+ 0x1C, 0x1D, 0x1E, 0x1F, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x33,
+ 0x34, 0x35, 0x36, 0x37, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x2D,
+ 0x2E, 0x2F, 0x30, 0x31, 0x32, 0x14, 0x15, 0x16, 0x17, 0x18, 0x28, 0x29,
+ 0x2A, 0x2B, 0x2C,
+ /* Table set B, code table 1, wordlen 2 - 81 entries */
+ 0x00, 0x40, 0x04, 0x01, 0x10, 0x50, 0x44, 0x14, 0x54, 0x41, 0x11, 0x51,
+ 0x05, 0x45, 0x15, 0x55, 0x80, 0x90, 0x20, 0x60, 0x84, 0x94, 0x24, 0x64,
+ 0x08, 0x48, 0x18, 0x81, 0x91, 0x61, 0x85, 0x95, 0x25, 0x65, 0x09, 0x49,
+ 0x19, 0x59, 0x02, 0x42, 0x12, 0x52, 0x06, 0x46, 0x16, 0x56, 0xA4, 0x58,
+ 0x68, 0x21, 0xA5, 0x29, 0x69, 0x1A, 0x5A, 0xA0, 0x88, 0x98, 0x28, 0xA1,
+ 0x89, 0x99, 0xA9, 0x92, 0x22, 0x62, 0x86, 0x96, 0x26, 0x66, 0x0A, 0x4A,
+ 0x6A, 0xA8, 0x82, 0xA2, 0xA6, 0x8A, 0x9A, 0x2A, 0xAA,
+ /* Table set B, code table 1, wordlen 4 - 121 entries */
+ 0x00, 0x10, 0xF0, 0x01, 0x0F, 0xF1, 0x1F, 0xFF, 0x20, 0xE0, 0x11, 0x02,
+ 0x0E, 0x30, 0x50, 0xB0, 0xD0, 0x21, 0xE1, 0x12, 0xF2, 0x03, 0x05, 0x0B,
+ 0x0D, 0x1E, 0xFE, 0x2F, 0xEF, 0x40, 0xC0, 0x31, 0x51, 0xB1, 0xC1, 0xD1,
+ 0x22, 0x52, 0xE2, 0x13, 0xF3, 0x04, 0x15, 0xF5, 0x1B, 0xEB, 0xFB, 0x0C,
+ 0x1D, 0xFD, 0x2E, 0x5E, 0xEE, 0x3F, 0x5F, 0xBF, 0xDF, 0x41, 0x32, 0x42,
+ 0xB2, 0xD2, 0x23, 0x53, 0xB3, 0xE3, 0x14, 0x24, 0xE4, 0xF4, 0x25, 0x35,
+ 0xD5, 0xE5, 0x2B, 0x3B, 0xDB, 0x1C, 0x2C, 0xBC, 0xEC, 0xFC, 0x2D, 0xBD,
+ 0xED, 0x3E, 0x4E, 0xBE, 0xDE, 0x4F, 0xCF, 0xC2, 0x33, 0x43, 0xC3, 0xD3,
+ 0x34, 0x44, 0x54, 0xB4, 0xD4, 0x45, 0x55, 0xC5, 0x4B, 0xCB, 0x3C, 0x4C,
+ 0x5C, 0xCC, 0xDC, 0x3D, 0x4D, 0x5D, 0xCD, 0xDD, 0xCE, 0xC4, 0xB5, 0x5B,
+ 0xBB,
+ /* Table set B, code table 1, wordlen 6 - 256 entries */
+ 0x00, 0x10, 0x01, 0x11, 0x20, 0x21, 0x02, 0x12, 0x30, 0x31, 0x41, 0x22,
+ 0x32, 0x03, 0x13, 0x23, 0x14, 0x40, 0x51, 0x61, 0x42, 0x52, 0x33, 0x43,
+ 0x04, 0x24, 0x34, 0x15, 0x25, 0x16, 0x50, 0x60, 0x70, 0x71, 0x81, 0xD1,
+ 0xE1, 0x62, 0x72, 0x82, 0xD2, 0x53, 0x63, 0x73, 0xD3, 0x44, 0x54, 0x05,
+ 0x35, 0x45, 0x55, 0x06, 0x26, 0x36, 0x07, 0x17, 0x27, 0x37, 0x18, 0x28,
+ 0x19, 0x1D, 0x2D, 0x3D, 0x1E, 0x2E, 0x1F, 0x80, 0x90, 0xD0, 0xE0, 0xF0,
+ 0x91, 0xA1, 0xB1, 0xC1, 0xF1, 0x92, 0xA2, 0xB2, 0xC2, 0xE2, 0xF2, 0x83,
+ 0x93, 0xA3, 0xC3, 0xE3, 0xF3, 0x64, 0x74, 0x84, 0x94, 0xD4, 0xE4, 0xF4,
+ 0x65, 0x75, 0x85, 0xD5, 0xE5, 0x46, 0x56, 0x66, 0x76, 0xD6, 0xE6, 0x47,
+ 0x57, 0x67, 0xD7, 0x08, 0x38, 0x48, 0x58, 0x09, 0x29, 0x39, 0x49, 0x0A,
+ 0x1A, 0x2A, 0x3A, 0x1B, 0x2B, 0x0C, 0x1C, 0x2C, 0x3C, 0x0D, 0x4D, 0x5D,
+ 0x6D, 0x7D, 0x0E, 0x3E, 0x4E, 0x5E, 0x6E, 0x0F, 0x2F, 0x3F, 0x4F, 0xA0,
+ 0xB0, 0xC0, 0xB3, 0xA4, 0xB4, 0xC4, 0x95, 0xA5, 0xB5, 0xC5, 0xF5, 0x86,
+ 0x96, 0xA6, 0xB6, 0xC6, 0xF6, 0x77, 0x87, 0x97, 0xA7, 0xC7, 0xE7, 0xF7,
+ 0x68, 0x78, 0x88, 0x98, 0xD8, 0xE8, 0xF8, 0x59, 0x69, 0x79, 0x89, 0xD9,
+ 0xE9, 0xF9, 0x4A, 0x5A, 0x6A, 0x7A, 0xDA, 0xEA, 0x0B, 0x3B, 0x4B, 0x5B,
+ 0xDB, 0xEB, 0x4C, 0x5C, 0x6C, 0x7C, 0x8C, 0xDC, 0x8D, 0x9D, 0xAD, 0xBD,
+ 0xCD, 0x7E, 0x8E, 0x9E, 0xAE, 0xBE, 0x5F, 0x6F, 0x7F, 0x8F, 0x9F, 0xB7,
+ 0xA8, 0xB8, 0xC8, 0x99, 0xA9, 0xB9, 0xC9, 0x8A, 0x9A, 0xAA, 0xBA, 0xCA,
+ 0xFA, 0x6B, 0x7B, 0x8B, 0x9B, 0xAB, 0xBB, 0xCB, 0xFB, 0x9C, 0xAC, 0xBC,
+ 0xCC, 0xEC, 0xFC, 0xDD, 0xED, 0xFD, 0xCE, 0xDE, 0xEE, 0xFE, 0xAF, 0xBF,
+ 0xCF, 0xDF, 0xEF, 0xFF,
+ /* Table set B, code table 2, wordlen 6 - 256 entries */
+ 0x00, 0x01, 0x10, 0x11, 0x20, 0x21, 0x02, 0x12, 0x30, 0x31, 0x22, 0x03,
+ 0x13, 0x40, 0x41, 0x51, 0x32, 0x42, 0x23, 0x33, 0x04, 0x14, 0x24, 0x15,
+ 0x50, 0x61, 0x71, 0xD1, 0xE1, 0x52, 0x62, 0xD2, 0x43, 0x53, 0xD3, 0x34,
+ 0x44, 0x05, 0x25, 0x35, 0x06, 0x16, 0x26, 0x17, 0x18, 0x1D, 0x2D, 0x3D,
+ 0x1E, 0x2E, 0x60, 0x70, 0x80, 0xD0, 0xE0, 0xF0, 0x81, 0x91, 0xA1, 0xC1,
+ 0xF1, 0x72, 0x82, 0x92, 0xC2, 0xE2, 0xF2, 0x63, 0x73, 0xE3, 0xF3, 0x54,
+ 0x64, 0x74, 0xD4, 0xE4, 0xF4, 0x45, 0x55, 0x65, 0xD5, 0xE5, 0xF5, 0x36,
+ 0x46, 0x56, 0xD6, 0xE6, 0x07, 0x27, 0x37, 0x47, 0xD7, 0x08, 0x28, 0x38,
+ 0x19, 0x29, 0x1A, 0x1B, 0x1C, 0x2C, 0x0D, 0x4D, 0x5D, 0x6D, 0x7D, 0x0E,
+ 0x3E, 0x4E, 0x5E, 0x6E, 0x0F, 0x1F, 0x2F, 0x3F, 0x4F, 0x90, 0xA0, 0xC0,
+ 0xB1, 0xA2, 0xB2, 0x83, 0x93, 0xA3, 0xB3, 0xC3, 0x84, 0x94, 0xA4, 0xC4,
+ 0x75, 0x85, 0x95, 0xC5, 0x66, 0x76, 0x86, 0x96, 0xC6, 0xF6, 0x57, 0x67,
+ 0x77, 0xE7, 0xF7, 0x48, 0x58, 0x68, 0x78, 0xD8, 0xE8, 0xF8, 0x09, 0x39,
+ 0x49, 0x59, 0xD9, 0xE9, 0xF9, 0x0A, 0x2A, 0x3A, 0x4A, 0xDA, 0xEA, 0x0B,
+ 0x2B, 0x3B, 0xDB, 0xEB, 0x0C, 0x3C, 0x4C, 0x5C, 0x6C, 0xDC, 0x8D, 0x9D,
+ 0xAD, 0xBD, 0xCD, 0x7E, 0x8E, 0x9E, 0xAE, 0xBE, 0xCE, 0x5F, 0x6F, 0x7F,
+ 0x8F, 0x9F, 0xAF, 0xB0, 0xB4, 0xA5, 0xB5, 0xA6, 0xB6, 0x87, 0x97, 0xA7,
+ 0xB7, 0xC7, 0x88, 0x98, 0xA8, 0xC8, 0x69, 0x79, 0x89, 0x99, 0xA9, 0xC9,
+ 0x5A, 0x6A, 0x7A, 0x9A, 0xCA, 0xFA, 0x4B, 0x5B, 0x6B, 0x7B, 0xCB, 0xFB,
+ 0x7C, 0x8C, 0x9C, 0xAC, 0xBC, 0xCC, 0xEC, 0xFC, 0xDD, 0xED, 0xFD, 0xDE,
+ 0xEE, 0xFE, 0xBF, 0xCF, 0xDF, 0xEF, 0xB8, 0xB9, 0x8A, 0xAA, 0xBA, 0x8B,
+ 0x9B, 0xAB, 0xBB, 0xFF,
+ /* Table set B, code table 3, wordlen 2 - 81 entries */
+ 0x00, 0x40, 0x10, 0x04, 0x01, 0x50, 0x44, 0x14, 0x41, 0x11, 0x05, 0x80,
+ 0x54, 0x51, 0x45, 0x15, 0x55, 0x02, 0x90, 0x20, 0x60, 0x84, 0x24, 0x08,
+ 0x18, 0x09, 0x12, 0x06, 0xA0, 0x94, 0x64, 0x48, 0x58, 0x81, 0x91, 0x21,
+ 0x61, 0x85, 0x95, 0x25, 0x65, 0x49, 0x19, 0x59, 0x42, 0x52, 0x46, 0x16,
+ 0x56, 0x0A, 0xA4, 0x28, 0x68, 0xA1, 0xA5, 0x29, 0x69, 0x26, 0x4A, 0x1A,
+ 0x5A, 0x88, 0x98, 0xA8, 0x89, 0x99, 0xA9, 0x82, 0x92, 0x22, 0x62, 0x86,
+ 0x96, 0x66, 0x9A, 0x2A, 0x6A, 0xA2, 0xA6, 0x8A, 0xAA,
+ /* Table set B, code table 3, wordlen 3 - 256 entries */
+ 0x00, 0x40, 0x10, 0x04, 0x01, 0x50, 0x44, 0x14, 0x54, 0x41, 0x11, 0x51,
+ 0x05, 0x45, 0x15, 0x55, 0x20, 0x95, 0x65, 0x49, 0x59, 0x52, 0x46, 0x16,
+ 0x80, 0x90, 0x60, 0x84, 0x94, 0x24, 0x64, 0xA4, 0x08, 0x48, 0x18, 0x58,
+ 0x81, 0x91, 0x21, 0x61, 0x85, 0x25, 0x09, 0x19, 0x69, 0x02, 0x42, 0x12,
+ 0x06, 0x56, 0x5A, 0x57, 0xD0, 0x74, 0x68, 0x5C, 0xC1, 0xD5, 0xA5, 0xE5,
+ 0x75, 0xB5, 0xF5, 0x99, 0xD9, 0xA9, 0xE9, 0x79, 0xB9, 0xF9, 0x1D, 0x5D,
+ 0x9D, 0xDD, 0x6D, 0xAD, 0xED, 0x7D, 0xBD, 0xFD, 0x82, 0x92, 0xD2, 0x62,
+ 0x96, 0xD6, 0x26, 0x66, 0xA6, 0xE6, 0x76, 0xB6, 0xF6, 0x0A, 0x4A, 0x1A,
+ 0x9A, 0xDA, 0x2A, 0x6A, 0xAA, 0xEA, 0x7A, 0xBA, 0xFA, 0x5E, 0x9E, 0xDE,
+ 0x6E, 0xAE, 0xEE, 0x7E, 0xBE, 0xFE, 0x03, 0x13, 0x53, 0x17, 0x97, 0xD7,
+ 0x67, 0xA7, 0xE7, 0x77, 0xB7, 0xF7, 0x5B, 0x9B, 0xDB, 0x6B, 0xAB, 0xEB,
+ 0x7B, 0xBB, 0xFB, 0x5F, 0x9F, 0xDF, 0x6F, 0xAF, 0xEF, 0x7F, 0xBF, 0xFF,
+ 0xC0, 0xA0, 0xE0, 0x30, 0xC4, 0xD4, 0xE4, 0x34, 0xB4, 0xF4, 0x88, 0xC8,
+ 0x98, 0xD8, 0x28, 0xA8, 0xE8, 0x38, 0x78, 0xB8, 0xF8, 0x0C, 0x4C, 0x1C,
+ 0x9C, 0xDC, 0x6C, 0xAC, 0xEC, 0x7C, 0xBC, 0xFC, 0xD1, 0xA1, 0xE1, 0x31,
+ 0x71, 0xB1, 0xF1, 0xC5, 0x35, 0x89, 0xC9, 0x29, 0x39, 0x0D, 0x4D, 0x8D,
+ 0xCD, 0x2D, 0x3D, 0x22, 0xA2, 0xE2, 0x72, 0xB2, 0xF2, 0x86, 0xC6, 0x36,
+ 0x8A, 0xCA, 0x3A, 0x0E, 0x4E, 0x8E, 0xCE, 0x1E, 0x2E, 0x3E, 0x43, 0x83,
+ 0x93, 0xD3, 0x23, 0x63, 0xA3, 0xE3, 0x73, 0xB3, 0xF3, 0x07, 0x47, 0x87,
+ 0xC7, 0x27, 0x37, 0x4B, 0x8B, 0xCB, 0x1B, 0x2B, 0x3B, 0x4F, 0x8F, 0xCF,
+ 0x1F, 0x70, 0xB0, 0xF0, 0x8C, 0xCC, 0x2C, 0x3C, 0xC2, 0x32, 0xC3, 0x0F,
+ 0x2F, 0x3F, 0x33, 0x0B,
+ /* Table set B, code table 3, wordlen 5 - 225 entries */
+ 0x00, 0x10, 0xF0, 0x01, 0x0F, 0x11, 0xF1, 0x02, 0x0E, 0x1F, 0xFF, 0x20,
+ 0xE0, 0x21, 0xF2, 0xFE, 0xEF, 0x30, 0xD0, 0xE1, 0x12, 0x22, 0xE2, 0x03,
+ 0x0D, 0x1D, 0x1E, 0x2E, 0xEE, 0x2F, 0xDF, 0x40, 0x60, 0x70, 0x90, 0xA0,
+ 0xB0, 0xC0, 0x31, 0x71, 0x91, 0xC1, 0xD1, 0x32, 0xD2, 0x13, 0xE3, 0xF3,
+ 0x04, 0x05, 0x06, 0x07, 0x17, 0xF7, 0x09, 0x19, 0x0A, 0x1A, 0xFA, 0x0C,
+ 0x1C, 0x2D, 0xED, 0xFD, 0x3E, 0x7E, 0xDE, 0x3F, 0x6F, 0x7F, 0x9F, 0xAF,
+ 0xCF, 0x50, 0x41, 0x51, 0x61, 0xA1, 0xB1, 0x62, 0x72, 0x92, 0xA2, 0xC2,
+ 0x23, 0x33, 0x63, 0x73, 0x93, 0xA3, 0xD3, 0x14, 0x24, 0x34, 0xD4, 0xE4,
+ 0xF4, 0x15, 0xF5, 0x16, 0x26, 0xD6, 0xE6, 0xF6, 0x27, 0x37, 0x47, 0xE7,
+ 0x29, 0x39, 0xC9, 0xD9, 0xE9, 0xF9, 0x2A, 0xEA, 0x0B, 0x1B, 0xFB, 0x2C,
+ 0x7C, 0xEC, 0xFC, 0x3D, 0x4D, 0x6D, 0x7D, 0xDD, 0x4E, 0x5E, 0x6E, 0x9E,
+ 0xAE, 0xCE, 0x4F, 0x5F, 0x42, 0x52, 0xB2, 0x43, 0xB3, 0xC3, 0x44, 0x64,
+ 0x74, 0x94, 0xA4, 0x25, 0x35, 0x65, 0x75, 0x95, 0xA5, 0xE5, 0x36, 0x46,
+ 0x66, 0x76, 0x96, 0xA6, 0xB6, 0xC6, 0x57, 0xA7, 0xB7, 0xC7, 0xD7, 0x59,
+ 0xA9, 0xB9, 0x3A, 0x4A, 0x6A, 0xCA, 0xDA, 0x2B, 0x3B, 0x6B, 0x9B, 0xAB,
+ 0xDB, 0xEB, 0x3C, 0x6C, 0x9C, 0xAC, 0xCC, 0xDC, 0x5D, 0x9D, 0xAD, 0xBD,
+ 0xCD, 0xBE, 0xBF, 0x53, 0x54, 0xB4, 0xC4, 0x45, 0x55, 0xB5, 0xC5, 0xD5,
+ 0x56, 0x67, 0x77, 0x97, 0x49, 0x69, 0x79, 0x99, 0x5A, 0x7A, 0x9A, 0xAA,
+ 0xBA, 0x4B, 0x5B, 0x7B, 0xBB, 0xCB, 0x4C, 0x5C, 0xBC,
+ /* Table set B, code table 3, wordlen 7 - 63 entries */
+ 0x00, 0x01, 0x3F, 0x02, 0x3E, 0x03, 0x3D, 0x04, 0x05, 0x06, 0x3A, 0x3B,
+ 0x3C, 0x07, 0x08, 0x09, 0x0A, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x22, 0x23,
+ 0x25, 0x26, 0x27, 0x37, 0x38, 0x39, 0x0B, 0x0D, 0x0E, 0x0F, 0x1E, 0x1F,
+ 0x21, 0x24, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x0C, 0x10, 0x11, 0x12,
+ 0x13, 0x15, 0x29, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30, 0x14, 0x16, 0x17,
+ 0x18, 0x28, 0x2A,
+ /* Table set B, code table 4, wordlen 1 - 81 entries */
+ 0x00, 0x01, 0x40, 0xC0, 0x10, 0x30, 0x04, 0x0C, 0x03, 0x50, 0xD0, 0x70,
+ 0xF0, 0xC4, 0x14, 0x34, 0x4C, 0x1C, 0x3C, 0xC1, 0x11, 0x31, 0x05, 0x0D,
+ 0xC3, 0x13, 0x33, 0x07, 0x0F, 0x44, 0xCC, 0x41, 0x43, 0x54, 0x74, 0xDC,
+ 0xFC, 0x71, 0x15, 0x4D, 0x1D, 0x37, 0x3F, 0xD4, 0xF4, 0x5C, 0x7C, 0x51,
+ 0xD1, 0xF1, 0x45, 0xC5, 0x35, 0xCD, 0xDD, 0x3D, 0x53, 0xD3, 0x73, 0xF3,
+ 0x47, 0xC7, 0x17, 0x77, 0x4F, 0xCF, 0x1F, 0x55, 0xFF, 0xD5, 0x75, 0xF5,
+ 0x5D, 0x7D, 0xFD, 0x57, 0xD7, 0xF7, 0x5F, 0xDF, 0x7F,
+ /* Table set B, code table 4, wordlen 2 - 25 entries */
+ 0x00, 0x07, 0x08, 0x38, 0x01, 0x39, 0x0F, 0x10, 0x09, 0x3F, 0x30, 0x31,
+ 0x02, 0x3A, 0x06, 0x0E, 0x17, 0x11, 0x0A, 0x3E, 0x37, 0x12, 0x32, 0x16,
+ 0x36,
+ /* Table set B, code table 4, wordlen 3 - 49 entries */
+ 0x00, 0x07, 0x08, 0x38, 0x01, 0x09, 0x39, 0x0F, 0x3F, 0x10, 0x30, 0x31,
+ 0x02, 0x3A, 0x06, 0x0E, 0x17, 0x37, 0x18, 0x28, 0x11, 0x19, 0x29, 0x0A,
+ 0x03, 0x0B, 0x3B, 0x05, 0x0D, 0x3D, 0x3E, 0x1F, 0x2F, 0x12, 0x1A, 0x2A,
+ 0x32, 0x13, 0x33, 0x15, 0x35, 0x16, 0x1E, 0x2E, 0x36, 0x1B, 0x2B, 0x1D,
+ 0x2D,
+ /* Table set B, code table 4, wordlen 7 - 63 entries */
+ 0x00, 0x01, 0x02, 0x3E, 0x3F, 0x03, 0x04, 0x3C, 0x3D, 0x05, 0x06, 0x07,
+ 0x39, 0x3A, 0x3B, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x1A, 0x1B, 0x25, 0x26,
+ 0x34, 0x35, 0x36, 0x37, 0x38, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x19,
+ 0x1C, 0x1D, 0x1E, 0x1F, 0x21, 0x22, 0x23, 0x24, 0x27, 0x2E, 0x2F, 0x30,
+ 0x31, 0x32, 0x33, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x28, 0x29, 0x2A,
+ 0x2B, 0x2C, 0x2D,
+ /* Table set B, code table 5, wordlen 2 - 25 entries */
+ 0x00, 0x01, 0x08, 0x38, 0x07, 0x39, 0x0F, 0x30, 0x09, 0x3F, 0x10, 0x31,
+ 0x02, 0x3A, 0x06, 0x0E, 0x17, 0x11, 0x0A, 0x3E, 0x37, 0x12, 0x32, 0x16,
+ 0x36,
+ /* Table set B, code table 5, wordlen 3 - 7 entries */
+ 0x00, 0x07, 0x01, 0x02, 0x03, 0x05, 0x06,
+ /* Table set B, code table 5, wordlen 6 - 31 entries */
+ 0x00, 0x01, 0x1F, 0x02, 0x1E, 0x03, 0x04, 0x0D, 0x1D, 0x05, 0x06, 0x07,
+ 0x0E, 0x0F, 0x11, 0x12, 0x13, 0x1A, 0x1B, 0x1C, 0x08, 0x09, 0x0C, 0x14,
+ 0x15, 0x16, 0x17, 0x18, 0x19, 0x0A, 0x0B,
+ /* Table set B, code table 6, wordlen 2 - 81 entries */
+ 0x00, 0x40, 0x01, 0x10, 0x04, 0x02, 0x80, 0x50, 0x90, 0x05, 0x06, 0x20,
+ 0x60, 0x44, 0x14, 0x54, 0x24, 0x08, 0x18, 0x41, 0x11, 0x15, 0x09, 0xA0,
+ 0x84, 0x94, 0x64, 0xA4, 0x28, 0x51, 0x45, 0x55, 0x19, 0x12, 0x16, 0x0A,
+ 0x1A, 0x48, 0x58, 0x68, 0x81, 0x91, 0x21, 0x61, 0x85, 0x95, 0x25, 0x65,
+ 0x49, 0x59, 0x29, 0x69, 0x42, 0x46, 0x56, 0x88, 0x98, 0xA8, 0xA1, 0xA5,
+ 0x99, 0xA9, 0x52, 0x22, 0x26, 0x66, 0x4A, 0x5A, 0x2A, 0x6A, 0x89, 0x82,
+ 0x92, 0x62, 0x86, 0x96, 0xA6, 0x8A, 0xAA, 0xA2, 0x9A,
+ /* Table set B, code table 6, wordlen 3 - 7 entries */
+ 0x00, 0x01, 0x07, 0x02, 0x03, 0x05, 0x06,
+ /* Table set B, code table 6, wordlen 4 - 6 entries */
+ 0x01, 0x00, 0x02, 0x05, 0x03, 0x04,
+ /* Table set B, code table 6, wordlen 5 - 225 entries */
+ 0x00, 0xF0, 0x01, 0x10, 0x0F, 0x11, 0xF1, 0x20, 0xE0, 0x02, 0x0E, 0x1F,
+ 0xFF, 0xD0, 0x21, 0xE1, 0x12, 0xF2, 0x07, 0x0A, 0x0D, 0x1E, 0xFE, 0x2F,
+ 0xEF, 0x30, 0x70, 0x90, 0xA0, 0xC0, 0x71, 0x91, 0xC1, 0xD1, 0x32, 0x92,
+ 0xE2, 0x03, 0x13, 0x63, 0x04, 0x06, 0xE6, 0xE7, 0xF7, 0x09, 0x19, 0x39,
+ 0xFA, 0x0C, 0x1C, 0xDD, 0xED, 0xFD, 0x2E, 0x7E, 0x9E, 0x3F, 0x9F, 0x40,
+ 0x50, 0x60, 0xB0, 0x31, 0x41, 0x61, 0xA1, 0xB1, 0x22, 0x42, 0x72, 0xA2,
+ 0xB2, 0xC2, 0xD2, 0x23, 0x33, 0x73, 0xA3, 0xC3, 0xD3, 0xE3, 0xF3, 0x14,
+ 0x24, 0x34, 0x44, 0x74, 0xD4, 0xE4, 0x05, 0x25, 0x45, 0x65, 0x95, 0xA5,
+ 0x16, 0x26, 0x46, 0x76, 0xA6, 0xB6, 0xC6, 0xD6, 0xF6, 0x17, 0x27, 0x37,
+ 0x47, 0x67, 0xA7, 0xD7, 0x29, 0x69, 0xB9, 0xD9, 0xE9, 0xF9, 0x1A, 0x2A,
+ 0x3A, 0x9A, 0xCA, 0xDA, 0xEA, 0x0B, 0x1B, 0x3B, 0x6B, 0xEB, 0xFB, 0x2C,
+ 0x6C, 0xEC, 0xFC, 0x1D, 0x2D, 0x4D, 0x6D, 0x9D, 0xAD, 0x3E, 0x4E, 0x6E,
+ 0xAE, 0xCE, 0xEE, 0x4F, 0x5F, 0x6F, 0xDF, 0x51, 0x52, 0x62, 0x43, 0x93,
+ 0xB3, 0x54, 0x94, 0xA4, 0xF4, 0x15, 0x75, 0xB5, 0xE5, 0xF5, 0x36, 0x56,
+ 0x66, 0x96, 0x57, 0x77, 0x49, 0x59, 0xA9, 0xC9, 0x4A, 0x5A, 0x6A, 0x7A,
+ 0xAA, 0xBA, 0x2B, 0x4B, 0x7B, 0x9B, 0xAB, 0xDB, 0x3C, 0x4C, 0x7C, 0x9C,
+ 0xAC, 0xBC, 0xCC, 0x3D, 0x5D, 0x7D, 0xBD, 0xCD, 0x5E, 0xBE, 0xDE, 0xBF,
+ 0xCF, 0x53, 0x64, 0xB4, 0xC4, 0x35, 0x55, 0xC5, 0xD5, 0x97, 0xB7, 0xC7,
+ 0x79, 0x99, 0x5B, 0xBB, 0xCB, 0x5C, 0xDC, 0x7F, 0xAF,
+ /* Table set B, code table 6, wordlen 6 - 256 entries */
+ 0x00, 0x10, 0x01, 0x11, 0x21, 0x02, 0x12, 0x20, 0x22, 0x13, 0x30, 0x31,
+ 0x41, 0xD1, 0xE1, 0x32, 0x52, 0x03, 0x23, 0x2D, 0x40, 0x50, 0x60, 0x80,
+ 0xD0, 0xE0, 0x51, 0x61, 0xF1, 0x42, 0x62, 0xD2, 0xE2, 0xF2, 0x33, 0x43,
+ 0xC3, 0xD3, 0xE3, 0x04, 0x14, 0xD4, 0xF4, 0x25, 0x35, 0x16, 0x17, 0xF7,
+ 0xD8, 0x1C, 0x3C, 0x0D, 0x1D, 0x3D, 0x5D, 0x0E, 0x1E, 0x2E, 0x7E, 0x2F,
+ 0xC0, 0xF0, 0x71, 0x81, 0x91, 0xC1, 0x72, 0x82, 0x92, 0xB2, 0xC2, 0x53,
+ 0x63, 0x73, 0x93, 0xA3, 0xF3, 0x24, 0x44, 0x64, 0x84, 0xA4, 0xB4, 0x05,
+ 0x15, 0x95, 0xD5, 0x06, 0x26, 0x36, 0x46, 0x96, 0xD6, 0xE6, 0xF6, 0x07,
+ 0x27, 0x37, 0xD7, 0xE7, 0x08, 0x18, 0x28, 0x38, 0xE8, 0xF8, 0x09, 0x19,
+ 0x29, 0xE9, 0xF9, 0x0A, 0x1A, 0xCA, 0xDA, 0xEA, 0x0B, 0x1B, 0xDB, 0xEB,
+ 0xFB, 0x2C, 0x4C, 0x5C, 0x7C, 0x8C, 0x4D, 0x6D, 0x8D, 0x9D, 0xFD, 0x3E,
+ 0x5E, 0x6E, 0x8E, 0x9E, 0xEE, 0x0F, 0x1F, 0x3F, 0x4F, 0x5F, 0x6F, 0x7F,
+ 0xCF, 0x70, 0xA1, 0xA2, 0x83, 0xB3, 0x34, 0x74, 0xC4, 0xE4, 0x55, 0x65,
+ 0x85, 0xA5, 0xC5, 0xE5, 0xF5, 0x56, 0x66, 0x76, 0x86, 0xA6, 0xC6, 0x57,
+ 0x67, 0x77, 0x97, 0xA7, 0x48, 0x88, 0x98, 0x49, 0x59, 0x79, 0x99, 0x3A,
+ 0x4A, 0x8A, 0xBA, 0xFA, 0x2B, 0x7B, 0x0C, 0xAC, 0xBC, 0xCC, 0xEC, 0x7D,
+ 0xAD, 0xBD, 0xDD, 0x4E, 0xBE, 0xCE, 0xFE, 0x8F, 0x9F, 0xAF, 0xBF, 0xDF,
+ 0xEF, 0xFF, 0x90, 0xA0, 0xB0, 0xB1, 0x54, 0x94, 0x45, 0x75, 0xB5, 0xB6,
+ 0x47, 0x87, 0xB7, 0xC7, 0x58, 0x68, 0x78, 0xA8, 0xB8, 0xC8, 0x39, 0x69,
+ 0x89, 0xA9, 0xB9, 0xC9, 0xD9, 0x2A, 0x5A, 0x6A, 0x7A, 0x9A, 0xAA, 0x3B,
+ 0x4B, 0x5B, 0x6B, 0x8B, 0x9B, 0xAB, 0xBB, 0xCB, 0x6C, 0x9C, 0xDC, 0xFC,
+ 0xCD, 0xED, 0xAE, 0xDE,
+ /* Table set B, code table 6, wordlen 7 - 63 entries */
+ 0x00, 0x01, 0x3F, 0x3E, 0x02, 0x03, 0x3C, 0x3D, 0x04, 0x05, 0x06, 0x07,
+ 0x39, 0x3A, 0x3B, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x34, 0x35, 0x36, 0x37,
+ 0x38, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x19, 0x1A, 0x1B, 0x1C, 0x1D,
+ 0x1E, 0x1F, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x2E, 0x2F, 0x30,
+ 0x31, 0x32, 0x33, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x28, 0x29, 0x2A,
+ 0x2B, 0x2C, 0x2D,
+ /* Table set B, code table 7, wordlen 1 - 81 entries */
+ 0x00, 0x03, 0x40, 0xC0, 0x10, 0x30, 0x04, 0x0C, 0x01, 0x50, 0xD0, 0x70,
+ 0xF0, 0xC4, 0x14, 0x34, 0x4C, 0x1C, 0x3C, 0xC1, 0x11, 0x31, 0x05, 0x0D,
+ 0x13, 0x33, 0x07, 0x0F, 0x44, 0xCC, 0x41, 0x43, 0xC3, 0x54, 0x74, 0xDC,
+ 0xFC, 0xF1, 0xC5, 0x15, 0x1D, 0x53, 0xC7, 0x37, 0x4F, 0x3F, 0xD4, 0xF4,
+ 0x5C, 0x7C, 0x51, 0xD1, 0x71, 0x45, 0x55, 0x35, 0x4D, 0xCD, 0xDD, 0x3D,
+ 0xD3, 0x73, 0xF3, 0x47, 0x17, 0x77, 0xCF, 0x1F, 0xFF, 0xD5, 0x75, 0xF5,
+ 0x5D, 0x7D, 0xFD, 0x57, 0xD7, 0xF7, 0x5F, 0xDF, 0x7F,
+ /* Table set B, code table 7, wordlen 3 - 256 entries */
+ 0x00, 0x40, 0x10, 0x04, 0x01, 0x05, 0x50, 0x14, 0x54, 0x41, 0x11, 0x51,
+ 0x45, 0x15, 0x55, 0x44, 0x95, 0x6A, 0x03, 0x80, 0xC0, 0x90, 0xD0, 0x94,
+ 0xD4, 0x24, 0x64, 0x58, 0x91, 0xA1, 0x85, 0xD5, 0x25, 0x65, 0xA5, 0xE5,
+ 0x75, 0xB5, 0xF5, 0x19, 0x59, 0x99, 0xD9, 0x69, 0xA9, 0xE9, 0x79, 0xB9,
+ 0xF9, 0x4D, 0x5D, 0x9D, 0xDD, 0x6D, 0xAD, 0xED, 0x7D, 0xBD, 0xFD, 0x02,
+ 0x42, 0x52, 0x06, 0x46, 0x16, 0x56, 0x96, 0xD6, 0x26, 0x66, 0xA6, 0xE6,
+ 0x76, 0xB6, 0xF6, 0x1A, 0x5A, 0x9A, 0xDA, 0xAA, 0xEA, 0x7A, 0xBA, 0xFA,
+ 0x5E, 0x9E, 0xDE, 0x6E, 0xAE, 0xEE, 0x7E, 0xBE, 0xFE, 0x07, 0x47, 0x57,
+ 0x97, 0xD7, 0x67, 0xA7, 0xE7, 0x77, 0xB7, 0xF7, 0x5B, 0x9B, 0xDB, 0x6B,
+ 0xAB, 0xEB, 0x7B, 0xBB, 0xFB, 0x5F, 0x9F, 0xDF, 0x6F, 0xAF, 0xEF, 0x7F,
+ 0xBF, 0xFF, 0x20, 0x60, 0x70, 0xB0, 0xF0, 0x84, 0xC4, 0xA4, 0xE4, 0x74,
+ 0xB4, 0xF4, 0x08, 0x88, 0x18, 0x98, 0xD8, 0x68, 0xA8, 0xE8, 0x78, 0xB8,
+ 0xF8, 0x1C, 0x5C, 0x9C, 0xDC, 0x6C, 0xAC, 0xEC, 0x3C, 0x7C, 0xBC, 0xFC,
+ 0x81, 0xD1, 0x21, 0x61, 0xE1, 0x71, 0xB1, 0xF1, 0xC5, 0x35, 0x09, 0x49,
+ 0x89, 0xC9, 0x29, 0x39, 0x0D, 0x8D, 0xCD, 0x1D, 0x2D, 0x3D, 0x92, 0xD2,
+ 0x22, 0x62, 0xA2, 0xE2, 0x72, 0xB2, 0xF2, 0x86, 0xC6, 0x36, 0x0A, 0x4A,
+ 0x8A, 0xCA, 0x2A, 0x3A, 0x0E, 0x4E, 0x8E, 0xCE, 0x1E, 0x2E, 0x3E, 0x13,
+ 0x53, 0x93, 0xD3, 0x63, 0xA3, 0xE3, 0x73, 0xB3, 0xF3, 0x87, 0xC7, 0x17,
+ 0x27, 0x37, 0x0B, 0x4B, 0x8B, 0xCB, 0x1B, 0x2B, 0x3B, 0x0F, 0x4F, 0x8F,
+ 0xCF, 0x1F, 0x2F, 0x3F, 0xA0, 0xE0, 0x30, 0x34, 0x48, 0xC8, 0x28, 0x38,
+ 0x0C, 0x4C, 0x8C, 0xCC, 0x2C, 0xC1, 0x31, 0x82, 0xC2, 0x12, 0x32, 0x43,
+ 0x83, 0xC3, 0x23, 0x33,
+ /* Table set B, code table 7, wordlen 4 - 11 entries */
+ 0x00, 0x01, 0x0F, 0x02, 0x0E, 0x05, 0x0D, 0x03, 0x04, 0x0B, 0x0C,
+ /* Table set B, code table 7, wordlen 5 - 225 entries */
+ 0x00, 0x10, 0xF0, 0x01, 0x0F, 0x20, 0xE0, 0x11, 0xF1, 0x02, 0x0E, 0x1F,
+ 0xFF, 0xD0, 0x21, 0xE1, 0x12, 0xF2, 0x03, 0x0D, 0x1E, 0xFE, 0x2F, 0xEF,
+ 0x30, 0x40, 0x60, 0x70, 0x90, 0xA0, 0xC0, 0x31, 0xD1, 0x22, 0xE2, 0x13,
+ 0xF3, 0x04, 0x06, 0x07, 0x09, 0x0C, 0x1D, 0xFD, 0x2E, 0xEE, 0x3F, 0xDF,
+ 0x50, 0xB0, 0x41, 0x61, 0x71, 0x91, 0xA1, 0xC1, 0x32, 0x62, 0x72, 0x92,
+ 0xA2, 0xD2, 0x23, 0xD3, 0xE3, 0x14, 0xF4, 0x05, 0x16, 0x26, 0xE6, 0xF6,
+ 0x17, 0x27, 0xE7, 0xF7, 0x19, 0x29, 0xF9, 0x0A, 0x1A, 0x2A, 0xFA, 0x0B,
+ 0x1C, 0x2C, 0xFC, 0x2D, 0x3D, 0xED, 0x3E, 0x4E, 0x7E, 0x9E, 0xDE, 0x4F,
+ 0x6F, 0x7F, 0x9F, 0xAF, 0xCF, 0x51, 0xB1, 0x42, 0x52, 0xB2, 0xC2, 0x33,
+ 0x63, 0x73, 0x93, 0xA3, 0xB3, 0xC3, 0x24, 0x34, 0x74, 0xA4, 0xD4, 0xE4,
+ 0x15, 0x25, 0x65, 0x95, 0xE5, 0xF5, 0x36, 0xD6, 0x37, 0x47, 0xC7, 0xD7,
+ 0x39, 0x59, 0xB9, 0xC9, 0xD9, 0xE9, 0x3A, 0x6A, 0xDA, 0xEA, 0x1B, 0x2B,
+ 0x9B, 0xAB, 0xEB, 0xFB, 0x6C, 0x7C, 0x9C, 0xAC, 0xEC, 0x4D, 0x6D, 0x7D,
+ 0x9D, 0xAD, 0xBD, 0xDD, 0x5E, 0x6E, 0xAE, 0xCE, 0x5F, 0x43, 0x53, 0x44,
+ 0x54, 0x64, 0x94, 0xB4, 0xC4, 0x35, 0x45, 0x55, 0x75, 0xA5, 0xB5, 0xC5,
+ 0xD5, 0x46, 0x56, 0x66, 0x76, 0x96, 0xA6, 0xB6, 0xC6, 0x57, 0x67, 0x77,
+ 0x97, 0xA7, 0xB7, 0x49, 0x69, 0x79, 0x99, 0xA9, 0x4A, 0x5A, 0x7A, 0x9A,
+ 0xAA, 0xBA, 0xCA, 0x3B, 0x4B, 0x5B, 0x6B, 0x7B, 0xBB, 0xCB, 0xDB, 0x3C,
+ 0x4C, 0x5C, 0xBC, 0xCC, 0xDC, 0x5D, 0xCD, 0xBE, 0xBF,
+ /* Table set B, code table 7, wordlen 7 - 63 entries */
+ 0x00, 0x01, 0x02, 0x3E, 0x3F, 0x03, 0x04, 0x05, 0x3B, 0x3C, 0x3D, 0x06,
+ 0x07, 0x08, 0x09, 0x0A, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x0B, 0x0C, 0x0D,
+ 0x0E, 0x0F, 0x10, 0x2F, 0x31, 0x32, 0x33, 0x34, 0x35, 0x11, 0x12, 0x13,
+ 0x14, 0x2D, 0x2E, 0x30, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x25,
+ 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x1C, 0x1D, 0x1E, 0x23, 0x1F,
+ 0x21, 0x22, 0x24,
+ /* Table set B, code table 7, wordlen 7 - 8 entries */
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ /* Table set B, code table 7, wordlen 7 - 8 entries */
+ 0x00, 0x01, 0x07, 0x02, 0x06, 0x03, 0x04, 0x05,
+ /* Table set B, code table 7, wordlen 7 - 16 entries */
+ 0x07, 0x05, 0x08, 0x06, 0x09, 0x04, 0x0A, 0x0B, 0x00, 0x01, 0x02, 0x03,
+ 0x0C, 0x0D, 0x0E, 0x0F,
+ /* Table set B, code table 7, wordlen 7 - 15 entries */
+ 0x0F, 0x0E, 0x01, 0x0D, 0x02, 0x03, 0x0C, 0x04, 0x05, 0x06, 0x07, 0x08,
+ 0x09, 0x0A, 0x0B,
+ /* Table set B, code table 7, wordlen 7 - 16 entries */
+ 0x00, 0x01, 0x0E, 0x0F, 0x02, 0x0D, 0x03, 0x0C, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0A, 0x0B,
+ /* Table set B, code table 7, wordlen 7 - 16 entries */
+ 0x00, 0x01, 0x0F, 0x0E, 0x02, 0x0D, 0x03, 0x0C, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0A, 0x0B,
+ /* Table set B, code table 7, wordlen 7 - 32 entries */
+ 0x00, 0x01, 0x1F, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x1A, 0x1B, 0x1C,
+ 0x1D, 0x1E, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11,
+ 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19,
+ /* Table set B, code table 7, wordlen 7 - 31 entries */
+ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C,
+ 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
+ 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,
+ /* Table set B, code table 7, wordlen 7 - 32 entries */
+ 0x00, 0x1C, 0x1D, 0x01, 0x02, 0x03, 0x04, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B,
+ 0x1E, 0x1F, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A,
+ /* Table set B, code table 7, wordlen 7 - 31 entries */
+ 0x02, 0x03, 0x04, 0x05, 0x06, 0x01, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C,
+ 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
+ 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,
+ /* Table set B, code table 7, wordlen 7 - 32 entries */
+ 0x00, 0x01, 0x02, 0x1F, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x1D, 0x1E,
+ 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14,
+ 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C,
+ /* Table set B, code table 7, wordlen 7 - 16 entries */
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B,
+ 0x0C, 0x0D, 0x0E, 0x0F,
+ /* Table set B, code table 7, wordlen 7 - 8 entries */
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ /* Table set B, code table 7, wordlen 7 - 8 entries */
+ 0x00, 0x01, 0x07, 0x02, 0x03, 0x04, 0x05, 0x06,
+ /* Table set B, code table 7, wordlen 7 - 32 entries */
+ 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x05, 0x06,
+ 0x07, 0x12, 0x13, 0x14, 0x15, 0x16, 0x04, 0x17, 0x18, 0x19, 0x1A, 0x1B,
+ 0x00, 0x01, 0x02, 0x03, 0x1C, 0x1D, 0x1E, 0x1F,
+ /* Table set B, code table 7, wordlen 7 - 32 entries */
+ 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x0E,
+ 0x0F, 0x10, 0x11, 0x1D, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x1E, 0x04, 0x05,
+ 0x06, 0x07, 0x08, 0x1F, 0x00, 0x01, 0x02, 0x03,
+ /* Table set B, code table 7, wordlen 7 - 32 entries */
+ 0x00, 0x01, 0x02, 0x1F, 0x03, 0x1D, 0x1E, 0x04, 0x05, 0x06, 0x1B, 0x1C,
+ 0x07, 0x18, 0x19, 0x1A, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+ /* Table set B, code table 7, wordlen 7 - 256 entries */
+ 0x00, 0x01, 0xFF, 0x02, 0xFE, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0xFB,
+ 0xFC, 0xFD, 0x09, 0x0A, 0x0B, 0x0C, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0x0D,
+ 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19,
+ 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25,
+ 0x26, 0xF3, 0xF4, 0xF5, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E,
+ 0x2F, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A,
+ 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46,
+ 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, 0x51, 0x52,
+ 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0xC2,
+ 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE,
+ 0xCF, 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA,
+ 0xDB, 0xDC, 0xDD, 0xDE, 0xDF, 0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6,
+ 0xE7, 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF, 0xF0, 0xF1, 0xF2,
+ 0x5E, 0x5F, 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69,
+ 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75,
+ 0x76, 0x77, 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F, 0x80, 0x81,
+ 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D,
+ 0x8E, 0x8F, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99,
+ 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F, 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5,
+ 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF, 0xB0, 0xB1,
+ 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD,
+ 0xBE, 0xBF, 0xC0, 0xC1,
+};
+
+/** Tables for spectrum coding. */
+typedef struct Atrac3pSpecCodeTab {
+ uint8_t group_size; ///< number of coefficients grouped together
+ uint8_t num_coeffs; ///< 1 - map index to a single value, > 1 - map index to a vector of values
+ uint8_t bits; ///< number of bits a single coefficient occupy
+ uint8_t is_signed; ///< 1 - values in that table are signed ones, otherwise - absolute ones
+} Atrac3pSpecCodeTab;
+
+static const Atrac3pSpecCodeTab atrac3p_spectra_tabs[112] = {
+ /* table set = A */
+ /* code table = 0 */
+ { 1, 4, 2, 1 }, // wordlen = 1
+ { 1, 4, 2, 0 }, // wordlen = 2
+ { 1, 2, 3, 1 }, // wordlen = 3
+ { 1, 1, 3, 0 }, // wordlen = 4
+ { 1, 2, 4, 1 }, // wordlen = 5
+ { 1, 1, 4, 0 }, // wordlen = 6
+ { 1, 1, 6, 1 }, // wordlen = 7
+
+ /* code table = 1 */
+ { 4, 4, 2, 1 }, // wordlen = 1
+ { 1, 4, 2, 0 }, // wordlen = 2
+ { 1, 2, 3, 1 }, // wordlen = 3
+ { 1, 2, 4, 1 }, // wordlen = 4
+ { 1, 2, 4, 1 }, // wordlen = 5
+ { 1, 2, 4, 0 }, // wordlen = 6
+ { 1, 1, 6, 1 }, // wordlen = 7
+
+ /* code table = 2 */
+ { 1, 4, 2, 1 }, // wordlen = 1
+ { 1, 2, 3, 1 }, // wordlen = 2
+ { 1, 2, 3, 1 }, // wordlen = 3
+ { 1, 1, 3, 0 }, // wordlen = 4
+ { 1, 1, 3, 0 }, // wordlen = 5
+ { 1, 2, 4, 0 }, // wordlen = 6
+ { 1, 1, 6, 1 }, // wordlen = 7
+
+ /* code table = 3 */
+ { 1, 2, 2, 1 }, // wordlen = 1
+ { 1, 4, 2, 0 }, // wordlen = 2
+ { 1, 4, 2, 0 }, // wordlen = 3
+ { 1, 1, 3, 0 }, // wordlen = 4
+ { 1, 2, 4, 1 }, // wordlen = 5
+ { 1, 2, 4, 0 }, // wordlen = 6
+ { 1, 1, 6, 1 }, // wordlen = 7
+
+ /* code table = 4 */
+ { 1, 4, 2, 1 }, // wordlen = 1
+ { 1, 4, 2, 0 }, // wordlen = 2
+ { 1, 1, 3, 1 }, // wordlen = 3
+ { 1, 2, 4, 1 }, // wordlen = 4
+ { 1, 1, 3, 0 }, // wordlen = 5
+ { 1, 2, 4, 0 }, // wordlen = 6
+ { 1, 1, 6, 1 }, // wordlen = 7
+
+ /* code table = 5 */
+ { 1, 4, 2, 1 }, // wordlen = 1
+ { 1, 2, 3, 1 }, // wordlen = 2
+ { 1, 1, 3, 1 }, // wordlen = 3
+ { 1, 2, 4, 1 }, // wordlen = 4
+ { 1, 1, 3, 0 }, // wordlen = 5
+ { 1, 1, 5, 1 }, // wordlen = 6
+ { 1, 1, 6, 1 }, // wordlen = 7
+
+ /* code table = 6 */
+ { 2, 4, 2, 1 }, // wordlen = 1
+ { 1, 2, 3, 1 }, // wordlen = 2
+ { 1, 4, 2, 0 }, // wordlen = 3
+ { 1, 2, 4, 1 }, // wordlen = 4
+ { 1, 1, 4, 1 }, // wordlen = 5
+ { 1, 1, 5, 1 }, // wordlen = 6
+ { 1, 1, 6, 1 }, // wordlen = 7
+
+ /* code table = 7 */
+ { 1, 2, 1, 0 }, // wordlen = 1
+ { 2, 4, 2, 0 }, // wordlen = 2
+ { 1, 2, 3, 1 }, // wordlen = 3
+ { 1, 2, 4, 1 }, // wordlen = 4
+ { 1, 1, 4, 1 }, // wordlen = 5
+ { 2, 2, 4, 0 }, // wordlen = 6
+ { 4, 1, 6, 1 }, // wordlen = 7
+
+ /* table set = B */
+ /* code table = 0 */
+ { 4, 4, 2, 1 }, // wordlen = 1
+ { 1, 4, 2, 0 }, // wordlen = 2
+ { 4, 2, 3, 1 }, // wordlen = 3
+ { 1, 2, 4, 1 }, // wordlen = 4
+ { 1, 2, 4, 1 }, // wordlen = 5
+ { 1, 1, 4, 0 }, // wordlen = 6
+ { 1, 1, 6, 1 }, // wordlen = 7
+
+ /* code table = 1 */
+ { 1, 4, 2, 1 }, // wordlen = 1
+ { 1, 4, 2, 0 }, // wordlen = 2
+ { 1, 2, 3, 1 }, // wordlen = 3
+ { 1, 2, 4, 1 }, // wordlen = 4
+ { 1, 2, 4, 1 }, // wordlen = 5
+ { 1, 2, 4, 0 }, // wordlen = 6
+ { 1, 1, 6, 1 }, // wordlen = 7
+
+ /* code table = 2 */
+ { 4, 4, 2, 1 }, // wordlen = 1
+ { 4, 4, 2, 0 }, // wordlen = 2
+ { 1, 2, 3, 1 }, // wordlen = 3
+ { 1, 2, 4, 1 }, // wordlen = 4
+ { 2, 2, 4, 1 }, // wordlen = 5
+ { 2, 2, 4, 0 }, // wordlen = 6
+ { 4, 1, 6, 1 }, // wordlen = 7
+
+ /* code table = 3 */
+ { 1, 4, 2, 1 }, // wordlen = 1
+ { 1, 4, 2, 0 }, // wordlen = 2
+ { 1, 4, 2, 0 }, // wordlen = 3
+ { 2, 2, 4, 1 }, // wordlen = 4
+ { 1, 2, 4, 1 }, // wordlen = 5
+ { 1, 2, 4, 0 }, // wordlen = 6
+ { 1, 1, 6, 1 }, // wordlen = 7
+
+ /* code table = 4 */
+ { 1, 4, 2, 1 }, // wordlen = 1
+ { 4, 2, 3, 1 }, // wordlen = 2
+ { 1, 2, 3, 1 }, // wordlen = 3
+ { 4, 2, 4, 1 }, // wordlen = 4
+ { 1, 1, 3, 0 }, // wordlen = 5
+ { 1, 2, 4, 0 }, // wordlen = 6
+ { 1, 1, 6, 1 }, // wordlen = 7
+
+ /* code table = 5 */
+ { 2, 4, 2, 1 }, // wordlen = 1
+ { 1, 2, 3, 1 }, // wordlen = 2
+ { 4, 1, 3, 1 }, // wordlen = 3
+ { 1, 1, 3, 0 }, // wordlen = 4
+ { 1, 1, 3, 0 }, // wordlen = 5
+ { 1, 1, 5, 1 }, // wordlen = 6
+ { 2, 1, 6, 1 }, // wordlen = 7
+
+ /* code table = 6 */
+ { 1, 4, 2, 1 }, // wordlen = 1
+ { 1, 4, 2, 0 }, // wordlen = 2
+ { 1, 1, 3, 1 }, // wordlen = 3
+ { 1, 1, 3, 0 }, // wordlen = 4
+ { 4, 2, 4, 1 }, // wordlen = 5
+ { 1, 2, 4, 0 }, // wordlen = 6
+ { 1, 1, 6, 1 }, // wordlen = 7
+
+ /* code table = 7 */
+ { 1, 4, 2, 1 }, // wordlen = 1
+ { 4, 4, 2, 0 }, // wordlen = 2
+ { 4, 4, 2, 0 }, // wordlen = 3
+ { 1, 1, 4, 1 }, // wordlen = 4
+ { 1, 2, 4, 1 }, // wordlen = 5
+ { 1, 1, 5, 1 }, // wordlen = 6
+ { 1, 1, 6, 1 }, // wordlen = 7
+};
+
+/* Huffman tables for gain control data. */
+static const uint8_t atrac3p_gain_cbs[][12] = {
+ { 1, 1, 1, 1, 1, 1, 2, 0, 0, 0, 0, 0 },
+ { 1, 1, 1, 1, 1, 1, 2, 0, 0, 0, 0, 0 },
+ { 1, 0, 2, 2, 1, 2, 8, 0, 0, 0, 0, 0 },
+ { 1, 1, 1, 1, 1, 0, 2, 0, 8, 0, 0, 0 },
+ { 1, 0, 3, 1, 1, 0, 2, 0, 8, 0, 0, 0 },
+ { 1, 1, 1, 1, 1, 0, 1, 2, 8, 0, 0, 0 },
+ { 0, 1, 0, 2, 11, 18, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 2, 4, 4, 4, 0, 16, 0, 0, 0, 0 },
+ { 0, 0, 0, 3, 23, 6, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 5, 3, 2, 3, 2, 16, 0, 0, 0, 0 },
+ { 1, 0, 0, 3, 2, 6, 20, 0, 0, 0, 0, 0 },
+};
+
+static const uint8_t atrac3p_gain_xlats[] = {
+ /* Number of gain control points 1 - 8 entries */
+ 0, 1, 2, 3, 4, 5, 6, 7,
+ /* Number of gain control points 2 - 8 entries */
+ 0, 1, 7, 2, 6, 3, 4, 5,
+ /* Gain compensation level 1 - 16 entries */
+ 7, 5, 8, 6, 9, 4, 10, 11, 0, 1, 2, 3, 12, 13, 14, 15,
+ /* Gain compensation level 2 - 15 entries */
+ 15, 14, 1, 13, 2, 3, 12, 4, 5, 6, 7, 8, 9, 10, 11,
+ /* Gain compensation level 3 - 16 entries */
+ 0, 1, 14, 15, 2, 13, 3, 12, 4, 5, 6, 7, 8, 9, 10, 11,
+ /* Gain compensation level 4 - 16 entries */
+ 0, 1, 15, 14, 2, 13, 3, 12, 4, 5, 6, 7, 8, 9, 10, 11,
+ /* Gain compensation location 3 - 32 entries */
+ 0, 1, 31, 2, 3, 4, 5, 6, 7, 26, 27, 28, 29, 30, 8, 9, 10, 11, 12,
+ 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,
+ /* Gain compensation location 1 - 31 entries */
+ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
+ 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+ /* Gain compensation location 4 - 32 entries */
+ 0, 28, 29, 1, 2, 3, 4, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22,
+ 23, 24, 25, 26, 27, 30, 31, 5, 6, 7, 8, 9, 10,
+ /* Gain compensation location 2 - 31 entries */
+ 2, 3, 4, 5, 6, 1, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
+ 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+ /* Gain compensation location 5 - 32 entries */
+ 0, 1, 2, 31, 3, 4, 5, 6, 7, 8, 29, 30, 9, 10, 11, 12, 13, 14, 15,
+ 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28,
+};
+
+/* Huffman tables for GHA waves data. */
+static const uint8_t atrac3p_tone_cbs[][12] = {
+ { 1, 0, 1, 2, 4, 8, 0, 0, 0, 0, 0, 0 },
+ { 1, 1, 1, 1, 1, 1, 2, 0, 0, 0, 0, 0 },
+ { 1, 1, 1, 1, 0, 4, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 10, 8, 6, 0, 8, 0, 0, 0, 0 },
+ { 0, 0, 0, 11, 5, 6, 6, 4, 0, 0, 0, 0 },
+ { 0, 1, 3, 3, 1, 4, 4, 16, 0, 0, 0, 0 },
+ { 1, 0, 0, 2, 2, 0, 9, 9, 29,104, 100, 0 },
+};
+
+static const uint8_t atrac3p_tone_xlats[] = {
+ /* Number of tone bands - 16 entries */
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
+ 15,
+ /* Number of tones 1 - 8 entries */
+ 0, 1, 2, 3, 4, 5, 6, 7,
+ /* Number of tones 2 - 8 entries */
+ 0, 1, 7, 2, 3, 4, 5, 6,
+ /* Amplitude information 1 - 32 entries */
+ 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 5, 6, 7, 18, 19,
+ 20, 21, 22, 4, 23, 24, 25, 26, 27, 0, 1, 2, 3, 28, 29,
+ 30, 31,
+ /* Amplitude information 2 - 32 entries */
+ 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 14, 15, 16, 17,
+ 29, 9, 10, 11, 12, 13, 30, 4, 5, 6, 7, 8, 31, 0, 1,
+ 2, 3,
+ /* Amplitude information 3 - 32 entries */
+ 0, 1, 2, 31, 3, 29, 30, 4, 5, 6, 27, 28, 7, 24, 25,
+ 26, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
+ 22, 23,
+ /* Frequencies - 256 entries */
+ 0, 1, 255, 2, 254, 3, 4, 5, 6, 7, 8, 251, 252, 253, 9,
+ 10, 11, 12, 246, 247, 248, 249, 250, 13, 14, 15, 16, 17, 18, 19,
+ 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34,
+ 35, 36, 37, 38, 243, 244, 245, 39, 40, 41, 42, 43, 44, 45, 46,
+ 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61,
+ 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76,
+ 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91,
+ 92, 93, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206,
+ 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221,
+ 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236,
+ 237, 238, 239, 240, 241, 242, 94, 95, 96, 97, 98, 99, 100, 101, 102,
+ 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117,
+ 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132,
+ 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147,
+ 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162,
+ 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177,
+ 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192,
+ 193,
+};
+
+#endif /* AVCODEC_ATRAC3PLUS_DATA_H */
diff --git a/src/atrac/at3p/ff/atrac3plusdsp.c b/src/atrac/at3p/ff/atrac3plusdsp.c
new file mode 100644
index 0000000..5859876
--- /dev/null
+++ b/src/atrac/at3p/ff/atrac3plusdsp.c
@@ -0,0 +1,204 @@
+/*
+ * ATRAC3+ compatible decoder
+ *
+ * Copyright (c) 2010-2013 Maxim Poliakovski
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * @file
+ * DSP functions for ATRAC3+ decoder.
+ */
+
+#define _USE_MATH_DEFINES
+#include <math.h>
+#include <string.h>
+
+#include "atrac3plus.h"
+
+#define TWOPI (2 * M_PI)
+#define DEQUANT_PHASE(ph) (((ph) & 0x1F) << 6)
+
+static float sine_table[2048]; ///< wave table
+static float hann_window[256]; ///< Hann windowing function
+static float amp_sf_tab[64]; ///< scalefactors for quantized amplitudes
+
+static void vector_fmul(float *dst, const float *src0, const float *src1,
+ int len)
+{
+ int i;
+ for (i = 0; i < len; i++)
+ dst[i] = src0[i] * src1[i];
+}
+
+void ff_atrac3p_init_dsp_static(void)
+{
+ int i;
+
+ /* generate sine wave table */
+ for (i = 0; i < 2048; i++)
+ sine_table[i] = sin(TWOPI * i / 2048);
+
+ /* generate Hann window */
+ for (i = 0; i < 256; i++)
+ hann_window[i] = (1.0f - cos(TWOPI * i / 256.0f)) * 0.5f;
+
+ /* generate amplitude scalefactors table */
+ for (i = 0; i < 64; i++)
+ amp_sf_tab[i] = exp2f((i - 3) / 4.0f);
+}
+
+/**
+ * Synthesize sine waves according to given parameters.
+ *
+ * @param[in] synth_param ptr to common synthesis parameters
+ * @param[in] waves_info parameters for each sine wave
+ * @param[in] envelope envelope data for all waves in a group
+ * @param[in] invert_phase flag indicating 180° phase shift
+ * @param[in] reg_offset region offset for trimming envelope data
+ * @param[out] out receives sythesized data
+ */
+
+static void waves_synth(Atrac3pWaveSynthParams *synth_param,
+ Atrac3pWavesData *waves_info,
+ Atrac3pWaveEnvelope *envelope,
+ int invert_phase, int reg_offset, float *out)
+{
+ int i, wn, inc, pos;
+ double amp;
+ Atrac3pWaveParam *wave_param = &synth_param->waves[waves_info->start_index];
+
+ for (wn = 0; wn < waves_info->num_wavs; wn++, wave_param++) {
+ /* amplitude dequantization */
+ amp = amp_sf_tab[wave_param->amp_sf] *
+ (!synth_param->amplitude_mode
+ ? (wave_param->amp_index + 1) / 15.13f
+ : 1.0f);
+
+ inc = wave_param->freq_index;
+ pos = DEQUANT_PHASE(wave_param->phase_index) - (reg_offset ^ 128) * inc & 2047;
+
+ /* waveform generation */
+ for (i = 0; i < 128; i++) {
+ out[i] += sine_table[pos] * amp;
+ pos = (pos + inc) & 2047;
+ }
+ }
+
+ /* invert phase if requested */
+ if (invert_phase)
+ for (i = 0; i < 128; i++)
+ out[i] *= -1.0f;
+
+ /* fade in with steep Hann window if requested */
+ if (envelope->has_start_point) {
+ pos = (envelope->start_pos << 2) - reg_offset;
+ if (pos > 0 && pos <= 128) {
+ memset(out, 0, pos * sizeof(*out));
+ if (!envelope->has_stop_point ||
+ envelope->start_pos != envelope->stop_pos) {
+ out[pos + 0] *= hann_window[0];
+ out[pos + 1] *= hann_window[32];
+ out[pos + 2] *= hann_window[64];
+ out[pos + 3] *= hann_window[96];
+ }
+ }
+ }
+
+ /* fade out with steep Hann window if requested */
+ if (envelope->has_stop_point) {
+ pos = (envelope->stop_pos + 1 << 2) - reg_offset;
+ if (pos > 0 && pos <= 128) {
+ out[pos - 4] *= hann_window[96];
+ out[pos - 3] *= hann_window[64];
+ out[pos - 2] *= hann_window[32];
+ out[pos - 1] *= hann_window[0];
+ memset(&out[pos], 0, (128 - pos) * sizeof(out[pos]));
+ }
+ }
+}
+
+void ff_atrac3p_generate_tones(Atrac3pChanUnitCtx *ch_unit,
+ int ch_num, int sb, float *out)
+{
+ float wavreg1[128] = { 0 };
+ float wavreg2[128] = { 0 };
+ int i, reg1_env_nonzero, reg2_env_nonzero;
+ Atrac3pWavesData *tones_now = &ch_unit->channels[ch_num].tones_info_prev[sb];
+ Atrac3pWavesData *tones_next = &ch_unit->channels[ch_num].tones_info[sb];
+
+ /* reconstruct full envelopes for both overlapping regions
+ * from truncated bitstream data */
+ if (tones_next->pend_env.has_start_point &&
+ tones_next->pend_env.start_pos < tones_next->pend_env.stop_pos) {
+ tones_next->curr_env.has_start_point = 1;
+ tones_next->curr_env.start_pos = tones_next->pend_env.start_pos + 32;
+ } else if (tones_now->pend_env.has_start_point) {
+ tones_next->curr_env.has_start_point = 1;
+ tones_next->curr_env.start_pos = tones_now->pend_env.start_pos;
+ } else {
+ tones_next->curr_env.has_start_point = 0;
+ tones_next->curr_env.start_pos = 0;
+ }
+
+ if (tones_now->pend_env.has_stop_point &&
+ tones_now->pend_env.stop_pos >= tones_next->curr_env.start_pos) {
+ tones_next->curr_env.has_stop_point = 1;
+ tones_next->curr_env.stop_pos = tones_now->pend_env.stop_pos;
+ } else if (tones_next->pend_env.has_stop_point) {
+ tones_next->curr_env.has_stop_point = 1;
+ tones_next->curr_env.stop_pos = tones_next->pend_env.stop_pos + 32;
+ } else {
+ tones_next->curr_env.has_stop_point = 0;
+ tones_next->curr_env.stop_pos = 64;
+ }
+
+ /* is the visible part of the envelope non-zero? */
+ reg1_env_nonzero = (tones_now->curr_env.stop_pos < 32) ? 0 : 1;
+ reg2_env_nonzero = (tones_next->curr_env.start_pos >= 32) ? 0 : 1;
+
+ /* synthesize waves for both overlapping regions */
+ if (tones_now->num_wavs && reg1_env_nonzero) {
+ waves_synth(ch_unit->waves_info_prev, tones_now, &tones_now->curr_env,
+ ch_unit->waves_info_prev->invert_phase[sb] & ch_num,
+ 128, wavreg1);
+ }
+
+ if (tones_next->num_wavs && reg2_env_nonzero) {
+ waves_synth(ch_unit->waves_info, tones_next, &tones_next->curr_env,
+ ch_unit->waves_info->invert_phase[sb] & ch_num, 0, wavreg2);
+ }
+
+ /* Hann windowing for non-faded wave signals */
+ if (tones_now->num_wavs && tones_next->num_wavs &&
+ reg1_env_nonzero && reg2_env_nonzero) {
+ vector_fmul(wavreg1, wavreg1, &hann_window[128], 128);
+ vector_fmul(wavreg2, wavreg2, hann_window, 128);
+ } else {
+ if (tones_now->num_wavs && !tones_now->curr_env.has_stop_point)
+ vector_fmul(wavreg1, wavreg1, &hann_window[128], 128);
+
+ if (tones_next->num_wavs && !tones_next->curr_env.has_start_point)
+ vector_fmul(wavreg2, wavreg2, hann_window, 128);
+ }
+
+ /* Overlap and subtract to get residual */
+ for (i = 0; i < 128; i++) {
+ out[i] -= wavreg1[i] + wavreg2[i];
+ }
+}
diff --git a/src/atrac/at3p/ghasend_tool.cpp b/src/atrac/at3p/ghasend_tool.cpp
new file mode 100644
index 0000000..c6be7c5
--- /dev/null
+++ b/src/atrac/at3p/ghasend_tool.cpp
@@ -0,0 +1,90 @@
+#include "at3p_bitstream.h"
+#include "oma.h"
+
+#include <string>
+#include <iostream>
+
+using namespace std;
+
+void process(const string& in, NAtracDEnc::TAt3PBitStream* bs) {
+ size_t pos = 0;
+ int cur_num_pos = 0;
+ enum {
+ TAB,
+ NUM,
+ ERR,
+ } state = NUM;
+
+ std::vector<int> nums;
+
+ while (pos < in.size()) {
+ switch (state) {
+ case TAB:
+ if (in[pos] == '\t') {
+ break;
+ } else if (('0' <= in[pos] && in[pos] <= '9') || in[pos] == '-') {
+ state = NUM;
+ cur_num_pos = pos;
+ break;
+ } else {
+ fprintf(stderr, "TAB state: %s\n", &in[pos]);
+ abort();
+ }
+ case NUM:
+ if (in[pos] == '\t') {
+ nums.push_back(stoi(in.substr(cur_num_pos, pos - cur_num_pos)));
+ state = TAB;
+ break;
+ } else if (pos == in.size() - 1) {
+ nums.push_back(stoi(in.substr(cur_num_pos)));
+ break;
+ } else if (('0' <= in[pos] && in[pos] <= '9') || in[pos] == '-') {
+ break;
+ } else {
+ fprintf(stderr, "NUM state: %s\n", &in[pos]);
+ abort();
+ }
+ case ERR:
+ abort();
+ }
+ pos++;
+ }
+
+ if (nums.size() != 3)
+ return;
+
+ std::cerr << "gen: " << nums[0] << '\t' << nums[1] << '\t' << nums[2] << std::endl;
+
+ NAtracDEnc::TAt3PGhaData frame;
+ frame.NumToneBands = 1;
+ frame.Waves[0].WaveParams.push_back(NAtracDEnc::TAt3PGhaData::TWaveParam{(uint32_t)nums[1], 53, 0, 0});
+ frame.Waves[0].WaveSbInfos.resize(1);
+ frame.Waves[0].WaveSbInfos[0].WaveIndex = 0;
+ frame.Waves[0].WaveSbInfos[0].WaveNums = 1;
+ frame.Waves[0].WaveSbInfos[0].Envelope = {(uint32_t)nums[0], (uint32_t)nums[2]};
+
+ //bs->WriteFrame(1, &frame);
+}
+
+int main(int argc, char** argv) {
+ if (argc != 2)
+ return -1;
+
+ string path(argv[1]);
+
+ std::unique_ptr<TOma> out(new TOma(path,
+ "test",
+ 1,
+ 1, OMAC_ID_ATRAC3PLUS,
+ 2048,
+ false));
+
+ NAtracDEnc::TAt3PBitStream bs(out.get(), 2048);
+
+ cout << "output: " << path << endl;
+ string textline;
+ while (getline(cin, textline)) {
+ process(textline, &bs);
+ }
+ return 0;
+}
diff --git a/src/atrac/atrac3plus_pqf/ut/ipqf_ut.cpp b/src/atrac/atrac3plus_pqf/ut/ipqf_ut.cpp
index 4492cb9..3344a00 100644
--- a/src/atrac/atrac3plus_pqf/ut/ipqf_ut.cpp
+++ b/src/atrac/atrac3plus_pqf/ut/ipqf_ut.cpp
@@ -133,6 +133,8 @@ TEST(pqf, DC_Short) {
for (int i = 368; i < 2048; i++) {
EXPECT_NEAR(tmp[i], x[i], err);
}
+
+ at3plus_pqf_free_a_ctx(actx);
}
TEST(pqf, DC_Long) {
@@ -160,6 +162,8 @@ TEST(pqf, DC_Long) {
for (int i = 368; i < 4096; i++) {
EXPECT_NEAR(tmp[i], x[i-368], err);
}
+
+ at3plus_pqf_free_a_ctx(actx);
}
TEST(pqf, Seq_Short) {
@@ -187,6 +191,8 @@ TEST(pqf, Seq_Short) {
for (int i = 368; i < 2048; i++) {
EXPECT_NEAR(tmp[i], x[i - 368], err);
}
+
+ at3plus_pqf_free_a_ctx(actx);
}
TEST(pqf, Seq_Long) {
@@ -213,6 +219,8 @@ TEST(pqf, Seq_Long) {
for (int i = 368; i < 4096; i++) {
EXPECT_NEAR(tmp[i], x[i-368], err);
}
+
+ at3plus_pqf_free_a_ctx(actx);
}
TEST(pqf, Chirp_Short) {
@@ -238,6 +246,8 @@ TEST(pqf, Chirp_Short) {
for (int i = 368; i < 2048; i++) {
EXPECT_NEAR(tmp[i], x[i - 368], err);
}
+
+ at3plus_pqf_free_a_ctx(actx);
}
TEST(pqf, Chirp_Long) {
@@ -264,6 +274,8 @@ TEST(pqf, Chirp_Long) {
for (int i = 368; i < 4096; i++) {
EXPECT_NEAR(tmp[i], x[i-368], err);
}
+
+ at3plus_pqf_free_a_ctx(actx);
}
TEST(pqf, Noise_Long) {
@@ -290,6 +302,8 @@ TEST(pqf, Noise_Long) {
for (int i = 368; i < 4096; i++) {
EXPECT_NEAR(tmp[i], x[i-368], err);
}
+
+ at3plus_pqf_free_a_ctx(actx);
}
diff --git a/src/atrac/atrac_scale.cpp b/src/atrac/atrac_scale.cpp
index 5a75bdd..b3cb324 100644
--- a/src/atrac/atrac_scale.cpp
+++ b/src/atrac/atrac_scale.cpp
@@ -19,6 +19,7 @@
#include "atrac_scale.h"
#include "atrac1.h"
#include "atrac3.h"
+#include "atrac/at3p/at3p_tables.h"
#include "util.h"
#include <cmath>
#include <iostream>
@@ -193,4 +194,7 @@ class TScaler<NAtrac1::TAtrac1Data>;
template
class TScaler<NAtrac3::TAtrac3Data>;
+template
+class TScaler<NAt3p::TScaleTable>;
+
} //namespace NAtracDEnc
diff --git a/src/atrac1denc.cpp b/src/atrac1denc.cpp
index 4ac10c1..a6e2d45 100644
--- a/src/atrac1denc.cpp
+++ b/src/atrac1denc.cpp
@@ -159,7 +159,7 @@ TPCMEngine::TProcessLambda TAtrac1Decoder::GetLambda() {
data[i * srcChannels + channel] = sum[i];
}
}
-
+ return TPCMEngine::EProcessResult::PROCESSED;
};
}
@@ -236,6 +236,8 @@ TPCMEngine::TProcessLambda TAtrac1Encoder::GetLambda() {
for (uint32_t channel = 0; channel < srcChannels; channel++) {
bitAlloc[channel]->Write(Scaler.ScaleFrame((*buf)[channel].Specs, blockSz[channel]), blockSz[channel], Loudness / LoudFactor);
}
+
+ return TPCMEngine::EProcessResult::PROCESSED;
};
}
diff --git a/src/atrac1denc.h b/src/atrac1denc.h
index 9756ee2..525596e 100644
--- a/src/atrac1denc.h
+++ b/src/atrac1denc.h
@@ -30,11 +30,6 @@
namespace NAtracDEnc {
-enum EMode {
- E_ENCODE = 1,
- E_DECODE = 2,
- E_ATRAC3 = 4
-};
class TAtrac1MDCT {
NMDCT::TMDCT<512> Mdct512;
diff --git a/src/atrac3denc.cpp b/src/atrac3denc.cpp
index 3dc9027..3a1ad18 100644
--- a/src/atrac3denc.cpp
+++ b/src/atrac3denc.cpp
@@ -371,6 +371,7 @@ TPCMEngine::TProcessLambda TAtrac3Encoder::GetLambda()
}
bitStreamWriter->WriteSoundUnit(SingleChannelElements, Loudness);
+ return TPCMEngine::EProcessResult::PROCESSED;
};
}
diff --git a/src/atrac3p.h b/src/atrac3p.h
new file mode 100644
index 0000000..779929d
--- /dev/null
+++ b/src/atrac3p.h
@@ -0,0 +1,55 @@
+/*
+ * This file is part of AtracDEnc.
+ *
+ * AtracDEnc is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * AtracDEnc is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with AtracDEnc; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#pragma once
+
+#include "config.h"
+#include "pcmengin.h"
+#include "compressed_io.h"
+
+namespace NAtracDEnc {
+
+class TAt3PEnc : public IProcessor {
+public:
+ struct TSettings {
+ enum GhaProcessingFlags : uint8_t {
+ GHA_PASS_INPUT = 1,
+ GHA_WRITE_TONAL = 1 << 1,
+ GHA_WRITE_RESIUDAL = 1 << 2,
+
+ GHA_ENABLED = GHA_PASS_INPUT | GHA_WRITE_TONAL | GHA_WRITE_RESIUDAL
+ };
+ uint8_t UseGha;
+
+ TSettings()
+ : UseGha(GHA_ENABLED)
+ {}
+ };
+ TAt3PEnc(TCompressedOutputPtr&& out, int channels, TSettings settings);
+ TPCMEngine::TProcessLambda GetLambda() override;
+ static constexpr int NumSamples = 2048;
+ static void ParseAdvancedOpt(const char* opt, TSettings& settings);
+
+private:
+ TCompressedOutputPtr Out;
+ int Channels;
+ class TImpl;
+ std::unique_ptr<TImpl> Impl;
+};
+
+}
diff --git a/src/lib/bs_encode/encode.cpp b/src/lib/bs_encode/encode.cpp
new file mode 100644
index 0000000..230ae0f
--- /dev/null
+++ b/src/lib/bs_encode/encode.cpp
@@ -0,0 +1,184 @@
+/*
+ * This file is part of AtracDEnc.
+ *
+ * AtracDEnc is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * AtracDEnc is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with AtracDEnc; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "encode.h"
+
+#include <iostream>
+
+namespace NAtracDEnc {
+
+using NBitStream::TBitStream;
+
+class TBitStreamEncoder::TImpl : public TBitAllocHandler {
+public:
+ explicit TImpl(std::vector<IBitStreamPartEncoder::TPtr>&& encoders);
+ void DoStart(size_t targetBits, float minLambda, float maxLambda) noexcept;
+ float DoContinue() noexcept;
+ void DoSubmit(size_t gotBits) noexcept;
+ bool DoCheck(size_t gotBits) const noexcept;
+ void DoRun(void* frameData, TBitStream& bs);
+ uint32_t DoGetCurGlobalConsumption() const noexcept;
+private:
+ std::vector<IBitStreamPartEncoder::TPtr> Encoders;
+ size_t CurEncPos;
+ size_t RepeatEncPos;
+
+ size_t TargetBits;
+ float MinLambda;
+ float MaxLambda;
+ float CurLambda;
+ float LastLambda;
+
+ bool NeedRepeat = false;
+};
+
+TBitStreamEncoder::TImpl::TImpl(std::vector<IBitStreamPartEncoder::TPtr>&& encoders)
+ : Encoders(std::move(encoders))
+ , CurEncPos(0)
+ , RepeatEncPos(0)
+{
+}
+
+void TBitStreamEncoder::TImpl::DoStart(size_t targetBits, float minLambda, float maxLambda) noexcept
+{
+ TargetBits = targetBits;
+ MinLambda = minLambda;
+ MaxLambda = maxLambda;
+}
+
+float TBitStreamEncoder::TImpl::DoContinue() noexcept
+{
+ if (MaxLambda <= MinLambda) {
+ return LastLambda;
+ }
+
+ CurLambda = (MaxLambda + MinLambda) / 2.0;
+ RepeatEncPos = CurEncPos;
+ return CurLambda;
+}
+
+void TBitStreamEncoder::TImpl::DoSubmit(size_t gotBits) noexcept
+{
+ if (MaxLambda <= MinLambda) {
+ NeedRepeat = false;
+ } else {
+ if (gotBits < TargetBits) {
+ LastLambda = CurLambda;
+ MaxLambda = CurLambda - 0.01f;
+ NeedRepeat = true;
+ } else if (gotBits > TargetBits) {
+ MinLambda = CurLambda + 0.01f;
+ NeedRepeat = true;
+ } else {
+ NeedRepeat = false;
+ }
+ }
+}
+
+bool TBitStreamEncoder::TImpl::DoCheck(size_t gotBits) const noexcept
+{
+ return gotBits < TargetBits;
+}
+
+void TBitStreamEncoder::TImpl::DoRun(void* frameData, TBitStream& bs)
+{
+ bool cont = false;
+ do {
+ for (CurEncPos = RepeatEncPos; CurEncPos < Encoders.size(); CurEncPos++) {
+ auto status = Encoders[CurEncPos]->Encode(frameData, *this);
+ if (NeedRepeat) {
+ NeedRepeat = false;
+ cont = true;
+ break;
+ } else {
+ cont = false;
+ }
+ if (status == IBitStreamPartEncoder::EStatus::Repeat) {
+ cont = true;
+ for (size_t i = 0; i < CurEncPos; i++) {
+ Encoders[i]->Reset();
+ }
+ RepeatEncPos = 0;
+ break;
+ }
+ }
+ } while (cont);
+
+ for (size_t i = 0; i < Encoders.size(); i++) {
+ Encoders[i]->Dump(bs);
+ }
+}
+
+uint32_t TBitStreamEncoder::TImpl::DoGetCurGlobalConsumption() const noexcept
+{
+ uint32_t consumption = 0;
+ for (size_t i = 0; i < CurEncPos; i++) {
+ consumption += Encoders[i]->GetConsumption();
+ }
+ return consumption;
+}
+
+/////
+
+TBitStreamEncoder::TBitStreamEncoder(std::vector<IBitStreamPartEncoder::TPtr>&& encoders)
+ : Impl(new TBitStreamEncoder::TImpl(std::move(encoders)))
+{}
+
+TBitStreamEncoder::~TBitStreamEncoder()
+{
+ delete Impl;
+}
+
+void TBitStreamEncoder::Do(void* frameData, TBitStream& bs)
+{
+ Impl->DoRun(frameData, bs);
+}
+
+/////
+
+void TBitAllocHandler::Start(size_t targetBits, float minLambda, float maxLambda) noexcept
+{
+ TBitStreamEncoder::TImpl* self = static_cast<TBitStreamEncoder::TImpl*>(this);
+ self->DoStart(targetBits, minLambda, maxLambda);
+}
+
+float TBitAllocHandler::Continue() noexcept
+{
+ TBitStreamEncoder::TImpl* self = static_cast<TBitStreamEncoder::TImpl*>(this);
+ return self->DoContinue();
+}
+
+void TBitAllocHandler::Submit(size_t gotBits) noexcept
+{
+ TBitStreamEncoder::TImpl* self = static_cast<TBitStreamEncoder::TImpl*>(this);
+ self->DoSubmit(gotBits);
+}
+
+bool TBitAllocHandler::Check(size_t gotBits) const noexcept
+{
+ const TBitStreamEncoder::TImpl* self = static_cast<const TBitStreamEncoder::TImpl*>(this);
+ return self->DoCheck(gotBits);
+}
+
+uint32_t TBitAllocHandler::GetCurGlobalConsumption() const noexcept
+{
+ const TBitStreamEncoder::TImpl* self = static_cast<const TBitStreamEncoder::TImpl*>(this);
+ return self->DoGetCurGlobalConsumption();
+}
+
+}
diff --git a/src/lib/bs_encode/encode.h b/src/lib/bs_encode/encode.h
new file mode 100644
index 0000000..3302d10
--- /dev/null
+++ b/src/lib/bs_encode/encode.h
@@ -0,0 +1,71 @@
+/*
+ * This file is part of AtracDEnc.
+ *
+ * AtracDEnc is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * AtracDEnc is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with AtracDEnc; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#pragma once
+
+#include <memory>
+#include <vector>
+#include <functional>
+
+namespace NBitStream {
+class TBitStream;
+}
+
+namespace NAtracDEnc {
+
+class TBitAllocHandler {
+public:
+ void Start(size_t targetBits, float minLambda, float maxLambda) noexcept;
+ float Continue() noexcept;
+ bool Check(size_t gitBits) const noexcept;
+ void Submit(size_t gotBits) noexcept;
+
+ // Returns consumption of all previous encoded parts (except part from this method called)
+ uint32_t GetCurGlobalConsumption() const noexcept;
+};
+
+class IBitStreamPartEncoder {
+public:
+ using TPtr = std::unique_ptr<IBitStreamPartEncoder>;
+ enum class EStatus {
+ Ok, // Ok, go to the next stage
+ Repeat, // Repeat from first stage
+ };
+
+ virtual ~IBitStreamPartEncoder() = default;
+ virtual EStatus Encode(void* frameData, TBitAllocHandler& ba) = 0;
+ virtual void Dump(NBitStream::TBitStream& bs) = 0;
+ virtual void Reset() noexcept {};
+ virtual uint32_t GetConsumption() const noexcept = 0;
+};
+
+class TBitStreamEncoder {
+public:
+ class TImpl;
+ explicit TBitStreamEncoder(std::vector<IBitStreamPartEncoder::TPtr>&& encoders);
+ ~TBitStreamEncoder();
+
+ void Do(void* frameData, NBitStream::TBitStream& bs);
+ TBitStreamEncoder(const TBitStreamEncoder&) = delete;
+ TBitStreamEncoder& operator=(const TBitStreamEncoder&) = delete;
+private:
+ std::vector<IBitStreamPartEncoder::TPtr> Encoders;
+ TImpl* Impl;
+};
+
+}
diff --git a/src/lib/bs_encode/encode_ut.cpp b/src/lib/bs_encode/encode_ut.cpp
new file mode 100644
index 0000000..39f0ff1
--- /dev/null
+++ b/src/lib/bs_encode/encode_ut.cpp
@@ -0,0 +1,178 @@
+/*
+ * This file is part of AtracDEnc.
+ *
+ * AtracDEnc is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * AtracDEnc is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with AtracDEnc; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "encode.h"
+#include <gtest/gtest.h>
+#include <cmath>
+#include <memory>
+#include <bitstream/bitstream.h>
+
+using namespace NAtracDEnc;
+
+static size_t SomeBitFn1(float lambda) {
+ return sqrt(lambda * (-1.0f)) * 300;
+}
+
+static size_t SomeBitFn2(float lambda) {
+ return 1 + (SomeBitFn1(lambda) & (~(size_t)7));
+}
+
+class TPartEncoder1 : public IBitStreamPartEncoder {
+public:
+ explicit TPartEncoder1(size_t expCalls)
+ : ExpCalls(expCalls)
+ {}
+
+ EStatus Encode(void* frameData, TBitAllocHandler& ba) override {
+ EncCalls++;
+ ba.Start(1000, -15, -1);
+ return EStatus::Ok;
+ }
+
+ void Dump(NBitStream::TBitStream& bs) override {
+ EXPECT_EQ(EncCalls, ExpCalls);
+ }
+
+ uint32_t GetConsumption() const noexcept override {
+ return 0;
+ }
+private:
+ const size_t ExpCalls;
+ size_t EncCalls = 0;
+};
+
+template<size_t (*F)(float)>
+class TPartEncoder2 : public IBitStreamPartEncoder {
+public:
+ explicit TPartEncoder2(size_t expCalls)
+ : ExpCalls(expCalls)
+ {}
+
+ EStatus Encode(void* frameData, TBitAllocHandler& ba) override {
+ EncCalls++;
+ auto lambda = ba.Continue();
+ auto bits = F(lambda);
+ ba.Submit(bits);
+ Bits = bits;
+ return EStatus::Ok;
+ }
+
+ void Dump(NBitStream::TBitStream& bs) override {
+ EXPECT_EQ(EncCalls, ExpCalls);
+ for (size_t i = 0; i < Bits; i++) {
+ bs.Write(1, 1);
+ }
+ }
+
+ uint32_t GetConsumption() const noexcept override {
+ return 1 * Bits;
+ }
+private:
+ const size_t ExpCalls;
+ size_t EncCalls = 0;
+ size_t Bits = 0;
+};
+
+class TPartEncoder3 : public IBitStreamPartEncoder {
+public:
+ explicit TPartEncoder3(size_t expCalls)
+ : ExpCalls(expCalls)
+ {}
+
+ EStatus Encode(void* frameData, TBitAllocHandler& ba) override {
+ EncCalls++;
+ return EStatus::Ok;
+ }
+
+ void Dump(NBitStream::TBitStream& bs) override {
+ EXPECT_EQ(EncCalls, ExpCalls);
+ }
+
+ uint32_t GetConsumption() const noexcept override {
+ return 0;
+ }
+private:
+ const size_t ExpCalls;
+ size_t EncCalls = 0;
+};
+
+class TPartEncoder4 : public IBitStreamPartEncoder {
+public:
+ TPartEncoder4() = default;
+
+ EStatus Encode(void* frameData, TBitAllocHandler& ba) override {
+ if (EncCalls == 0) {
+ EncCalls++;
+ return EStatus::Repeat;
+ }
+
+ return EStatus::Ok;
+ }
+
+ void Dump(NBitStream::TBitStream& bs) override {
+ EXPECT_EQ(EncCalls, 1);
+ }
+
+ uint32_t GetConsumption() const noexcept override {
+ return 0;
+ }
+private:
+ size_t EncCalls = 0;
+};
+
+TEST(BsEncode, SimpleAlloc) {
+ std::vector<IBitStreamPartEncoder::TPtr> encoders;
+ encoders.emplace_back(std::make_unique<TPartEncoder1>(1));
+ encoders.emplace_back(std::make_unique<TPartEncoder2<SomeBitFn1>>(8));
+ encoders.emplace_back(std::make_unique<TPartEncoder3>(1));
+
+ NBitStream::TBitStream bs;
+ TBitStreamEncoder encoder(std::move(encoders));
+ encoder.Do(nullptr, bs);
+
+ EXPECT_EQ(bs.GetSizeInBits(), 1000);
+}
+
+TEST(BsEncode, AllocWithRepeat) {
+ std::vector<IBitStreamPartEncoder::TPtr> encoders;
+ encoders.emplace_back(std::make_unique<TPartEncoder1>(2));
+ encoders.emplace_back(std::make_unique<TPartEncoder2<SomeBitFn1>>(16));
+ encoders.emplace_back(std::make_unique<TPartEncoder3>(2));
+ encoders.emplace_back(std::make_unique<TPartEncoder4>());
+
+ NBitStream::TBitStream bs;
+ TBitStreamEncoder encoder(std::move(encoders));
+ encoder.Do(nullptr, bs);
+
+ EXPECT_EQ(bs.GetSizeInBits(), 1000);
+}
+
+TEST(BsEncode, NotExactAlloc) {
+ std::vector<IBitStreamPartEncoder::TPtr> encoders;
+ encoders.emplace_back(std::make_unique<TPartEncoder1>(1));
+ encoders.emplace_back(std::make_unique<TPartEncoder2<SomeBitFn2>>(11));
+ encoders.emplace_back(std::make_unique<TPartEncoder3>(1));
+
+ NBitStream::TBitStream bs;
+ TBitStreamEncoder encoder(std::move(encoders));
+ encoder.Do(nullptr, bs);
+
+ EXPECT_EQ(bs.GetSizeInBits(), 993);
+}
+
+
diff --git a/src/lib/fft/kissfft_impl/kiss_fft.h b/src/lib/fft/kissfft_impl/kiss_fft.h
index 7786eb6..64c50f4 100644
--- a/src/lib/fft/kissfft_impl/kiss_fft.h
+++ b/src/lib/fft/kissfft_impl/kiss_fft.h
@@ -44,7 +44,6 @@ extern "C" {
#else
# ifndef kiss_fft_scalar
/* default is float */
-# error "wrong type"
# define kiss_fft_scalar float
# endif
#endif
diff --git a/src/lib/fft/kissfft_impl/tools/kiss_fftr.c b/src/lib/fft/kissfft_impl/tools/kiss_fftr.c
new file mode 100644
index 0000000..8102132
--- /dev/null
+++ b/src/lib/fft/kissfft_impl/tools/kiss_fftr.c
@@ -0,0 +1,153 @@
+/*
+ * Copyright (c) 2003-2004, Mark Borgerding. All rights reserved.
+ * This file is part of KISS FFT - https://github.com/mborgerding/kissfft
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ * See COPYING file for more information.
+ */
+
+#include "kiss_fftr.h"
+#include "_kiss_fft_guts.h"
+
+struct kiss_fftr_state{
+ kiss_fft_cfg substate;
+ kiss_fft_cpx * tmpbuf;
+ kiss_fft_cpx * super_twiddles;
+#ifdef USE_SIMD
+ void * pad;
+#endif
+};
+
+kiss_fftr_cfg kiss_fftr_alloc(int nfft,int inverse_fft,void * mem,size_t * lenmem)
+{
+ int i;
+ kiss_fftr_cfg st = NULL;
+ size_t subsize = 0, memneeded;
+
+ if (nfft & 1) {
+ fprintf(stderr,"Real FFT optimization must be even.\n");
+ return NULL;
+ }
+ nfft >>= 1;
+
+ kiss_fft_alloc (nfft, inverse_fft, NULL, &subsize);
+ memneeded = sizeof(struct kiss_fftr_state) + subsize + sizeof(kiss_fft_cpx) * ( nfft * 3 / 2);
+
+ if (lenmem == NULL) {
+ st = (kiss_fftr_cfg) KISS_FFT_MALLOC (memneeded);
+ } else {
+ if (*lenmem >= memneeded)
+ st = (kiss_fftr_cfg) mem;
+ *lenmem = memneeded;
+ }
+ if (!st)
+ return NULL;
+
+ st->substate = (kiss_fft_cfg) (st + 1); /*just beyond kiss_fftr_state struct */
+ st->tmpbuf = (kiss_fft_cpx *) (((char *) st->substate) + subsize);
+ st->super_twiddles = st->tmpbuf + nfft;
+ kiss_fft_alloc(nfft, inverse_fft, st->substate, &subsize);
+
+ for (i = 0; i < nfft/2; ++i) {
+ double phase =
+ -3.14159265358979323846264338327 * ((double) (i+1) / nfft + .5);
+ if (inverse_fft)
+ phase *= -1;
+ kf_cexp (st->super_twiddles+i,phase);
+ }
+ return st;
+}
+
+void kiss_fftr(kiss_fftr_cfg st,const kiss_fft_scalar *timedata,kiss_fft_cpx *freqdata)
+{
+ /* input buffer timedata is stored row-wise */
+ int k,ncfft;
+ kiss_fft_cpx fpnk,fpk,f1k,f2k,tw,tdc;
+
+ if ( st->substate->inverse) {
+ fprintf(stderr,"kiss fft usage error: improper alloc\n");
+ exit(1);
+ }
+
+ ncfft = st->substate->nfft;
+
+ /*perform the parallel fft of two real signals packed in real,imag*/
+ kiss_fft( st->substate , (const kiss_fft_cpx*)timedata, st->tmpbuf );
+ /* The real part of the DC element of the frequency spectrum in st->tmpbuf
+ * contains the sum of the even-numbered elements of the input time sequence
+ * The imag part is the sum of the odd-numbered elements
+ *
+ * The sum of tdc.r and tdc.i is the sum of the input time sequence.
+ * yielding DC of input time sequence
+ * The difference of tdc.r - tdc.i is the sum of the input (dot product) [1,-1,1,-1...
+ * yielding Nyquist bin of input time sequence
+ */
+
+ tdc.r = st->tmpbuf[0].r;
+ tdc.i = st->tmpbuf[0].i;
+ C_FIXDIV(tdc,2);
+ CHECK_OVERFLOW_OP(tdc.r ,+, tdc.i);
+ CHECK_OVERFLOW_OP(tdc.r ,-, tdc.i);
+ freqdata[0].r = tdc.r + tdc.i;
+ freqdata[ncfft].r = tdc.r - tdc.i;
+#ifdef USE_SIMD
+ freqdata[ncfft].i = freqdata[0].i = _mm_set1_ps(0);
+#else
+ freqdata[ncfft].i = freqdata[0].i = 0;
+#endif
+
+ for ( k=1;k <= ncfft/2 ; ++k ) {
+ fpk = st->tmpbuf[k];
+ fpnk.r = st->tmpbuf[ncfft-k].r;
+ fpnk.i = - st->tmpbuf[ncfft-k].i;
+ C_FIXDIV(fpk,2);
+ C_FIXDIV(fpnk,2);
+
+ C_ADD( f1k, fpk , fpnk );
+ C_SUB( f2k, fpk , fpnk );
+ C_MUL( tw , f2k , st->super_twiddles[k-1]);
+
+ freqdata[k].r = HALF_OF(f1k.r + tw.r);
+ freqdata[k].i = HALF_OF(f1k.i + tw.i);
+ freqdata[ncfft-k].r = HALF_OF(f1k.r - tw.r);
+ freqdata[ncfft-k].i = HALF_OF(tw.i - f1k.i);
+ }
+}
+
+void kiss_fftri(kiss_fftr_cfg st,const kiss_fft_cpx *freqdata,kiss_fft_scalar *timedata)
+{
+ /* input buffer timedata is stored row-wise */
+ int k, ncfft;
+
+ if (st->substate->inverse == 0) {
+ fprintf (stderr, "kiss fft usage error: improper alloc\n");
+ exit (1);
+ }
+
+ ncfft = st->substate->nfft;
+
+ st->tmpbuf[0].r = freqdata[0].r + freqdata[ncfft].r;
+ st->tmpbuf[0].i = freqdata[0].r - freqdata[ncfft].r;
+ C_FIXDIV(st->tmpbuf[0],2);
+
+ for (k = 1; k <= ncfft / 2; ++k) {
+ kiss_fft_cpx fk, fnkc, fek, fok, tmp;
+ fk = freqdata[k];
+ fnkc.r = freqdata[ncfft - k].r;
+ fnkc.i = -freqdata[ncfft - k].i;
+ C_FIXDIV( fk , 2 );
+ C_FIXDIV( fnkc , 2 );
+
+ C_ADD (fek, fk, fnkc);
+ C_SUB (tmp, fk, fnkc);
+ C_MUL (fok, tmp, st->super_twiddles[k-1]);
+ C_ADD (st->tmpbuf[k], fek, fok);
+ C_SUB (st->tmpbuf[ncfft - k], fek, fok);
+#ifdef USE_SIMD
+ st->tmpbuf[ncfft - k].i *= _mm_set1_ps(-1.0);
+#else
+ st->tmpbuf[ncfft - k].i *= -1;
+#endif
+ }
+ kiss_fft (st->substate, st->tmpbuf, (kiss_fft_cpx *) timedata);
+}
diff --git a/src/lib/fft/kissfft_impl/tools/kiss_fftr.h b/src/lib/fft/kissfft_impl/tools/kiss_fftr.h
new file mode 100644
index 0000000..588948d
--- /dev/null
+++ b/src/lib/fft/kissfft_impl/tools/kiss_fftr.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2003-2004, Mark Borgerding. All rights reserved.
+ * This file is part of KISS FFT - https://github.com/mborgerding/kissfft
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ * See COPYING file for more information.
+ */
+
+#ifndef KISS_FTR_H
+#define KISS_FTR_H
+
+#include "kiss_fft.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/*
+
+ Real optimized version can save about 45% cpu time vs. complex fft of a real seq.
+
+
+
+ */
+
+typedef struct kiss_fftr_state *kiss_fftr_cfg;
+
+
+kiss_fftr_cfg kiss_fftr_alloc(int nfft,int inverse_fft,void * mem, size_t * lenmem);
+/*
+ nfft must be even
+
+ If you don't care to allocate space, use mem = lenmem = NULL
+*/
+
+
+void kiss_fftr(kiss_fftr_cfg cfg,const kiss_fft_scalar *timedata,kiss_fft_cpx *freqdata);
+/*
+ input timedata has nfft scalar points
+ output freqdata has nfft/2+1 complex points
+*/
+
+void kiss_fftri(kiss_fftr_cfg cfg,const kiss_fft_cpx *freqdata,kiss_fft_scalar *timedata);
+/*
+ input freqdata has nfft/2+1 complex points
+ output timedata has nfft scalar points
+*/
+
+#define kiss_fftr_free KISS_FFT_FREE
+
+#ifdef __cplusplus
+}
+#endif
+#endif
diff --git a/src/lib/libgha b/src/lib/libgha
new file mode 160000
+Subproject 0c3e65863f31459c4be8a12051a8d6260cb1d30
diff --git a/src/main.cpp b/src/main.cpp
index faf88e9..861495f 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -32,6 +32,7 @@
#include "config.h"
#include "atrac1denc.h"
#include "atrac3denc.h"
+#include "atrac3p.h"
#ifdef PLATFORM_WINDOWS
#include <windows.h>
@@ -89,6 +90,13 @@ static int checkedStoi(const char* data, int min, int max, int def)
}
}
+enum EMode {
+ E_ENCODE = 1,
+ E_DECODE = 2,
+ E_ATRAC3 = 4,
+ E_ATRAC3PLUS = 8
+};
+
enum EOptions
{
O_ENCODE = 'e',
@@ -102,6 +110,7 @@ enum EOptions
O_NOSTDOUT = '4',
O_NOTONAL = 5,
O_NOGAINCONTROL = 6,
+ O_ADVANCED_OPT = 7,
};
static void CheckInputFormat(const TWav* p)
@@ -243,9 +252,68 @@ static void PrepareAtrac3Encoder(const string& inFile,
atracProcessor->reset(new TAtrac3Encoder(std::move(omaIO), std::move(encoderSettings)));
}
+static void PrepareAtrac3PEncoder(const string& inFile,
+ const string& outFile,
+ const bool noStdOut,
+ int numChannels,
+ uint64_t* totalSamples,
+ const TWavPtr& wavIO,
+ TPcmEnginePtr* pcmEngine,
+ TAtracProcessorPtr* atracProcessor,
+ const char* advancedOpt)
+{
+ *totalSamples = wavIO->GetTotalSamples();
+ const uint64_t numFrames = (*totalSamples) / 2048;
+ if (numFrames >= UINT32_MAX) {
+ std::cerr << "Number of input samples exceeds output format limitation,"
+ "the result will be incorrect" << std::endl;
+ }
+
+ const string ext = GetFileExt(outFile);
+
+ TCompressedOutputPtr omaIO;
+
+ string contName;
+ if (ext == "wav" || ext == "at3") {
+ throw std::runtime_error("Not implemented");
+ } else if (ext == "rm") {
+ throw std::runtime_error("RealMedia container is not supported for ATRAC3PLUS");
+ } else {
+ contName = "OMA";
+ omaIO.reset(new TOma(outFile,
+ "test",
+ numChannels,
+ (int32_t)numFrames, OMAC_ID_ATRAC3PLUS,
+ 2048,
+ false));
+ }
+
+ if (!noStdOut)
+ cout << "Input:\n Filename: " << inFile
+ << "\n Channels: " << (int)numChannels
+ << "\n SampleRate: " << wavIO->GetSampleRate()
+ << "\n Duration (sec): " << *totalSamples / wavIO->GetSampleRate()
+ << "\nOutput:\n Filename: " << outFile
+ << "\n Codec: ATRAC3Plus"
+ << "\n Container: " << contName
+ //<< "\n Bitrate: " << encoderSettings.ConteinerParams->Bitrate
+ << endl;
+
+ pcmEngine->reset(new TPCMEngine(4096,
+ numChannels,
+ TPCMEngine::TReaderPtr(wavIO->GetPCMReader())));
+ TAt3PEnc::TSettings settings;
+ if (advancedOpt) {
+ TAt3PEnc::ParseAdvancedOpt(advancedOpt, settings);
+ }
+ atracProcessor->reset(new TAt3PEnc(std::move(omaIO), numChannels, settings));
+}
+
+
int main_(int argc, char* const* argv)
{
const char* myName = argv[0];
+ const char* advancedOpt = nullptr;
static struct option longopts[] = {
{ "encode", optional_argument, NULL, O_ENCODE },
{ "decode", no_argument, NULL, O_DECODE },
@@ -256,6 +324,7 @@ int main_(int argc, char* const* argv)
{ "notransient", optional_argument, NULL, O_NOTRANSIENT},
{ "nostdout", no_argument, NULL, O_NOSTDOUT},
{ "nogaincontrol", no_argument, NULL, O_NOGAINCONTROL},
+ { "advanced", required_argument, NULL, O_ADVANCED_OPT},
{ NULL, 0, NULL, 0}
};
@@ -282,6 +351,8 @@ int main_(int argc, char* const* argv)
} else if (strcmp(optarg, "atrac3_lp4") == 0) {
mode |= E_ATRAC3;
bitrate = 64;
+ } else if (strcmp(optarg, "atrac3plus") == 0) {
+ mode |= E_ATRAC3PLUS;
} else if (strcmp(optarg, "atrac1") == 0) {
// this is the default
} else {
@@ -336,6 +407,9 @@ int main_(int argc, char* const* argv)
case O_NOGAINCONTROL:
noGainControl = true;
break;
+ case O_ADVANCED_OPT:
+ advancedOpt = optarg;
+ break;
default:
printUsage(myName);
return 1;
@@ -399,6 +473,14 @@ int main_(int argc, char* const* argv)
pcmFrameSz = TAtrac3Data::NumSamples;;
}
break;
+ case (E_ENCODE | E_ATRAC3PLUS):
+ {
+ wavIO = OpenWavFile(inFile);
+ PrepareAtrac3PEncoder(inFile, outFile, noStdOut, wavIO->GetChannelNum(),
+ &totalSamples, wavIO, &pcmEngine, &atracProcessor, advancedOpt);
+ pcmFrameSz = 2048;
+ }
+ break;
default:
{
throw std::runtime_error("Processing mode was not specified");
diff --git a/src/oma.cpp b/src/oma.cpp
index bef90dd..7ef06c1 100644
--- a/src/oma.cpp
+++ b/src/oma.cpp
@@ -24,12 +24,14 @@ using std::string;
using std::vector;
using std::unique_ptr;
-TOma::TOma(const string& filename, const string&, size_t /*numChannel*/,
+TOma::TOma(const string& filename, const string&, size_t numChannel,
uint32_t /*numFrames*/, int cid, uint32_t framesize, bool jointStereo) {
oma_info_t info;
info.codec = cid;
info.samplerate = 44100;
- info.channel_format = jointStereo ? OMA_STEREO_JS : OMA_STEREO;
+ info.channel_format = (cid == OMAC_ID_ATRAC3)
+ ? (jointStereo ? OMA_STEREO_JS : OMA_STEREO)
+ : (numChannel == 1 ? OMA_MONO : OMA_STEREO);
info.framesize = framesize;
File = oma_open(filename.c_str(), OMAM_W, &info);
if (!File)
diff --git a/src/pcmengin.h b/src/pcmengin.h
index d5d9644..8d1db3f 100644
--- a/src/pcmengin.h
+++ b/src/pcmengin.h
@@ -28,6 +28,9 @@
#include <assert.h>
#include <string.h>
+class TNoDataToRead : public std::exception {
+};
+
class TPCMBufferTooSmall : public std::exception {
virtual const char* what() const throw() {
return "PCM buffer too small";
@@ -99,7 +102,7 @@ class IPCMWriter {
class IPCMReader {
public:
- virtual void Read(TPCMBuffer& data , const uint32_t size) const = 0;
+ virtual bool Read(TPCMBuffer& data , const uint32_t size) const = 0;
IPCMReader() {};
virtual ~IPCMReader() {};
};
@@ -116,6 +119,7 @@ private:
TWriterPtr Writer;
TReaderPtr Reader;
uint64_t Processed = 0;
+ uint64_t ToDrain = 0;
public:
TPCMEngine(uint16_t bufSize, size_t numChannels)
: Buffer(bufSize, numChannels) {
@@ -137,23 +141,45 @@ public:
, Reader(std::move(reader)) {
}
- typedef std::function<void(float* data, const ProcessMeta& meta)> TProcessLambda;
+ enum class EProcessResult {
+ LOOK_AHEAD, // need more data to process
+ PROCESSED,
+ };
+
+ typedef std::function<EProcessResult(float* data, const ProcessMeta& meta)> TProcessLambda;
uint64_t ApplyProcess(size_t step, TProcessLambda lambda) {
if (step > Buffer.Size()) {
throw TPCMBufferTooSmall();
}
+ bool drain = false;
if (Reader) {
const uint32_t sizeToRead = Buffer.Size();
- Reader->Read(Buffer, sizeToRead);
+ const bool ok = Reader->Read(Buffer, sizeToRead);
+ if (!ok) {
+ if (ToDrain) {
+ drain = true;
+ } else {
+ throw TNoDataToRead();
+ }
+ }
}
size_t lastPos = 0;
ProcessMeta meta = {Buffer.Channels()};
+
for (size_t i = 0; i + step <= Buffer.Size(); i+=step) {
- lambda(Buffer[i], meta);
- lastPos = i + step;
+ auto res = lambda(Buffer[i], meta);
+ if (res == EProcessResult::PROCESSED) {
+ lastPos += step;
+ if (drain && ToDrain--) {
+ break;
+ }
+ } else {
+ assert(!drain);
+ ToDrain++;
+ }
}
assert(lastPos == Buffer.Size());
diff --git a/src/util.h b/src/util.h
index ff4399e..2587aa7 100644
--- a/src/util.h
+++ b/src/util.h
@@ -33,6 +33,11 @@
#define ASSERT(x) assert(x)
#endif
+#if defined(_MSC_VER)
+# define atde_noinline __declspec(noinline)
+#else
+# define atde_noinline __attribute__((noinline))
+#endif
template<class T>
inline void SwapArray(T* p, const size_t len) {
diff --git a/src/wav.cpp b/src/wav.cpp
index f62bbb3..08bff51 100644
--- a/src/wav.cpp
+++ b/src/wav.cpp
@@ -51,10 +51,12 @@ IPCMReader* TWav::GetPCMReader() const {
size_t read;
if ((read = Impl->Read(data, size)) != size) {
if (!read)
- throw TNoDataToRead();
+ return false;
data.Zero(read, size - read);
}
+
+ return true;
});
}
diff --git a/src/wav.h b/src/wav.h
index aed64f5..a101c8d 100644
--- a/src/wav.h
+++ b/src/wav.h
@@ -28,18 +28,15 @@
class TFileAlreadyExists : public std::exception {
};
-class TNoDataToRead : public std::exception {
-};
-
class TWavPcmReader : public IPCMReader {
public:
- typedef std::function<void(TPCMBuffer& data, const uint32_t size)> TLambda;
+ typedef std::function<bool(TPCMBuffer& data, const uint32_t size)> TLambda;
TLambda Lambda;
TWavPcmReader(TLambda lambda)
: Lambda(lambda)
{}
- void Read(TPCMBuffer& data , const uint32_t size) const override {
- Lambda(data, size);
+ bool Read(TPCMBuffer& data , const uint32_t size) const override {
+ return Lambda(data, size);
}
};