[FFmpeg-cvslog] ATRAC3+ decoder

Maxim Polijakowski git at videolan.org
Thu Jan 9 21:04:50 CET 2014


ffmpeg | branch: master | Maxim Polijakowski <max_pole at gmx.de> | Fri Jan  3 23:23:11 2014 +0100| [e6f0bb65270be51ea43345a28f8e4b1a728f7d0e] | committer: Kostya Shishkov

ATRAC3+ decoder

Cleanup by Diego Biurrun.

Signed-off-by: Kostya Shishkov <kostya.shishkov at gmail.com>

> http://git.videolan.org/gitweb.cgi/ffmpeg.git/?a=commit;h=e6f0bb65270be51ea43345a28f8e4b1a728f7d0e
---

 Changelog                    |    1 +
 configure                    |    1 +
 doc/general.texi             |    1 +
 libavcodec/Makefile          |    2 +
 libavcodec/allcodecs.c       |    1 +
 libavcodec/atrac3plus.c      | 1818 +++++++++++++++++++++++++++++++++++++++
 libavcodec/atrac3plus.h      |  242 ++++++
 libavcodec/atrac3plus_data.h | 1914 ++++++++++++++++++++++++++++++++++++++++++
 libavcodec/atrac3plusdec.c   |  387 +++++++++
 libavcodec/atrac3plusdsp.c   |  638 ++++++++++++++
 libavcodec/version.h         |    2 +-
 libavformat/omadec.c         |    3 +-
 12 files changed, 5007 insertions(+), 3 deletions(-)

diff --git a/Changelog b/Changelog
index efd474a..c97d4e5 100644
--- a/Changelog
+++ b/Changelog
@@ -53,6 +53,7 @@ version 10:
 - stereoscopic 3d metadata handling
 - png standalone parser
 - WebP encoding via libwebp
+- ATRAC3+ decoder
 
 
 version 9:
diff --git a/configure b/configure
index e9fc08c..d16bc6a 100755
--- a/configure
+++ b/configure
@@ -1630,6 +1630,7 @@ asv2_decoder_select="dsputil"
 asv2_encoder_select="dsputil"
 atrac1_decoder_select="mdct sinewin"
 atrac3_decoder_select="mdct"
+atrac3p_decoder_select="mdct sinewin"
 bink_decoder_select="dsputil hpeldsp"
 binkaudio_dct_decoder_select="mdct rdft dct sinewin"
 binkaudio_rdft_decoder_select="mdct rdft sinewin"
diff --git a/doc/general.texi b/doc/general.texi
index a528280..9fa79f5 100644
--- a/doc/general.texi
+++ b/doc/general.texi
@@ -729,6 +729,7 @@ following image formats are supported:
     @tab QuickTime fourcc 'alac'
 @item ATRAC1                 @tab     @tab  X
 @item ATRAC3                 @tab     @tab  X
+ at item ATRAC3+                @tab     @tab  X
 @item Bink Audio             @tab     @tab  X
     @tab Used in Bink and Smacker files in many games.
 @item Delphine Software International CIN audio  @tab     @tab  X
diff --git a/libavcodec/Makefile b/libavcodec/Makefile
index fd7808e..7a978bb 100644
--- a/libavcodec/Makefile
+++ b/libavcodec/Makefile
@@ -107,6 +107,8 @@ OBJS-$(CONFIG_ASV2_DECODER)            += asvdec.o asv.o mpeg12data.o
 OBJS-$(CONFIG_ASV2_ENCODER)            += asvenc.o asv.o mpeg12data.o
 OBJS-$(CONFIG_ATRAC1_DECODER)          += atrac1.o atrac.o
 OBJS-$(CONFIG_ATRAC3_DECODER)          += atrac3.o atrac.o
+OBJS-$(CONFIG_ATRAC3P_DECODER)         += atrac3plusdec.o atrac3plus.o \
+                                          atrac3plusdsp.o atrac.o
 OBJS-$(CONFIG_AURA_DECODER)            += cyuv.o
 OBJS-$(CONFIG_AURA2_DECODER)           += aura.o
 OBJS-$(CONFIG_AVS_DECODER)             += avs.o
diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c
index 5a6c914..2e56ec1 100644
--- a/libavcodec/allcodecs.c
+++ b/libavcodec/allcodecs.c
@@ -287,6 +287,7 @@ void avcodec_register_all(void)
     REGISTER_DECODER(APE,               ape);
     REGISTER_DECODER(ATRAC1,            atrac1);
     REGISTER_DECODER(ATRAC3,            atrac3);
+    REGISTER_DECODER(ATRAC3P,           atrac3p);
     REGISTER_DECODER(BINKAUDIO_DCT,     binkaudio_dct);
     REGISTER_DECODER(BINKAUDIO_RDFT,    binkaudio_rdft);
     REGISTER_DECODER(BMV_AUDIO,         bmv_audio);
diff --git a/libavcodec/atrac3plus.c b/libavcodec/atrac3plus.c
new file mode 100644
index 0000000..f337fab
--- /dev/null
+++ b/libavcodec/atrac3plus.c
@@ -0,0 +1,1818 @@
+/*
+ * ATRAC3+ compatible decoder
+ *
+ * Copyright (c) 2010-2013 Maxim Poliakovski
+ *
+ * This file is part of Libav.
+ *
+ * Libav 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.
+ *
+ * Libav 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 Libav; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * @file
+ * Bitstream parser for ATRAC3+ decoder.
+ */
+
+#include "libavutil/avassert.h"
+#include "avcodec.h"
+#include "get_bits.h"
+#include "atrac3plus.h"
+#include "atrac3plus_data.h"
+
+static VLC_TYPE tables_data[154276][2];
+static VLC wl_vlc_tabs[4];
+static VLC sf_vlc_tabs[8];
+static VLC ct_vlc_tabs[4];
+static VLC spec_vlc_tabs[112];
+static VLC gain_vlc_tabs[11];
+static VLC tone_vlc_tabs[7];
+
+#define GET_DELTA(gb, delta_bits) \
+    ((delta_bits) ? get_bits((gb), (delta_bits)) : 0)
+
+/**
+ * Generate canonical VLC table from given descriptor.
+ *
+ * @param[in]     cb          ptr to codebook descriptor
+ * @param[in]     xlat        ptr to translation table or NULL
+ * @param[in,out] tab_offset  starting offset to the generated vlc table
+ * @param[out]    out_vlc     ptr to vlc table to be generated
+ */
+static av_cold void build_canonical_huff(const uint8_t *cb, const uint8_t *xlat,
+                                         int *tab_offset, VLC *out_vlc)
+{
+    int i, b;
+    uint16_t codes[256];
+    uint8_t bits[256];
+    unsigned code = 0;
+    int index = 0;
+    int min_len = *cb++; // get shortest codeword length
+    int max_len = *cb++; // get longest  codeword length
+
+    for (b = min_len; b <= max_len; b++) {
+        for (i = *cb++; i > 0; i--) {
+            av_assert0(index < 256);
+            bits[index]  = b;
+            codes[index] = code++;
+            index++;
+        }
+        code <<= 1;
+    }
+
+    out_vlc->table = &tables_data[*tab_offset];
+    out_vlc->table_allocated = 1 << max_len;
+
+    ff_init_vlc_sparse(out_vlc, max_len, index, bits, 1, 1, codes, 2, 2,
+                       xlat, 1, 1, INIT_VLC_USE_NEW_STATIC);
+
+    *tab_offset += 1 << max_len;
+}
+
+av_cold void ff_atrac3p_init_vlcs(AVCodec *codec)
+{
+    int i, wl_vlc_offs, ct_vlc_offs, sf_vlc_offs, tab_offset;
+
+    static int wl_nb_bits[4]  = { 2, 3, 5, 5 };
+    static int wl_nb_codes[4] = { 3, 5, 8, 8 };
+    static const uint8_t *wl_bits[4] = {
+        atrac3p_wl_huff_bits1, atrac3p_wl_huff_bits2,
+        atrac3p_wl_huff_bits3, atrac3p_wl_huff_bits4
+    };
+    static const uint8_t *wl_codes[4] = {
+        atrac3p_wl_huff_code1, atrac3p_wl_huff_code2,
+        atrac3p_wl_huff_code3, atrac3p_wl_huff_code4
+    };
+    static const uint8_t *wl_xlats[4] = {
+        atrac3p_wl_huff_xlat1, atrac3p_wl_huff_xlat2, NULL, NULL
+    };
+
+    static int ct_nb_bits[4]  = { 3, 4, 4, 4 };
+    static int ct_nb_codes[4] = { 4, 8, 8, 8 };
+    static const uint8_t *ct_bits[4]  = {
+        atrac3p_ct_huff_bits1, atrac3p_ct_huff_bits2,
+        atrac3p_ct_huff_bits2, atrac3p_ct_huff_bits3
+    };
+    static const uint8_t *ct_codes[4] = {
+        atrac3p_ct_huff_code1, atrac3p_ct_huff_code2,
+        atrac3p_ct_huff_code2, atrac3p_ct_huff_code3
+    };
+    static const uint8_t *ct_xlats[4] = {
+        NULL, NULL, atrac3p_ct_huff_xlat1, NULL
+    };
+
+    static int sf_nb_bits[8]  = {  9,  9,  9,  9,  6,  6,  7,  7 };
+    static int sf_nb_codes[8] = { 64, 64, 64, 64, 16, 16, 16, 16 };
+    static const uint8_t  *sf_bits[8]  = {
+        atrac3p_sf_huff_bits1, atrac3p_sf_huff_bits1, atrac3p_sf_huff_bits2,
+        atrac3p_sf_huff_bits3, atrac3p_sf_huff_bits4, atrac3p_sf_huff_bits4,
+        atrac3p_sf_huff_bits5, atrac3p_sf_huff_bits6
+    };
+    static const uint16_t *sf_codes[8] = {
+        atrac3p_sf_huff_code1, atrac3p_sf_huff_code1, atrac3p_sf_huff_code2,
+        atrac3p_sf_huff_code3, atrac3p_sf_huff_code4, atrac3p_sf_huff_code4,
+        atrac3p_sf_huff_code5, atrac3p_sf_huff_code6
+    };
+    static const uint8_t  *sf_xlats[8] = {
+        atrac3p_sf_huff_xlat1, atrac3p_sf_huff_xlat2, NULL, NULL,
+        atrac3p_sf_huff_xlat4, atrac3p_sf_huff_xlat5, NULL, NULL
+    };
+
+    static const uint8_t *gain_cbs[11] = {
+        atrac3p_huff_gain_npoints1_cb, atrac3p_huff_gain_npoints1_cb,
+        atrac3p_huff_gain_lev1_cb, atrac3p_huff_gain_lev2_cb,
+        atrac3p_huff_gain_lev3_cb, atrac3p_huff_gain_lev4_cb,
+        atrac3p_huff_gain_loc3_cb, atrac3p_huff_gain_loc1_cb,
+        atrac3p_huff_gain_loc4_cb, atrac3p_huff_gain_loc2_cb,
+        atrac3p_huff_gain_loc5_cb
+    };
+    static const uint8_t *gain_xlats[11] = {
+        NULL, atrac3p_huff_gain_npoints2_xlat, atrac3p_huff_gain_lev1_xlat,
+        atrac3p_huff_gain_lev2_xlat, atrac3p_huff_gain_lev3_xlat,
+        atrac3p_huff_gain_lev4_xlat, atrac3p_huff_gain_loc3_xlat,
+        atrac3p_huff_gain_loc1_xlat, atrac3p_huff_gain_loc4_xlat,
+        atrac3p_huff_gain_loc2_xlat, atrac3p_huff_gain_loc5_xlat
+    };
+
+    static const uint8_t *tone_cbs[7] = {
+        atrac3p_huff_tonebands_cb,  atrac3p_huff_numwavs1_cb,
+        atrac3p_huff_numwavs2_cb,   atrac3p_huff_wav_ampsf1_cb,
+        atrac3p_huff_wav_ampsf2_cb, atrac3p_huff_wav_ampsf3_cb,
+        atrac3p_huff_freq_cb
+    };
+    static const uint8_t *tone_xlats[7] = {
+        NULL, NULL, atrac3p_huff_numwavs2_xlat, atrac3p_huff_wav_ampsf1_xlat,
+        atrac3p_huff_wav_ampsf2_xlat, atrac3p_huff_wav_ampsf3_xlat,
+        atrac3p_huff_freq_xlat
+    };
+
+    for (i = 0, wl_vlc_offs = 0, ct_vlc_offs = 2508; i < 4; i++) {
+        wl_vlc_tabs[i].table = &tables_data[wl_vlc_offs];
+        wl_vlc_tabs[i].table_allocated = 1 << wl_nb_bits[i];
+        ct_vlc_tabs[i].table = &tables_data[ct_vlc_offs];
+        ct_vlc_tabs[i].table_allocated = 1 << ct_nb_bits[i];
+
+        ff_init_vlc_sparse(&wl_vlc_tabs[i], wl_nb_bits[i], wl_nb_codes[i],
+                           wl_bits[i],  1, 1,
+                           wl_codes[i], 1, 1,
+                           wl_xlats[i], 1, 1,
+                           INIT_VLC_USE_NEW_STATIC);
+
+        ff_init_vlc_sparse(&ct_vlc_tabs[i], ct_nb_bits[i], ct_nb_codes[i],
+                           ct_bits[i],  1, 1,
+                           ct_codes[i], 1, 1,
+                           ct_xlats[i], 1, 1,
+                           INIT_VLC_USE_NEW_STATIC);
+
+        wl_vlc_offs += wl_vlc_tabs[i].table_allocated;
+        ct_vlc_offs += ct_vlc_tabs[i].table_allocated;
+    }
+
+    for (i = 0, sf_vlc_offs = 76; i < 8; i++) {
+        sf_vlc_tabs[i].table = &tables_data[sf_vlc_offs];
+        sf_vlc_tabs[i].table_allocated = 1 << sf_nb_bits[i];
+
+        ff_init_vlc_sparse(&sf_vlc_tabs[i], sf_nb_bits[i], sf_nb_codes[i],
+                           sf_bits[i],  1, 1,
+                           sf_codes[i], 2, 2,
+                           sf_xlats[i], 1, 1,
+                           INIT_VLC_USE_NEW_STATIC);
+        sf_vlc_offs += sf_vlc_tabs[i].table_allocated;
+    }
+
+    tab_offset = 2564;
+
+    /* build huffman tables for spectrum decoding */
+    for (i = 0; i < 112; i++) {
+        if (atrac3p_spectra_tabs[i].cb)
+            build_canonical_huff(atrac3p_spectra_tabs[i].cb,
+                                 atrac3p_spectra_tabs[i].xlat,
+                                 &tab_offset, &spec_vlc_tabs[i]);
+        else
+            spec_vlc_tabs[i].table = 0;
+    }
+
+    /* build huffman tables for gain data decoding */
+    for (i = 0; i < 11; i++)
+        build_canonical_huff(gain_cbs[i], gain_xlats[i], &tab_offset, &gain_vlc_tabs[i]);
+
+    /* build huffman tables for tone decoding */
+    for (i = 0; i < 7; i++)
+        build_canonical_huff(tone_cbs[i], tone_xlats[i], &tab_offset, &tone_vlc_tabs[i]);
+}
+
+/**
+ * Decode number of coded quantization units.
+ *
+ * @param[in]     gb            the GetBit context
+ * @param[in,out] chan          ptr to the channel parameters
+ * @param[in,out] ctx           ptr to the channel unit context
+ * @param[in]     avctx         ptr to the AVCodecContext
+ * @return result code: 0 = OK, otherwise - error code
+ */
+static int num_coded_units(GetBitContext *gb, Atrac3pChanParams *chan,
+                           Atrac3pChanUnitCtx *ctx, AVCodecContext *avctx)
+{
+    chan->fill_mode = get_bits(gb, 2);
+    if (!chan->fill_mode) {
+        chan->num_coded_vals = ctx->num_quant_units;
+    } else {
+        chan->num_coded_vals = get_bits(gb, 5);
+        if (chan->num_coded_vals > ctx->num_quant_units) {
+            av_log(avctx, AV_LOG_ERROR,
+                   "Invalid number of transmitted units!\n");
+            return AVERROR_INVALIDDATA;
+        }
+
+        if (chan->fill_mode == 3)
+            chan->split_point = get_bits(gb, 2) + (chan->ch_num << 1) + 1;
+    }
+
+    return 0;
+}
+
+/**
+ * Add weighting coefficients to the decoded word-length information.
+ *
+ * @param[in,out] ctx           ptr to the channel unit context
+ * @param[in,out] chan          ptr to the channel parameters
+ * @param[in]     wtab_idx      index of the table of weights
+ * @param[in]     avctx         ptr to the AVCodecContext
+ * @return result code: 0 = OK, otherwise - error code
+ */
+static int add_wordlen_weights(Atrac3pChanUnitCtx *ctx,
+                               Atrac3pChanParams *chan, int wtab_idx,
+                               AVCodecContext *avctx)
+{
+    int i;
+    const int8_t *weights_tab =
+        &atrac3p_wl_weights[chan->ch_num * 3 + wtab_idx - 1][0];
+
+    for (i = 0; i < ctx->num_quant_units; i++) {
+        chan->qu_wordlen[i] += weights_tab[i];
+        if (chan->qu_wordlen[i] < 0 || chan->qu_wordlen[i] > 7) {
+            av_log(avctx, AV_LOG_ERROR,
+                   "WL index out of range: pos=%d, val=%d!\n",
+                   i, chan->qu_wordlen[i]);
+            return AVERROR_INVALIDDATA;
+        }
+    }
+
+    return 0;
+}
+
+/**
+ * Subtract weighting coefficients from decoded scalefactors.
+ *
+ * @param[in,out] ctx           ptr to the channel unit context
+ * @param[in,out] chan          ptr to the channel parameters
+ * @param[in]     wtab_idx      index of table of weights
+ * @param[in]     avctx         ptr to the AVCodecContext
+ * @return result code: 0 = OK, otherwise - error code
+ */
+static int subtract_sf_weights(Atrac3pChanUnitCtx *ctx,
+                               Atrac3pChanParams *chan, int wtab_idx,
+                               AVCodecContext *avctx)
+{
+    int i;
+    const int8_t *weights_tab = &atrac3p_sf_weights[wtab_idx - 1][0];
+
+    for (i = 0; i < ctx->used_quant_units; i++) {
+        chan->qu_sf_idx[i] -= weights_tab[i];
+        if (chan->qu_sf_idx[i] < 0 || chan->qu_sf_idx[i] > 63) {
+            av_log(avctx, AV_LOG_ERROR,
+                   "SF index out of range: pos=%d, val=%d!\n",
+                   i, chan->qu_sf_idx[i]);
+            return AVERROR_INVALIDDATA;
+        }
+    }
+
+    return 0;
+}
+
+/**
+ * Unpack vector quantization tables.
+ *
+ * @param[in]    start_val    start value for the unpacked table
+ * @param[in]    shape_vec    ptr to table to unpack
+ * @param[out]   dst          ptr to output array
+ * @param[in]    num_values   number of values to unpack
+ */
+static inline void unpack_vq_shape(int start_val, const int8_t *shape_vec,
+                                   int *dst, int num_values)
+{
+    int i;
+
+    if (num_values) {
+        dst[0] = dst[1] = dst[2] = start_val;
+        for (i = 3; i < num_values; i++)
+            dst[i] = start_val - shape_vec[atrac3p_qu_num_to_seg[i] - 1];
+    }
+}
+
+#define UNPACK_SF_VQ_SHAPE(gb, dst, num_vals)                            \
+    start_val = get_bits((gb), 6);                                       \
+    unpack_vq_shape(start_val, &atrac3p_sf_shapes[get_bits((gb), 6)][0], \
+                    (dst), (num_vals))
+
+/**
+ * Decode word length for each quantization unit of a channel.
+ *
+ * @param[in]     gb            the GetBit context
+ * @param[in,out] ctx           ptr to the channel unit context
+ * @param[in]     ch_num        channel to process
+ * @param[in]     avctx         ptr to the AVCodecContext
+ * @return result code: 0 = OK, otherwise - error code
+ */
+static int decode_channel_wordlen(GetBitContext *gb, Atrac3pChanUnitCtx *ctx,
+                                  int ch_num, AVCodecContext *avctx)
+{
+    int i, weight_idx = 0, delta, diff, pos, delta_bits, min_val, flag,
+        ret, start_val;
+    VLC *vlc_tab;
+    Atrac3pChanParams *chan     = &ctx->channels[ch_num];
+    Atrac3pChanParams *ref_chan = &ctx->channels[0];
+
+    chan->fill_mode = 0;
+
+    switch (get_bits(gb, 2)) { /* switch according to coding mode */
+    case 0: /* coded using constant number of bits */
+        for (i = 0; i < ctx->num_quant_units; i++)
+            chan->qu_wordlen[i] = get_bits(gb, 3);
+        break;
+    case 1:
+        if (ch_num) {
+            if ((ret = num_coded_units(gb, chan, ctx, avctx)) < 0)
+                return ret;
+
+            if (chan->num_coded_vals) {
+                vlc_tab = &wl_vlc_tabs[get_bits(gb, 2)];
+
+                for (i = 0; i < chan->num_coded_vals; i++) {
+                    delta = get_vlc2(gb, vlc_tab->table, vlc_tab->bits, 1);
+                    chan->qu_wordlen[i] = (ref_chan->qu_wordlen[i] + delta) & 7;
+                }
+            }
+        } else {
+            weight_idx = get_bits(gb, 2);
+            if ((ret = num_coded_units(gb, chan, ctx, avctx)) < 0)
+                return ret;
+
+            if (chan->num_coded_vals) {
+                pos = get_bits(gb, 5);
+                if (pos > chan->num_coded_vals) {
+                    av_log(avctx, AV_LOG_ERROR,
+                           "WL mode 1: invalid position!\n");
+                    return AVERROR_INVALIDDATA;
+                }
+
+                delta_bits = get_bits(gb, 2);
+                min_val    = get_bits(gb, 3);
+
+                for (i = 0; i < pos; i++)
+                    chan->qu_wordlen[i] = get_bits(gb, 3);
+
+                for (i = pos; i < chan->num_coded_vals; i++)
+                    chan->qu_wordlen[i] = (min_val + GET_DELTA(gb, delta_bits)) & 7;
+            }
+        }
+        break;
+    case 2:
+        if ((ret = num_coded_units(gb, chan, ctx, avctx)) < 0)
+            return ret;
+
+        if (ch_num && chan->num_coded_vals) {
+            vlc_tab = &wl_vlc_tabs[get_bits(gb, 2)];
+            delta = get_vlc2(gb, vlc_tab->table, vlc_tab->bits, 1);
+            chan->qu_wordlen[0] = (ref_chan->qu_wordlen[0] + delta) & 7;
+
+            for (i = 1; i < chan->num_coded_vals; i++) {
+                diff = ref_chan->qu_wordlen[i] - ref_chan->qu_wordlen[i - 1];
+                delta = get_vlc2(gb, vlc_tab->table, vlc_tab->bits, 1);
+                chan->qu_wordlen[i] = (chan->qu_wordlen[i - 1] + diff + delta) & 7;
+            }
+        } else if (chan->num_coded_vals) {
+            flag    = get_bits(gb, 1);
+            vlc_tab = &wl_vlc_tabs[get_bits(gb, 1)];
+
+            start_val = get_bits(gb, 3);
+            unpack_vq_shape(start_val,
+                            &atrac3p_wl_shapes[start_val][get_bits(gb, 4)][0],
+                            chan->qu_wordlen, chan->num_coded_vals);
+
+            if (!flag) {
+                for (i = 0; i < chan->num_coded_vals; i++) {
+                    delta = get_vlc2(gb, vlc_tab->table, vlc_tab->bits, 1);
+                    chan->qu_wordlen[i] = (chan->qu_wordlen[i] + delta) & 7;
+                }
+            } else {
+                for (i = 0; i < (chan->num_coded_vals & - 2); i += 2)
+                    if (!get_bits1(gb)) {
+                        chan->qu_wordlen[i]     = (chan->qu_wordlen[i] +
+                                                   get_vlc2(gb, vlc_tab->table,
+                                                            vlc_tab->bits, 1)) & 7;
+                        chan->qu_wordlen[i + 1] = (chan->qu_wordlen[i + 1] +
+                                                   get_vlc2(gb, vlc_tab->table,
+                                                            vlc_tab->bits, 1)) & 7;
+                    }
+
+                if (chan->num_coded_vals & 1)
+                    chan->qu_wordlen[i] = (chan->qu_wordlen[i] +
+                                           get_vlc2(gb, vlc_tab->table,
+                                                    vlc_tab->bits, 1)) & 7;
+            }
+        }
+        break;
+    case 3:
+        weight_idx = get_bits(gb, 2);
+        if ((ret = num_coded_units(gb, chan, ctx, avctx)) < 0)
+            return ret;
+
+        if (chan->num_coded_vals) {
+            vlc_tab = &wl_vlc_tabs[get_bits(gb, 2)];
+
+            /* first coefficient is coded directly */
+            chan->qu_wordlen[0] = get_bits(gb, 3);
+
+            for (i = 1; i < chan->num_coded_vals; i++) {
+                delta = get_vlc2(gb, vlc_tab->table, vlc_tab->bits, 1);
+                chan->qu_wordlen[i] = (chan->qu_wordlen[i - 1] + delta) & 7;
+            }
+        }
+        break;
+    }
+
+    if (chan->fill_mode == 2) {
+        for (i = chan->num_coded_vals; i < ctx->num_quant_units; i++)
+            chan->qu_wordlen[i] = ch_num ? get_bits1(gb) : 1;
+    } else if (chan->fill_mode == 3) {
+        pos = ch_num ? chan->num_coded_vals + chan->split_point
+                     : ctx->num_quant_units - chan->split_point;
+        for (i = chan->num_coded_vals; i < pos; i++)
+            chan->qu_wordlen[i] = 1;
+    }
+
+    if (weight_idx)
+        return add_wordlen_weights(ctx, chan, weight_idx, avctx);
+
+    return 0;
+}
+
+/**
+ * Decode scale factor indexes for each quant unit of a channel.
+ *
+ * @param[in]     gb            the GetBit context
+ * @param[in,out] ctx           ptr to the channel unit context
+ * @param[in]     ch_num        channel to process
+ * @param[in]     avctx         ptr to the AVCodecContext
+ * @return result code: 0 = OK, otherwise - error code
+ */
+static int decode_channel_sf_idx(GetBitContext *gb, Atrac3pChanUnitCtx *ctx,
+                                 int ch_num, AVCodecContext *avctx)
+{
+    int i, weight_idx = 0, delta, diff, num_long_vals,
+        delta_bits, min_val, vlc_sel, start_val;
+    VLC *vlc_tab;
+    Atrac3pChanParams *chan     = &ctx->channels[ch_num];
+    Atrac3pChanParams *ref_chan = &ctx->channels[0];
+
+    switch (get_bits(gb, 2)) { /* switch according to coding mode */
+    case 0: /* coded using constant number of bits */
+        for (i = 0; i < ctx->used_quant_units; i++)
+            chan->qu_sf_idx[i] = get_bits(gb, 6);
+        break;
+    case 1:
+        if (ch_num) {
+            vlc_tab = &sf_vlc_tabs[get_bits(gb, 2)];
+
+            for (i = 0; i < ctx->used_quant_units; i++) {
+                delta = get_vlc2(gb, vlc_tab->table, vlc_tab->bits, 1);
+                chan->qu_sf_idx[i] = (ref_chan->qu_sf_idx[i] + delta) & 0x3F;
+            }
+        } else {
+            weight_idx = get_bits(gb, 2);
+            if (weight_idx == 3) {
+                UNPACK_SF_VQ_SHAPE(gb, chan->qu_sf_idx, ctx->used_quant_units);
+
+                num_long_vals = get_bits(gb, 5);
+                delta_bits    = get_bits(gb, 2);
+                min_val       = get_bits(gb, 4) - 7;
+
+                for (i = 0; i < num_long_vals; i++)
+                    chan->qu_sf_idx[i] = (chan->qu_sf_idx[i] +
+                                          get_bits(gb, 4) - 7) & 0x3F;
+
+                /* all others are: min_val + delta */
+                for (i = num_long_vals; i < ctx->used_quant_units; i++)
+                    chan->qu_sf_idx[i] = (chan->qu_sf_idx[i] + min_val +
+                                          GET_DELTA(gb, delta_bits)) & 0x3F;
+            } else {
+                num_long_vals = get_bits(gb, 5);
+                delta_bits    = get_bits(gb, 3);
+                min_val       = get_bits(gb, 6);
+                if (num_long_vals > ctx->used_quant_units || delta_bits == 7) {
+                    av_log(avctx, AV_LOG_ERROR,
+                           "SF mode 1: invalid parameters!\n");
+                    return AVERROR_INVALIDDATA;
+                }
+
+                /* read full-precision SF indexes */
+                for (i = 0; i < num_long_vals; i++)
+                    chan->qu_sf_idx[i] = get_bits(gb, 6);
+
+                /* all others are: min_val + delta */
+                for (i = num_long_vals; i < ctx->used_quant_units; i++)
+                    chan->qu_sf_idx[i] = (min_val +
+                                          GET_DELTA(gb, delta_bits)) & 0x3F;
+            }
+        }
+        break;
+    case 2:
+        if (ch_num) {
+            vlc_tab = &sf_vlc_tabs[get_bits(gb, 2)];
+
+            delta = get_vlc2(gb, vlc_tab->table, vlc_tab->bits, 1);
+            chan->qu_sf_idx[0] = (ref_chan->qu_sf_idx[0] + delta) & 0x3F;
+
+            for (i = 1; i < ctx->used_quant_units; i++) {
+                diff  = ref_chan->qu_sf_idx[i] - ref_chan->qu_sf_idx[i - 1];
+                delta = get_vlc2(gb, vlc_tab->table, vlc_tab->bits, 1);
+                chan->qu_sf_idx[i] = (chan->qu_sf_idx[i - 1] + diff + delta) & 0x3F;
+            }
+        } else {
+            vlc_tab = &sf_vlc_tabs[get_bits(gb, 2) + 4];
+
+            UNPACK_SF_VQ_SHAPE(gb, chan->qu_sf_idx, ctx->used_quant_units);
+
+            for (i = 0; i < ctx->used_quant_units; i++) {
+                delta = get_vlc2(gb, vlc_tab->table, vlc_tab->bits, 1);
+                chan->qu_sf_idx[i] = (chan->qu_sf_idx[i] +
+                                      sign_extend(delta, 4)) & 0x3F;
+            }
+        }
+        break;
+    case 3:
+        if (ch_num) {
+            /* copy coefficients from reference channel */
+            for (i = 0; i < ctx->used_quant_units; i++)
+                chan->qu_sf_idx[i] = ref_chan->qu_sf_idx[i];
+        } else {
+            weight_idx = get_bits(gb, 2);
+            vlc_sel    = get_bits(gb, 2);
+            vlc_tab    = &sf_vlc_tabs[vlc_sel];
+
+            if (weight_idx == 3) {
+                vlc_tab = &sf_vlc_tabs[vlc_sel + 4];
+
+                UNPACK_SF_VQ_SHAPE(gb, chan->qu_sf_idx, ctx->used_quant_units);
+
+                diff               = (get_bits(gb, 4)    + 56)   & 0x3F;
+                chan->qu_sf_idx[0] = (chan->qu_sf_idx[0] + diff) & 0x3F;
+
+                for (i = 1; i < ctx->used_quant_units; i++) {
+                    delta = get_vlc2(gb, vlc_tab->table, vlc_tab->bits, 1);
+                    diff               = (diff + sign_extend(delta, 4)) & 0x3F;
+                    chan->qu_sf_idx[i] = (diff + chan->qu_sf_idx[i])    & 0x3F;
+                }
+            } else {
+                /* 1st coefficient is coded directly */
+                chan->qu_sf_idx[0] = get_bits(gb, 6);
+
+                for (i = 1; i < ctx->used_quant_units; i++) {
+                    delta = get_vlc2(gb, vlc_tab->table, vlc_tab->bits, 1);
+                    chan->qu_sf_idx[i] = (chan->qu_sf_idx[i - 1] + delta) & 0x3F;
+                }
+            }
+        }
+        break;
+    }
+
+    if (weight_idx && weight_idx < 3)
+        return subtract_sf_weights(ctx, chan, weight_idx, avctx);
+
+    return 0;
+}
+
+/**
+ * Decode word length information for each channel.
+ *
+ * @param[in]     gb            the GetBit context
+ * @param[in,out] ctx           ptr to the channel unit context
+ * @param[in]     num_channels  number of channels to process
+ * @param[in]     avctx         ptr to the AVCodecContext
+ * @return result code: 0 = OK, otherwise - error code
+ */
+static int decode_quant_wordlen(GetBitContext *gb, Atrac3pChanUnitCtx *ctx,
+                                int num_channels, AVCodecContext *avctx)
+{
+    int ch_num, i, ret;
+
+    for (ch_num = 0; ch_num < num_channels; ch_num++) {
+        memset(ctx->channels[ch_num].qu_wordlen, 0,
+               sizeof(ctx->channels[ch_num].qu_wordlen));
+
+        if ((ret = decode_channel_wordlen(gb, ctx, ch_num, avctx)) < 0)
+            return ret;
+    }
+
+    /* scan for last non-zero coeff in both channels and
+     * set number of quant units having coded spectrum */
+    for (i = ctx->num_quant_units - 1; i >= 0; i--)
+        if (ctx->channels[0].qu_wordlen[i] ||
+            (num_channels == 2 && ctx->channels[1].qu_wordlen[i]))
+            break;
+    ctx->used_quant_units = i + 1;
+
+    return 0;
+}
+
+/**
+ * Decode scale factor indexes for each channel.
+ *
+ * @param[in]     gb            the GetBit context
+ * @param[in,out] ctx           ptr to the channel unit context
+ * @param[in]     num_channels  number of channels to process
+ * @param[in]     avctx         ptr to the AVCodecContext
+ * @return result code: 0 = OK, otherwise - error code
+ */
+static int decode_scale_factors(GetBitContext *gb, Atrac3pChanUnitCtx *ctx,
+                                int num_channels, AVCodecContext *avctx)
+{
+    int ch_num, ret;
+
+    if (!ctx->used_quant_units)
+        return 0;
+
+    for (ch_num = 0; ch_num < num_channels; ch_num++) {
+        memset(ctx->channels[ch_num].qu_sf_idx, 0,
+               sizeof(ctx->channels[ch_num].qu_sf_idx));
+
+        if ((ret = decode_channel_sf_idx(gb, ctx, ch_num, avctx)) < 0)
+            return ret;
+    }
+
+    return 0;
+}
+
+/**
+ * Decode number of code table values.
+ *
+ * @param[in]     gb            the GetBit context
+ * @param[in,out] ctx           ptr to the channel unit context
+ * @param[in]     avctx         ptr to the AVCodecContext
+ * @return result code: 0 = OK, otherwise - error code
+ */
+static int get_num_ct_values(GetBitContext *gb, Atrac3pChanUnitCtx *ctx,
+                             AVCodecContext *avctx)
+{
+    int num_coded_vals;
+
+    if (get_bits1(gb)) {
+        num_coded_vals = get_bits(gb, 5);
+        if (num_coded_vals > ctx->used_quant_units) {
+            av_log(avctx, AV_LOG_ERROR,
+                   "Invalid number of code table indexes: %d!\n", num_coded_vals);
+            return AVERROR_INVALIDDATA;
+        }
+        return num_coded_vals;
+    } else
+        return ctx->used_quant_units;
+}
+
+#define DEC_CT_IDX_COMMON(OP)                                           \
+    num_vals = get_num_ct_values(gb, ctx, avctx);                       \
+    if (num_vals < 0)                                                   \
+        return num_vals;                                                \
+                                                                        \
+    for (i = 0; i < num_vals; i++) {                                    \
+        if (chan->qu_wordlen[i]) {                                      \
+            chan->qu_tab_idx[i] = OP;                                   \
+        } else if (ch_num && ref_chan->qu_wordlen[i])                   \
+            /* get clone master flag */                                 \
+            chan->qu_tab_idx[i] = get_bits1(gb);                        \
+    }
+
+#define CODING_DIRECT get_bits(gb, num_bits)
+
+#define CODING_VLC get_vlc2(gb, vlc_tab->table, vlc_tab->bits, 1)
+
+#define CODING_VLC_DELTA                                                \
+    (!i) ? CODING_VLC                                                   \
+         : (pred + get_vlc2(gb, delta_vlc->table,                       \
+                            delta_vlc->bits, 1)) & mask;                \
+    pred = chan->qu_tab_idx[i]
+
+#define CODING_VLC_DIFF                                                 \
+    (ref_chan->qu_tab_idx[i] +                                          \
+     get_vlc2(gb, vlc_tab->table, vlc_tab->bits, 1)) & mask
+
+/**
+ * Decode code table indexes for each quant unit of a channel.
+ *
+ * @param[in]     gb            the GetBit context
+ * @param[in,out] ctx           ptr to the channel unit context
+ * @param[in]     ch_num        channel to process
+ * @param[in]     avctx         ptr to the AVCodecContext
+ * @return result code: 0 = OK, otherwise - error code
+ */
+static int decode_channel_code_tab(GetBitContext *gb, Atrac3pChanUnitCtx *ctx,
+                                   int ch_num, AVCodecContext *avctx)
+{
+    int i, num_vals, num_bits, pred;
+    int mask = ctx->use_full_table ? 7 : 3; /* mask for modular arithmetic */
+    VLC *vlc_tab, *delta_vlc;
+    Atrac3pChanParams *chan     = &ctx->channels[ch_num];
+    Atrac3pChanParams *ref_chan = &ctx->channels[0];
+
+    chan->table_type = get_bits1(gb);
+
+    switch (get_bits(gb, 2)) { /* switch according to coding mode */
+    case 0: /* directly coded */
+        num_bits = ctx->use_full_table + 2;
+        DEC_CT_IDX_COMMON(CODING_DIRECT);
+        break;
+    case 1: /* entropy-coded */
+        vlc_tab = ctx->use_full_table ? &ct_vlc_tabs[1]
+                                      : ct_vlc_tabs;
+        DEC_CT_IDX_COMMON(CODING_VLC);
+        break;
+    case 2: /* entropy-coded delta */
+        if (ctx->use_full_table) {
+            vlc_tab   = &ct_vlc_tabs[1];
+            delta_vlc = &ct_vlc_tabs[2];
+        } else {
+            vlc_tab   = ct_vlc_tabs;
+            delta_vlc = ct_vlc_tabs;
+        }
+        pred = 0;
+        DEC_CT_IDX_COMMON(CODING_VLC_DELTA);
+        break;
+    case 3: /* entropy-coded difference to master */
+        if (ch_num) {
+            vlc_tab = ctx->use_full_table ? &ct_vlc_tabs[3]
+                                          : ct_vlc_tabs;
+            DEC_CT_IDX_COMMON(CODING_VLC_DIFF);
+        }
+        break;
+    }
+
+    return 0;
+}
+
+/**
+ * Decode code table indexes for each channel.
+ *
+ * @param[in]     gb            the GetBit context
+ * @param[in,out] ctx           ptr to the channel unit context
+ * @param[in]     num_channels  number of channels to process
+ * @param[in]     avctx         ptr to the AVCodecContext
+ * @return result code: 0 = OK, otherwise - error code
+ */
+static int decode_code_table_indexes(GetBitContext *gb, Atrac3pChanUnitCtx *ctx,
+                                     int num_channels, AVCodecContext *avctx)
+{
+    int ch_num, ret;
+
+    if (!ctx->used_quant_units)
+        return 0;
+
+    ctx->use_full_table = get_bits1(gb);
+
+    for (ch_num = 0; ch_num < num_channels; ch_num++) {
+        memset(ctx->channels[ch_num].qu_tab_idx, 0,
+               sizeof(ctx->channels[ch_num].qu_tab_idx));
+
+        if ((ret = decode_channel_code_tab(gb, ctx, ch_num, avctx)) < 0)
+            return ret;
+    }
+
+    return 0;
+}
+
+/**
+ * Decode huffman-coded spectral lines for a given quant unit.
+ *
+ * This is a generalized version for all known coding modes.
+ * Its speed can be improved by creating separate functions for each mode.
+ *
+ * @param[in]   gb          the GetBit context
+ * @param[in]   tab         code table telling how to decode spectral lines
+ * @param[in]   vlc_tab     ptr to the huffman table associated with the code table
+ * @param[out]  out         pointer to buffer where decoded data should be stored
+ * @param[in]   num_specs   number of spectral lines to decode
+ */
+static void decode_qu_spectra(GetBitContext *gb, const Atrac3pSpecCodeTab *tab,
+                              VLC *vlc_tab, int16_t *out, const int num_specs)
+{
+    int i, j, pos, cf;
+    int group_size = tab->group_size;
+    int num_coeffs = tab->num_coeffs;
+    int bits       = tab->bits;
+    int is_signed  = tab->is_signed;
+    unsigned val, mask = (1 << bits) - 1;
+
+    for (pos = 0; pos < num_specs;) {
+        if (group_size == 1 || get_bits1(gb)) {
+            for (j = 0; j < group_size; j++) {
+                val = get_vlc2(gb, vlc_tab->table, vlc_tab->bits, 1);
+
+                for (i = 0; i < num_coeffs; i++) {
+                    cf = val & mask;
+                    if (is_signed)
+                        cf = sign_extend(cf, bits);
+                    else if (cf && get_bits1(gb))
+                        cf = -cf;
+
+                    out[pos++] = cf;
+                    val      >>= bits;
+                }
+            }
+        } else /* group skipped */
+            pos += group_size * num_coeffs;
+    }
+}
+
+/**
+ * Decode huffman-coded IMDCT spectrum for all channels.
+ *
+ * @param[in]     gb            the GetBit context
+ * @param[in,out] ctx           ptr to the channel unit context
+ * @param[in]     num_channels  number of channels to process
+ * @param[in]     avctx         ptr to the AVCodecContext
+ */
+static void decode_spectrum(GetBitContext *gb, Atrac3pChanUnitCtx *ctx,
+                            int num_channels, AVCodecContext *avctx)
+{
+    int i, ch_num, qu, wordlen, codetab, tab_index, num_specs;
+    const Atrac3pSpecCodeTab *tab;
+    Atrac3pChanParams *chan;
+
+    for (ch_num = 0; ch_num < num_channels; ch_num++) {
+        chan = &ctx->channels[ch_num];
+
+        memset(chan->spectrum, 0, sizeof(chan->spectrum));
+
+        /* set power compensation level to disabled */
+        memset(chan->power_levs, ATRAC3P_POWER_COMP_OFF, sizeof(chan->power_levs));
+
+        for (qu = 0; qu < ctx->used_quant_units; qu++) {
+            num_specs = ff_atrac3p_qu_to_spec_pos[qu + 1] -
+                        ff_atrac3p_qu_to_spec_pos[qu];
+
+            wordlen = chan->qu_wordlen[qu];
+            codetab = chan->qu_tab_idx[qu];
+            if (wordlen) {
+                if (!ctx->use_full_table)
+                    codetab = atrac3p_ct_restricted_to_full[chan->table_type][wordlen - 1][codetab];
+
+                tab_index = (chan->table_type * 8 + codetab) * 7 + wordlen - 1;
+                tab       = &atrac3p_spectra_tabs[tab_index];
+
+                /* this allows reusing VLC tables */
+                if (tab->redirect >= 0)
+                    tab_index = tab->redirect;
+
+                decode_qu_spectra(gb, tab, &spec_vlc_tabs[tab_index],
+                                  &chan->spectrum[ff_atrac3p_qu_to_spec_pos[qu]],
+                                  num_specs);
+            } else if (ch_num && ctx->channels[0].qu_wordlen[qu] && !codetab) {
+                /* copy coefficients from master */
+                memcpy(&chan->spectrum[ff_atrac3p_qu_to_spec_pos[qu]],
+                       &ctx->channels[0].spectrum[ff_atrac3p_qu_to_spec_pos[qu]],
+                       num_specs *
+                       sizeof(chan->spectrum[ff_atrac3p_qu_to_spec_pos[qu]]));
+                chan->qu_wordlen[qu] = ctx->channels[0].qu_wordlen[qu];
+            }
+        }
+
+        /* Power compensation levels only present in the bitstream
+         * if there are more than 2 quant units. The lowest two units
+         * correspond to the frequencies 0...351 Hz, whose shouldn't
+         * be affected by the power compensation. */
+        if (ctx->used_quant_units > 2) {
+            num_specs = atrac3p_subband_to_num_powgrps[ctx->num_coded_subbands - 1];
+            for (i = 0; i < num_specs; i++)
+                chan->power_levs[i] = get_bits(gb, 4);
+        }
+    }
+}
+
+/**
+ * Retrieve specified amount of flag bits from the input bitstream.
+ * The data can be shortened in the case of the following two common conditions:
+ * if all bits are zero then only one signal bit = 0 will be stored,
+ * if all bits are ones then two signal bits = 1,0 will be stored.
+ * Otherwise, all necessary bits will be directly stored
+ * prefixed by two signal bits = 1,1.
+ *
+ * @param[in]   gb              ptr to the GetBitContext
+ * @param[out]  out             where to place decoded flags
+ * @param[in]   num_flags       number of flags to process
+ * @return: 0 = all flag bits are zero, 1 = there is at least one non-zero flag bit
+ */
+static int get_subband_flags(GetBitContext *gb, uint8_t *out, int num_flags)
+{
+    int i, result;
+
+    memset(out, 0, num_flags);
+
+    result = get_bits1(gb);
+    if (result) {
+        if (get_bits1(gb))
+            for (i = 0; i < num_flags; i++)
+                out[i] = get_bits1(gb);
+        else
+            memset(out, 1, num_flags);
+    }
+
+    return result;
+}
+
+/**
+ * Decode mdct window shape flags for all channels.
+ *
+ * @param[in]     gb            the GetBit context
+ * @param[in,out] ctx           ptr to the channel unit context
+ * @param[in]     num_channels  number of channels to process
+ */
+static void decode_window_shape(GetBitContext *gb, Atrac3pChanUnitCtx *ctx,
+                                int num_channels)
+{
+    int ch_num;
+
+    for (ch_num = 0; ch_num < num_channels; ch_num++)
+        get_subband_flags(gb, ctx->channels[ch_num].wnd_shape,
+                          ctx->num_subbands);
+}
+
+/**
+ * Decode number of gain control points.
+ *
+ * @param[in]     gb              the GetBit context
+ * @param[in,out] ctx             ptr to the channel unit context
+ * @param[in]     ch_num          channel to process
+ * @param[in]     coded_subbands  number of subbands to process
+ * @return result code: 0 = OK, otherwise - error code
+ */
+static int decode_gainc_npoints(GetBitContext *gb, Atrac3pChanUnitCtx *ctx,
+                                int ch_num, int coded_subbands)
+{
+    int i, delta, delta_bits, min_val;
+    Atrac3pChanParams *chan     = &ctx->channels[ch_num];
+    Atrac3pChanParams *ref_chan = &ctx->channels[0];
+
+    switch (get_bits(gb, 2)) { /* switch according to coding mode */
+    case 0: /* fixed-length coding */
+        for (i = 0; i < coded_subbands; i++)
+            chan->gain_data[i].num_points = get_bits(gb, 3);
+        break;
+    case 1: /* variable-length coding */
+        for (i = 0; i < coded_subbands; i++)
+            chan->gain_data[i].num_points =
+                get_vlc2(gb, gain_vlc_tabs[0].table,
+                         gain_vlc_tabs[0].bits, 1);
+        break;
+    case 2:
+        if (ch_num) { /* VLC modulo delta to master channel */
+            for (i = 0; i < coded_subbands; i++) {
+                delta = get_vlc2(gb, gain_vlc_tabs[1].table,
+                                 gain_vlc_tabs[1].bits, 1);
+                chan->gain_data[i].num_points =
+                    (ref_chan->gain_data[i].num_points + delta) & 7;
+            }
+        } else { /* VLC modulo delta to previous */
+            chan->gain_data[0].num_points =
+                get_vlc2(gb, gain_vlc_tabs[0].table,
+                         gain_vlc_tabs[0].bits, 1);
+
+            for (i = 1; i < coded_subbands; i++) {
+                delta = get_vlc2(gb, gain_vlc_tabs[1].table,
+                                 gain_vlc_tabs[1].bits, 1);
+                chan->gain_data[i].num_points =
+                    (chan->gain_data[i - 1].num_points + delta) & 7;
+            }
+        }
+        break;
+    case 3:
+        if (ch_num) { /* copy data from master channel */
+            for (i = 0; i < coded_subbands; i++)
+                chan->gain_data[i].num_points =
+                    ref_chan->gain_data[i].num_points;
+        } else { /* shorter delta to min */
+            delta_bits = get_bits(gb, 2);
+            min_val    = get_bits(gb, 3);
+
+            for (i = 0; i < coded_subbands; i++) {
+                chan->gain_data[i].num_points = min_val + GET_DELTA(gb, delta_bits);
+                if (chan->gain_data[i].num_points > 7)
+                    return AVERROR_INVALIDDATA;
+            }
+        }
+    }
+
+    return 0;
+}
+
+/**
+ * Implements coding mode 3 (slave) for gain compensation levels.
+ *
+ * @param[out]   dst   ptr to the output array
+ * @param[in]    ref   ptr to the reference channel
+ */
+static inline void gainc_level_mode3s(AtracGainInfo *dst, AtracGainInfo *ref)
+{
+    int i;
+
+    for (i = 0; i < dst->num_points; i++)
+        dst->lev_code[i] = (i >= ref->num_points) ? 7 : ref->lev_code[i];
+}
+
+/**
+ * Implements coding mode 1 (master) for gain compensation levels.
+ *
+ * @param[in]     gb     the GetBit context
+ * @param[in]     ctx    ptr to the channel unit context
+ * @param[out]    dst    ptr to the output array
+ */
+static inline void gainc_level_mode1m(GetBitContext *gb,
+                                      Atrac3pChanUnitCtx *ctx,
+                                      AtracGainInfo *dst)
+{
+    int i, delta;
+
+    if (dst->num_points > 0)
+        dst->lev_code[0] = get_vlc2(gb, gain_vlc_tabs[2].table,
+                                    gain_vlc_tabs[2].bits, 1);
+
+    for (i = 1; i < dst->num_points; i++) {
+        delta = get_vlc2(gb, gain_vlc_tabs[3].table,
+                         gain_vlc_tabs[3].bits, 1);
+        dst->lev_code[i] = (dst->lev_code[i - 1] + delta) & 0xF;
+    }
+}
+
+/**
+ * Decode level code for each gain control point.
+ *
+ * @param[in]     gb              the GetBit context
+ * @param[in,out] ctx             ptr to the channel unit context
+ * @param[in]     ch_num          channel to process
+ * @param[in]     coded_subbands  number of subbands to process
+ * @return result code: 0 = OK, otherwise - error code
+ */
+static int decode_gainc_levels(GetBitContext *gb, Atrac3pChanUnitCtx *ctx,
+                               int ch_num, int coded_subbands)
+{
+    int sb, i, delta, delta_bits, min_val, pred;
+    Atrac3pChanParams *chan     = &ctx->channels[ch_num];
+    Atrac3pChanParams *ref_chan = &ctx->channels[0];
+
+    switch (get_bits(gb, 2)) { /* switch according to coding mode */
+    case 0: /* fixed-length coding */
+        for (sb = 0; sb < coded_subbands; sb++)
+            for (i = 0; i < chan->gain_data[sb].num_points; i++)
+                chan->gain_data[sb].lev_code[i] = get_bits(gb, 4);
+        break;
+    case 1:
+        if (ch_num) { /* VLC modulo delta to master channel */
+            for (sb = 0; sb < coded_subbands; sb++)
+                for (i = 0; i < chan->gain_data[sb].num_points; i++) {
+                    delta = get_vlc2(gb, gain_vlc_tabs[5].table,
+                                     gain_vlc_tabs[5].bits, 1);
+                    pred = (i >= ref_chan->gain_data[sb].num_points)
+                           ? 7 : ref_chan->gain_data[sb].lev_code[i];
+                    chan->gain_data[sb].lev_code[i] = (pred + delta) & 0xF;
+                }
+        } else { /* VLC modulo delta to previous */
+            for (sb = 0; sb < coded_subbands; sb++)
+                gainc_level_mode1m(gb, ctx, &chan->gain_data[sb]);
+        }
+        break;
+    case 2:
+        if (ch_num) { /* VLC modulo delta to previous or clone master */
+            for (sb = 0; sb < coded_subbands; sb++)
+                if (chan->gain_data[sb].num_points > 0) {
+                    if (get_bits1(gb))
+                        gainc_level_mode1m(gb, ctx, &chan->gain_data[sb]);
+                    else
+                        gainc_level_mode3s(&chan->gain_data[sb],
+                                           &ref_chan->gain_data[sb]);
+                }
+        } else { /* VLC modulo delta to lev_codes of previous subband */
+            if (chan->gain_data[0].num_points > 0)
+                gainc_level_mode1m(gb, ctx, &chan->gain_data[0]);
+
+            for (sb = 1; sb < coded_subbands; sb++)
+                for (i = 0; i < chan->gain_data[sb].num_points; i++) {
+                    delta = get_vlc2(gb, gain_vlc_tabs[4].table,
+                                     gain_vlc_tabs[4].bits, 1);
+                    pred = (i >= chan->gain_data[sb - 1].num_points)
+                           ? 7 : chan->gain_data[sb - 1].lev_code[i];
+                    chan->gain_data[sb].lev_code[i] = (pred + delta) & 0xF;
+                }
+        }
+        break;
+    case 3:
+        if (ch_num) { /* clone master */
+            for (sb = 0; sb < coded_subbands; sb++)
+                gainc_level_mode3s(&chan->gain_data[sb],
+                                   &ref_chan->gain_data[sb]);
+        } else { /* shorter delta to min */
+            delta_bits = get_bits(gb, 2);
+            min_val    = get_bits(gb, 4);
+
+            for (sb = 0; sb < coded_subbands; sb++)
+                for (i = 0; i < chan->gain_data[sb].num_points; i++) {
+                    chan->gain_data[sb].lev_code[i] = min_val + GET_DELTA(gb, delta_bits);
+                    if (chan->gain_data[sb].lev_code[i] > 15)
+                        return AVERROR_INVALIDDATA;
+                }
+        }
+        break;
+    }
+
+    return 0;
+}
+
+/**
+ * Implements coding mode 0 for gain compensation locations.
+ *
+ * @param[in]     gb     the GetBit context
+ * @param[in]     ctx    ptr to the channel unit context
+ * @param[out]    dst    ptr to the output array
+ * @param[in]     pos    position of the value to be processed
+ */
+static inline void gainc_loc_mode0(GetBitContext *gb, Atrac3pChanUnitCtx *ctx,
+                                   AtracGainInfo *dst, int pos)
+{
+    int delta_bits;
+
+    if (!pos || dst->loc_code[pos - 1] < 15)
+        dst->loc_code[pos] = get_bits(gb, 5);
+    else if (dst->loc_code[pos - 1] >= 30)
+        dst->loc_code[pos] = 31;
+    else {
+        delta_bits         = av_log2(30 - dst->loc_code[pos - 1]) + 1;
+        dst->loc_code[pos] = dst->loc_code[pos - 1] +
+                             get_bits(gb, delta_bits) + 1;
+    }
+}
+
+/**
+ * Implements coding mode 1 for gain compensation locations.
+ *
+ * @param[in]     gb     the GetBit context
+ * @param[in]     ctx    ptr to the channel unit context
+ * @param[out]    dst    ptr to the output array
+ */
+static inline void gainc_loc_mode1(GetBitContext *gb, Atrac3pChanUnitCtx *ctx,
+                                   AtracGainInfo *dst)
+{
+    int i;
+    VLC *tab;
+
+    if (dst->num_points > 0) {
+        /* 1st coefficient is stored directly */
+        dst->loc_code[0] = get_bits(gb, 5);
+
+        for (i = 1; i < dst->num_points; i++) {
+            /* switch VLC according to the curve direction
+             * (ascending/descending) */
+            tab              = (dst->lev_code[i] <= dst->lev_code[i - 1])
+                               ? &gain_vlc_tabs[7]
+                               : &gain_vlc_tabs[9];
+            dst->loc_code[i] = dst->loc_code[i - 1] +
+                               get_vlc2(gb, tab->table, tab->bits, 1);
+        }
+    }
+}
+
+/**
+ * Decode location code for each gain control point.
+ *
+ * @param[in]     gb              the GetBit context
+ * @param[in,out] ctx             ptr to the channel unit context
+ * @param[in]     ch_num          channel to process
+ * @param[in]     coded_subbands  number of subbands to process
+ * @param[in]     avctx           ptr to the AVCodecContext
+ * @return result code: 0 = OK, otherwise - error code
+ */
+static int decode_gainc_loc_codes(GetBitContext *gb, Atrac3pChanUnitCtx *ctx,
+                                  int ch_num, int coded_subbands,
+                                  AVCodecContext *avctx)
+{
+    int sb, i, delta, delta_bits, min_val, pred, more_than_ref;
+    AtracGainInfo *dst, *ref;
+    VLC *tab;
+    Atrac3pChanParams *chan     = &ctx->channels[ch_num];
+    Atrac3pChanParams *ref_chan = &ctx->channels[0];
+
+    switch (get_bits(gb, 2)) { /* switch according to coding mode */
+    case 0: /* sequence of numbers in ascending order */
+        for (sb = 0; sb < coded_subbands; sb++)
+            for (i = 0; i < chan->gain_data[sb].num_points; i++)
+                gainc_loc_mode0(gb, ctx, &chan->gain_data[sb], i);
+        break;
+    case 1:
+        if (ch_num) {
+            for (sb = 0; sb < coded_subbands; sb++) {
+                if (chan->gain_data[sb].num_points <= 0)
+                    continue;
+                dst = &chan->gain_data[sb];
+                ref = &ref_chan->gain_data[sb];
+
+                /* 1st value is vlc-coded modulo delta to master */
+                delta = get_vlc2(gb, gain_vlc_tabs[10].table,
+                                 gain_vlc_tabs[10].bits, 1);
+                pred = ref->num_points > 0 ? ref->loc_code[0] : 0;
+                dst->loc_code[0] = (pred + delta) & 0x1F;
+
+                for (i = 1; i < dst->num_points; i++) {
+                    more_than_ref = i >= ref->num_points;
+                    if (dst->lev_code[i] > dst->lev_code[i - 1]) {
+                        /* ascending curve */
+                        if (more_than_ref) {
+                            delta =
+                                get_vlc2(gb, gain_vlc_tabs[9].table,
+                                         gain_vlc_tabs[9].bits, 1);
+                            dst->loc_code[i] = dst->loc_code[i - 1] + delta;
+                        } else {
+                            if (get_bits1(gb))
+                                gainc_loc_mode0(gb, ctx, dst, i);  // direct coding
+                            else
+                                dst->loc_code[i] = ref->loc_code[i];  // clone master
+                        }
+                    } else { /* descending curve */
+                        tab   = more_than_ref ? &gain_vlc_tabs[7]
+                                              : &gain_vlc_tabs[10];
+                        delta = get_vlc2(gb, tab->table, tab->bits, 1);
+                        if (more_than_ref)
+                            dst->loc_code[i] = dst->loc_code[i - 1] + delta;
+                        else
+                            dst->loc_code[i] = (ref->loc_code[i] + delta) & 0x1F;
+                    }
+                }
+            }
+        } else /* VLC delta to previous */
+            for (sb = 0; sb < coded_subbands; sb++)
+                gainc_loc_mode1(gb, ctx, &chan->gain_data[sb]);
+        break;
+    case 2:
+        if (ch_num) {
+            for (sb = 0; sb < coded_subbands; sb++) {
+                if (chan->gain_data[sb].num_points <= 0)
+                    continue;
+                dst = &chan->gain_data[sb];
+                ref = &ref_chan->gain_data[sb];
+                if (dst->num_points > ref->num_points || get_bits1(gb))
+                    gainc_loc_mode1(gb, ctx, dst);
+                else /* clone master for the whole subband */
+                    for (i = 0; i < chan->gain_data[sb].num_points; i++)
+                        dst->loc_code[i] = ref->loc_code[i];
+            }
+        } else {
+            /* data for the first subband is coded directly */
+            for (i = 0; i < chan->gain_data[0].num_points; i++)
+                gainc_loc_mode0(gb, ctx, &chan->gain_data[0], i);
+
+            for (sb = 1; sb < coded_subbands; sb++) {
+                if (chan->gain_data[sb].num_points <= 0)
+                    continue;
+                dst = &chan->gain_data[sb];
+
+                /* 1st value is vlc-coded modulo delta to the corresponding
+                 * value of the previous subband if any or zero */
+                delta = get_vlc2(gb, gain_vlc_tabs[6].table,
+                                 gain_vlc_tabs[6].bits, 1);
+                pred             = dst[-1].num_points > 0
+                                   ? dst[-1].loc_code[0] : 0;
+                dst->loc_code[0] = (pred + delta) & 0x1F;
+
+                for (i = 1; i < dst->num_points; i++) {
+                    more_than_ref = i >= dst[-1].num_points;
+                    /* Select VLC table according to curve direction and
+                     * presence of prediction. */
+                    tab = &gain_vlc_tabs[(dst->lev_code[i] > dst->lev_code[i - 1]) *
+                                                   2 + more_than_ref + 6];
+                    delta = get_vlc2(gb, tab->table, tab->bits, 1);
+                    if (more_than_ref)
+                        dst->loc_code[i] = dst->loc_code[i - 1] + delta;
+                    else
+                        dst->loc_code[i] = (dst[-1].loc_code[i] + delta) & 0x1F;
+                }
+            }
+        }
+        break;
+    case 3:
+        if (ch_num) { /* clone master or direct or direct coding */
+            for (sb = 0; sb < coded_subbands; sb++)
+                for (i = 0; i < chan->gain_data[sb].num_points; i++) {
+                    if (i >= ref_chan->gain_data[sb].num_points)
+                        gainc_loc_mode0(gb, ctx, &chan->gain_data[sb], i);
+                    else
+                        chan->gain_data[sb].loc_code[i] =
+                            ref_chan->gain_data[sb].loc_code[i];
+                }
+        } else { /* shorter delta to min */
+            delta_bits = get_bits(gb, 2) + 1;
+            min_val    = get_bits(gb, 5);
+
+            for (sb = 0; sb < coded_subbands; sb++)
+                for (i = 0; i < chan->gain_data[sb].num_points; i++)
+                    chan->gain_data[sb].loc_code[i] = min_val + i +
+                                                      get_bits(gb, delta_bits);
+        }
+        break;
+    }
+
+    /* Validate decoded information */
+    for (sb = 0; sb < coded_subbands; sb++) {
+        dst = &chan->gain_data[sb];
+        for (i = 0; i < chan->gain_data[sb].num_points; i++) {
+            if (dst->loc_code[i] < 0 || dst->loc_code[i] > 31 ||
+                (i && dst->loc_code[i] <= dst->loc_code[i - 1])) {
+                av_log(avctx, AV_LOG_ERROR,
+                       "Invalid gain location: ch=%d, sb=%d, pos=%d, val=%d\n",
+                       ch_num, sb, i, dst->loc_code[i]);
+                return AVERROR_INVALIDDATA;
+            }
+        }
+    }
+
+    return 0;
+}
+
+/**
+ * Decode gain control data for all channels.
+ *
+ * @param[in]     gb            the GetBit context
+ * @param[in,out] ctx           ptr to the channel unit context
+ * @param[in]     num_channels  number of channels to process
+ * @param[in]     avctx         ptr to the AVCodecContext
+ * @return result code: 0 = OK, otherwise - error code
+ */
+static int decode_gainc_data(GetBitContext *gb, Atrac3pChanUnitCtx *ctx,
+                             int num_channels, AVCodecContext *avctx)
+{
+    int ch_num, coded_subbands, sb, ret;
+
+    for (ch_num = 0; ch_num < num_channels; ch_num++) {
+        memset(ctx->channels[ch_num].gain_data, 0,
+               sizeof(*ctx->channels[ch_num].gain_data) * ATRAC3P_SUBBANDS);
+
+        if (get_bits1(gb)) { /* gain control data present? */
+            coded_subbands = get_bits(gb, 4) + 1;
+            if (get_bits1(gb)) /* is high band gain data replication on? */
+                ctx->channels[ch_num].num_gain_subbands = get_bits(gb, 4) + 1;
+            else
+                ctx->channels[ch_num].num_gain_subbands = coded_subbands;
+
+            if ((ret = decode_gainc_npoints(gb, ctx, ch_num, coded_subbands)) < 0 ||
+                (ret = decode_gainc_levels(gb, ctx, ch_num, coded_subbands))  < 0 ||
+                (ret = decode_gainc_loc_codes(gb, ctx, ch_num, coded_subbands, avctx)) < 0)
+                return ret;
+
+            if (coded_subbands > 0) { /* propagate gain data if requested */
+                for (sb = coded_subbands; sb < ctx->channels[ch_num].num_gain_subbands; sb++)
+                    ctx->channels[ch_num].gain_data[sb] =
+                        ctx->channels[ch_num].gain_data[sb - 1];
+            }
+        } else {
+            ctx->channels[ch_num].num_gain_subbands = 0;
+        }
+    }
+
+    return 0;
+}
+
+/**
+ * Decode envelope for all tones of a channel.
+ *
+ * @param[in]     gb                the GetBit context
+ * @param[in,out] ctx               ptr to the channel unit context
+ * @param[in]     ch_num            channel to process
+ * @param[in]     band_has_tones    ptr to an array of per-band-flags:
+ *                                  1 - tone data present
+ */
+static void decode_tones_envelope(GetBitContext *gb, Atrac3pChanUnitCtx *ctx,
+                                  int ch_num, int band_has_tones[])
+{
+    int sb;
+    Atrac3pWavesData *dst = ctx->channels[ch_num].tones_info;
+    Atrac3pWavesData *ref = ctx->channels[0].tones_info;
+
+    if (!ch_num || !get_bits1(gb)) { /* mode 0: fixed-length coding */
+        for (sb = 0; sb < ctx->waves_info->num_tone_bands; sb++) {
+            if (!band_has_tones[sb])
+                continue;
+            dst[sb].pend_env.has_start_point = get_bits1(gb);
+            dst[sb].pend_env.start_pos       = dst[sb].pend_env.has_start_point
+                                               ? get_bits(gb, 5) : -1;
+            dst[sb].pend_env.has_stop_point  = get_bits1(gb);
+            dst[sb].pend_env.stop_pos        = dst[sb].pend_env.has_stop_point
+                                               ? get_bits(gb, 5) : 32;
+        }
+    } else { /* mode 1(slave only): copy master */
+        for (sb = 0; sb < ctx->waves_info->num_tone_bands; sb++) {
+            if (!band_has_tones[sb])
+                continue;
+            dst[sb].pend_env.has_start_point = ref[sb].pend_env.has_start_point;
+            dst[sb].pend_env.has_stop_point  = ref[sb].pend_env.has_stop_point;
+            dst[sb].pend_env.start_pos       = ref[sb].pend_env.start_pos;
+            dst[sb].pend_env.stop_pos        = ref[sb].pend_env.stop_pos;
+        }
+    }
+}
+
+/**
+ * Decode number of tones for each subband of a channel.
+ *
+ * @param[in]     gb                the GetBit context
+ * @param[in,out] ctx               ptr to the channel unit context
+ * @param[in]     ch_num            channel to process
+ * @param[in]     band_has_tones    ptr to an array of per-band-flags:
+ *                                  1 - tone data present
+ * @param[in]     avctx             ptr to the AVCodecContext
+ * @return result code: 0 = OK, otherwise - error code
+ */
+static int decode_band_numwavs(GetBitContext *gb, Atrac3pChanUnitCtx *ctx,
+                               int ch_num, int band_has_tones[],
+                               AVCodecContext *avctx)
+{
+    int mode, sb, delta;
+    Atrac3pWavesData *dst = ctx->channels[ch_num].tones_info;
+    Atrac3pWavesData *ref = ctx->channels[0].tones_info;
+
+    mode = get_bits(gb, ch_num + 1);
+    switch (mode) {
+    case 0: /** fixed-length coding */
+        for (sb = 0; sb < ctx->waves_info->num_tone_bands; sb++)
+            if (band_has_tones[sb])
+                dst[sb].num_wavs = get_bits(gb, 4);
+        break;
+    case 1: /** variable-length coding */
+        for (sb = 0; sb < ctx->waves_info->num_tone_bands; sb++)
+            if (band_has_tones[sb])
+                dst[sb].num_wavs =
+                    get_vlc2(gb, tone_vlc_tabs[1].table,
+                             tone_vlc_tabs[1].bits, 1);
+        break;
+    case 2: /** VLC modulo delta to master (slave only) */
+        for (sb = 0; sb < ctx->waves_info->num_tone_bands; sb++)
+            if (band_has_tones[sb]) {
+                delta = get_vlc2(gb, tone_vlc_tabs[2].table,
+                                 tone_vlc_tabs[2].bits, 1);
+                delta = sign_extend(delta, 3);
+                dst[sb].num_wavs = (ref[sb].num_wavs + delta) & 0xF;
+            }
+        break;
+    case 3: /** copy master (slave only) */
+        for (sb = 0; sb < ctx->waves_info->num_tone_bands; sb++)
+            if (band_has_tones[sb])
+                dst[sb].num_wavs = ref[sb].num_wavs;
+        break;
+    }
+
+    /** initialize start tone index for each subband */
+    for (sb = 0; sb < ctx->waves_info->num_tone_bands; sb++)
+        if (band_has_tones[sb]) {
+            if (ctx->waves_info->tones_index + dst[sb].num_wavs > 48) {
+                av_log(avctx, AV_LOG_ERROR,
+                       "Too many tones: %d (max. 48), frame: %d!\n",
+                       ctx->waves_info->tones_index + dst[sb].num_wavs,
+                       avctx->frame_number);
+                return AVERROR_INVALIDDATA;
+            }
+            dst[sb].start_index           = ctx->waves_info->tones_index;
+            ctx->waves_info->tones_index += dst[sb].num_wavs;
+        }
+
+    return 0;
+}
+
+/**
+ * Decode frequency information for each subband of a channel.
+ *
+ * @param[in]     gb                the GetBit context
+ * @param[in,out] ctx               ptr to the channel unit context
+ * @param[in]     ch_num            channel to process
+ * @param[in]     band_has_tones    ptr to an array of per-band-flags:
+ *                                  1 - tone data present
+ */
+static void decode_tones_frequency(GetBitContext *gb, Atrac3pChanUnitCtx *ctx,
+                                   int ch_num, int band_has_tones[])
+{
+    int sb, i, direction, nbits, pred, delta;
+    Atrac3pWaveParam *iwav, *owav;
+    Atrac3pWavesData *dst = ctx->channels[ch_num].tones_info;
+    Atrac3pWavesData *ref = ctx->channels[0].tones_info;
+
+    if (!ch_num || !get_bits1(gb)) { /* mode 0: fixed-length coding */
+        for (sb = 0; sb < ctx->waves_info->num_tone_bands; sb++) {
+            if (!band_has_tones[sb] || !dst[sb].num_wavs)
+                continue;
+            iwav      = &ctx->waves_info->waves[dst[sb].start_index];
+            direction = (dst[sb].num_wavs > 1) ? get_bits1(gb) : 0;
+            if (direction) { /** packed numbers in descending order */
+                if (dst[sb].num_wavs)
+                    iwav[dst[sb].num_wavs - 1].freq_index = get_bits(gb, 10);
+                for (i = dst[sb].num_wavs - 2; i >= 0 ; i--) {
+                    nbits = av_log2(iwav[i+1].freq_index) + 1;
+                    iwav[i].freq_index = get_bits(gb, nbits);
+                }
+            } else { /** packed numbers in ascending order */
+                for (i = 0; i < dst[sb].num_wavs; i++) {
+                    if (!i || iwav[i - 1].freq_index < 512)
+                        iwav[i].freq_index = get_bits(gb, 10);
+                    else {
+                        nbits = av_log2(1023 - iwav[i - 1].freq_index) + 1;
+                        iwav[i].freq_index = get_bits(gb, nbits) +
+                                             1024 - (1 << nbits);
+                    }
+                }
+            }
+        }
+    } else { /* mode 1: VLC modulo delta to master (slave only) */
+        for (sb = 0; sb < ctx->waves_info->num_tone_bands; sb++) {
+            if (!band_has_tones[sb] || !dst[sb].num_wavs)
+                continue;
+            iwav = &ctx->waves_info->waves[ref[sb].start_index];
+            owav = &ctx->waves_info->waves[dst[sb].start_index];
+            for (i = 0; i < dst[sb].num_wavs; i++) {
+                delta = get_vlc2(gb, tone_vlc_tabs[6].table,
+                                 tone_vlc_tabs[6].bits, 1);
+                delta = sign_extend(delta, 8);
+                pred  = (i < ref[sb].num_wavs) ? iwav[i].freq_index :
+                        (ref[sb].num_wavs ? iwav[ref[sb].num_wavs - 1].freq_index : 0);
+                owav[i].freq_index = (pred + delta) & 0x3FF;
+            }
+        }
+    }
+}
+
+/**
+ * Decode amplitude information for each subband of a channel.
+ *
+ * @param[in]     gb                the GetBit context
+ * @param[in,out] ctx               ptr to the channel unit context
+ * @param[in]     ch_num            channel to process
+ * @param[in]     band_has_tones    ptr to an array of per-band-flags:
+ *                                  1 - tone data present
+ */
+static void decode_tones_amplitude(GetBitContext *gb, Atrac3pChanUnitCtx *ctx,
+                                   int ch_num, int band_has_tones[])
+{
+    int mode, sb, j, i, diff, maxdiff, fi, delta, pred;
+    Atrac3pWaveParam *wsrc, *wref;
+    int refwaves[48];
+    Atrac3pWavesData *dst = ctx->channels[ch_num].tones_info;
+    Atrac3pWavesData *ref = ctx->channels[0].tones_info;
+
+    if (ch_num) {
+        for (sb = 0; sb < ctx->waves_info->num_tone_bands; sb++) {
+            if (!band_has_tones[sb] || !dst[sb].num_wavs)
+                continue;
+            wsrc = &ctx->waves_info->waves[dst[sb].start_index];
+            wref = &ctx->waves_info->waves[ref[sb].start_index];
+            for (j = 0; j < dst[sb].num_wavs; j++) {
+                for (i = 0, fi = 0, maxdiff = 1024; i < ref[sb].num_wavs; i++) {
+                    diff = FFABS(wsrc[j].freq_index - wref[i].freq_index);
+                    if (diff < maxdiff) {
+                        maxdiff = diff;
+                        fi      = i;
+                    }
+                }
+
+                if (maxdiff < 8)
+                    refwaves[dst[sb].start_index + j] = fi + ref[sb].start_index;
+                else if (j < ref[sb].num_wavs)
+                    refwaves[dst[sb].start_index + j] = j + ref[sb].start_index;
+                else
+                    refwaves[dst[sb].start_index + j] = -1;
+            }
+        }
+    }
+
+    mode = get_bits(gb, ch_num + 1);
+
+    switch (mode) {
+    case 0: /** fixed-length coding */
+        for (sb = 0; sb < ctx->waves_info->num_tone_bands; sb++) {
+            if (!band_has_tones[sb] || !dst[sb].num_wavs)
+                continue;
+            if (ctx->waves_info->amplitude_mode)
+                for (i = 0; i < dst[sb].num_wavs; i++)
+                    ctx->waves_info->waves[dst[sb].start_index + i].amp_sf = get_bits(gb, 6);
+            else
+                ctx->waves_info->waves[dst[sb].start_index].amp_sf = get_bits(gb, 6);
+        }
+        break;
+    case 1: /** min + VLC delta */
+        for (sb = 0; sb < ctx->waves_info->num_tone_bands; sb++) {
+            if (!band_has_tones[sb] || !dst[sb].num_wavs)
+                continue;
+            if (ctx->waves_info->amplitude_mode)
+                for (i = 0; i < dst[sb].num_wavs; i++)
+                    ctx->waves_info->waves[dst[sb].start_index + i].amp_sf =
+                        get_vlc2(gb, tone_vlc_tabs[3].table,
+                                 tone_vlc_tabs[3].bits, 1) + 20;
+            else
+                ctx->waves_info->waves[dst[sb].start_index].amp_sf =
+                    get_vlc2(gb, tone_vlc_tabs[4].table,
+                             tone_vlc_tabs[4].bits, 1) + 24;
+        }
+        break;
+    case 2: /** VLC modulo delta to master (slave only) */
+        for (sb = 0; sb < ctx->waves_info->num_tone_bands; sb++) {
+            if (!band_has_tones[sb] || !dst[sb].num_wavs)
+                continue;
+            for (i = 0; i < dst[sb].num_wavs; i++) {
+                delta = get_vlc2(gb, tone_vlc_tabs[5].table,
+                                 tone_vlc_tabs[5].bits, 1);
+                delta = sign_extend(delta, 5);
+                pred  = refwaves[dst[sb].start_index + i] >= 0 ?
+                        ctx->waves_info->waves[refwaves[dst[sb].start_index + i]].amp_sf : 34;
+                ctx->waves_info->waves[dst[sb].start_index + i].amp_sf = (pred + delta) & 0x3F;
+            }
+        }
+        break;
+    case 3: /** clone master (slave only) */
+        for (sb = 0; sb < ctx->waves_info->num_tone_bands; sb++) {
+            if (!band_has_tones[sb])
+                continue;
+            for (i = 0; i < dst[sb].num_wavs; i++)
+                ctx->waves_info->waves[dst[sb].start_index + i].amp_sf =
+                    refwaves[dst[sb].start_index + i] >= 0
+                    ? ctx->waves_info->waves[refwaves[dst[sb].start_index + i]].amp_sf
+                    : 32;
+        }
+        break;
+    }
+}
+
+/**
+ * Decode phase information for each subband of a channel.
+ *
+ * @param[in]     gb                the GetBit context
+ * @param[in,out] ctx               ptr to the channel unit context
+ * @param[in]     ch_num            channel to process
+ * @param[in]     band_has_tones    ptr to an array of per-band-flags:
+ *                                  1 - tone data present
+ */
+static void decode_tones_phase(GetBitContext *gb, Atrac3pChanUnitCtx *ctx,
+                               int ch_num, int band_has_tones[])
+{
+    int sb, i;
+    Atrac3pWaveParam *wparam;
+    Atrac3pWavesData *dst = ctx->channels[ch_num].tones_info;
+
+    for (sb = 0; sb < ctx->waves_info->num_tone_bands; sb++) {
+        if (!band_has_tones[sb])
+            continue;
+        wparam = &ctx->waves_info->waves[dst[sb].start_index];
+        for (i = 0; i < dst[sb].num_wavs; i++)
+            wparam[i].phase_index = get_bits(gb, 5);
+    }
+}
+
+/**
+ * Decode tones info for all channels.
+ *
+ * @param[in]     gb            the GetBit context
+ * @param[in,out] ctx           ptr to the channel unit context
+ * @param[in]     num_channels  number of channels to process
+ * @param[in]     avctx         ptr to the AVCodecContext
+ * @return result code: 0 = OK, otherwise - error code
+ */
+static int decode_tones_info(GetBitContext *gb, Atrac3pChanUnitCtx *ctx,
+                             int num_channels, AVCodecContext *avctx)
+{
+    int ch_num, i, ret;
+    int band_has_tones[16];
+
+    for (ch_num = 0; ch_num < num_channels; ch_num++)
+        memset(ctx->channels[ch_num].tones_info, 0,
+               sizeof(*ctx->channels[ch_num].tones_info) * ATRAC3P_SUBBANDS);
+
+    ctx->waves_info->tones_present = get_bits1(gb);
+    if (!ctx->waves_info->tones_present)
+        return 0;
+
+    memset(ctx->waves_info->waves, 0, sizeof(ctx->waves_info->waves));
+
+    ctx->waves_info->amplitude_mode = get_bits1(gb);
+    if (!ctx->waves_info->amplitude_mode) {
+        avpriv_report_missing_feature(avctx, "GHA amplitude mode 0");
+        return AVERROR_PATCHWELCOME;
+    }
+
+    ctx->waves_info->num_tone_bands =
+        get_vlc2(gb, tone_vlc_tabs[0].table,
+                 tone_vlc_tabs[0].bits, 1) + 1;
+
+    if (num_channels == 2) {
+        get_subband_flags(gb, ctx->waves_info->tone_sharing, ctx->waves_info->num_tone_bands);
+        get_subband_flags(gb, ctx->waves_info->tone_master,  ctx->waves_info->num_tone_bands);
+        if (get_subband_flags(gb, ctx->waves_info->phase_shift,
+                              ctx->waves_info->num_tone_bands)) {
+            avpriv_report_missing_feature(avctx, "GHA Phase shifting");
+            return AVERROR_PATCHWELCOME;
+        }
+    }
+
+    ctx->waves_info->tones_index = 0;
+
+    for (ch_num = 0; ch_num < num_channels; ch_num++) {
+        for (i = 0; i < ctx->waves_info->num_tone_bands; i++)
+            band_has_tones[i] = !ch_num ? 1 : !ctx->waves_info->tone_sharing[i];
+
+        decode_tones_envelope(gb, ctx, ch_num, band_has_tones);
+        if ((ret = decode_band_numwavs(gb, ctx, ch_num, band_has_tones,
+                                       avctx)) < 0)
+            return ret;
+
+        decode_tones_frequency(gb, ctx, ch_num, band_has_tones);
+        decode_tones_amplitude(gb, ctx, ch_num, band_has_tones);
+        decode_tones_phase(gb, ctx, ch_num, band_has_tones);
+    }
+
+    if (num_channels == 2) {
+        for (i = 0; i < ctx->waves_info->num_tone_bands; i++) {
+            if (ctx->waves_info->tone_sharing[i])
+                ctx->channels[1].tones_info[i] = ctx->channels[0].tones_info[i];
+
+            if (ctx->waves_info->tone_master[i])
+                FFSWAP(Atrac3pWavesData, ctx->channels[0].tones_info[i],
+                       ctx->channels[1].tones_info[i]);
+        }
+    }
+
+    return 0;
+}
+
+int ff_atrac3p_decode_channel_unit(GetBitContext *gb, Atrac3pChanUnitCtx *ctx,
+                                   int num_channels, AVCodecContext *avctx)
+{
+    int ret;
+
+    /* parse sound header */
+    ctx->num_quant_units = get_bits(gb, 5) + 1;
+    if (ctx->num_quant_units > 28 && ctx->num_quant_units < 32) {
+        av_log(avctx, AV_LOG_ERROR,
+               "Invalid number of quantization units: %d!\n",
+               ctx->num_quant_units);
+        return AVERROR_INVALIDDATA;
+    }
+
+    ctx->mute_flag = get_bits1(gb);
+
+    /* decode various sound parameters */
+    if ((ret = decode_quant_wordlen(gb, ctx, num_channels, avctx)) < 0)
+        return ret;
+
+    ctx->num_subbands       = atrac3p_qu_to_subband[ctx->num_quant_units - 1] + 1;
+    ctx->num_coded_subbands = ctx->used_quant_units
+                              ? atrac3p_qu_to_subband[ctx->used_quant_units - 1] + 1
+                              : 0;
+
+    if ((ret = decode_scale_factors(gb, ctx, num_channels, avctx)) < 0)
+        return ret;
+
+    if ((ret = decode_code_table_indexes(gb, ctx, num_channels, avctx)) < 0)
+        return ret;
+
+    decode_spectrum(gb, ctx, num_channels, avctx);
+
+    if (num_channels == 2) {
+        get_subband_flags(gb, ctx->swap_channels, ctx->num_coded_subbands);
+        get_subband_flags(gb, ctx->negate_coeffs, ctx->num_coded_subbands);
+    }
+
+    decode_window_shape(gb, ctx, num_channels);
+
+    if ((ret = decode_gainc_data(gb, ctx, num_channels, avctx)) < 0)
+        return ret;
+
+    if ((ret = decode_tones_info(gb, ctx, num_channels, avctx)) < 0)
+        return ret;
+
+    /* decode global noise info */
+    ctx->noise_present = get_bits1(gb);
+    if (ctx->noise_present) {
+        ctx->noise_level_index = get_bits(gb, 4);
+        ctx->noise_table_index = get_bits(gb, 4);
+    }
+
+    return 0;
+}
diff --git a/libavcodec/atrac3plus.h b/libavcodec/atrac3plus.h
new file mode 100644
index 0000000..e56c444
--- /dev/null
+++ b/libavcodec/atrac3plus.h
@@ -0,0 +1,242 @@
+/*
+ * ATRAC3+ compatible decoder
+ *
+ * Copyright (c) 2010-2013 Maxim Poliakovski
+ *
+ * This file is part of Libav.
+ *
+ * Libav 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.
+ *
+ * Libav 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 Libav; 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>
+
+#include "libavutil/float_dsp.h"
+#include "atrac.h"
+#include "avcodec.h"
+#include "fft.h"
+#include "get_bits.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
+
+/** 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
+};
+
+/** Per-channel IPQF history */
+typedef struct Atrac3pIPQFChannelCtx {
+    DECLARE_ALIGNED(32, float, buf1)[ATRAC3P_PQF_FIR_LEN * 2][8];
+    DECLARE_ALIGNED(32, float, buf2)[ATRAC3P_PQF_FIR_LEN * 2][8];
+    int pos;
+} Atrac3pIPQFChannelCtx;
+
+/** 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
+
+    /* gain control data history (2 frames) for overlapping. */
+    AtracGainInfo gain_data_hist[2][ATRAC3P_SUBBANDS];  ///< gain control data for all subbands
+    AtracGainInfo *gain_data;       ///< gain control data for next frame
+    AtracGainInfo *gain_data_prev;  ///< gain control data 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 phase_shift[ATRAC3P_SUBBANDS];  ///< 1 - subband-wise 180° phase shifting
+    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 VLC tables for bitstream parsing.
+ *
+ * @param[in]   codec    ptr to the AVCodec
+ */
+void ff_atrac3p_init_vlcs(AVCodec *codec);
+
+/**
+ * Decode bitstream data of a channel unit.
+ *
+ * @param[in]     gb            the GetBit context
+ * @param[in,out] ctx           ptr to the channel unit context
+ * @param[in]     num_channels  number of channels to process
+ * @param[in]     avctx         ptr to the AVCodecContext
+ * @return result code: 0 = OK, otherwise - error code
+ */
+int  ff_atrac3p_decode_channel_unit(GetBitContext *gb, Atrac3pChanUnitCtx *ctx,
+                                    int num_channels, AVCodecContext *avctx);
+
+/**
+ * Initialize IMDCT transform.
+ *
+ * @param[in]   avctx      ptr to the AVCodecContext
+ * @param[in]   mdct_ctx   pointer to MDCT transform context
+ */
+void ff_atrac3p_init_imdct(AVCodecContext *avctx, FFTContext *mdct_ctx);
+
+/**
+ * Initialize sine waves synthesizer.
+ */
+void ff_atrac3p_init_wave_synth(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, AVFloatDSPContext *fdsp,
+                               int ch_num, int sb, float *out);
+
+/**
+ * Perform power compensation aka noise dithering.
+ *
+ * @param[in]      ctx         ptr to the channel context
+ * @param[in]      ch_index    which channel to process
+ * @param[in,out]  sp          ptr to channel spectrum to process
+ * @param[in]      rng_index   indicates which RNG table to use
+ * @param[in]      sb_num      which subband to process
+ */
+void ff_atrac3p_power_compensation(Atrac3pChanUnitCtx *ctx, int ch_index,
+                                   float *sp, int rng_index, int sb_num);
+
+/**
+ * Regular IMDCT and windowing without overlapping,
+ * with spectrum reversal in the odd subbands.
+ *
+ * @param[in]   fdsp       pointer to float DSP context
+ * @param[in]   mdct_ctx   pointer to MDCT transform context
+ * @param[in]   pIn        float input
+ * @param[out]  pOut       float output
+ * @param[in]   wind_id    which MDCT window to apply
+ * @param[in]   sb         subband number
+ */
+void ff_atrac3p_imdct(AVFloatDSPContext *fdsp, FFTContext *mdct_ctx, float *pIn,
+                      float *pOut, int wind_id, int sb);
+
+/**
+ * Subband synthesis filter based on the polyphase quadrature (pseudo-QMF)
+ * filter bank.
+ *
+ * @param[in]      dct_ctx   ptr to the pre-initialized IDCT context
+ * @param[in,out]  hist      ptr to the filter history
+ * @param[in]      in        input data to process
+ * @param[out]     out       receives processed data
+ */
+void ff_atrac3p_ipqf(FFTContext *dct_ctx, Atrac3pIPQFChannelCtx *hist,
+                     const float *in, float *out);
+
+extern const uint16_t ff_atrac3p_qu_to_spec_pos[33];
+extern const float ff_atrac3p_sf_tab[64];
+extern const float ff_atrac3p_mant_tab[8];
+
+#endif /* AVCODEC_ATRAC3PLUS_H */
diff --git a/libavcodec/atrac3plus_data.h b/libavcodec/atrac3plus_data.h
new file mode 100644
index 0000000..5026a59
--- /dev/null
+++ b/libavcodec/atrac3plus_data.h
@@ -0,0 +1,1914 @@
+/*
+ * ATRAC3+ compatible decoder
+ *
+ * Copyright (c) 2010-2013 Maxim Poliakovski
+ *
+ * This file is part of Libav.
+ *
+ * Libav 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.
+ *
+ * Libav 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 Libav; 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>
+
+/** VLC tables for wordlen */
+static const uint8_t atrac3p_wl_huff_code1[3] = { 0, 2, 3 };
+
+static const uint8_t atrac3p_wl_huff_bits1[3] = { 1, 2, 2 };
+
+static const uint8_t atrac3p_wl_huff_xlat1[3] = { 0, 1, 7 };
+
+static const uint8_t atrac3p_wl_huff_code2[5] = { 0, 4, 5, 6, 7 };
+
+static const uint8_t atrac3p_wl_huff_bits2[5] = { 1, 3, 3, 3, 3 };
+
+static const uint8_t atrac3p_wl_huff_xlat2[5] = { 0, 1, 2, 6, 7 };
+
+static const uint8_t atrac3p_wl_huff_code3[8] = {
+    0, 4, 0xC, 0x1E, 0x1F, 0xD, 0xE, 5
+};
+
+static const uint8_t atrac3p_wl_huff_bits3[8] = { 1, 3, 4, 5, 5, 4, 4, 3 };
+
+static const uint8_t atrac3p_wl_huff_code4[8] = {
+    0, 4, 0xC, 0xD, 0x1E, 0x1F, 0xE, 5
+};
+
+static const uint8_t atrac3p_wl_huff_bits4[8] = { 1, 3, 4, 4, 5, 5, 4, 3 };
+
+/** VLC tables for scale factor indexes */
+static const uint16_t atrac3p_sf_huff_code1[64] = {
+        0,     2,     3,     4,     5,   0xC,   0xD,  0xE0,
+     0xE1,  0xE2,  0xE3,  0xE4,  0xE5,  0xE6, 0x1CE, 0x1CF,
+    0x1D0, 0x1D1, 0x1D2, 0x1D3, 0x1D4, 0x1D5, 0x1D6, 0x1D7,
+    0x1D8, 0x1D9, 0x1DA, 0x1DB, 0x1DC, 0x1DD, 0x1DE, 0x1DF,
+    0x1E0, 0x1E1, 0x1E2, 0x1E3, 0x1E4, 0x1E5, 0x1E6, 0x1E7,
+    0x1E8, 0x1E9, 0x1EA, 0x1EB, 0x1EC, 0x1ED, 0x1EE, 0x1EF,
+    0x1F0, 0x1F1, 0x1F2, 0x1F3, 0x1F4, 0x1F5, 0x1F6, 0x1F7,
+    0x1F8, 0x1F9, 0x1FA, 0x1FB, 0x1FC, 0x1FD, 0x1FE, 0x1FF
+};
+
+static const uint8_t atrac3p_sf_huff_bits1[64] = {
+    2, 3, 3, 3, 3, 4, 4, 8, 8, 8, 8, 8, 8, 8, 9, 9,
+    9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+    9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+    9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9
+};
+
+static const uint8_t atrac3p_sf_huff_xlat1[64] = {
+     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
+};
+
+static const uint8_t atrac3p_sf_huff_xlat2[64] = {
+    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
+};
+
+static const uint16_t atrac3p_sf_huff_code2[64] = {
+        0,     4,  0x18,  0x19,  0x70, 0x1CA, 0x1CB, 0x1CC,
+    0x1CD, 0x1CE, 0x1CF, 0x1D0, 0x1D1, 0x1D2, 0x1D3, 0x1D4,
+    0x1D5, 0x1D6, 0x1D7, 0x1D8, 0x1D9, 0x1DA, 0x1DB, 0x1DC,
+    0x1DD, 0x1DE, 0x1DF, 0x1E0, 0x1E1, 0x1E2, 0x1E3, 0x1E4,
+    0x1E5, 0x1E6, 0x1E7, 0x1E8, 0x1E9, 0x1EA, 0x1EB, 0x1EC,
+    0x1ED, 0x1EE, 0x1EF, 0x1F0, 0x1F1, 0x1F2, 0x1F3, 0x1F4,
+    0x1F5, 0x1F6, 0x1F7, 0x1F8, 0x1F9, 0x1FA, 0x1FB, 0x1FC,
+    0x1FD, 0x1FE, 0x1FF,  0xE4,  0x71,  0x1A,  0x1B,     5
+};
+
+static const uint8_t atrac3p_sf_huff_bits2[64] = {
+    1, 3, 5, 5, 7, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+    9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+    9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+    9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 8, 7, 5, 5, 3
+};
+
+static const uint16_t atrac3p_sf_huff_code3[64] = {
+        0,     2,     3,  0x18,  0x19,  0x70, 0x1CC, 0x1CD,
+    0x1CE, 0x1CF, 0x1D0, 0x1D1, 0x1D2, 0x1D3, 0x1D4, 0x1D5,
+    0x1D6, 0x1D7, 0x1D8, 0x1D9, 0x1DA, 0x1DB, 0x1DC, 0x1DD,
+    0x1DE, 0x1DF, 0x1E0, 0x1E1, 0x1E2, 0x1E3, 0x1E4, 0x1E5,
+    0x1E6, 0x1E7, 0x1E8, 0x1E9, 0x1EA, 0x1EB, 0x1EC, 0x1ED,
+    0x1EE, 0x1EF, 0x1F0, 0x1F1, 0x1F2, 0x1F3, 0x1F4, 0x1F5,
+    0x1F6, 0x1F7, 0x1F8, 0x1F9, 0x1FA, 0x1FB, 0x1FC, 0x1FD,
+    0x1FE, 0x1FF,  0x71,  0x72,  0x1A,  0x1B,     4,     5
+};
+
+static const uint8_t atrac3p_sf_huff_bits3[64] = {
+    2, 3, 3, 5, 5, 7, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+    9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+    9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+    9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 7, 7, 5, 5, 3, 3
+};
+
+static const uint16_t atrac3p_sf_huff_code4[16] = {
+    0, 2, 3, 4, 5, 0xC, 0xD, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0, 0x3D, 0x3E, 0x3F
+};
+
+static const uint8_t atrac3p_sf_huff_bits4[16] = {
+    2, 3, 3, 3, 3, 4, 4, 6, 6, 6, 6, 6, 0, 6, 6, 6
+};
+
+static const uint8_t atrac3p_sf_huff_xlat4[16] = {
+    0, 1, 13, 14, 15, 2, 12, 3, 4, 5, 6, 7, 8, 9, 10, 11
+};
+
+static const uint8_t atrac3p_sf_huff_xlat5[16] = {
+    0, 1, 2, 14, 15, 3, 13, 4, 5, 6, 7, 9, 8, 10, 11, 12
+};
+
+static const uint16_t atrac3p_sf_huff_code5[16] = {
+    0,    4,  0xC, 0x1C, 0x78, 0x79, 0x7A, 0x7B,
+    0, 0x7C, 0x7D, 0x7E, 0x7F, 0x1D, 0xD,     5
+};
+
+static const uint8_t atrac3p_sf_huff_bits5[16] = {
+    1, 3, 4, 5, 7, 7, 7, 7, 0, 7, 7, 7, 7, 5, 4, 3
+};
+
+static const uint16_t atrac3p_sf_huff_code6[16] = {
+    0, 2, 3, 0xC, 0x1C, 0x3C, 0x7C, 0x7D, 0, 0x7E, 0x7F, 0x3D, 0x1D, 0xD, 4, 5
+};
+
+static const uint8_t atrac3p_sf_huff_bits6[16] = {
+    2, 3, 3, 4, 5, 6, 7, 7, 0, 7, 7, 6, 5, 4, 3, 3
+};
+
+/** VLC tables for code table indexes */
+static const uint8_t atrac3p_ct_huff_code1[4] = { 0, 2, 6, 7 };
+
+static const uint8_t atrac3p_ct_huff_bits1[4] = { 1, 2, 3, 3 };
+
+static const uint8_t atrac3p_ct_huff_code2[8] = { 0, 2, 3, 4, 5, 6, 0xE, 0xF };
+
+static const uint8_t atrac3p_ct_huff_bits2[8] = { 2, 3, 3, 3, 3, 3, 4, 4 };
+
+static const uint8_t atrac3p_ct_huff_xlat1[8] = { 0, 1, 2, 3, 6, 7, 4, 5 };
+
+static const uint8_t atrac3p_ct_huff_code3[8] = {
+    0, 4, 0xA, 0xB, 0xC, 0xD, 0xE, 0xF
+};
+
+static const uint8_t atrac3p_ct_huff_bits3[8] = { 1, 3, 4, 4, 4, 4, 4, 4 };
+
+/* 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 */
+static const uint8_t huff_a01_cb[14] = {
+    1, 12, 1, 0, 0, 1, 7, 0, 19, 5, 13, 21, 6, 8
+};
+
+static const uint8_t huff_a01_xlat[81] = {
+    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
+};
+
+static const uint8_t huff_a02_cb[13] = {
+    2, 12, 1, 0, 4, 11, 0, 1, 29, 6, 20, 7, 2
+};
+
+static const uint8_t huff_a02_xlat[81] = {
+    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
+};
+
+static const uint8_t huff_a03_cb[9] = { 3, 9, 1, 8, 0, 13, 18, 7, 2 };
+
+static const uint8_t huff_a03_xlat[49] = {
+    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
+};
+
+static const uint8_t huff_a04_cb[4]   = { 2, 3, 2, 4 };
+static const uint8_t huff_a04_xlat[6] = { 1, 2, 0, 3, 4, 5 };
+
+static const uint8_t huff_a05_cb[12] = {
+    3, 12, 1, 3, 5, 8, 12, 23, 72, 68, 31, 2
+};
+
+static const uint8_t huff_a05_xlat[225] = {
+    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
+};
+
+static const uint8_t huff_a06_cb[7] = {
+    2, 6, 1, 3, 2, 6, 4
+};
+
+static const uint8_t huff_a06_xlat[16] = {
+    1, 0, 2, 3, 4, 5, 6, 7, 8, 9, 13, 14, 10, 11, 12, 15
+};
+
+static const uint8_t huff_a07_cb[11] = {
+    2, 10, 1, 2, 2, 2, 6, 14, 21, 13, 2
+};
+
+static const uint8_t huff_a07_xlat[63] = {
+    0,   1, 63,  2, 62,  3, 61,  4,  5,  6, 58, 59, 60,  7,  8,  9,
+    10, 26, 27, 28, 36, 37, 38, 54, 55, 56, 57, 11, 12, 13, 14, 15,
+    16, 25, 29, 30, 31, 33, 34, 35, 39, 47, 48, 49, 50, 51, 52, 53,
+    17, 18, 19, 20, 21, 22, 23, 41, 42, 43, 44, 45, 46, 24, 40
+};
+
+static const uint8_t huff_a11_cb[13] = {
+    1, 11, 1, 0, 0, 0, 8, 1, 18, 9, 22, 10, 12
+};
+
+static const uint8_t huff_a11_xlat[81] = {
+    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
+};
+
+static const uint8_t huff_a12_cb[8] = { 5, 10, 16, 11, 32, 19, 1, 2 };
+
+static const uint8_t huff_a12_xlat[81] = {
+    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
+};
+
+static const uint8_t huff_a13_cb[12] = {
+    1, 10, 1, 0, 0, 4, 2, 2, 9, 15, 12, 4
+};
+
+static const uint8_t huff_a13_xlat[49] = {
+    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
+};
+
+static const uint8_t huff_a14_cb[12] = {
+    2, 11, 1, 0, 4, 3, 5, 16, 28, 34, 26, 4
+};
+
+static const uint8_t huff_a14_xlat[121] = {
+    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
+};
+
+static const uint8_t huff_a15_cb[9] = { 5, 11, 9, 12, 16, 44, 98, 42, 4 };
+
+static const uint8_t huff_a15_xlat[225] = {
+    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
+};
+
+static const uint8_t huff_a16_cb[13] = {
+    2, 12, 1, 1, 2, 2, 5, 7, 21, 54, 85, 62, 16
+};
+
+static const uint8_t huff_a16_xlat[256] = {
+    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
+};
+
+static const uint8_t huff_a17_cb[9] = { 3, 9, 3, 2, 5, 7, 17, 23, 6 };
+
+static const uint8_t huff_a17_xlat[63] = {
+    0,   1, 63,  2, 62,  3,  4, 59, 60, 61,  5,  6,  7,  8, 56, 57,
+    58,  9, 10, 11, 12, 13, 14, 26, 27, 36, 37, 38, 50, 51, 52, 53,
+    54, 55, 15, 16, 17, 18, 19, 20, 21, 25, 28, 29, 30, 31, 33, 34,
+    35, 39, 43, 44, 45, 46, 47, 48, 49, 22, 23, 24, 40, 41, 42
+};
+
+static const uint8_t huff_a21_cb[14] = {
+    1, 12, 1, 0, 0, 2, 6, 0, 7, 21, 15, 17, 8, 4
+};
+
+static const uint8_t huff_a21_xlat[81] = {
+    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
+};
+
+static const uint8_t huff_a22_cb[10] = { 2, 9, 1, 4, 0, 4, 3, 8, 3, 2 };
+
+static const uint8_t huff_a22_xlat[25] = {
+    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
+};
+
+static const uint8_t huff_a23_cb[9] = { 3, 9, 5, 0, 4, 6, 10, 16, 8 };
+
+static const uint8_t huff_a23_xlat[49] = {
+    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
+};
+
+static const uint8_t huff_a24_cb[5] = { 2, 4, 3, 1, 2 };
+
+static const uint8_t huff_a25_cb[5] = { 2, 4, 1, 5, 2 };
+
+static const uint8_t huff_a25_xlat[8] = { 1, 0, 2, 3, 4, 5, 6, 7 };
+
+static const uint8_t huff_a26_cb[10] = { 4, 11, 3, 4, 12, 15, 34, 83, 75, 30 };
+
+static const uint8_t huff_a26_xlat[256] = {
+    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
+};
+
+static const uint8_t huff_a27_cb[7] = { 4, 8, 3, 14, 10, 20, 16 };
+
+static const uint8_t huff_a27_xlat[63] = {
+     0,  2,  3,  1,  5,  6,  7,  9, 54, 55, 56, 58, 59, 60, 61, 62,
+    63,  4,  8, 10, 11, 12, 14, 49, 52, 53, 57, 13, 15, 16, 17, 18,
+    19, 22, 23, 25, 26, 30, 39, 43, 44, 45, 46, 47, 48, 50, 51, 20,
+    21, 24, 27, 28, 29, 31, 33, 34, 35, 36, 37, 38, 40, 41, 42
+};
+
+static const uint8_t huff_a31_cb[8] = { 1, 6, 1, 0, 3, 1, 0, 4 };
+
+static const uint8_t huff_a31_xlat[9] = {
+    0x00, 0x04, 0x0C, 0x01, 0x03, 0x05, 0x0D, 0x07, 0x0F
+};
+
+static const uint8_t huff_a32_cb[13] = {
+    1, 11, 1, 0, 0, 2, 2, 6, 12, 18, 19, 15, 6
+};
+
+static const uint8_t huff_a32_xlat[81] = {
+    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
+};
+
+static const uint8_t huff_a33_cb[12] = {
+    3, 12, 1, 1, 13, 1, 14, 28, 33, 81, 32, 52
+};
+
+static const uint8_t huff_a33_xlat[256] = {
+    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
+};
+
+static const uint8_t huff_a34_cb[7] = { 1, 5, 1, 1, 1, 1, 2 };
+
+static const uint8_t huff_a34_xlat[6] = { 1, 0, 2, 3, 4, 5 };
+
+static const uint8_t huff_a35_cb[11] = { 2, 10, 1, 0, 2, 3, 6, 19, 9, 75, 110 };
+
+static const uint8_t huff_a35_xlat[225] = {
+    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
+};
+
+static const uint8_t huff_a36_cb[12] = {
+    3, 12, 1, 3, 5, 5, 13, 27, 69, 96, 35, 2
+};
+
+static const uint8_t huff_a36_xlat[256] = {
+    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
+};
+
+static const uint8_t huff_a37_cb[7] = { 4, 8, 7, 6, 8, 22, 20 };
+
+static const uint8_t huff_a37_xlat[63] = {
+     0,  1,  2,  3, 61, 62, 63,  4,  5,  6, 58, 59, 60,  7,  8,  9,
+    10, 54, 55, 56, 57, 11, 12, 13, 14, 15, 16, 25, 26, 27, 28, 29,
+    30, 35, 36, 37, 38, 48, 49, 50, 51, 52, 53, 17, 18, 19, 20, 21,
+    22, 23, 24, 31, 33, 34, 39, 40, 41, 42, 43, 44, 45, 46, 47
+};
+
+static const uint8_t huff_a41_cb[14] = {
+    1, 12, 1, 0, 0, 6, 2, 0, 0, 0, 19, 9, 24, 20
+};
+
+static const uint8_t huff_a41_xlat[81] = {
+    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
+};
+
+static const uint8_t huff_a42_cb[10] = { 3, 10, 1, 2, 13, 1, 31, 13, 16, 4 };
+
+static const uint8_t huff_a42_xlat[81] = {
+    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
+};
+
+static const uint8_t huff_a43_cb[5] = { 2, 4, 2, 3, 2 };
+
+static const uint8_t huff_a43_xlat[7] = { 0, 7, 1, 2, 6, 3, 5 };
+
+static const uint8_t huff_a44_cb[9] = { 4, 10, 5, 4, 12, 17, 47, 24, 12 };
+
+static const uint8_t huff_a44_xlat[121] = {
+    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
+};
+
+static const uint8_t huff_a45_cb[5] = { 2, 4, 2, 2, 4 };
+
+static const uint8_t huff_a45_xlat[8] = { 1, 2, 0, 3, 4, 5, 6, 7 };
+
+static const uint8_t huff_a46_cb[7] = { 5, 9, 1, 16, 31, 36, 172 };
+
+static const uint8_t huff_a46_xlat[256] = {
+    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
+};
+
+static const uint8_t huff_a47_cb[8] = { 4, 9, 5, 12, 9, 12, 15, 10 };
+
+static const uint8_t huff_a47_xlat[63] = {
+     0,  1,  2, 62, 63,  3,  4,  5,  6,  8, 54, 56, 57, 58, 59, 60,
+    61,  7,  9, 10, 11, 12, 13, 14, 53, 55, 15, 16, 17, 18, 19, 20,
+    21, 36, 37, 39, 42, 52, 22, 25, 28, 35, 38, 40, 41, 43, 45, 46,
+    47, 48, 49, 50, 51, 23, 24, 26, 27, 29, 30, 31, 33, 34, 44
+};
+
+static const uint8_t huff_a51_cb[12] = {
+    2, 11, 1, 0, 6, 2, 6, 18, 4, 26, 6, 12
+};
+
+static const uint8_t huff_a51_xlat[81] = {
+    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
+};
+
+static const uint8_t huff_a52_cb[12] = { 1, 10, 1, 0, 2, 2, 0, 4, 3, 8, 3, 2 };
+
+static const uint8_t huff_a52_xlat[25] = {
+    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
+};
+
+static const uint8_t huff_a53_xlat[7] = { 0, 1, 2, 6, 7, 3, 5 };
+
+static const uint8_t huff_a54_cb[8] = { 4, 9, 4, 7, 12, 19, 21, 58 };
+
+static const uint8_t huff_a54_xlat[121] = {
+    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
+};
+
+static const uint8_t huff_a55_cb[8] = { 1, 6, 1, 1, 1, 0, 3, 2 };
+
+static const uint8_t huff_a55_xlat[8] = { 0, 1, 2, 3, 6, 7, 4, 5 };
+
+static const uint8_t huff_a56_cb[7] = { 3, 7, 1, 8, 6, 8, 8 };
+
+static const uint8_t huff_a56_xlat[31] = {
+    4,  0,  1,  2,  3, 28, 29, 30, 31,  5,  6,  7, 24, 25, 27, 8,
+    9, 14, 19, 21, 22, 23, 26, 10, 11, 12, 13, 15, 17, 18, 20
+};
+
+static const uint8_t huff_a57_cb[9] = { 3, 9, 1, 5, 7, 8, 16, 22, 4 };
+
+static const uint8_t huff_a57_xlat[63] = {
+     0,  1,  2, 61, 62, 63,  3,  4,  5,  6, 58, 59,
+    60,  7,  8,  9, 10, 54, 55, 56, 57, 11, 12, 13,
+    14, 15, 26, 27, 28, 36, 37, 38, 49, 50, 51, 52,
+    53, 16, 17, 18, 19, 20, 21, 23, 24, 25, 29, 30,
+    31, 33, 34, 35, 39, 43, 44, 45, 46, 47, 48, 22,
+    40, 41, 42
+};
+
+static const uint8_t huff_a61_cb[12] = {
+    2, 11, 1, 0, 8, 0, 1, 16, 10, 29, 12, 4
+};
+
+static const uint8_t huff_a61_xlat[81] = {
+    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
+};
+
+static const uint8_t huff_a62_cb[8] = { 3, 8, 5, 2, 2, 9, 5, 2 };
+
+static const uint8_t huff_a62_xlat[25] = {
+    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
+};
+
+static const uint8_t huff_a63_cb[11] = {
+    3, 11, 1, 1, 10, 4, 16, 29, 46, 75, 74
+};
+
+static const uint8_t huff_a63_xlat[256] = {
+    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
+};
+
+static const uint8_t huff_a64_cb[8] = { 4, 9, 1, 7, 12, 36, 63, 2 };
+
+static const uint8_t huff_a64_xlat[121] = {
+    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
+};
+
+static const uint8_t huff_a65_cb[8] = { 2, 7, 3, 0, 1, 3, 4, 4 };
+
+static const uint8_t huff_a65_xlat[15] = {
+    0, 1, 15, 14, 2, 3, 13, 4, 6, 10, 12, 5, 7, 9, 11
+};
+
+static const uint8_t huff_a66_cb[11] = { 2, 10, 1, 2, 2, 6, 8, 6, 3, 1, 2 };
+
+static const uint8_t huff_a66_xlat[31] = {
+     0,  1, 31, 2, 30,  3,  4, 15, 17, 28, 29,  5,  6,  7,  8, 24,
+    25, 26, 27, 9, 10, 11, 21, 22, 23, 12, 19, 20, 13, 14, 18
+};
+
+static const uint8_t huff_a67_cb[10] = { 2, 9, 1, 1, 3, 4, 6, 13, 25, 10 };
+
+static const uint8_t huff_a67_xlat[63] = {
+     0,  1,  2, 62, 63,  3,  4, 60, 61,  5,  6,  7, 57, 58, 59,  8,
+     9, 10, 11, 12, 13, 26, 38, 52, 53, 54, 55, 56, 14, 15, 16, 17,
+    18, 19, 25, 27, 28, 29, 30, 31, 33, 34, 35, 36, 37, 39, 45, 46,
+    47, 48, 49, 50, 51, 20, 21, 22, 23, 24, 40, 41, 42, 43, 44
+};
+
+static const uint8_t huff_a71_cb[5] = { 1, 3, 1, 1, 2 };
+
+static const uint8_t huff_a72_cb[12] = {
+    2, 11, 1, 0, 4, 8, 3, 8, 24, 17, 12, 4
+};
+
+static const uint8_t huff_a72_xlat[81] = {
+    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
+};
+
+static const uint8_t huff_a73_cb[11] = { 2, 10, 1, 1, 5, 2, 8, 7, 13, 8, 4 };
+
+static const uint8_t huff_a73_xlat[49] = {
+    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
+};
+
+static const uint8_t huff_a74_cb[14] = {
+    1, 12, 1, 0, 0, 4, 0, 4, 5, 9, 30, 45, 21, 2
+};
+
+static const uint8_t huff_a74_xlat[121] = {
+    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
+};
+
+static const uint8_t huff_a75_cb[7] = { 2, 6, 1, 3, 3, 4, 4 };
+
+static const uint8_t huff_a75_xlat[15] = {
+    0, 1, 14, 15, 2, 3, 13, 4, 6, 10, 12, 5, 7, 9, 11
+};
+
+static const uint8_t huff_a76_cb[12] = {
+    3, 12, 1, 3, 4, 8, 10, 36, 60, 78, 48, 8
+};
+
+static const uint8_t huff_a76_xlat[256] = {
+    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
+};
+
+static const uint8_t huff_b01_cb[14] = {
+    1, 12, 1, 0, 0, 2, 6, 0, 11, 13, 12, 24, 4, 8
+};
+
+static const uint8_t huff_b01_xlat[81] = {
+    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
+};
+
+static const uint8_t huff_b02_cb[14] = {
+    1, 12, 1, 0, 0, 4, 0, 8, 4, 9, 19, 13, 13, 10
+};
+
+static const uint8_t huff_b02_xlat[81] = {
+    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
+};
+
+static const uint8_t huff_b03_cb[11] = { 1, 9, 1, 0, 0, 4, 0, 5, 12, 13, 14 };
+
+static const uint8_t huff_b03_xlat[49] = {
+    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
+};
+
+static const uint8_t huff_b04_cb[12] = {
+    2, 11, 1, 0, 4, 4, 5, 9, 30, 45, 21, 2
+};
+
+static const uint8_t huff_b04_xlat[121] = {
+    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
+};
+
+static const uint8_t huff_b05_cb[11] = {
+    3, 11, 1, 4, 4, 4, 12, 30, 73, 75, 22
+};
+
+static const uint8_t huff_b05_xlat[225] = {
+    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
+};
+
+static const uint8_t huff_b07_cb[9] = { 3, 9, 3, 2, 4, 8, 23, 13, 10 };
+
+static const uint8_t huff_b07_xlat[63] = {
+     0,  1, 63,  2, 62,  3,  4, 60, 61,  5,  6,  7,  8, 56, 57, 58,
+    59,  9, 10, 11, 12, 25, 26, 27, 28, 29, 30, 31, 33, 34, 35, 36,
+    37, 38, 39, 51, 52, 53, 54, 55, 13, 14, 15, 16, 17, 18, 19, 45,
+    46, 47, 48, 49, 50, 20, 21, 22, 23, 24, 40, 41, 42, 43, 44
+};
+
+static const uint8_t huff_b12_cb[10] = { 3, 10, 1, 3, 12, 0, 30, 9, 18, 8 };
+
+static const uint8_t huff_b12_xlat[81] = {
+    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
+};
+
+static const uint8_t huff_b14_cb[14] = {
+    1, 12, 1, 0, 0, 4, 0, 3, 5, 16, 28, 34, 26, 4
+};
+
+static const uint8_t huff_b14_xlat[121] = {
+    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
+};
+
+static const uint8_t huff_b16_cb[11] = {
+    4, 12, 4, 4, 9, 13, 37, 76, 72, 39, 2
+};
+
+static const uint8_t huff_b16_xlat[256] = {
+    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
+};
+
+static const uint8_t huff_b26_cb[12] = {
+    3, 12, 2, 2, 4, 5, 11, 26, 67, 78, 51, 10
+};
+
+static const uint8_t huff_b26_xlat[256] = {
+    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
+};
+
+static const uint8_t huff_b32_cb[12] = {
+    2, 11, 1, 0, 4, 6, 7, 10, 22, 11, 16, 4
+};
+
+static const uint8_t huff_b32_xlat[81] = {
+    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
+};
+
+static const uint8_t huff_b33_cb[13] = {
+    2, 12, 1, 0, 0, 4, 11, 8, 28, 92, 97, 13, 2
+};
+
+static const uint8_t huff_b33_xlat[256] = {
+    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
+};
+
+static const uint8_t huff_b35_cb[14] = {
+    1, 12, 1, 0, 0, 0, 4, 6, 6, 14, 42, 63, 59, 30
+};
+
+static const uint8_t huff_b35_xlat[225] = {
+    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
+};
+
+static const uint8_t huff_b37_cb[13] = {
+    1, 11, 1, 0, 2, 0, 2, 2, 6, 17, 14, 13, 6
+};
+
+static const uint8_t huff_b37_xlat[63] = {
+     0,  1, 63,  2, 62,  3, 61,  4,  5,  6, 58, 59, 60,  7,  8,  9,
+    10, 25, 26, 27, 28, 29, 34, 35, 37, 38, 39, 55, 56, 57, 11, 13,
+    14, 15, 30, 31, 33, 36, 49, 50, 51, 52, 53, 54, 12, 16, 17, 18,
+    19, 21, 41, 43, 44, 45, 46, 47, 48, 20, 22, 23, 24, 40, 42
+};
+
+static const uint8_t huff_b41_cb[14] = {
+    1, 12, 1, 0, 0, 1, 7, 0, 20, 4, 10, 24, 2, 12
+};
+
+static const uint8_t huff_b41_xlat[81] = {
+    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
+};
+
+static const uint8_t huff_b42_cb[11] = { 1, 9, 1, 0, 1, 3, 2, 3, 7, 4, 4 };
+
+static const uint8_t huff_b42_xlat[25] = {
+    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
+};
+
+static const uint8_t huff_b43_cb[10] = { 2, 9, 1, 1, 3, 4, 9, 15, 12, 4 };
+
+static const uint8_t huff_b43_xlat[49] = {
+    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
+};
+
+static const uint8_t huff_b47_cb[10] = { 2, 9, 1, 1, 3, 4, 6, 14, 22, 12 };
+
+static const uint8_t huff_b47_xlat[63] = {
+     0,  1,  2, 62, 63,  3,  4, 60, 61,  5,  6,  7, 57, 58, 59,  8,
+     9, 10, 11, 12, 26, 27, 37, 38, 52, 53, 54, 55, 56, 13, 14, 15,
+    16, 17, 18, 25, 28, 29, 30, 31, 33, 34, 35, 36, 39, 46, 47, 48,
+    49, 50, 51, 19, 20, 21, 22, 23, 24, 40, 41, 42, 43, 44, 45
+};
+
+static const uint8_t huff_b52_cb[11] = { 1, 9, 1, 0, 1, 3, 2, 3, 7, 4, 4 };
+
+static const uint8_t huff_b52_xlat[25] = {
+    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
+};
+
+static const uint8_t huff_b53_cb[7] = { 1, 5, 1, 1, 1, 0, 4 }; // same as b63!!!
+
+static const uint8_t huff_b53_xlat[7] = { 0, 7, 1, 2, 3, 5, 6 };
+
+static const uint8_t huff_b56_cb[11] = { 1, 9, 1, 0, 2, 0, 2, 4, 11, 9, 2 };
+
+static const uint8_t huff_b56_xlat[31] = {
+     0,  1, 31,  2, 30, 3,  4, 13, 29,  5,  6,  7, 14, 15, 17, 18,
+    19, 26, 27, 28,  8, 9, 12, 20, 21, 22, 23, 24, 25, 10, 11
+};
+
+static const uint8_t huff_b62_cb[14] = {
+    1, 12, 1, 0, 0, 2, 3, 5, 12, 14, 18, 15, 9, 2
+};
+
+static const uint8_t huff_b62_xlat[81] = {
+    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
+};
+
+static const uint8_t huff_b63_cb[7] = { 1, 5, 1, 1, 1, 0, 4 };
+
+static const uint8_t huff_b63_xlat[7] = { 0, 1, 7, 2, 3, 5, 6 };
+
+static const uint8_t huff_b64_cb[7] = { 1, 5, 1, 1, 1, 1, 2 };
+
+static const uint8_t huff_b64_xlat[6] = { 1, 0, 2, 5, 3, 4 };
+
+static const uint8_t huff_b65_cb[14] = {
+    1, 12, 1, 0, 0, 2, 2, 2, 6, 12, 34, 92, 54, 20
+};
+
+static const uint8_t huff_b65_xlat[225] = {
+    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
+};
+
+static const uint8_t huff_b66_cb[14] = {
+    1, 12, 1, 0, 0, 3, 0, 3, 3, 10, 40, 85, 61, 50
+};
+
+static const uint8_t huff_b66_xlat[256] = {
+    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
+};
+
+static const uint8_t huff_b67_cb[10] = { 2, 9, 1, 2, 1, 4, 7, 10, 26, 12 };
+
+static const uint8_t huff_b67_xlat[63] = {
+     0,  1, 63, 62,  2,  3, 60, 61,  4,  5,  6,  7, 57, 58, 59,  8,
+     9, 10, 11, 12, 52, 53, 54, 55, 56, 13, 14, 15, 16, 17, 18, 25,
+    26, 27, 28, 29, 30, 31, 33, 34, 35, 36, 37, 38, 39, 46, 47, 48,
+    49, 50, 51, 19, 20, 21, 22, 23, 24, 40, 41, 42, 43, 44, 45
+};
+
+static const uint8_t huff_b71_cb[14] = {
+    1, 12, 1, 0, 0, 1, 7, 0, 19, 5, 13, 23, 0, 12
+};
+
+static const uint8_t huff_b71_xlat[81] = {
+    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
+};
+
+static const uint8_t huff_b73_cb[13] = {
+    1, 11, 1, 0, 0, 0, 1, 4, 9, 4, 103, 110, 24
+};
+
+static const uint8_t huff_b73_xlat[256] = {
+    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
+};
+
+static const uint8_t huff_b74_cb[8] = { 1, 6, 1, 0, 2, 2, 2, 4 };
+
+static const uint8_t huff_b74_xlat[11] = {
+    0, 1, 15, 2, 14, 5, 13, 3, 4, 11, 12
+};
+
+static const uint8_t huff_b75_cb[13] = {
+    2, 12, 1, 4, 0, 0, 0, 8, 11, 24, 53, 64, 60
+};
+
+static const uint8_t huff_b75_xlat[225] = {
+    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
+};
+
+static const uint8_t huff_b77_cb[12] = {
+    2, 11, 1, 0, 4, 6, 10, 12, 7, 15, 4, 4
+};
+
+static const uint8_t huff_b77_xlat[63] = {
+     0,  1,  2, 62, 63,  3,  4,  5, 59, 60, 61,  6,  7,  8,  9, 10,
+    54, 55, 56, 57, 58, 11, 12, 13, 14, 15, 16, 47, 49, 50, 51, 52,
+    53, 17, 18, 19, 20, 45, 46, 48, 21, 22, 23, 24, 25, 26, 27, 37,
+    38, 39, 40, 41, 42, 43, 44, 28, 29, 30, 35, 31, 33, 34, 36
+};
+
+/** 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
+
+    int redirect;        ///< if >= 0: tells which huffman table must be reused
+    const uint8_t *cb;   ///< pointer to the codebook descriptor
+    const uint8_t *xlat; ///< pointer to the translation table or NULL if none
+} Atrac3pSpecCodeTab;
+
+static const Atrac3pSpecCodeTab atrac3p_spectra_tabs[112] = {
+    /* table set = A */
+    /* code table = 0 */
+    { 1, 4, 2, 1, -1, huff_a01_cb, huff_a01_xlat }, // wordlen = 1
+    { 1, 4, 2, 0, -1, huff_a02_cb, huff_a02_xlat }, // wordlen = 2
+    { 1, 2, 3, 1, -1, huff_a03_cb, huff_a03_xlat }, // wordlen = 3
+    { 1, 1, 3, 0, -1, huff_a04_cb, huff_a04_xlat }, // wordlen = 4
+    { 1, 2, 4, 1, -1, huff_a05_cb, huff_a05_xlat }, // wordlen = 5
+    { 1, 1, 4, 0, -1, huff_a06_cb, huff_a06_xlat }, // wordlen = 6
+    { 1, 1, 6, 1, -1, huff_a07_cb, huff_a07_xlat }, // wordlen = 7
+
+    /* code table = 1 */
+    { 4, 4, 2, 1, -1, huff_a11_cb, huff_a11_xlat }, // wordlen = 1
+    { 1, 4, 2, 0, -1, huff_a12_cb, huff_a12_xlat }, // wordlen = 2
+    { 1, 2, 3, 1, -1, huff_a13_cb, huff_a13_xlat }, // wordlen = 3
+    { 1, 2, 4, 1, -1, huff_a14_cb, huff_a14_xlat }, // wordlen = 4
+    { 1, 2, 4, 1, -1, huff_a15_cb, huff_a15_xlat }, // wordlen = 5
+    { 1, 2, 4, 0, -1, huff_a16_cb, huff_a16_xlat }, // wordlen = 6
+    { 1, 1, 6, 1, -1, huff_a17_cb, huff_a17_xlat }, // wordlen = 7
+
+    /* code table = 2 */
+    { 1, 4, 2, 1, -1, huff_a21_cb, huff_a21_xlat }, // wordlen = 1
+    { 1, 2, 3, 1, -1, huff_a22_cb, huff_a22_xlat }, // wordlen = 2
+    { 1, 2, 3, 1, -1, huff_a23_cb, huff_a23_xlat }, // wordlen = 3
+    { 1, 1, 3, 0, -1, huff_a24_cb, NULL          }, // wordlen = 4
+    { 1, 1, 3, 0, -1, huff_a25_cb, huff_a25_xlat }, // wordlen = 5
+    { 1, 2, 4, 0, -1, huff_a26_cb, huff_a26_xlat }, // wordlen = 6
+    { 1, 1, 6, 1, -1, huff_a27_cb, huff_a27_xlat }, // wordlen = 7
+
+    /* code table = 3 */
+    { 1, 2, 2, 1, -1, huff_a31_cb, huff_a31_xlat }, // wordlen = 1
+    { 1, 4, 2, 0, -1, huff_a32_cb, huff_a32_xlat }, // wordlen = 2
+    { 1, 4, 2, 0, -1, huff_a33_cb, huff_a33_xlat }, // wordlen = 3
+    { 1, 1, 3, 0, -1, huff_a34_cb, huff_a34_xlat }, // wordlen = 4
+    { 1, 2, 4, 1, -1, huff_a35_cb, huff_a35_xlat }, // wordlen = 5
+    { 1, 2, 4, 0, -1, huff_a36_cb, huff_a36_xlat }, // wordlen = 6
+    { 1, 1, 6, 1, -1, huff_a37_cb, huff_a37_xlat }, // wordlen = 7
+
+    /* code table = 4 */
+    { 1, 4, 2, 1, -1, huff_a41_cb, huff_a41_xlat }, // wordlen = 1
+    { 1, 4, 2, 0, -1, huff_a42_cb, huff_a42_xlat }, // wordlen = 2
+    { 1, 1, 3, 1, -1, huff_a43_cb, huff_a43_xlat }, // wordlen = 3
+    { 1, 2, 4, 1, -1, huff_a44_cb, huff_a44_xlat }, // wordlen = 4
+    { 1, 1, 3, 0, -1, huff_a45_cb, huff_a45_xlat }, // wordlen = 5
+    { 1, 2, 4, 0, -1, huff_a46_cb, huff_a46_xlat }, // wordlen = 6
+    { 1, 1, 6, 1, -1, huff_a47_cb, huff_a47_xlat }, // wordlen = 7
+
+    /* code table = 5 */
+    { 1, 4, 2, 1, -1, huff_a51_cb, huff_a51_xlat }, // wordlen = 1
+    { 1, 2, 3, 1, -1, huff_a52_cb, huff_a52_xlat }, // wordlen = 2
+    { 1, 1, 3, 1, -1, huff_a43_cb, huff_a53_xlat }, // wordlen = 3
+    { 1, 2, 4, 1, -1, huff_a54_cb, huff_a54_xlat }, // wordlen = 4
+    { 1, 1, 3, 0, -1, huff_a55_cb, huff_a55_xlat }, // wordlen = 5
+    { 1, 1, 5, 1, -1, huff_a56_cb, huff_a56_xlat }, // wordlen = 6
+    { 1, 1, 6, 1, -1, huff_a57_cb, huff_a57_xlat }, // wordlen = 7
+
+    /* code table = 6 */
+    { 2, 4, 2, 1, -1, huff_a61_cb, huff_a61_xlat }, // wordlen = 1
+    { 1, 2, 3, 1, -1, huff_a62_cb, huff_a62_xlat }, // wordlen = 2
+    { 1, 4, 2, 0, -1, huff_a63_cb, huff_a63_xlat }, // wordlen = 3
+    { 1, 2, 4, 1, -1, huff_a64_cb, huff_a64_xlat }, // wordlen = 4
+    { 1, 1, 4, 1, -1, huff_a65_cb, huff_a65_xlat }, // wordlen = 5
+    { 1, 1, 5, 1, -1, huff_a66_cb, huff_a66_xlat }, // wordlen = 6
+    { 1, 1, 6, 1, -1, huff_a67_cb, huff_a67_xlat }, // wordlen = 7
+
+    /* code table = 7 */
+    { 1, 2, 1, 0, -1, huff_a71_cb, NULL          }, // wordlen = 1
+    { 2, 4, 2, 0, -1, huff_a72_cb, huff_a72_xlat }, // wordlen = 2
+    { 1, 2, 3, 1, -1, huff_a73_cb, huff_a73_xlat }, // wordlen = 3
+    { 1, 2, 4, 1, -1, huff_a74_cb, huff_a74_xlat }, // wordlen = 4
+    { 1, 1, 4, 1, -1, huff_a75_cb, huff_a75_xlat }, // wordlen = 5
+    { 2, 2, 4, 0, -1, huff_a76_cb, huff_a76_xlat }, // wordlen = 6
+    { 4, 1, 6, 1,  6, NULL,        NULL          }, // wordlen = 7
+
+    /* table set = B */
+    /* code table = 0 */
+    { 4, 4, 2, 1, -1, huff_b01_cb, huff_b01_xlat }, // wordlen = 1
+    { 1, 4, 2, 0, -1, huff_b02_cb, huff_b02_xlat }, // wordlen = 2
+    { 4, 2, 3, 1, -1, huff_b03_cb, huff_b03_xlat }, // wordlen = 3
+    { 1, 2, 4, 1, -1, huff_b04_cb, huff_b04_xlat }, // wordlen = 4
+    { 1, 2, 4, 1, -1, huff_b05_cb, huff_b05_xlat }, // wordlen = 5
+    { 1, 1, 4, 0,  5, NULL,        NULL          }, // wordlen = 6
+    { 1, 1, 6, 1, -1, huff_b07_cb, huff_b07_xlat }, // wordlen = 7
+
+    /* code table = 1 */
+    { 1, 4, 2, 1, 14, NULL,        NULL          }, // wordlen = 1
+    { 1, 4, 2, 0, -1, huff_b12_cb, huff_b12_xlat }, // wordlen = 2
+    { 1, 2, 3, 1,  9, NULL,        NULL          }, // wordlen = 3
+    { 1, 2, 4, 1, -1, huff_b14_cb, huff_b14_xlat }, // wordlen = 4
+    { 1, 2, 4, 1, 11, NULL,        NULL          }, // wordlen = 5
+    { 1, 2, 4, 0, -1, huff_b16_cb, huff_b16_xlat }, // wordlen = 6
+    { 1, 1, 6, 1,  6, NULL,        NULL          }, // wordlen = 7
+
+    /* code table = 2 */
+    { 4, 4, 2, 1, 28, NULL,        NULL          }, // wordlen = 1
+    { 4, 4, 2, 0, 22, NULL,        NULL          }, // wordlen = 2
+    { 1, 2, 3, 1,  2, NULL,        NULL          }, // wordlen = 3
+    { 1, 2, 4, 1, 31, NULL,        NULL          }, // wordlen = 4
+    { 2, 2, 4, 1, 60, NULL,        NULL          }, // wordlen = 5
+    { 2, 2, 4, 0, -1, huff_b26_cb, huff_b26_xlat }, // wordlen = 6
+    { 4, 1, 6, 1,  6, NULL,        NULL          }, // wordlen = 7
+
+    /* code table = 3 */
+    { 1, 4, 2, 1, 35, NULL,        NULL          }, // wordlen = 1
+    { 1, 4, 2, 0, -1, huff_b32_cb, huff_b32_xlat }, // wordlen = 2
+    { 1, 4, 2, 0, -1, huff_b33_cb, huff_b33_xlat }, // wordlen = 3
+    { 2, 2, 4, 1, 59, NULL,        NULL          }, // wordlen = 4
+    { 1, 2, 4, 1, -1, huff_b35_cb, huff_b35_xlat }, // wordlen = 5
+    { 1, 2, 4, 0, 75, NULL,        NULL          }, // wordlen = 6
+    { 1, 1, 6, 1, -1, huff_b37_cb, huff_b37_xlat }, // wordlen = 7
+
+    /* code table = 4 */
+    { 1, 4, 2, 1, -1, huff_b41_cb, huff_b41_xlat }, // wordlen = 1
+    { 4, 2, 3, 1, -1, huff_b42_cb, huff_b42_xlat }, // wordlen = 2
+    { 1, 2, 3, 1, -1, huff_b43_cb, huff_b43_xlat }, // wordlen = 3
+    { 4, 2, 4, 1, 66, NULL,        NULL          }, // wordlen = 4
+    { 1, 1, 3, 0, 32, NULL,        NULL          }, // wordlen = 5
+    { 1, 2, 4, 0, 12, NULL,        NULL          }, // wordlen = 6
+    { 1, 1, 6, 1, -1, huff_b47_cb, huff_b47_xlat }, // wordlen = 7
+
+    /* code table = 5 */
+    { 2, 4, 2, 1, 42, NULL,        NULL          }, // wordlen = 1
+    { 1, 2, 3, 1, -1, huff_b52_cb, huff_b52_xlat }, // wordlen = 2
+    { 4, 1, 3, 1, -1, huff_b53_cb, huff_b53_xlat }, // wordlen = 3
+    { 1, 1, 3, 0, 17, NULL,        NULL          }, // wordlen = 4
+    { 1, 1, 3, 0, 39, NULL,        NULL          }, // wordlen = 5
+    { 1, 1, 5, 1, -1, huff_b56_cb, huff_b56_xlat }, // wordlen = 6
+    { 2, 1, 6, 1, 62, NULL,        NULL          }, // wordlen = 7
+
+    /* code table = 6 */
+    { 1, 4, 2, 1, 28, NULL,        NULL          }, // wordlen = 1
+    { 1, 4, 2, 0, -1, huff_b62_cb, huff_b62_xlat }, // wordlen = 2
+    { 1, 1, 3, 1, -1, huff_b63_cb, huff_b63_xlat }, // wordlen = 3
+    { 1, 1, 3, 0, -1, huff_b64_cb, huff_b64_xlat }, // wordlen = 4
+    { 4, 2, 4, 1, -1, huff_b65_cb, huff_b65_xlat }, // wordlen = 5
+    { 1, 2, 4, 0, -1, huff_b66_cb, huff_b66_xlat }, // wordlen = 6
+    { 1, 1, 6, 1, -1, huff_b67_cb, huff_b67_xlat }, // wordlen = 7
+
+    /* code table = 7 */
+    { 1, 4, 2, 1, -1, huff_b71_cb, huff_b71_xlat }, // wordlen = 1
+    { 4, 4, 2, 0, 78, NULL,        NULL          }, // wordlen = 2
+    { 4, 4, 2, 0, -1, huff_b73_cb, huff_b73_xlat }, // wordlen = 3
+    { 1, 1, 4, 1, -1, huff_b74_cb, huff_b74_xlat }, // wordlen = 4
+    { 1, 2, 4, 1, -1, huff_b75_cb, huff_b75_xlat }, // wordlen = 5
+    { 1, 1, 5, 1, 47, NULL,        NULL          }, // wordlen = 6
+    { 1, 1, 6, 1, -1, huff_b77_cb, huff_b77_xlat }, // wordlen = 7
+};
+
+/* Huffman tables for gain control data. */
+static const uint8_t atrac3p_huff_gain_npoints1_cb[9] = {
+    1, 7, 1, 1, 1, 1, 1, 1, 2
+};
+
+static const uint8_t atrac3p_huff_gain_npoints2_xlat[8] = {
+    0, 1, 7, 2, 6, 3, 4, 5
+};
+
+static const uint8_t atrac3p_huff_gain_lev1_cb[9] = { 1, 7, 1, 0, 2, 2, 1, 2, 8 };
+static const uint8_t atrac3p_huff_gain_lev1_xlat[16] = {
+    7, 5, 8, 6, 9, 4, 10, 11, 0, 1, 2, 3, 12, 13, 14, 15
+};
+
+static const uint8_t atrac3p_huff_gain_lev2_cb[11] = {
+    1, 9, 1, 1, 1, 1, 1, 0, 2, 0, 8
+};
+
+static const uint8_t atrac3p_huff_gain_lev2_xlat[15] = {
+    15, 14, 1, 13, 2, 3, 12, 4, 5, 6, 7, 8, 9, 10, 11
+};
+
+static const uint8_t atrac3p_huff_gain_lev3_cb[11] = {
+    1, 9, 1, 0, 3, 1, 1, 0, 2, 0, 8
+};
+
+static const uint8_t atrac3p_huff_gain_lev3_xlat[16] = {
+    0, 1, 14, 15, 2, 13, 3, 12, 4, 5, 6, 7, 8, 9, 10, 11
+};
+
+static const uint8_t atrac3p_huff_gain_lev4_cb[11] = {
+    1, 9, 1, 1, 1, 1, 1, 0, 1, 2, 8
+};
+
+static const uint8_t atrac3p_huff_gain_lev4_xlat[16] = {
+    0, 1, 15, 14, 2, 13, 3, 12, 4, 5, 6, 7, 8, 9, 10, 11
+};
+
+static const uint8_t atrac3p_huff_gain_loc1_cb[9] = { 2, 8, 1, 2, 4, 4, 4, 0, 16 };
+static const uint8_t atrac3p_huff_gain_loc1_xlat[31] = {
+     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
+};
+
+static const uint8_t atrac3p_huff_gain_loc2_cb[8] = { 3, 8, 5, 3, 2, 3, 2, 16 };
+static const uint8_t atrac3p_huff_gain_loc2_xlat[31] = {
+     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
+};
+
+static const uint8_t atrac3p_huff_gain_loc3_cb[7] = { 2, 6, 1, 0, 2, 11, 18 };
+static const uint8_t atrac3p_huff_gain_loc3_xlat[32] = {
+    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
+};
+
+static const uint8_t atrac3p_huff_gain_loc4_cb[5] = { 4, 6, 3, 23, 6 };
+static const uint8_t atrac3p_huff_gain_loc4_xlat[32] = {
+    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
+};
+
+static const uint8_t atrac3p_huff_gain_loc5_cb[9] = { 1, 7, 1, 0, 0, 3, 2, 6, 20 };
+static const uint8_t atrac3p_huff_gain_loc5_xlat[32] = {
+    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_huff_tonebands_cb[8] = { 1, 6, 1, 0, 1, 2, 4, 8 };
+static const uint8_t atrac3p_huff_numwavs1_cb[9] = { 1, 7, 1, 1, 1, 1, 1, 1, 2 };
+static const uint8_t atrac3p_huff_numwavs2_cb[8] = { 1, 6, 1, 1, 1, 1, 0, 4 };
+static const uint8_t atrac3p_huff_numwavs2_xlat[8] = { 0, 1, 7, 2, 3, 4, 5, 6 };
+static const uint8_t atrac3p_huff_wav_ampsf1_cb[7] = { 4, 8, 10, 8, 6, 0, 8 };
+static const uint8_t atrac3p_huff_wav_ampsf1_xlat[32] = {
+     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
+};
+
+static const uint8_t atrac3p_huff_wav_ampsf2_cb[7] = { 4, 8, 11, 5, 6, 6, 4 };
+static const uint8_t atrac3p_huff_wav_ampsf2_xlat[32] = {
+    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
+};
+
+static const uint8_t atrac3p_huff_wav_ampsf3_cb[9] = { 2, 8, 1, 3, 3, 1, 4, 4, 16 };
+static const uint8_t atrac3p_huff_wav_ampsf3_xlat[32] = {
+    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
+};
+
+static const uint8_t atrac3p_huff_freq_cb[13] = {
+    1, 11, 1, 0, 0, 2, 2, 0, 9, 9, 29, 104, 100
+};
+
+static const uint8_t atrac3p_huff_freq_xlat[256] = {
+      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/libavcodec/atrac3plusdec.c b/libavcodec/atrac3plusdec.c
new file mode 100644
index 0000000..dbdb3b3
--- /dev/null
+++ b/libavcodec/atrac3plusdec.c
@@ -0,0 +1,387 @@
+/*
+ * ATRAC3+ compatible decoder
+ *
+ * Copyright (c) 2010-2013 Maxim Poliakovski
+ *
+ * This file is part of Libav.
+ *
+ * Libav 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.
+ *
+ * Libav 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 Libav; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * @file
+ * Sony ATRAC3+ compatible decoder.
+ *
+ * Container formats used to store its data:
+ * RIFF WAV (.at3) and Sony OpenMG (.oma, .aa3).
+ *
+ * Technical description of this codec can be found here:
+ * http://wiki.multimedia.cx/index.php?title=ATRAC3plus
+ *
+ * Kudos to Benjamin Larsson and Michael Karcher
+ * for their precious technical help!
+ */
+
+#include <stdint.h>
+#include <string.h>
+
+#include "libavutil/channel_layout.h"
+#include "libavutil/float_dsp.h"
+#include "avcodec.h"
+#include "get_bits.h"
+#include "internal.h"
+#include "atrac.h"
+#include "atrac3plus.h"
+
+typedef struct ATRAC3PContext {
+    GetBitContext gb;
+    AVFloatDSPContext fdsp;
+
+    DECLARE_ALIGNED(32, float, samples)[2][ATRAC3P_FRAME_SAMPLES];  ///< quantized MDCT spectrum
+    DECLARE_ALIGNED(32, float, mdct_buf)[2][ATRAC3P_FRAME_SAMPLES]; ///< output of the IMDCT
+    DECLARE_ALIGNED(32, float, time_buf)[2][ATRAC3P_FRAME_SAMPLES]; ///< output of the gain compensation
+    DECLARE_ALIGNED(32, float, outp_buf)[2][ATRAC3P_FRAME_SAMPLES];
+
+    AtracGCContext gainc_ctx;   ///< gain compensation context
+    FFTContext mdct_ctx;
+    FFTContext ipqf_dct_ctx;    ///< IDCT context used by IPQF
+
+    Atrac3pChanUnitCtx *ch_units;   ///< global channel units
+
+    int num_channel_blocks;     ///< number of channel blocks
+    uint8_t channel_blocks[5];  ///< channel configuration descriptor
+    uint64_t my_channel_layout; ///< current channel layout
+} ATRAC3PContext;
+
+static av_cold int atrac3p_decode_close(AVCodecContext *avctx)
+{
+    av_free(((ATRAC3PContext *)(avctx->priv_data))->ch_units);
+
+    return 0;
+}
+
+static av_cold int set_channel_params(ATRAC3PContext *ctx,
+                                      AVCodecContext *avctx)
+{
+    memset(ctx->channel_blocks, 0, sizeof(ctx->channel_blocks));
+
+    switch (avctx->channel_layout) {
+    case AV_CH_FRONT_LEFT:
+    case AV_CH_LAYOUT_MONO:
+        ctx->num_channel_blocks = 1;
+        ctx->channel_blocks[0]  = CH_UNIT_MONO;
+        break;
+    case AV_CH_LAYOUT_STEREO:
+        ctx->num_channel_blocks = 1;
+        ctx->channel_blocks[0]  = CH_UNIT_STEREO;
+        break;
+    case AV_CH_LAYOUT_SURROUND:
+        ctx->num_channel_blocks = 2;
+        ctx->channel_blocks[0]  = CH_UNIT_STEREO;
+        ctx->channel_blocks[1]  = CH_UNIT_MONO;
+        break;
+    case AV_CH_LAYOUT_4POINT0:
+        ctx->num_channel_blocks = 3;
+        ctx->channel_blocks[0]  = CH_UNIT_STEREO;
+        ctx->channel_blocks[1]  = CH_UNIT_MONO;
+        ctx->channel_blocks[2]  = CH_UNIT_MONO;
+        break;
+    case AV_CH_LAYOUT_5POINT1_BACK:
+        ctx->num_channel_blocks = 4;
+        ctx->channel_blocks[0]  = CH_UNIT_STEREO;
+        ctx->channel_blocks[1]  = CH_UNIT_MONO;
+        ctx->channel_blocks[2]  = CH_UNIT_STEREO;
+        ctx->channel_blocks[3]  = CH_UNIT_MONO;
+        break;
+    case AV_CH_LAYOUT_6POINT1_BACK:
+        ctx->num_channel_blocks = 5;
+        ctx->channel_blocks[0]  = CH_UNIT_STEREO;
+        ctx->channel_blocks[1]  = CH_UNIT_MONO;
+        ctx->channel_blocks[2]  = CH_UNIT_STEREO;
+        ctx->channel_blocks[3]  = CH_UNIT_MONO;
+        ctx->channel_blocks[4]  = CH_UNIT_MONO;
+        break;
+    case AV_CH_LAYOUT_7POINT1:
+        ctx->num_channel_blocks = 5;
+        ctx->channel_blocks[0]  = CH_UNIT_STEREO;
+        ctx->channel_blocks[1]  = CH_UNIT_MONO;
+        ctx->channel_blocks[2]  = CH_UNIT_STEREO;
+        ctx->channel_blocks[3]  = CH_UNIT_STEREO;
+        ctx->channel_blocks[4]  = CH_UNIT_MONO;
+        break;
+    default:
+        av_log(avctx, AV_LOG_ERROR,
+               "Unsupported channel layout: %"PRIx64"!\n", avctx->channel_layout);
+        return AVERROR_INVALIDDATA;
+    }
+
+    return 0;
+}
+
+static av_cold int atrac3p_decode_init(AVCodecContext *avctx)
+{
+    ATRAC3PContext *ctx = avctx->priv_data;
+    int i, ch, ret;
+
+    if (!avctx->block_align) {
+        av_log(avctx, AV_LOG_ERROR, "block_align is not set\n");
+        return AVERROR(EINVAL);
+    }
+
+    avpriv_float_dsp_init(&ctx->fdsp, avctx->flags & CODEC_FLAG_BITEXACT);
+
+    /* initialize IPQF */
+    ff_mdct_init(&ctx->ipqf_dct_ctx, 5, 1, 32.0 / 32768.0);
+
+    ff_atrac3p_init_imdct(avctx, &ctx->mdct_ctx);
+
+    ff_atrac_init_gain_compensation(&ctx->gainc_ctx, 6, 2);
+
+    ff_atrac3p_init_wave_synth();
+
+    if ((ret = set_channel_params(ctx, avctx)) < 0)
+        return ret;
+
+    ctx->my_channel_layout = avctx->channel_layout;
+
+    ctx->ch_units = av_mallocz(sizeof(*ctx->ch_units) *
+                               ctx->num_channel_blocks);
+    if (!ctx->ch_units) {
+        atrac3p_decode_close(avctx);
+        return AVERROR(ENOMEM);
+    }
+
+    for (i = 0; i < ctx->num_channel_blocks; i++) {
+        for (ch = 0; ch < 2; ch++) {
+            ctx->ch_units[i].channels[ch].ch_num          = ch;
+            ctx->ch_units[i].channels[ch].wnd_shape       = &ctx->ch_units[i].channels[ch].wnd_shape_hist[0][0];
+            ctx->ch_units[i].channels[ch].wnd_shape_prev  = &ctx->ch_units[i].channels[ch].wnd_shape_hist[1][0];
+            ctx->ch_units[i].channels[ch].gain_data       = &ctx->ch_units[i].channels[ch].gain_data_hist[0][0];
+            ctx->ch_units[i].channels[ch].gain_data_prev  = &ctx->ch_units[i].channels[ch].gain_data_hist[1][0];
+            ctx->ch_units[i].channels[ch].tones_info      = &ctx->ch_units[i].channels[ch].tones_info_hist[0][0];
+            ctx->ch_units[i].channels[ch].tones_info_prev = &ctx->ch_units[i].channels[ch].tones_info_hist[1][0];
+        }
+
+        ctx->ch_units[i].waves_info      = &ctx->ch_units[i].wave_synth_hist[0];
+        ctx->ch_units[i].waves_info_prev = &ctx->ch_units[i].wave_synth_hist[1];
+    }
+
+    avctx->sample_fmt = AV_SAMPLE_FMT_FLTP;
+
+    return 0;
+}
+
+static void decode_residual_spectrum(Atrac3pChanUnitCtx *ctx,
+                                     float out[2][ATRAC3P_FRAME_SAMPLES],
+                                     int num_channels,
+                                     AVCodecContext *avctx)
+{
+    int i, sb, ch, qu, nspeclines, RNG_index;
+    float *dst, q;
+    int16_t *src;
+    /* calculate RNG table index for each subband */
+    int sb_RNG_index[ATRAC3P_SUBBANDS] = { 0 };
+
+    if (ctx->mute_flag) {
+        for (ch = 0; ch < num_channels; ch++)
+            memset(out[ch], 0, ATRAC3P_FRAME_SAMPLES * sizeof(*out[ch]));
+        return;
+    }
+
+    for (qu = 0, RNG_index = 0; qu < ctx->used_quant_units; qu++)
+        RNG_index += ctx->channels[0].qu_sf_idx[qu] +
+                     ctx->channels[1].qu_sf_idx[qu];
+
+    for (sb = 0; sb < ctx->num_coded_subbands; sb++, RNG_index += 128)
+        sb_RNG_index[sb] = RNG_index & 0x3FC;
+
+    /* inverse quant and power compensation */
+    for (ch = 0; ch < num_channels; ch++) {
+        /* clear channel's residual spectrum */
+        memset(out[ch], 0, ATRAC3P_FRAME_SAMPLES * sizeof(*out[ch]));
+
+        for (qu = 0; qu < ctx->used_quant_units; qu++) {
+            src        = &ctx->channels[ch].spectrum[ff_atrac3p_qu_to_spec_pos[qu]];
+            dst        = &out[ch][ff_atrac3p_qu_to_spec_pos[qu]];
+            nspeclines = ff_atrac3p_qu_to_spec_pos[qu + 1] -
+                         ff_atrac3p_qu_to_spec_pos[qu];
+
+            if (ctx->channels[ch].qu_wordlen[qu] > 0) {
+                q = ff_atrac3p_sf_tab[ctx->channels[ch].qu_sf_idx[qu]] *
+                    ff_atrac3p_mant_tab[ctx->channels[ch].qu_wordlen[qu]];
+                for (i = 0; i < nspeclines; i++)
+                    dst[i] = src[i] * q;
+            }
+        }
+
+        for (sb = 0; sb < ctx->num_coded_subbands; sb++)
+            ff_atrac3p_power_compensation(ctx, ch, &out[ch][0],
+                                          sb_RNG_index[sb], sb);
+    }
+
+    if (ctx->unit_type == CH_UNIT_STEREO) {
+        for (sb = 0; sb < ctx->num_coded_subbands; sb++) {
+            if (ctx->swap_channels[sb]) {
+                for (i = 0; i < ATRAC3P_SUBBAND_SAMPLES; i++)
+                    FFSWAP(float, out[0][sb * ATRAC3P_SUBBAND_SAMPLES + i],
+                                  out[1][sb * ATRAC3P_SUBBAND_SAMPLES + i]);
+            }
+
+            /* flip coefficients' sign if requested */
+            if (ctx->negate_coeffs[sb])
+                for (i = 0; i < ATRAC3P_SUBBAND_SAMPLES; i++)
+                    out[1][sb * ATRAC3P_SUBBAND_SAMPLES + i] = -(out[1][sb * ATRAC3P_SUBBAND_SAMPLES + i]);
+        }
+    }
+}
+
+static void reconstruct_frame(ATRAC3PContext *ctx, Atrac3pChanUnitCtx *ch_unit,
+                              int num_channels, AVCodecContext *avctx)
+{
+    int ch, sb;
+
+    for (ch = 0; ch < num_channels; ch++) {
+        for (sb = 0; sb < ch_unit->num_subbands; sb++) {
+            /* inverse transform and windowing */
+            ff_atrac3p_imdct(&ctx->fdsp, &ctx->mdct_ctx,
+                             &ctx->samples[ch][sb * ATRAC3P_SUBBAND_SAMPLES],
+                             &ctx->mdct_buf[ch][sb * ATRAC3P_SUBBAND_SAMPLES],
+                             (ch_unit->channels[ch].wnd_shape_prev[sb] << 1) +
+                             ch_unit->channels[ch].wnd_shape[sb], sb);
+
+            /* gain compensation and overlapping */
+            ff_atrac_gain_compensation(&ctx->gainc_ctx,
+                                       &ctx->mdct_buf[ch][sb * ATRAC3P_SUBBAND_SAMPLES],
+                                       &ch_unit->prev_buf[ch][sb * ATRAC3P_SUBBAND_SAMPLES],
+                                       &ch_unit->channels[ch].gain_data_prev[sb],
+                                       &ch_unit->channels[ch].gain_data[sb],
+                                       ATRAC3P_SUBBAND_SAMPLES,
+                                       &ctx->time_buf[ch][sb * ATRAC3P_SUBBAND_SAMPLES]);
+        }
+
+        /* zero unused subbands in both output and overlapping buffers */
+        memset(&ch_unit->prev_buf[ch][ch_unit->num_subbands * ATRAC3P_SUBBAND_SAMPLES],
+               0,
+               (ATRAC3P_SUBBANDS - ch_unit->num_subbands) *
+               ATRAC3P_SUBBAND_SAMPLES *
+               sizeof(ch_unit->prev_buf[ch][ch_unit->num_subbands * ATRAC3P_SUBBAND_SAMPLES]));
+        memset(&ctx->time_buf[ch][ch_unit->num_subbands * ATRAC3P_SUBBAND_SAMPLES],
+               0,
+               (ATRAC3P_SUBBANDS - ch_unit->num_subbands) *
+               ATRAC3P_SUBBAND_SAMPLES *
+               sizeof(ctx->time_buf[ch][ch_unit->num_subbands * ATRAC3P_SUBBAND_SAMPLES]));
+
+        /* resynthesize and add tonal signal */
+        if (ch_unit->waves_info->tones_present ||
+            ch_unit->waves_info_prev->tones_present) {
+            for (sb = 0; sb < ch_unit->num_subbands; sb++)
+                if (ch_unit->channels[ch].tones_info[sb].num_wavs ||
+                    ch_unit->channels[ch].tones_info_prev[sb].num_wavs) {
+                    ff_atrac3p_generate_tones(ch_unit, &ctx->fdsp, ch, sb,
+                                              &ctx->time_buf[ch][sb * 128]);
+                }
+        }
+
+        /* subband synthesis and acoustic signal output */
+        ff_atrac3p_ipqf(&ctx->ipqf_dct_ctx, &ch_unit->ipqf_ctx[ch],
+                        &ctx->time_buf[ch][0], &ctx->outp_buf[ch][0]);
+    }
+
+    /* swap window shape and gain control buffers. */
+    for (ch = 0; ch < num_channels; ch++) {
+        FFSWAP(uint8_t *, ch_unit->channels[ch].wnd_shape,
+               ch_unit->channels[ch].wnd_shape_prev);
+        FFSWAP(AtracGainInfo *, ch_unit->channels[ch].gain_data,
+               ch_unit->channels[ch].gain_data_prev);
+        FFSWAP(Atrac3pWavesData *, ch_unit->channels[ch].tones_info,
+               ch_unit->channels[ch].tones_info_prev);
+    }
+
+    FFSWAP(Atrac3pWaveSynthParams *, ch_unit->waves_info, ch_unit->waves_info_prev);
+}
+
+static int atrac3p_decode_frame(AVCodecContext *avctx, void *data,
+                                int *got_frame_ptr, AVPacket *avpkt)
+{
+    ATRAC3PContext *ctx = avctx->priv_data;
+    AVFrame *frame      = data;
+    int i, ret, ch_unit_id, ch_block = 0, out_ch_index = 0, channels_to_process;
+    float **samples_p = (float **)frame->extended_data;
+
+    frame->nb_samples = ATRAC3P_FRAME_SAMPLES;
+    if ((ret = ff_get_buffer(avctx, frame, 0)) < 0) {
+        av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
+        return ret;
+    }
+
+    if ((ret = init_get_bits8(&ctx->gb, avpkt->data, avpkt->size)) < 0)
+        return ret;
+
+    if (get_bits1(&ctx->gb)) {
+        av_log(avctx, AV_LOG_ERROR, "Invalid start bit!\n");
+        return AVERROR_INVALIDDATA;
+    }
+
+    while (get_bits_left(&ctx->gb) >= 2 &&
+           (ch_unit_id = get_bits(&ctx->gb, 2)) != CH_UNIT_TERMINATOR) {
+        if (ch_unit_id == CH_UNIT_EXTENSION) {
+            avpriv_report_missing_feature(avctx, "Channel unit extension");
+            return AVERROR_PATCHWELCOME;
+        }
+        if (ch_block >= ctx->num_channel_blocks ||
+            ctx->channel_blocks[ch_block] != ch_unit_id) {
+            av_log(avctx, AV_LOG_ERROR,
+                   "Frame data doesn't match channel configuration!\n");
+            return AVERROR_INVALIDDATA;
+        }
+
+        ctx->ch_units[ch_block].unit_type = ch_unit_id;
+        channels_to_process               = ch_unit_id + 1;
+
+        if ((ret = ff_atrac3p_decode_channel_unit(&ctx->gb,
+                                                  &ctx->ch_units[ch_block],
+                                                  channels_to_process,
+                                                  avctx)) < 0)
+            return ret;
+
+        decode_residual_spectrum(&ctx->ch_units[ch_block], ctx->samples,
+                                 channels_to_process, avctx);
+        reconstruct_frame(ctx, &ctx->ch_units[ch_block],
+                          channels_to_process, avctx);
+
+        for (i = 0; i < channels_to_process; i++)
+            memcpy(samples_p[out_ch_index + i], ctx->outp_buf[i],
+                   ATRAC3P_FRAME_SAMPLES * sizeof(**samples_p));
+
+        ch_block++;
+        out_ch_index += channels_to_process;
+    }
+
+    *got_frame_ptr = 1;
+
+    return avctx->block_align;
+}
+
+AVCodec ff_atrac3p_decoder = {
+    .name             = "atrac3plus",
+    .long_name        = NULL_IF_CONFIG_SMALL("ATRAC3+ (Adaptive TRansform Acoustic Coding 3+)"),
+    .type             = AVMEDIA_TYPE_AUDIO,
+    .id               = AV_CODEC_ID_ATRAC3P,
+    .priv_data_size   = sizeof(ATRAC3PContext),
+    .init             = atrac3p_decode_init,
+    .init_static_data = ff_atrac3p_init_vlcs,
+    .close            = atrac3p_decode_close,
+    .decode           = atrac3p_decode_frame,
+};
diff --git a/libavcodec/atrac3plusdsp.c b/libavcodec/atrac3plusdsp.c
new file mode 100644
index 0000000..468f098
--- /dev/null
+++ b/libavcodec/atrac3plusdsp.c
@@ -0,0 +1,638 @@
+/*
+ * ATRAC3+ compatible decoder
+ *
+ * Copyright (c) 2010-2013 Maxim Poliakovski
+ *
+ * This file is part of Libav.
+ *
+ * Libav 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.
+ *
+ * Libav 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 Libav; 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.
+ */
+
+#include <math.h>
+
+#include "libavutil/float_dsp.h"
+#include "avcodec.h"
+#include "sinewin.h"
+#include "fft.h"
+#include "atrac3plus.h"
+
+/**
+ *  Map quant unit number to its position in the spectrum.
+ *  To get the number of spectral lines in each quant unit do the following:
+ *  num_specs = qu_to_spec_pos[i+1] - qu_to_spec_pos[i]
+ */
+const uint16_t ff_atrac3p_qu_to_spec_pos[33] = {
+      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
+};
+
+/* Scalefactors table. */
+/* Approx. Equ: pow(2.0, (i - 16.0 + 0.501783948) / 3.0) */
+const float ff_atrac3p_sf_tab[64] = {
+    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
+};
+
+/* Mantissa table. */
+/* pow(10, x * log10(2) + 0.05) / 2 / ([1,2,3,5,7,15,31] + 0.5) */
+const float ff_atrac3p_mant_tab[8] = {
+    0.0,
+    0.74801636,
+    0.44882202,
+    0.32058716,
+    0.20400238,
+    0.1496048,
+    0.07239151,
+    0.035619736
+};
+
+#define ATRAC3P_MDCT_SIZE (ATRAC3P_SUBBAND_SAMPLES * 2)
+
+av_cold void ff_atrac3p_init_imdct(AVCodecContext *avctx, FFTContext *mdct_ctx)
+{
+    ff_init_ff_sine_windows(7);
+    ff_init_ff_sine_windows(6);
+
+    /* Initialize the MDCT transform. */
+    ff_mdct_init(mdct_ctx, 8, 1, -1.0);
+}
+
+#define TWOPI (2 * M_PI)
+
+#define DEQUANT_PHASE(ph) (((ph) & 0x1F) << 6)
+
+static DECLARE_ALIGNED(32, float, sine_table)[2048]; ///< wave table
+static DECLARE_ALIGNED(32, float, hann_window)[256]; ///< Hann windowing function
+static float amp_sf_tab[64];   ///< scalefactors for quantized amplitudes
+
+av_cold void ff_atrac3p_init_wave_synth(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] = pow(2.0f, ((double)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]    phase_shift   flag indicates 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 phase_shift, 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;
+        }
+    }
+
+    /* 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, AVFloatDSPContext *fdsp,
+                               int ch_num, int sb, float *out)
+{
+    DECLARE_ALIGNED(32, float, wavreg1)[128] = { 0 };
+    DECLARE_ALIGNED(32, 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->phase_shift[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->phase_shift[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) {
+        fdsp->vector_fmul(wavreg1, wavreg1, &hann_window[128], 128);
+        fdsp->vector_fmul(wavreg2, wavreg2,  hann_window,      128);
+    } else {
+        if (tones_now->num_wavs && !tones_now->curr_env.has_stop_point)
+            fdsp->vector_fmul(wavreg1, wavreg1, &hann_window[128], 128);
+
+        if (tones_next->num_wavs && !tones_next->curr_env.has_start_point)
+            fdsp->vector_fmul(wavreg2, wavreg2, hann_window, 128);
+    }
+
+    /* Overlap and add to residual */
+    for (i = 0; i < 128; i++)
+        out[i] += wavreg1[i] + wavreg2[i];
+}
+
+static const int subband_to_powgrp[ATRAC3P_SUBBANDS] = {
+    0, 1, 1, 2, 2, 2, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4
+};
+
+/* noise table for power compensation */
+static const float noise_tab[1024] = {
+    -0.01358032,  -0.05593872,   0.01696777,  -0.14871216,  -0.26412964,  -0.09893799,   0.25723267,
+     0.02008057,  -0.72235107,  -0.44351196,  -0.22985840,   0.16833496,   0.46902466,   0.05917358,
+    -0.15179443,   0.41299438,  -0.01287842,   0.13360596,   0.43557739,  -0.09530640,  -0.58422852,
+     0.39266968,  -0.08343506,  -0.25604248,   0.22848511,   0.26013184,  -0.65588379,   0.17288208,
+    -0.08673096,  -0.05203247,   0.07299805,  -0.28665161,  -0.35806274,   0.06552124,  -0.09387207,
+     0.21099854,  -0.28347778,  -0.72402954,   0.05050659,  -0.10635376,  -0.18853760,   0.29724121,
+     0.20703125,  -0.29791260,  -0.37634277,   0.47970581,  -0.09976196,   0.32641602,  -0.29248047,
+    -0.28237915,   0.26028442,  -0.36157227,   0.22042847,  -0.03222656,  -0.37268066,  -0.03759766,
+     0.09909058,   0.23284912,   0.19320679,   0.14453125,  -0.02139282,  -0.19702148,   0.31533813,
+    -0.16741943,   0.35031128,  -0.35656738,  -0.66128540,  -0.00701904,   0.20898438,   0.26837158,
+    -0.33706665,  -0.04568481,   0.12600708,   0.10284424,   0.07321167,  -0.18280029,   0.38101196,
+     0.21301270,   0.04541016,   0.01156616,  -0.26391602,  -0.02346802,  -0.22125244,   0.29760742,
+    -0.36233521,  -0.31314087,  -0.13967896,  -0.11276245,  -0.19433594,   0.34490967,   0.02343750,
+     0.21963501,  -0.02777100,  -0.67678833,  -0.08999634,   0.14233398,  -0.27697754,   0.51422119,
+    -0.05047607,   0.48327637,   0.37167358,  -0.60806274,   0.18728638,  -0.15191650,   0.00637817,
+     0.02832031,  -0.15618896,   0.60644531,   0.21826172,   0.06384277,  -0.31863403,   0.08816528,
+     0.15447998,  -0.07015991,  -0.08154297,  -0.40966797,  -0.39785767,  -0.11709595,   0.22052002,
+     0.18466187,  -0.17257690,   0.03759766,  -0.06195068,   0.00433350,   0.12176514,   0.34011841,
+     0.25610352,  -0.05294800,   0.41033936,   0.16854858,  -0.76187134,   0.13845825,  -0.19418335,
+    -0.21524048,  -0.44412231,  -0.08160400,  -0.28195190,  -0.01873779,   0.15524292,  -0.37438965,
+    -0.44860840,   0.43096924,  -0.24746704,   0.49856567,   0.14859009,   0.38159180,   0.20541382,
+    -0.39175415,  -0.65850830,  -0.43716431,   0.13037109,  -0.05111694,   0.39956665,   0.21447754,
+    -0.04861450,   0.33654785,   0.10589600,  -0.88085938,  -0.30822754,   0.38577271,   0.30047607,
+     0.38836670,   0.09118652,  -0.36477661,  -0.01641846,  -0.23031616,   0.26058960,   0.18859863,
+    -0.21868896,  -0.17861938,  -0.29754639,   0.09777832,   0.10806274,  -0.51605225,   0.00076294,
+     0.13259888,   0.11090088,  -0.24084473,   0.24957275,   0.01379395,  -0.04141235,  -0.04937744,
+     0.57394409,   0.27410889,   0.27587891,   0.45013428,  -0.32592773,   0.11160278,  -0.00970459,
+     0.29092407,   0.03356934,  -0.70925903,   0.04882812,   0.43499756,   0.07720947,  -0.27554321,
+    -0.01742554,  -0.08413696,  -0.04028320,  -0.52850342,  -0.07330322,   0.05181885,   0.21362305,
+    -0.18765259,   0.07058716,  -0.03009033,   0.32662964,   0.27023315,  -0.28002930,   0.17568970,
+     0.03338623,   0.30242920,  -0.03921509,   0.32174683,  -0.23733521,   0.08575439,  -0.38269043,
+     0.09194946,  -0.07238770,   0.17941284,  -0.51278687,  -0.25146484,   0.19790649,  -0.19195557,
+     0.16549683,   0.42456055,   0.39129639,  -0.02868652,   0.17980957,   0.24902344,  -0.76583862,
+    -0.20959473,   0.61013794,   0.37011719,   0.36859131,  -0.04486084,   0.10678101,  -0.15994263,
+    -0.05328369,   0.28463745,  -0.06420898,  -0.36987305,  -0.28009033,  -0.11764526,   0.04312134,
+    -0.08038330,   0.04885864,  -0.03067017,  -0.00042725,   0.34289551,  -0.00988770,   0.34838867,
+     0.32516479,  -0.16271973,   0.38269043,   0.03240967,   0.12417603,  -0.14331055,  -0.34902954,
+    -0.18325806,   0.29421997,   0.44284058,   0.75170898,  -0.67245483,  -0.12176514,   0.27914429,
+    -0.29806519,   0.19863892,   0.30087280,   0.22680664,  -0.36633301,  -0.32534790,  -0.57553101,
+    -0.16641235,   0.43811035,   0.08331299,   0.15942383,   0.26516724,  -0.24240112,  -0.11761475,
+    -0.16827393,  -0.14260864,   0.46343994,   0.11804199,  -0.55514526,  -0.02520752,  -0.14309692,
+     0.00448608,   0.02749634,  -0.30545044,   0.70965576,   0.45108032,   0.66439819,  -0.68255615,
+    -0.12496948,   0.09146118,  -0.21109009,  -0.23791504,   0.79943848,  -0.35205078,  -0.24963379,
+     0.18719482,  -0.19079590,   0.07458496,   0.07623291,  -0.28781128,  -0.37121582,  -0.19580078,
+    -0.01773071,  -0.16717529,   0.13040161,   0.14672852,   0.42379761,   0.03582764,   0.11431885,
+     0.05145264,   0.44702148,   0.08963013,   0.01367188,  -0.54519653,  -0.12692261,   0.21176147,
+     0.04925537,   0.30670166,  -0.11029053,   0.19555664,  -0.27740479,   0.23043823,   0.15554810,
+    -0.19299316,  -0.25729370,   0.17800903,  -0.03579712,  -0.05065918,  -0.06933594,  -0.09500122,
+    -0.07821655,   0.23889160,  -0.31900024,   0.03073120,  -0.00415039,   0.61315918,   0.37176514,
+    -0.13442993,  -0.15536499,  -0.19216919,  -0.37899780,   0.19992065,   0.02630615,  -0.12573242,
+     0.25927734,  -0.02447510,   0.29629517,  -0.40731812,  -0.17333984,   0.24310303,  -0.10607910,
+     0.14828491,   0.08792114,  -0.18743896,  -0.05572510,  -0.04833984,   0.10473633,  -0.29028320,
+    -0.67687988,  -0.28170776,  -0.41687012,   0.05413818,  -0.23284912,   0.09555054,  -0.08969116,
+    -0.15112305,   0.12738037,   0.35986328,   0.28948975,   0.30691528,   0.23956299,   0.06973267,
+    -0.31198120,  -0.18450928,   0.22280884,  -0.21600342,   0.23522949,  -0.61840820,  -0.13012695,
+     0.26412964,   0.47320557,  -0.26440430,   0.38757324,   0.17352295,  -0.26104736,  -0.25866699,
+    -0.12274170,  -0.29733276,   0.07687378,   0.18588257,  -0.08880615,   0.31185913,   0.05313110,
+    -0.10885620,  -0.14901733,  -0.22323608,  -0.08538818,   0.19812012,   0.19732666,  -0.18927002,
+     0.29058838,   0.25555420,  -0.48599243,   0.18768311,   0.01345825,   0.34887695,   0.21530151,
+     0.19857788,   0.18661499,  -0.01394653,  -0.09063721,  -0.38781738,   0.27160645,  -0.20379639,
+    -0.32119751,  -0.23889160,   0.27096558,   0.24951172,   0.07922363,   0.07479858,  -0.50946045,
+     0.10220337,   0.58364868,  -0.19503784,  -0.18560791,  -0.01165771,   0.47195435,   0.22430420,
+    -0.38635254,  -0.03732300,  -0.09179688,   0.06991577,   0.15106201,   0.20605469,  -0.05969238,
+    -0.41821289,   0.12231445,  -0.04672241,  -0.05117798,  -0.11523438,  -0.51849365,  -0.04077148,
+     0.44284058,  -0.64086914,   0.17019653,   0.02236938,   0.22848511,  -0.23214722,  -0.32354736,
+    -0.14068604,  -0.29690552,  -0.19891357,   0.02774048,  -0.20965576,  -0.52191162,  -0.19299316,
+    -0.07290649,   0.49053955,  -0.22302246,   0.05642700,   0.13122559,  -0.20819092,  -0.83590698,
+    -0.08181763,   0.26797485,  -0.00091553,  -0.09457397,   0.17089844,  -0.27020264,   0.30270386,
+     0.05496216,   0.09564209,  -0.08590698,   0.02130127,   0.35931396,   0.21728516,  -0.15396118,
+    -0.05053711,   0.02719116,   0.16302490,   0.43212891,   0.10229492,  -0.40820312,   0.21646118,
+     0.08435059,  -0.11145020,  -0.39962769,  -0.05618286,  -0.10223389,  -0.60839844,   0.33724976,
+    -0.06341553,  -0.47369385,  -0.32852173,   0.05242920,   0.19635010,  -0.19137573,  -0.67901611,
+     0.16180420,   0.05133057,  -0.22283936,   0.09646606,   0.24288940,  -0.45007324,   0.08804321,
+     0.14053345,   0.22619629,  -0.01000977,   0.36355591,  -0.19863892,  -0.30364990,  -0.24118042,
+    -0.57461548,   0.26498413,   0.04345703,  -0.09796143,  -0.47714233,  -0.23739624,   0.18737793,
+     0.08926392,  -0.02795410,   0.00305176,  -0.08700562,  -0.38711548,   0.03222656,   0.10940552,
+    -0.41906738,  -0.01620483,  -0.47061157,   0.37985229,  -0.21624756,   0.47976685,  -0.20046997,
+    -0.62533569,  -0.26907349,  -0.02877808,   0.00671387,  -0.29071045,  -0.24685669,  -0.15722656,
+    -0.26055908,   0.29968262,   0.28225708,  -0.08990479,  -0.16748047,  -0.46759033,  -0.25067139,
+    -0.25183105,  -0.45932007,   0.05828857,   0.29006958,   0.23840332,  -0.17974854,   0.26931763,
+     0.10696411,  -0.06848145,  -0.17126465,  -0.10522461,  -0.55386353,  -0.42306519,  -0.07608032,
+     0.24380493,   0.38586426,   0.16882324,   0.26751709,   0.17303467,   0.35809326,  -0.22094727,
+    -0.30703735,  -0.28497314,  -0.04321289,   0.15219116,  -0.17071533,  -0.39334106,   0.03439331,
+    -0.10809326,  -0.30590820,   0.26449585,  -0.07412720,   0.13638306,  -0.01062012,   0.27996826,
+     0.04397583,  -0.05557251,  -0.56933594,   0.03363037,  -0.00949097,   0.52642822,  -0.44329834,
+     0.28308105,  -0.05499268,  -0.23312378,  -0.29870605,  -0.05123901,   0.26831055,  -0.35238647,
+    -0.30993652,   0.34646606,  -0.19775391,   0.44595337,   0.13769531,   0.45358276,   0.19961548,
+     0.42681885,   0.15722656,   0.00128174,   0.23757935,   0.40988159,   0.25164795,  -0.00732422,
+    -0.12405396,  -0.43420410,  -0.00402832,   0.34243774,   0.36264038,   0.18807983,  -0.09301758,
+    -0.10296631,   0.05532837,  -0.31652832,   0.14337158,   0.35040283,   0.32540894,   0.05728149,
+    -0.12030029,  -0.25942993,  -0.20312500,  -0.16491699,  -0.46051025,  -0.08004761,   0.50772095,
+     0.16168213,   0.28439331,   0.08105469,  -0.19104004,   0.38589478,  -0.16400146,  -0.25454712,
+     0.20281982,  -0.20730591,  -0.06311035,   0.32937622,   0.15032959,  -0.05340576,   0.30487061,
+    -0.11648560,   0.38009644,  -0.20062256,   0.43466187,   0.01150513,   0.35754395,  -0.13146973,
+     0.67489624,   0.05212402,   0.27914429,  -0.39431763,   0.75308228,  -0.13366699,   0.24453735,
+     0.42248535,  -0.65905762,  -0.00546265,  -0.03491211,  -0.13659668,  -0.08294678,  -0.45666504,
+     0.27188110,   0.12731934,   0.61148071,   0.10449219,  -0.28836060,   0.00091553,   0.24618530,
+     0.13119507,   0.05685425,   0.17355347,   0.42034912,   0.08514404,   0.24536133,   0.18951416,
+    -0.19107056,  -0.15036011,   0.02334595,   0.54986572,   0.32321167,  -0.16104126,  -0.03054810,
+     0.43594360,   0.17309570,   0.61053467,   0.24731445,   0.33334351,   0.15240479,   0.15588379,
+     0.36425781,  -0.30407715,  -0.13302612,   0.00427246,   0.04171753,  -0.33178711,   0.34216309,
+    -0.12463379,  -0.02764893,   0.05905151,  -0.31436157,   0.16531372,   0.34542847,  -0.03292847,
+     0.12527466,  -0.12313843,  -0.13171387,   0.04757690,  -0.45095825,  -0.19085693,   0.35342407,
+    -0.23239136,  -0.34387207,   0.11264038,  -0.15740967,   0.05273438,   0.74942017,   0.21505737,
+     0.08514404,  -0.42391968,  -0.19531250,   0.35293579,   0.25305176,   0.15731812,  -0.70324707,
+    -0.21591187,   0.35604858,   0.14132690,   0.11724854,   0.15853882,  -0.24597168,   0.07019043,
+     0.02127075,   0.12658691,   0.06390381,  -0.12292480,   0.15441895,  -0.47640991,   0.06195068,
+     0.58981323,  -0.15151978,  -0.03604126,  -0.45059204,  -0.01672363,  -0.46997070,   0.25750732,
+     0.18084717,   0.06661987,   0.13253784,   0.67828369,   0.11370850,   0.11325073,  -0.04611206,
+    -0.07791138,  -0.36544800,  -0.06747437,  -0.31594849,   0.16131592,   0.41983032,   0.11071777,
+    -0.36889648,   0.30963135,  -0.37875366,   0.58508301,   0.00393677,   0.12338257,   0.03424072,
+    -0.21728516,  -0.12838745,  -0.46981812,   0.05868530,  -0.25015259,   0.27407837,   0.65240479,
+    -0.34429932,  -0.15179443,   0.14056396,   0.33505249,   0.28826904,   0.09921265,   0.34390259,
+     0.13656616,  -0.23608398,   0.00863647,   0.02627563,  -0.19119263,   0.19775391,  -0.07214355,
+     0.07809448,   0.03454590,  -0.03417969,   0.00033569,  -0.23095703,   0.18673706,   0.05798340,
+     0.03814697,  -0.04318237,   0.05487061,   0.08633423,   0.55950928,  -0.06347656,   0.10333252,
+     0.25305176,   0.05853271,   0.12246704,  -0.25543213,  -0.34262085,  -0.36437988,  -0.21304321,
+    -0.05093384,   0.02777100,   0.07620239,  -0.21215820,  -0.09326172,   0.19021606,  -0.40579224,
+    -0.01193237,   0.19845581,  -0.35336304,  -0.07397461,   0.20104980,   0.08615112,  -0.44375610,
+     0.11419678,   0.24453735,  -0.16555786,  -0.05081177,  -0.01406860,   0.27893066,  -0.18692017,
+     0.07473755,   0.03451538,  -0.39733887,   0.21548462,  -0.22534180,  -0.39651489,  -0.04989624,
+    -0.57662964,   0.06390381,   0.62020874,  -0.13470459,   0.04345703,  -0.21862793,  -0.02789307,
+     0.51696777,  -0.27587891,   0.39004517,   0.09857178,  -0.00738525,   0.31317139,   0.00048828,
+    -0.46572876,   0.29531860,  -0.10009766,  -0.27856445,   0.03594971,   0.25048828,  -0.74584961,
+    -0.25350952,  -0.03302002,   0.31188965,   0.01571655,   0.46710205,   0.21591187,   0.07260132,
+    -0.42132568,  -0.53900146,  -0.13674927,  -0.16571045,  -0.34454346,   0.12359619,  -0.11184692,
+     0.00967407,   0.34576416,  -0.05761719,   0.34848022,   0.17645264,  -0.39395142,   0.10339355,
+     0.18215942,   0.20697021,   0.59109497,  -0.11560059,  -0.07385254,   0.10397339,   0.35437012,
+    -0.22863770,   0.01794434,   0.17559814,  -0.17495728,   0.12142944,   0.10928345,  -1.00000000,
+    -0.01379395,   0.21237183,  -0.27035522,   0.27319336,  -0.37066650,   0.41354370,  -0.40054321,
+     0.00689697,   0.26321411,   0.39266968,   0.65298462,   0.41625977,  -0.13909912,   0.78375244,
+    -0.30941772,   0.20169067,  -0.39367676,   0.94021606,  -0.24066162,   0.05557251,  -0.24533081,
+    -0.05444336,  -0.76754761,  -0.19375610,  -0.11041260,  -0.17532349,   0.16006470,   0.02188110,
+     0.17465210,  -0.04342651,  -0.56777954,  -0.40988159,   0.26687622,   0.11700439,  -0.00344849,
+    -0.05395508,   0.37426758,  -0.40719604,  -0.15032959,  -0.01660156,   0.04196167,  -0.04559326,
+    -0.12969971,   0.12011719,   0.08419800,  -0.11199951,   0.35174561,   0.10275269,  -0.25686646,
+     0.48446655,   0.03225708,   0.28408813,  -0.18701172,   0.36282349,  -0.03280640,   0.32302856,
+     0.17233276,   0.48269653,   0.31112671,  -0.04946899,   0.12774658,   0.52685547,   0.10211182,
+     0.05953979,   0.05999756,   0.20144653,   0.00744629,   0.27316284,   0.24377441,   0.39672852,
+     0.01702881,  -0.35513306,   0.11364746,  -0.13555908,   0.48880005,  -0.15417480,  -0.09149170,
+    -0.02615356,   0.46246338,  -0.72250366,   0.22332764,   0.23849487,  -0.25686646,  -0.08514404,
+    -0.02062988,  -0.34494019,  -0.02297974,  -0.80386353,  -0.08074951,  -0.12689209,  -0.06896973,
+     0.24099731,  -0.35650635,  -0.09558105,   0.29254150,   0.23132324,  -0.16726685,   0.00000000,
+    -0.24237061,   0.30899048,   0.29504395,  -0.20898438,   0.17059326,  -0.07672119,  -0.14395142,
+     0.05572510,   0.20602417,  -0.51550293,  -0.03167725,  -0.48840332,  -0.20425415,   0.14144897,
+     0.07275391,  -0.76669312,  -0.22488403,   0.20651245,   0.03259277,   0.00085449,   0.03039551,
+     0.47555542,   0.38351440
+};
+
+/** Noise level table for power compensation.
+ *  Equ: pow(2.0f, (double)(6 - i) / 3.0f) where i = 0...15 */
+static const float pwc_levs[16] = {
+    3.96875, 3.15625,     2.5,    2.0, 1.59375,   1.25,     1.0, 0.78125,
+    0.625,       0.5, 0.40625, 0.3125,    0.25, 0.1875, 0.15625, 0.0
+};
+
+/** Map subband number to quant unit number. */
+static const int subband_to_qu[17] = {
+    0, 8, 12, 16, 18, 20, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32
+};
+
+void ff_atrac3p_power_compensation(Atrac3pChanUnitCtx *ctx, int ch_index,
+                                   float *sp, int rng_index, int sb)
+{
+    AtracGainInfo *g1, *g2;
+    float pwcsp[ATRAC3P_SUBBAND_SAMPLES], *dst, grp_lev, qu_lev;
+    int i, gain_lev, gcv = 0, qu, nsp;
+    int swap_ch = (ctx->unit_type == CH_UNIT_STEREO && ctx->swap_channels[sb]) ? 1 : 0;
+
+    if (ctx->channels[ch_index ^ swap_ch].power_levs[subband_to_powgrp[sb]] == ATRAC3P_POWER_COMP_OFF)
+        return;
+
+    /* generate initial noise spectrum */
+    for (i = 0; i < ATRAC3P_SUBBAND_SAMPLES; i++, rng_index++)
+        pwcsp[i] = noise_tab[rng_index & 0x3FF];
+
+    /* check gain control information */
+    g1 = &ctx->channels[ch_index ^ swap_ch].gain_data[sb];
+    g2 = &ctx->channels[ch_index ^ swap_ch].gain_data_prev[sb];
+
+    gain_lev = (g1->num_points > 0) ? (6 - g1->lev_code[0]) : 0;
+
+    for (i = 0; i < g2->num_points; i++)
+        gcv = FFMAX(gcv, gain_lev - (g2->lev_code[i] - 6));
+
+    for (i = 0; i < g1->num_points; i++)
+        gcv = FFMAX(gcv, 6 - g1->lev_code[i]);
+
+    grp_lev = pwc_levs[ctx->channels[ch_index ^ swap_ch].power_levs[subband_to_powgrp[sb]]] / (1 << gcv);
+
+    /* skip the lowest two quant units (frequencies 0...351 Hz) for subband 0 */
+    for (qu = subband_to_qu[sb] + (!sb ? 2 : 0); qu < subband_to_qu[sb + 1]; qu++) {
+        if (ctx->channels[ch_index].qu_wordlen[qu] <= 0)
+            continue;
+
+        qu_lev = ff_atrac3p_sf_tab[ctx->channels[ch_index].qu_sf_idx[qu]] *
+                 ff_atrac3p_mant_tab[ctx->channels[ch_index].qu_wordlen[qu]] /
+                 (1 << ctx->channels[ch_index].qu_wordlen[qu]) * grp_lev;
+
+        dst = &sp[ff_atrac3p_qu_to_spec_pos[qu]];
+        nsp = ff_atrac3p_qu_to_spec_pos[qu + 1] - ff_atrac3p_qu_to_spec_pos[qu];
+
+        for (i = 0; i < nsp; i++)
+            dst[i] += pwcsp[i] * qu_lev;
+    }
+}
+
+void ff_atrac3p_imdct(AVFloatDSPContext *fdsp, FFTContext *mdct_ctx, float *pIn,
+                      float *pOut, int wind_id, int sb)
+{
+    int i;
+
+    if (sb & 1)
+        for (i = 0; i < ATRAC3P_SUBBAND_SAMPLES / 2; i++)
+            FFSWAP(float, pIn[i], pIn[ATRAC3P_SUBBAND_SAMPLES - 1 - i]);
+
+    mdct_ctx->imdct_calc(mdct_ctx, pOut, pIn);
+
+    /* Perform windowing on the output.
+     * ATRAC3+ uses two different MDCT windows:
+     * - The first one is just the plain sine window of size 256
+     * - The 2nd one is the plain sine window of size 128
+     *   wrapped into zero (at the start) and one (at the end) regions.
+     *   Both regions are 32 samples long. */
+    if (wind_id & 2) { /* 1st half: steep window */
+        memset(pOut, 0, sizeof(float) * 32);
+        fdsp->vector_fmul(&pOut[32], &pOut[32], ff_sine_64, 64);
+    } else /* 1st half: simple sine window */
+        fdsp->vector_fmul(pOut, pOut, ff_sine_128, ATRAC3P_MDCT_SIZE / 2);
+
+    if (wind_id & 1) { /* 2nd half: steep window */
+        fdsp->vector_fmul_reverse(&pOut[160], &pOut[160], ff_sine_64, 64);
+        memset(&pOut[224], 0, sizeof(float) * 32);
+    } else /* 2nd half: simple sine window */
+        fdsp->vector_fmul_reverse(&pOut[128], &pOut[128], ff_sine_128,
+                                  ATRAC3P_MDCT_SIZE / 2);
+}
+
+/* lookup table for fast modulo 23 op required for cyclic buffers of the IPQF */
+static const int mod23_lut[26] = {
+    23,  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11,
+    12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 0
+};
+
+/* First half of the 384-tap IPQF filtering coefficients. */
+static const float ipqf_coeffs1[ATRAC3P_PQF_FIR_LEN][16] = {
+    { -5.8336207e-7,    -8.0604229e-7,    -4.2005411e-7,    -4.4400572e-8,
+       3.226247e-8,      3.530856e-8,      1.2660377e-8,     0.000010516783,
+      -0.000011838618,   6.005389e-7,      0.0000014333754,  0.0000023108685,
+       0.0000032569742,  0.0000046192422,  0.0000063894258,  0.0000070302972 },
+    { -0.0000091622824, -0.000010502935,  -0.0000079212787, -0.0000041712024,
+      -0.0000026336629, -0.0000015432918, -5.7168614e-7,     0.0000018111954,
+       0.000023530851,   0.00002780562,    0.000032302323,   0.000036968919,
+       0.000041575615,   0.000045337845,   0.000046043948,   0.000048585582 },
+    { -0.000064464548,  -0.000068306952,  -0.000073081472,  -0.00007612785,
+      -0.000074850752,  -0.000070208509,  -0.000062285151,  -0.000058270442,
+      -0.000056296329,  -0.000049888811,  -0.000035615325,  -0.000018532943,
+       0.0000016657353,  0.00002610587,    0.000053397067,   0.00008079566 },
+    { -0.00054488552,   -0.00052537228,   -0.00049731287,   -0.00045778,
+      -0.00040612387,   -0.00034301577,   -0.00026866337,   -0.00018248901,
+      -0.000084307925,   0.000025081157,   0.00014135583,    0.00026649953,
+       0.00039945057,    0.00053928449,    0.00068422867,    0.00083093712 },
+    { -0.0014771431,    -0.001283227,     -0.0010566821,    -0.00079780724,
+      -0.00050782406,   -0.00018855913,    0.00015771533,    0.00052769453,
+       0.00091862219,    0.001326357,      0.0017469483,     0.0021754825,
+       0.0026067684,     0.0030352892,     0.0034549395,     0.0038591374 },
+    { -0.0022995141,    -0.001443546,     -0.00049266568,    0.00055068987,
+       0.001682895,      0.0028992873,     0.0041943151,     0.0055614738,
+       0.0069935122,     0.0084823566,     0.010018963,      0.011593862,
+       0.013196872,      0.014817309,      0.016444042,      0.018065533 },
+    { -0.034426283,     -0.034281436,     -0.033992987,     -0.033563249,
+      -0.032995768,     -0.032295227,     -0.031467363,     -0.030518902,
+      -0.02945766,      -0.028291954,     -0.027031265,     -0.025685543,
+      -0.024265358,     -0.022781773,     -0.021246184,     -0.019670162 },
+    { -0.0030586775,    -0.0037203205,    -0.0042847847,    -0.0047529764,
+      -0.0051268316,    -0.0054091476,    -0.0056034233,    -0.005714261,
+      -0.0057445862,    -0.0057025906,    -0.0055920109,    -0.0054194843,
+      -0.0051914565,    -0.0049146507,    -0.0045959447,    -0.0042418269 },
+    { -0.0016376863,    -0.0017651899,    -0.0018608454,    -0.0019252141,
+      -0.0019593791,    -0.0019653172,    -0.0019450618,    -0.0018990048,
+      -0.00183808,      -0.0017501717,    -0.0016481078,    -0.0015320742,
+      -0.0014046903,    -0.0012685474,    -0.001125814,     -0.00097943726 },
+    { -0.00055432378,   -0.00055472925,   -0.00054783461,   -0.00053276919,
+      -0.00051135791,   -0.00048466062,   -0.00045358928,   -0.00042499689,
+      -0.00036942671,   -0.0003392619,    -0.00030001783,   -0.00025986304,
+      -0.0002197204,    -0.00018116167,   -0.00014691355,   -0.00011279432 },
+    { -0.000064147389,  -0.00006174868,   -0.000054267788,  -0.000047133824,
+      -0.000042927582,  -0.000039477309,  -0.000036340745,  -0.000029687517,
+      -0.000049787737,  -0.000041577889,  -0.000033864744,  -0.000026534748,
+      -0.000019841305,  -0.000014789486,  -0.000013131184,  -0.0000099198869 },
+    { -0.0000062990207, -0.0000072701259, -0.000011984052,  -0.000017348082,
+      -0.000019907106,  -0.000021348773,  -0.000021961965,  -0.000012203576,
+      -0.000010840992,   4.6299544e-7,     5.2588763e-7,     2.7792686e-7,
+      -2.3649704e-7,    -0.0000010897784, -9.171448e-7,     -5.22682e-7 }
+};
+
+/* Second half of the 384-tap IPQF filtering coefficients. */
+static const float ipqf_coeffs2[ATRAC3P_PQF_FIR_LEN][16] = {
+    {  5.22682e-7,       9.171448e-7,      0.0000010897784,  2.3649704e-7,
+      -2.7792686e-7,    -5.2588763e-7,    -4.6299544e-7,     0.000010840992,
+      -0.000012203576,  -0.000021961965,  -0.000021348773,  -0.000019907106,
+      -0.000017348082,  -0.000011984052,  -0.0000072701259, -0.0000062990207 },
+    {  0.0000099198869,  0.000013131184,   0.000014789486,   0.000019841305,
+       0.000026534748,   0.000033864744,   0.000041577889,   0.000049787737,
+      -0.000029687517,  -0.000036340745,  -0.000039477309,  -0.000042927582,
+      -0.000047133824,  -0.000054267788,  -0.00006174868,   -0.000064147389 },
+    {  0.00011279432,    0.00014691355,    0.00018116167,    0.0002197204,
+       0.00025986304,    0.00030001783,    0.0003392619,     0.00036942671,
+      -0.00042499689,   -0.00045358928,   -0.00048466062,   -0.00051135791,
+      -0.00053276919,   -0.00054783461,   -0.00055472925,   -0.00055432378 },
+    {  0.00097943726,    0.001125814,      0.0012685474,     0.0014046903,
+       0.0015320742,     0.0016481078,     0.0017501717,     0.00183808,
+      -0.0018990048,    -0.0019450618,    -0.0019653172,    -0.0019593791,
+      -0.0019252141,    -0.0018608454,    -0.0017651899,    -0.0016376863 },
+    {  0.0042418269,     0.0045959447,     0.0049146507,     0.0051914565,
+       0.0054194843,     0.0055920109,     0.0057025906,     0.0057445862,
+      -0.005714261,     -0.0056034233,    -0.0054091476,    -0.0051268316,
+      -0.0047529764,    -0.0042847847,    -0.0037203205,    -0.0030586775 },
+    {  0.019670162,      0.021246184,      0.022781773,      0.024265358,
+       0.025685543,      0.027031265,      0.028291954,      0.02945766,
+      -0.030518902,     -0.031467363,     -0.032295227,     -0.032995768,
+      -0.033563249,     -0.033992987,     -0.034281436,     -0.034426283 },
+    { -0.018065533,     -0.016444042,     -0.014817309,     -0.013196872,
+      -0.011593862,     -0.010018963,     -0.0084823566,    -0.0069935122,
+       0.0055614738,     0.0041943151,     0.0028992873,     0.001682895,
+       0.00055068987,   -0.00049266568,   -0.001443546,     -0.0022995141 },
+    { -0.0038591374,    -0.0034549395,    -0.0030352892,    -0.0026067684,
+      -0.0021754825,    -0.0017469483,    -0.001326357,     -0.00091862219,
+       0.00052769453,    0.00015771533,   -0.00018855913,   -0.00050782406,
+      -0.00079780724,   -0.0010566821,    -0.001283227,     -0.0014771431 },
+    { -0.00083093712,   -0.00068422867,   -0.00053928449,   -0.00039945057,
+      -0.00026649953,   -0.00014135583,   -0.000025081157,   0.000084307925,
+      -0.00018248901,   -0.00026866337,   -0.00034301577,   -0.00040612387,
+      -0.00045778,      -0.00049731287,   -0.00052537228,   -0.00054488552 },
+    { -0.00008079566,   -0.000053397067,  -0.00002610587,   -0.0000016657353,
+       0.000018532943,   0.000035615325,   0.000049888811,   0.000056296329,
+      -0.000058270442,  -0.000062285151,  -0.000070208509,  -0.000074850752,
+      -0.00007612785,   -0.000073081472,  -0.000068306952,  -0.000064464548 },
+    { -0.000048585582,  -0.000046043948,  -0.000045337845,  -0.000041575615,
+      -0.000036968919,  -0.000032302323,  -0.00002780562,   -0.000023530851,
+       0.0000018111954, -5.7168614e-7,    -0.0000015432918, -0.0000026336629,
+      -0.0000041712024, -0.0000079212787, -0.000010502935,  -0.0000091622824 },
+    { -0.0000070302972, -0.0000063894258, -0.0000046192422, -0.0000032569742,
+      -0.0000023108685, -0.0000014333754, -6.005389e-7,      0.000011838618,
+       0.000010516783,   1.2660377e-8,     3.530856e-8,      3.226247e-8,
+      -4.4400572e-8,    -4.2005411e-7,    -8.0604229e-7,    -5.8336207e-7 }
+};
+
+void ff_atrac3p_ipqf(FFTContext *dct_ctx, Atrac3pIPQFChannelCtx *hist,
+                     const float *in, float *out)
+{
+    int i, s, sb, t, pos_now, pos_next;
+    DECLARE_ALIGNED(32, float, idct_in)[ATRAC3P_SUBBANDS];
+    DECLARE_ALIGNED(32, float, idct_out)[ATRAC3P_SUBBANDS];
+
+    memset(out, 0, ATRAC3P_FRAME_SAMPLES * sizeof(*out));
+
+    for (s = 0; s < ATRAC3P_SUBBAND_SAMPLES; s++) {
+        /* pick up one sample from each subband */
+        for (sb = 0; sb < ATRAC3P_SUBBANDS; sb++)
+            idct_in[sb] = in[sb * ATRAC3P_SUBBAND_SAMPLES + s];
+
+        /* Calculate the sine and cosine part of the PQF using IDCT-IV */
+        dct_ctx->imdct_half(dct_ctx, idct_out, idct_in);
+
+        /* append the result to the history */
+        for (i = 0; i < 8; i++) {
+            hist->buf1[hist->pos][i] = idct_out[i + 8];
+            hist->buf2[hist->pos][i] = idct_out[7 - i];
+        }
+
+        pos_now  = hist->pos;
+        pos_next = mod23_lut[pos_now + 2]; // pos_next = (pos_now + 1) % 23;
+
+        for (t = 0; t < ATRAC3P_PQF_FIR_LEN; t++) {
+            for (i = 0; i < 8; i++) {
+                out[s * 16 + i + 0] += hist->buf1[pos_now][i]  * ipqf_coeffs1[t][i] +
+                                       hist->buf2[pos_next][i] * ipqf_coeffs2[t][i];
+                out[s * 16 + i + 8] += hist->buf1[pos_now][7 - i]  * ipqf_coeffs1[t][i + 8] +
+                                       hist->buf2[pos_next][7 - i] * ipqf_coeffs2[t][i + 8];
+            }
+
+            pos_now  = mod23_lut[pos_next + 2]; // pos_now  = (pos_now  + 2) % 23;
+            pos_next = mod23_lut[pos_now + 2];  // pos_next = (pos_next + 2) % 23;
+        }
+
+        hist->pos = mod23_lut[hist->pos]; // hist->pos = (hist->pos - 1) % 23;
+    }
+}
diff --git a/libavcodec/version.h b/libavcodec/version.h
index 73c786d..2aee76e 100644
--- a/libavcodec/version.h
+++ b/libavcodec/version.h
@@ -29,7 +29,7 @@
 #include "libavutil/version.h"
 
 #define LIBAVCODEC_VERSION_MAJOR 55
-#define LIBAVCODEC_VERSION_MINOR 31
+#define LIBAVCODEC_VERSION_MINOR 32
 #define LIBAVCODEC_VERSION_MICRO  0
 
 #define LIBAVCODEC_VERSION_INT  AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \
diff --git a/libavformat/omadec.c b/libavformat/omadec.c
index 709a60b..6c27458 100644
--- a/libavformat/omadec.c
+++ b/libavformat/omadec.c
@@ -37,7 +37,7 @@
  * - Sound data organized in packets follow the EA3 header
  *   (can be encrypted using the Sony DRM!).
  *
- * CODEC SUPPORT: Only ATRAC3 codec is currently supported!
+ * Supported decoders: ATRAC3, ATRAC3+, MP3, LPCM
  */
 
 #include "libavutil/channel_layout.h"
@@ -386,7 +386,6 @@ static int oma_read_header(AVFormatContext *s)
         st->codec->sample_rate = samplerate;
         st->codec->bit_rate    = samplerate * framesize * 8 / 2048;
         avpriv_set_pts_info(st, 64, 1, samplerate);
-        av_log(s, AV_LOG_ERROR, "Unsupported codec ATRAC3+!\n");
         break;
     case OMA_CODECID_MP3:
         st->need_parsing = AVSTREAM_PARSE_FULL;




More information about the ffmpeg-cvslog mailing list