diff --git a/libavcodec/Makefile b/libavcodec/Makefile
index f1c032b456..8bc11b4e77 100644
--- a/libavcodec/Makefile
+++ b/libavcodec/Makefile
@@ -173,6 +173,7 @@ OBJS-$(CONFIG_AC3_FIXED_DECODER)       += ac3dec_fixed.o ac3dec_data.o ac3.o kbd
 OBJS-$(CONFIG_AC3_ENCODER)             += ac3enc_float.o ac3enc.o ac3tab.o \
                                           ac3.o kbdwin.o
 OBJS-$(CONFIG_AC3_FIXED_ENCODER)       += ac3enc_fixed.o ac3enc.o ac3tab.o ac3.o
+OBJS-$(CONFIG_AC4_DECODER)             += ac4dec.o
 OBJS-$(CONFIG_ACELP_KELVIN_DECODER)    += g729dec.o lsp.o celp_math.o celp_filters.o acelp_filters.o acelp_pitch_delay.o acelp_vectors.o g729postfilter.o
 OBJS-$(CONFIG_AGM_DECODER)             += agm.o
 OBJS-$(CONFIG_AIC_DECODER)             += aic.o
diff --git a/libavcodec/ac4dec.c b/libavcodec/ac4dec.c
new file mode 100644
index 0000000000..408466c9eb
--- /dev/null
+++ b/libavcodec/ac4dec.c
@@ -0,0 +1,5393 @@
+/*
+ * AC-4 Audio Decoder
+ *
+ * Copyright (c) 2019 Paul B Mahol
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#define ASSERT_LEVEL 5
+#include "libavutil/avassert.h"
+#include "libavutil/tx.h"
+#include "libavutil/channel_layout.h"
+#include "libavutil/float_dsp.h"
+#include "libavutil/thread.h"
+#include "libavutil/qsort.h"
+
+#include "ac4dec_data.h"
+#include "avcodec.h"
+#include "get_bits.h"
+#include "internal.h"
+#include "kbdwin.h"
+#include "unary.h"
+
+typedef struct EMDFInfo {
+    int     version;
+    int     key_id;
+    int     substream_index;
+} EMDFInfo;
+
+typedef struct SubstreamChannelParameters {
+    uint8_t long_frame;
+    uint8_t transf_length_idx[2];
+    int     transf_length[2];
+
+    uint8_t different_framing;
+    uint8_t max_sfb_side[2];
+    uint8_t max_sfb[2];
+    uint8_t scale_factor_grouping[15];
+
+    uint8_t num_windows;
+    uint8_t num_window_groups;
+    uint8_t window_to_group[16];
+    uint8_t num_win_in_group[16];
+
+    uint8_t dual_maxsfb;
+    uint8_t side_limited;
+    uint8_t side_channel;
+} SubstreamChannelParameters;
+
+typedef struct SubstreamChannel {
+    SubstreamChannelParameters scp;
+
+    int     sap_mode;
+
+    int     N_prev;
+
+    uint8_t ms_used[16][128];
+    uint8_t sap_coeff_used[16][128];
+    int     dpcm_alpha_q[16][128];
+
+    int     delta_code_time;
+
+    int     num_sec_lsf[16];
+    int     num_sec[16];
+    uint8_t sfb_cb[16][128];
+    uint8_t sect_cb[16][128];
+    int     sect_start[16][128];
+    int     sect_end[16][128];
+    int     sect_sfb_offset[16][128];
+
+    int16_t quant_spec[2048];
+    float   scaled_spec[2048];
+    float   spec_reord[2048];
+    int16_t offset2sfb[2048];
+    uint8_t offset2g[2048];
+    int     win_offset[16];
+    DECLARE_ALIGNED(32, float, overlap)[4096];
+
+    int     max_quant_idx[16][128];
+    int     dpcm_sf[16][128];
+    int     dpcm_snf[16][128];
+    int     snf_data_exists;
+
+    float   sf_gain[16][128];
+
+    int     aspx_int_class;
+    int     aspx_num_noise;
+    int     aspx_num_noise_prev;
+    int     aspx_num_rel_left;
+    int     aspx_num_rel_right;
+    int     aspx_num_env;
+    int     aspx_num_env_prev;
+    int     aspx_freq_res[32];
+    int     aspx_var_bord_left;
+    int     aspx_var_bord_right;
+    int     aspx_rel_bord_left[4];
+    int     aspx_rel_bord_right[4];
+    int     aspx_tsg_ptr;
+    int     aspx_tsg_ptr_prev;
+
+    int     aspx_qmode_env;
+    int     aspx_sig_delta_dir[8];
+    int     aspx_noise_delta_dir[2];
+    int     aspx_tna_mode[16];
+    int     aspx_tna_mode_prev[16];
+    int     aspx_add_harmonic[16];
+    int     aspx_fic_used_in_sfb[16];
+    int     aspx_tic_used_in_slot[16];
+    int     aspx_xover_subband_offset;
+    int     aspx_balance;
+
+    uint8_t atsg_freqres[32];
+    uint8_t atsg_freqres_prev[32];
+    int     atsg_sig[32];
+    int     atsg_noise[32];
+    int     previous_stop_pos;
+
+    int     num_sbg_master;
+    int     sba;
+    int     sbx;
+    int     sbz;
+    int     sbg_master[24];
+    int     sbg_noise[6];
+    int     sbg_sig_lowres[24];
+    int     sbg_sig_highres[24];
+    int     sbg_lim[32];
+    int     sbg_patches[6];
+    int     sbg_patch_num_sb[6];
+    int     sbg_patch_start_sb[6];
+
+    int     num_sb_aspx;
+    int     num_sbg_noise;
+    int     num_sbg_sig_highres;
+    int     num_sbg_sig_lowres;
+    int     num_sbg_sig[8];
+    int     sbg_sig[8][24];
+    int     num_sbg_patches;
+    int     num_sbg_lim;
+
+    int     aspx_data[2][32][64];
+
+    int     qscf_prev[32][64]; // XXX
+    int     qscf_sig_sbg[32][64]; // XXX
+    int     qscf_sig_sbg_prev[32][64]; // XXX
+    int     qscf_noise_sbg[32][64]; // XXX
+
+    float   scf_sig_sbg[32][64]; // XXX
+    float   scf_sig_sb[32][64]; // XXX
+    float   scf_noise_sbg[32][64]; // XXX
+    float   scf_noise_sb[32][64]; // XXX
+
+    float   gain_vec[32];
+    float   chirp_arr[6];
+    float   chirp_arr_prev[6];
+    float   est_sig_sb[32][64];
+    float   sine_idx_sb[32][64];
+    float   sine_idx_sb_prev[32][64];
+    float   sine_area_sb[32][64];
+    float   sine_lev_sb[32][64];
+    float   noise_lev_sb[32][64];
+    float   sig_gain_sb[32][64];
+    float   max_sig_gain_sbg[32][64];
+    float   max_sig_gain_sb[32][64];
+    float   noise_lev_sb_lim[32][64];
+    float   sig_gain_sb_lim[32][64];
+    float   boost_fact_sbg[32][64];
+    float   boost_fact_sb[32][64];
+    float   sig_gain_sb_adj[42][64];
+    float   noise_lev_sb_adj[42][64];
+    float   sine_lev_sb_adj[42][64];
+
+    float   qmf_sine[2][42][64];
+    int     sine_idx[64][42];
+    int     sine_idx_prev[64][42];
+
+    int     acpl_interpolation_type;
+    int     acpl_num_param_sets_cod;
+    int     acpl_param_timeslot[2];
+    int     acpl_data[11][16];
+
+    float   pcm[2048];
+
+    DECLARE_ALIGNED(32, float, qmf_filt)[640];
+    DECLARE_ALIGNED(32, float, qsyn_filt)[1280];
+    DECLARE_ALIGNED(32, float, Q)[2][32][64];
+    DECLARE_ALIGNED(32, float, Q_prev)[2][32][64];
+    DECLARE_ALIGNED(32, float, Q_low)[2][42][64];
+    DECLARE_ALIGNED(32, float, Q_low_prev)[2][42][64];
+    DECLARE_ALIGNED(32, float, Q_low_ext)[2][42][64];
+    DECLARE_ALIGNED(32, float, Q_high)[2][42][64];
+    DECLARE_ALIGNED(32, float, cov)[64][3][3][2];
+    DECLARE_ALIGNED(32, float, alpha0)[64][2];
+    DECLARE_ALIGNED(32, float, alpha1)[64][2];
+    DECLARE_ALIGNED(32, float, Y)[2][42][64];
+    DECLARE_ALIGNED(32, float, Y_prev)[2][42][64];
+} SubstreamChannel;
+
+typedef struct Substream {
+    int     codec_mode;
+
+    int     aspx_quant_mode_env;
+    int     aspx_start_freq;
+    int     prev_aspx_start_freq;
+    int     aspx_stop_freq;
+    int     prev_aspx_stop_freq;
+    int     aspx_master_freq_scale;
+    int     prev_aspx_master_freq_scale;
+    int     aspx_interpolation;
+    int     aspx_preflat;
+    int     aspx_limiter;
+    int     aspx_noise_sbg;
+    int     aspx_num_env_bits_fixfix;
+    int     aspx_freq_res_mode;
+
+    int     acpl_qmf_band;
+    int     acpl_param_band;
+    int     acpl_num_param_bands_id;
+    int     acpl_quant_mode[2];
+
+    uint8_t mode_2ch;
+    uint8_t chel_matsel;
+
+    uint8_t compand_on[5];
+    int     compand_avg;
+
+    int     max_sfb_master;
+
+    uint8_t coding_config;
+    uint8_t mdct_stereo_proc[2];
+    float   matrix_stereo[16][128][2][2];
+    float   alpha_q[16][128];
+
+    int     spec_frontend_l;
+    int     spec_frontend_r;
+    int     spec_frontend_m;
+    int     spec_frontend_s;
+
+    SubstreamChannel ssch[9];
+} Substream;
+
+typedef struct PresentationSubstreamInfo {
+    int     alternative;
+    int     pres_ndot;
+    int     substream_index;
+} PresentationSubstreamInfo;
+
+typedef struct Metadata {
+    int     dialnorm_bits;
+    int     pre_dmixtyp_2ch;
+    int     phase90_info_2ch;
+    int     loro_center_mixgain;
+    int     loro_surround_mixgain;
+    int     loro_dmx_loud_corr;
+    int     ltrt_center_mixgain;
+    int     ltrt_surround_mixgain;
+    int     ltrt_dmx_loud_corr;
+    int     lfe_mixgain;
+    int     preferred_dmx_method;
+    int     pre_dmixtyp_5ch;
+    int     pre_upmixtyp_5ch;
+    int     pre_upmixtyp_3_4;
+    int     pre_upmixtyp_3_2_2;
+    int     phase90_info_mc;
+    int     surround_attenuation_known;
+    int     lfe_attenuation_known;
+    int     dc_block_on;
+
+    int     loudness_version;
+    int     loud_prac_type;
+    int     dialgate_prac_type;
+    int     loudcorr_type;
+    int     loudrelgat;
+    int     loudspchgat;
+    int     loudstrm3s;
+    int     max_loudstrm3s;
+    int     truepk;
+    int     max_truepk;
+    int     prgmbndy;
+    int     end_or_start;
+    int     prgmbndy_offset;
+    int     lra;
+    int     lra_prac_type;
+    int     loudmntry;
+    int     max_loudmntry;
+
+    int     drc_decoder_nr_modes;
+    int     drc_eac3_profile;
+} Metadata;
+
+typedef struct SubstreamInfo {
+    int     sus_ver;
+    int     channel_mode;
+    int     substream_index;
+    int     sf_multiplier;
+    int     bitrate_indicator;
+    int     add_ch_base;
+    int     iframe[4];
+    int     back_channels_present;
+    int     centre_present;
+    int     top_channels_present;
+    Metadata meta;
+} SubstreamInfo;
+
+typedef struct SubstreamGroupInfo {
+    int     channel_coded;
+    int     group_index;
+} SubstreamGroupInfo;
+
+typedef struct PresentationInfo {
+    int     single_substream;
+    int     enable_presentation;
+    int     presentation_config;
+    int     presentation_version;
+    int     add_emdf_substreams;
+    int     n_add_emdf_substreams;
+    int     n_substream_groups;
+    int     mdcompat;
+    int     presentation_id;
+    int     multiplier;
+    int     multiplier_bit;
+    int     pre_virtualized;
+    int     frame_rate_factor;
+    int     frame_rate_fraction;
+    int     multi_pid;
+    int     hsf_ext;
+    EMDFInfo emdf[32];
+    PresentationSubstreamInfo psinfo;
+    SubstreamInfo ssinfo;
+} PresentationInfo;
+
+typedef struct AC4DecodeContext {
+    AVClass        *class;                  ///< class for AVOptions
+    AVCodecContext *avctx;                  ///< parent context
+    AVFloatDSPContext *fdsp;
+    GetBitContext   gbc;                    ///< bitstream reader
+
+    int             version;
+    int             sequence_counter;
+    int             sequence_counter_prev;
+    int             wait_frames;
+    int             nb_wait_frames;
+    int             fs_index;
+    int             frame_rate_index;
+    int             frame_len_base;
+    int             frame_len_base_idx;
+    AVRational      resampling_ratio;
+    int             num_qmf_timeslots;
+    int             num_aspx_timeslots;
+    int             num_ts_in_ats;
+    int             ts_offset_hfgen;
+    int             transform_length;
+    int             iframe_global;
+    int             have_iframe;
+    int             nb_presentations;
+    int             payload_base;
+    int             short_program_id;
+    int             nb_substreams;
+    int             total_groups;
+    int             substream_size[32];
+    int             substream_type[32];
+
+    DECLARE_ALIGNED(32, float, winl)[2048];
+    DECLARE_ALIGNED(32, float, winr)[2048];
+
+    SubstreamGroupInfo ssgroup[8];
+    PresentationInfo   pinfo[8];
+    Substream          substream;
+
+    av_tx_fn           tx_fn[8][5];
+    AVTXContext       *tx_ctx[8][5];
+
+    DECLARE_ALIGNED(32, float, kbd_window)[8][5][2048];
+
+    float              quant_lut[8192];
+
+    DECLARE_ALIGNED(32, float, cos_atab)[64][128];
+    DECLARE_ALIGNED(32, float, sin_atab)[64][128];
+    DECLARE_ALIGNED(32, float, cos_stab)[128][64];
+    DECLARE_ALIGNED(32, float, sin_stab)[128][64];
+} AC4DecodeContext;
+
+enum ACPLMode {
+    ACPL_FULL,
+    ACPL_PARTIAL,
+};
+
+enum SubstreamType {
+    ST_SUBSTREAM,
+    ST_PRESENTATION,
+};
+
+enum StereoMode {
+    SM_LEVEL,
+    SM_BALANCE,
+};
+
+enum DataType {
+    DT_SIGNAL,
+    DT_NOISE,
+};
+
+enum SpectralFrontend {
+    SF_ASF,
+    SF_SSF,
+};
+
+enum HCBType {
+    F0,
+    DF,
+    DT,
+};
+
+enum CodecMode {
+    CM_SIMPLE,
+    CM_ASPX,
+    CM_ASPX_ACPL_1,
+    CM_ASPX_ACPL_2,
+    CM_ASPX_ACPL_3,
+};
+
+enum IntervalClass {
+    FIXFIX,
+    FIXVAR,
+    VARFIX,
+    VARVAR,
+};
+
+enum ACPLDataType {
+    ALPHA1,
+    ALPHA2,
+    BETA1,
+    BETA2,
+    BETA3,
+    GAMMA1,
+    GAMMA2,
+    GAMMA3,
+    GAMMA4,
+    GAMMA5,
+    GAMMA6,
+};
+
+static const AVRational resampling_ratios[] = {
+    {25025, 24000},
+    {25, 24},
+    {15, 16},
+    {25025, 24000},
+    {25, 24},
+    {25025, 24000},
+    {25, 24},
+    {15, 16},
+    {25025, 24000},
+    {25, 24},
+    {15, 16},
+    {25025, 24000},
+    {25, 24},
+    {1, 1},
+    {1, 1},
+    {1, 1},
+};
+
+static const uint8_t channel_mode_nb_channels[] = {
+    1, 2, 3, 5, 6, 7, 8, 7, 8, 7, 8, 11, 12, 13, 14, 24, 0
+};
+
+static const uint64_t channel_mode_layouts[] = {
+    AV_CH_LAYOUT_MONO,
+    AV_CH_LAYOUT_STEREO,
+    AV_CH_LAYOUT_SURROUND,
+    AV_CH_LAYOUT_5POINT0,
+    AV_CH_LAYOUT_5POINT1,
+    AV_CH_LAYOUT_7POINT0,
+    AV_CH_LAYOUT_7POINT1,
+    AV_CH_LAYOUT_7POINT0_FRONT,
+    AV_CH_LAYOUT_7POINT0_FRONT|AV_CH_LOW_FREQUENCY,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+};
+
+static VLC channel_mode_vlc;
+static VLC bitrate_indicator_vlc;
+static VLC scale_factors_vlc;
+static VLC snf_vlc;
+static VLC asf_codebook_vlc[11];
+static VLC acpl_codebook_vlc[4][2][3];
+static VLC aspx_int_class_vlc;
+static VLC aspx_codebook_signal_vlc[2][2][3];
+static VLC aspx_codebook_noise_vlc[2][3];
+
+static av_cold int ac4_decode_init(AVCodecContext *avctx)
+{
+    AC4DecodeContext *s = avctx->priv_data;
+    int ret;
+
+    s->avctx = avctx;
+
+    avctx->sample_fmt = AV_SAMPLE_FMT_FLTP;
+
+    INIT_VLC_STATIC(&channel_mode_vlc, 9, sizeof(channel_mode_bits),
+                    channel_mode_bits, 1, 1, channel_mode_codes, 2, 2, 512);
+    INIT_VLC_STATIC(&bitrate_indicator_vlc, 5, sizeof(bitrate_indicator_bits),
+                    bitrate_indicator_bits, 1, 1, bitrate_indicator_codes, 1, 1, 32);
+    INIT_VLC_STATIC(&scale_factors_vlc, 9, sizeof(scale_factors_bits),
+                    scale_factors_bits, 1, 1, scale_factors_codes, 1, 1, 850);
+    INIT_VLC_STATIC(&snf_vlc, 6, sizeof(snf_bits),
+                    snf_bits, 1, 1, snf_codes, 1, 1, 70);
+
+    INIT_VLC_STATIC(&asf_codebook_vlc[0], 9, sizeof(asf_codebook_1_bits),
+                    asf_codebook_1_bits, 1, 1, asf_codebook_1_codes, 1, 1, 542);
+    INIT_VLC_STATIC(&asf_codebook_vlc[1], 9, sizeof(asf_codebook_2_bits),
+                    asf_codebook_2_bits, 1, 1, asf_codebook_2_codes, 1, 1, 512);
+    INIT_VLC_STATIC(&asf_codebook_vlc[2], 9, sizeof(asf_codebook_3_bits),
+                    asf_codebook_3_bits, 1, 1, asf_codebook_3_codes, 1, 1, 612);
+    INIT_VLC_STATIC(&asf_codebook_vlc[3], 9, sizeof(asf_codebook_4_bits),
+                    asf_codebook_4_bits, 1, 1, asf_codebook_4_codes, 1, 1, 544);
+    INIT_VLC_STATIC(&asf_codebook_vlc[4], 9, sizeof(asf_codebook_5_bits),
+                    asf_codebook_5_bits, 1, 1, asf_codebook_5_codes, 1, 1, 576);
+    INIT_VLC_STATIC(&asf_codebook_vlc[5], 9, sizeof(asf_codebook_6_bits),
+                    asf_codebook_6_bits, 1, 1, asf_codebook_6_codes, 1, 1, 546);
+    INIT_VLC_STATIC(&asf_codebook_vlc[6], 9, sizeof(asf_codebook_7_bits),
+                    asf_codebook_7_bits, 1, 1, asf_codebook_7_codes, 1, 1, 542);
+    INIT_VLC_STATIC(&asf_codebook_vlc[7], 9, sizeof(asf_codebook_8_bits),
+                    asf_codebook_8_bits, 1, 1, asf_codebook_8_codes, 1, 1, 522);
+    INIT_VLC_STATIC(&asf_codebook_vlc[8], 9, sizeof(asf_codebook_9_bits),
+                    asf_codebook_9_bits, 1, 1, asf_codebook_9_codes, 1, 1, 670);
+    INIT_VLC_STATIC(&asf_codebook_vlc[9], 9, sizeof(asf_codebook_10_bits),
+                    asf_codebook_10_bits, 1, 1, asf_codebook_10_codes, 1, 1, 604);
+    INIT_VLC_STATIC(&asf_codebook_vlc[10], 9, sizeof(asf_codebook_11_bits),
+                    asf_codebook_11_bits, 1, 1, asf_codebook_11_codes, 1, 1, 674);
+
+    INIT_VLC_STATIC(&aspx_int_class_vlc, 5, sizeof(aspx_int_class_bits),
+                    aspx_int_class_bits, 1, 1, aspx_int_class_codes, 1, 1, 32);
+
+    INIT_VLC_STATIC(&aspx_codebook_signal_vlc[0][0][0], 9, sizeof(aspx_hcb_env_level_15_f0_bits),
+                    aspx_hcb_env_level_15_f0_bits, 1, 1, aspx_hcb_env_level_15_f0_codes, 4, 4, 1024);
+    INIT_VLC_STATIC(&aspx_codebook_signal_vlc[0][0][1], 9, sizeof(aspx_hcb_env_level_15_df_bits),
+                    aspx_hcb_env_level_15_df_bits, 1, 1, aspx_hcb_env_level_15_df_codes, 4, 4, 1888);
+    INIT_VLC_STATIC(&aspx_codebook_signal_vlc[0][0][2], 9, sizeof(aspx_hcb_env_level_15_dt_bits),
+                    aspx_hcb_env_level_15_dt_bits, 1, 1, aspx_hcb_env_level_15_dt_codes, 4, 4, 1368);
+
+    INIT_VLC_STATIC(&aspx_codebook_signal_vlc[0][1][0], 9, sizeof(aspx_hcb_env_level_30_f0_bits),
+                    aspx_hcb_env_level_30_f0_bits, 1, 1, aspx_hcb_env_level_30_f0_codes, 4, 4, 772);
+    INIT_VLC_STATIC(&aspx_codebook_signal_vlc[0][1][1], 9, sizeof(aspx_hcb_env_level_30_df_bits),
+                    aspx_hcb_env_level_30_df_bits, 1, 1, aspx_hcb_env_level_30_df_codes, 4, 4, 1624);
+    INIT_VLC_STATIC(&aspx_codebook_signal_vlc[0][1][2], 9, sizeof(aspx_hcb_env_level_30_dt_bits),
+                    aspx_hcb_env_level_30_dt_bits, 1, 1, aspx_hcb_env_level_30_dt_codes, 4, 4, 1598);
+
+    INIT_VLC_STATIC(&aspx_codebook_signal_vlc[1][0][0], 9, sizeof(aspx_hcb_env_balance_15_f0_bits),
+                    aspx_hcb_env_balance_15_f0_bits, 1, 1, aspx_hcb_env_balance_15_f0_codes, 4, 4, 644);
+    INIT_VLC_STATIC(&aspx_codebook_signal_vlc[1][0][1], 9, sizeof(aspx_hcb_env_balance_15_df_bits),
+                    aspx_hcb_env_balance_15_df_bits, 1, 1, aspx_hcb_env_balance_15_df_codes, 4, 4, 1056);
+    INIT_VLC_STATIC(&aspx_codebook_signal_vlc[1][0][2], 9, sizeof(aspx_hcb_env_balance_15_dt_bits),
+                    aspx_hcb_env_balance_15_dt_bits, 1, 1, aspx_hcb_env_balance_15_dt_codes, 4, 4, 616);
+
+    INIT_VLC_STATIC(&aspx_codebook_signal_vlc[1][1][0], 9, sizeof(aspx_hcb_env_balance_30_f0_bits),
+                    aspx_hcb_env_balance_30_f0_bits, 1, 1, aspx_hcb_env_balance_30_f0_codes, 2, 2, 520);
+    INIT_VLC_STATIC(&aspx_codebook_signal_vlc[1][1][1], 9, sizeof(aspx_hcb_env_balance_30_df_bits),
+                    aspx_hcb_env_balance_30_df_bits, 1, 1, aspx_hcb_env_balance_30_df_codes, 4, 4, 768);
+    INIT_VLC_STATIC(&aspx_codebook_signal_vlc[1][1][2], 9, sizeof(aspx_hcb_env_balance_30_dt_bits),
+                    aspx_hcb_env_balance_30_dt_bits, 1, 1, aspx_hcb_env_balance_30_dt_codes, 2, 2, 576);
+
+    INIT_VLC_STATIC(&aspx_codebook_noise_vlc[0][0], 9, sizeof(aspx_hcb_noise_level_f0_bits),
+                    aspx_hcb_noise_level_f0_bits, 1, 1, aspx_hcb_noise_level_f0_codes, 2, 2, 672);
+    INIT_VLC_STATIC(&aspx_codebook_noise_vlc[0][1], 9, sizeof(aspx_hcb_noise_level_df_bits),
+                    aspx_hcb_noise_level_df_bits, 1, 1, aspx_hcb_noise_level_df_codes, 4, 4, 1024);
+    INIT_VLC_STATIC(&aspx_codebook_noise_vlc[0][2], 9, sizeof(aspx_hcb_noise_level_dt_bits),
+                    aspx_hcb_noise_level_dt_bits, 1, 1, aspx_hcb_noise_level_dt_codes, 2, 2, 768);
+
+    INIT_VLC_STATIC(&aspx_codebook_noise_vlc[1][0], 9, sizeof(aspx_hcb_noise_balance_f0_bits),
+                    aspx_hcb_noise_balance_f0_bits, 1, 1, aspx_hcb_noise_balance_f0_codes, 2, 2, 516);
+    INIT_VLC_STATIC(&aspx_codebook_noise_vlc[1][1], 9, sizeof(aspx_hcb_noise_balance_df_bits),
+                    aspx_hcb_noise_balance_df_bits, 1, 1, aspx_hcb_noise_balance_df_codes, 2, 2, 536);
+    INIT_VLC_STATIC(&aspx_codebook_noise_vlc[1][2], 9, sizeof(aspx_hcb_noise_balance_dt_bits),
+                    aspx_hcb_noise_balance_dt_bits, 1, 1, aspx_hcb_noise_balance_dt_codes, 2, 2, 530);
+
+    INIT_VLC_STATIC(&acpl_codebook_vlc[0][1][0], 9, sizeof(acpl_hcb_alpha_coarse_f0_bits),
+                    acpl_hcb_alpha_coarse_f0_bits, 1, 1, acpl_hcb_alpha_coarse_f0_codes, 2, 2, 516);
+    INIT_VLC_STATIC(&acpl_codebook_vlc[0][1][1], 9, sizeof(acpl_hcb_alpha_coarse_df_bits),
+                    acpl_hcb_alpha_coarse_df_bits, 1, 1, acpl_hcb_alpha_coarse_df_codes, 4, 4, 1032);
+    INIT_VLC_STATIC(&acpl_codebook_vlc[0][1][2], 9, sizeof(acpl_hcb_alpha_coarse_dt_bits),
+                    acpl_hcb_alpha_coarse_dt_bits, 1, 1, acpl_hcb_alpha_coarse_dt_codes, 4, 4, 642);
+
+    INIT_VLC_STATIC(&acpl_codebook_vlc[0][0][0], 9, sizeof(acpl_hcb_alpha_fine_f0_bits),
+                    acpl_hcb_alpha_fine_f0_bits, 1, 1, acpl_hcb_alpha_fine_f0_codes, 2, 2, 530);
+    INIT_VLC_STATIC(&acpl_codebook_vlc[0][0][1], 9, sizeof(acpl_hcb_alpha_fine_df_bits),
+                    acpl_hcb_alpha_fine_df_bits, 1, 1, acpl_hcb_alpha_fine_df_codes, 4, 4, 1176);
+    INIT_VLC_STATIC(&acpl_codebook_vlc[0][0][2], 9, sizeof(acpl_hcb_alpha_fine_dt_bits),
+                    acpl_hcb_alpha_fine_dt_bits, 1, 1, acpl_hcb_alpha_fine_dt_codes, 4, 4, 1158);
+
+    INIT_VLC_STATIC(&acpl_codebook_vlc[1][1][0], 9, sizeof(acpl_hcb_beta_coarse_f0_bits),
+                    acpl_hcb_beta_coarse_f0_bits, 1, 1, acpl_hcb_beta_coarse_f0_codes, 1, 1, 512);
+    INIT_VLC_STATIC(&acpl_codebook_vlc[1][1][1], 9, sizeof(acpl_hcb_beta_coarse_df_bits),
+                    acpl_hcb_beta_coarse_df_bits, 1, 1, acpl_hcb_beta_coarse_df_codes, 1, 1, 512);
+    INIT_VLC_STATIC(&acpl_codebook_vlc[1][1][2], 9, sizeof(acpl_hcb_beta_coarse_dt_bits),
+                    acpl_hcb_beta_coarse_dt_bits, 1, 1, acpl_hcb_beta_coarse_dt_codes, 1, 1, 512);
+
+    INIT_VLC_STATIC(&acpl_codebook_vlc[1][0][0], 9, sizeof(acpl_hcb_beta_fine_f0_bits),
+                    acpl_hcb_beta_fine_f0_bits, 1, 1, acpl_hcb_beta_fine_f0_codes, 1, 1, 512);
+    INIT_VLC_STATIC(&acpl_codebook_vlc[1][0][1], 9, sizeof(acpl_hcb_beta_fine_df_bits),
+                    acpl_hcb_beta_fine_df_bits, 1, 1, acpl_hcb_beta_fine_df_codes, 4, 4, 528);
+    INIT_VLC_STATIC(&acpl_codebook_vlc[1][0][2], 9, sizeof(acpl_hcb_beta_fine_dt_bits),
+                    acpl_hcb_beta_fine_dt_bits, 1, 1, acpl_hcb_beta_fine_dt_codes, 4, 4, 576);
+
+    INIT_VLC_STATIC(&acpl_codebook_vlc[2][1][0], 9, sizeof(acpl_hcb_beta3_coarse_f0_bits),
+                    acpl_hcb_beta3_coarse_f0_bits, 1, 1, acpl_hcb_beta3_coarse_f0_codes, 1, 1, 512);
+    INIT_VLC_STATIC(&acpl_codebook_vlc[2][1][1], 9, sizeof(acpl_hcb_beta3_coarse_df_bits),
+                    acpl_hcb_beta3_coarse_df_bits, 1, 1, acpl_hcb_beta3_coarse_df_codes, 4, 4, 528);
+    INIT_VLC_STATIC(&acpl_codebook_vlc[2][1][2], 9, sizeof(acpl_hcb_beta3_coarse_dt_bits),
+                    acpl_hcb_beta3_coarse_dt_bits, 1, 1, acpl_hcb_beta3_coarse_dt_codes, 2, 2, 576);
+
+    INIT_VLC_STATIC(&acpl_codebook_vlc[2][0][0], 9, sizeof(acpl_hcb_beta3_fine_f0_bits),
+                    acpl_hcb_beta3_fine_f0_bits, 1, 1, acpl_hcb_beta3_fine_f0_codes, 1, 1, 512);
+    INIT_VLC_STATIC(&acpl_codebook_vlc[2][0][1], 9, sizeof(acpl_hcb_beta3_fine_df_bits),
+                    acpl_hcb_beta3_fine_df_bits, 1, 1, acpl_hcb_beta3_fine_df_codes, 4, 4, 580);
+    INIT_VLC_STATIC(&acpl_codebook_vlc[2][0][2], 9, sizeof(acpl_hcb_beta3_fine_dt_bits),
+                    acpl_hcb_beta3_fine_dt_bits, 1, 1, acpl_hcb_beta3_fine_dt_codes, 4, 4, 768);
+
+    INIT_VLC_STATIC(&acpl_codebook_vlc[3][1][0], 9, sizeof(acpl_hcb_gamma_coarse_f0_bits),
+                    acpl_hcb_gamma_coarse_f0_bits, 1, 1, acpl_hcb_gamma_coarse_f0_codes, 2, 2, 528);
+    INIT_VLC_STATIC(&acpl_codebook_vlc[3][1][1], 9, sizeof(acpl_hcb_gamma_coarse_df_bits),
+                    acpl_hcb_gamma_coarse_df_bits, 1, 1, acpl_hcb_gamma_coarse_df_codes, 4, 4, 644);
+    INIT_VLC_STATIC(&acpl_codebook_vlc[3][1][2], 9, sizeof(acpl_hcb_gamma_coarse_dt_bits),
+                    acpl_hcb_gamma_coarse_dt_bits, 1, 1, acpl_hcb_gamma_coarse_dt_codes, 4, 4, 896);
+
+    INIT_VLC_STATIC(&acpl_codebook_vlc[3][0][0], 9, sizeof(acpl_hcb_gamma_fine_f0_bits),
+                    acpl_hcb_gamma_fine_f0_bits, 1, 1, acpl_hcb_gamma_fine_f0_codes, 4, 4, 544);
+    INIT_VLC_STATIC(&acpl_codebook_vlc[3][0][1], 9, sizeof(acpl_hcb_gamma_fine_df_bits),
+                    acpl_hcb_gamma_fine_df_bits, 1, 1, acpl_hcb_gamma_fine_df_codes, 4, 4, 1026);
+    INIT_VLC_STATIC(&acpl_codebook_vlc[3][0][2], 9, sizeof(acpl_hcb_gamma_fine_dt_bits),
+                    acpl_hcb_gamma_fine_dt_bits, 1, 1, acpl_hcb_gamma_fine_dt_codes, 4, 4, 1792);
+
+    for (int j = 0; j < 8; j++) {
+        const uint16_t *transf_lengths = transf_length_48khz[j];
+
+        for (int i = 0; i < 5; i++) {
+            int N_w = transf_lengths[i];
+            float alpha = kbd_window_alpha[j][i];
+            float scale = 1.f / (float)N_w;
+
+            if ((ret = av_tx_init(&s->tx_ctx[j][i], &s->tx_fn[j][i], AV_TX_FLOAT_MDCT, 1, N_w, &scale, 0)))
+                return ret;
+
+            ff_kbd_window_init(s->kbd_window[j][i], alpha, N_w);
+        }
+    }
+
+    for (int i = 0; i < 8192; i++)
+        s->quant_lut[i] = powf(i, 4.f / 3.f);
+
+    for (int i = 0; i < 64; i++) {
+        for (int n = 0; n < 128; n++) {
+            s->cos_atab[i][n] = cosf(M_PI/128*(i+0.5)*(2*n-1));
+            s->sin_atab[i][n] = sinf(M_PI/128*(i+0.5)*(2*n-1));
+            s->cos_stab[n][i] = cosf(M_PI/128*(i+0.5)*(2*n-255)) / 64;
+            s->sin_stab[n][i] = sinf(M_PI/128*(i+0.5)*(2*n-255)) / 64;
+        }
+    }
+
+    s->fdsp = avpriv_float_dsp_alloc(avctx->flags & AV_CODEC_FLAG_BITEXACT);
+    if (!s->fdsp)
+        return AVERROR(ENOMEM);
+
+    return 0;
+}
+
+static int variable_bits(GetBitContext *gb, int bits)
+{
+    int value = 0;
+    int read_more;
+
+    do {
+        value += get_bits(gb, bits);
+        read_more = get_bits1(gb);
+        if (read_more) {
+            value <<= bits;
+            value += 1 << bits;
+        }
+    } while (read_more);
+
+    return value;
+}
+
+static int check_sequence(AC4DecodeContext *s)
+{
+    if (s->sequence_counter > 1020)
+        return AVERROR_INVALIDDATA;
+
+    if (s->sequence_counter == s->sequence_counter_prev + 1)
+        return 0;
+
+    if (s->sequence_counter != 0 && s->sequence_counter_prev == 0)
+        return 0;
+
+    if (s->sequence_counter == 1 && s->sequence_counter_prev == 1020)
+        return 0;
+
+    if (s->sequence_counter == 0 && s->sequence_counter_prev == 0)
+        return 0;
+
+    return AVERROR_INVALIDDATA;
+}
+
+static int frame_rate_multiply_info(AC4DecodeContext *s, PresentationInfo *p)
+{
+    GetBitContext *gb = &s->gbc;
+
+    p->multiplier_bit = 0;
+
+    switch (s->frame_rate_index) {
+    case 2:
+    case 3:
+    case 4:
+        p->multiplier = get_bits1(gb);
+        if (p->multiplier)
+            p->multiplier_bit = get_bits1(gb);
+        p->frame_rate_factor = p->multiplier ? (p->multiplier_bit ? 4 : 2) : 1;
+        break;
+    case 0:
+    case 1:
+    case 7:
+    case 8:
+    case 9:
+        p->multiplier = get_bits1(gb);
+        p->frame_rate_factor = p->multiplier ? 2 : 1;
+        break;
+    default:
+        p->frame_rate_factor = 1;
+        break;
+    }
+
+    return 0;
+}
+
+static int emdf_payloads_substream_info(AC4DecodeContext *s, EMDFInfo *e)
+{
+    GetBitContext *gb = &s->gbc;
+
+    e->substream_index = get_bits(gb, 2);
+    if (e->substream_index == 3)
+        e->substream_index += variable_bits(gb, 2);
+
+    return 0;
+}
+
+static int emdf_protection(AC4DecodeContext *s, EMDFInfo *e)
+{
+    GetBitContext *gb = &s->gbc;
+    int first, second;
+
+    first = get_bits(gb, 2);
+    second = get_bits(gb, 2);
+
+    switch (first) {
+    case 0:
+        break;
+    case 1:
+        skip_bits(gb, 8);
+        break;
+    case 2:
+        skip_bits_long(gb, 32);
+        break;
+    case 3:
+        skip_bits_long(gb, 128);
+        break;
+    }
+
+    switch (second) {
+    case 0:
+        break;
+    case 1:
+        skip_bits(gb, 8);
+        break;
+    case 2:
+        skip_bits_long(gb, 32);
+        break;
+    case 3:
+        skip_bits_long(gb, 128);
+        break;
+    }
+
+    return 0;
+}
+
+static int emdf_info(AC4DecodeContext *s, EMDFInfo *e)
+{
+    GetBitContext *gb = &s->gbc;
+
+    e->version = get_bits(gb, 2);
+    if (e->version == 3)
+        e->version += variable_bits(gb, 2);
+    e->key_id = get_bits(gb, 3);
+    if (e->key_id == 7)
+        e->key_id += variable_bits(gb, 3);
+
+    if (get_bits1(gb))
+        emdf_payloads_substream_info(s, e);
+
+    emdf_protection(s, e);
+
+    return 0;
+}
+
+static int content_type(AC4DecodeContext *s, PresentationInfo *p)
+{
+    GetBitContext *gb = &s->gbc;
+
+    skip_bits(gb, 3);
+    if (get_bits1(gb)) {
+        if (get_bits1(gb)) {
+            skip_bits(gb, 1);
+            skip_bits(gb, 16);
+        } else {
+            int language_tag_bytes = get_bits(gb, 6);
+
+            skip_bits_long(gb, 8 * language_tag_bytes);
+        }
+    }
+
+    return 0;
+}
+
+static int ac4_substream_info(AC4DecodeContext *s, PresentationInfo *p,
+                              SubstreamInfo *ssi)
+{
+    GetBitContext *gb = &s->gbc;
+
+    ssi->sus_ver = 0;
+    ssi->channel_mode = get_vlc2(gb, channel_mode_vlc.table, channel_mode_vlc.bits, 1);
+    if (ssi->channel_mode < 0)
+        return AVERROR_INVALIDDATA;
+
+    if (ssi->channel_mode == 16)
+        ssi->channel_mode += variable_bits(gb, 2);
+
+    if (s->fs_index == 1 && get_bits1(gb))
+        ssi->sf_multiplier = 1 + get_bits1(gb);
+    av_log(s->avctx, AV_LOG_DEBUG, "sf_multiplier: %d\n", ssi->sf_multiplier);
+
+    if (get_bits1(gb))
+        ssi->bitrate_indicator = get_vlc2(gb, bitrate_indicator_vlc.table, bitrate_indicator_vlc.bits, 1);
+
+    if (ssi->channel_mode == 7 ||
+        ssi->channel_mode == 8 ||
+        ssi->channel_mode == 9 ||
+        ssi->channel_mode == 10) {
+        ssi->add_ch_base = get_bits1(gb);
+    }
+
+    if (get_bits1(gb))
+        content_type(s, p);
+
+    for (int i = 0; i < p->frame_rate_factor; i++)
+        ssi->iframe[i] = get_bits1(gb);
+
+    ssi->substream_index = get_bits(gb, 2);
+    if (ssi->substream_index == 3)
+        ssi->substream_index += variable_bits(gb, 2);
+    s->substream_type[ssi->substream_index] = ST_SUBSTREAM;
+    av_log(s->avctx, AV_LOG_DEBUG, "substream index: %d\n", ssi->substream_index);
+
+    return 0;
+}
+
+static int presentation_config_ext_info(AC4DecodeContext *s)
+{
+    GetBitContext *gb = &s->gbc;
+    int n_skip_bytes;
+
+    n_skip_bytes = get_bits(gb, 5);
+    if (get_bits1(gb))
+        n_skip_bytes += variable_bits(gb, 2) << 5;
+
+    skip_bits_long(gb, 8 * n_skip_bytes);
+
+    return 0;
+}
+
+static int ac4_presentation_info(AC4DecodeContext *s, PresentationInfo *p)
+{
+    GetBitContext *gb = &s->gbc;
+    int ret;
+
+    p->single_substream = get_bits1(gb);
+    if (p->single_substream != 1) {
+        p->presentation_config = get_bits(gb, 3);
+        if (p->presentation_config == 0x7) {
+            p->presentation_config += variable_bits(gb, 2);
+        }
+    }
+
+    p->presentation_version = get_unary(gb, 0, 31);
+
+    p->add_emdf_substreams = 0;
+    if (p->single_substream != 1 && p->presentation_config == 6) {
+        p->add_emdf_substreams = 1;
+    } else {
+        p->mdcompat = get_bits(gb, 3);
+
+        if (get_bits1(gb))
+            p->presentation_id = variable_bits(gb, 2);
+
+        frame_rate_multiply_info(s, p);
+        emdf_info(s, &p->emdf[0]);
+
+        if (p->single_substream == 1) {
+            ret = ac4_substream_info(s, p, &p->ssinfo);
+            if (ret < 0)
+                return ret;
+        } else {
+            p->hsf_ext = get_bits1(gb);
+            switch (p->presentation_config) {
+            case 0:
+                av_assert0(0);
+                ret = ac4_substream_info(s, p, &p->ssinfo);
+                if (ret < 0)
+                    return ret;
+                break;
+            default:
+                presentation_config_ext_info(s);
+            }
+        }
+
+        p->pre_virtualized = get_bits1(gb);
+        p->add_emdf_substreams = get_bits1(gb);
+    }
+
+    if (p->add_emdf_substreams) {
+        p->n_add_emdf_substreams = get_bits(gb, 2);
+        if (p->n_add_emdf_substreams == 0)
+            p->n_add_emdf_substreams = variable_bits(gb, 2) + 4;
+
+        for (int i = 0; i < p->n_add_emdf_substreams; i++)
+            emdf_info(s, &p->emdf[i]);
+    }
+
+    return 0;
+}
+
+static int substream_index_table(AC4DecodeContext *s)
+{
+    GetBitContext *gb = &s->gbc;
+    int size_present;
+
+    s->nb_substreams = get_bits(gb, 2);
+    if (s->nb_substreams == 0)
+        s->nb_substreams = variable_bits(gb, 2) + 4;
+
+    av_log(s->avctx, AV_LOG_DEBUG, "nb_substreams: %d\n", s->nb_substreams);
+
+    if (s->nb_substreams == 1) {
+        size_present = get_bits1(gb);
+    } else {
+        size_present = 1;
+    }
+
+    if (size_present) {
+        for (int i = 0; i < s->nb_substreams; i++) {
+            int more_bits = get_bits1(gb);
+
+            s->substream_size[i] = get_bits(gb, 10);
+            if (more_bits)
+                s->substream_size[i] += variable_bits(gb, 2) << 10;
+            av_log(s->avctx, AV_LOG_DEBUG, "substream[%d] size: %d\n", i, s->substream_size[i]);
+        }
+    }
+
+    return 0;
+}
+
+static int presentation_substream_info(AC4DecodeContext *s, PresentationSubstreamInfo *psi)
+{
+    GetBitContext *gb = &s->gbc;
+
+    psi->alternative = get_bits1(gb);
+    psi->pres_ndot = get_bits1(gb);
+    psi->substream_index = get_bits(gb, 2);
+    if (psi->substream_index == 3)
+        psi->substream_index += variable_bits(gb, 2);
+    s->substream_type[psi->substream_index] = ST_PRESENTATION;
+    av_log(s->avctx, AV_LOG_DEBUG, "presentation substream index: %d\n", psi->substream_index);
+
+    return 0;
+}
+
+static int frame_rate_fractions_info(AC4DecodeContext *s, PresentationInfo *p)
+{
+    GetBitContext *gb = &s->gbc;
+
+    p->frame_rate_fraction = 1;
+    if (s->frame_rate_index >= 5 && s->frame_rate_index <= 9) {
+        if (p->frame_rate_factor == 1) {
+            if (get_bits1(gb))
+                p->frame_rate_fraction = 2;
+        }
+    }
+
+    if (s->frame_rate_index >= 10 && s->frame_rate_index <= 12) {
+        if (get_bits1(gb)) {
+            if (get_bits1(gb))
+                p->frame_rate_fraction = 4;
+            else
+                p->frame_rate_fraction = 2;
+        }
+    }
+
+    return 0;
+}
+
+static int ac4_substream_info_chan(AC4DecodeContext *s, PresentationInfo *p,
+                                   SubstreamInfo *ssi, int substreams_present,
+                                   int sus_ver)
+{
+    GetBitContext *gb = &s->gbc;
+
+    ssi->sus_ver = sus_ver;
+    ssi->channel_mode = get_vlc2(gb, channel_mode_vlc.table, channel_mode_vlc.bits, 3);
+    if (ssi->channel_mode < 0)
+        return AVERROR_INVALIDDATA;
+
+    if (ssi->channel_mode == 16)
+        ssi->channel_mode += variable_bits(gb, 2);
+
+    if (ssi->channel_mode == 11 ||
+        ssi->channel_mode == 12 ||
+        ssi->channel_mode == 13 ||
+        ssi->channel_mode == 14) {
+        ssi->back_channels_present = get_bits1(gb);
+        ssi->centre_present        = get_bits1(gb);
+        ssi->top_channels_present  = get_bits(gb, 2);
+    }
+
+    if (s->fs_index && get_bits1(gb))
+        ssi->sf_multiplier = 1 + get_bits1(gb);
+    av_log(s->avctx, AV_LOG_DEBUG, "sf_multiplier: %d\n", ssi->sf_multiplier);
+
+    if (get_bits1(gb))
+        ssi->bitrate_indicator = get_vlc2(gb, bitrate_indicator_vlc.table, bitrate_indicator_vlc.bits, 1);
+
+    if (ssi->channel_mode == 7 ||
+        ssi->channel_mode == 8 ||
+        ssi->channel_mode == 9 ||
+        ssi->channel_mode == 10)
+        ssi->add_ch_base = get_bits1(gb);
+
+    for (int i = 0; i < p->frame_rate_factor; i++)
+        ssi->iframe[i] = get_bits1(gb);
+
+    if (substreams_present) {
+        ssi->substream_index = get_bits(gb, 2);
+        if (ssi->substream_index == 3)
+            ssi->substream_index += variable_bits(gb, 2);
+        av_log(s->avctx, AV_LOG_DEBUG, "substream index: %d\n", ssi->substream_index);
+    }
+
+    return 0;
+}
+
+static int ac4_substream_group_info(AC4DecodeContext *s,
+                                    SubstreamGroupInfo *g,
+                                    PresentationInfo *p)
+{
+    GetBitContext *gb = &s->gbc;
+    int substreams_present;
+    int n_lf_substreams;
+    int hsf_ext;
+    int sus_ver;
+
+    substreams_present = get_bits1(gb);
+    hsf_ext = get_bits1(gb);
+    if (get_bits1(gb)) {
+        n_lf_substreams = 1;
+    } else {
+        n_lf_substreams = get_bits(gb, 2) + 2;
+        if (n_lf_substreams == 5)
+            n_lf_substreams += variable_bits(gb, 2);
+    }
+    g->channel_coded = get_bits1(gb);
+    if (g->channel_coded) {
+        for (int sus = 0; sus < n_lf_substreams; sus++) {
+            if (s->version == 1) {
+                sus_ver = get_bits1(gb);
+            } else {
+                sus_ver = 1;
+            }
+            ac4_substream_info_chan(s, p, &p->ssinfo, substreams_present, sus_ver);
+            if (hsf_ext)
+                av_assert0(0);
+                //ac4_hsf_ext_substream_info(substreams_present);
+        }
+    } else {
+        av_assert0(0);
+        //if (get_bits1(gb))
+        //    oamd_substream_info(substreams_present);
+        //for (int sus = 0; sus < n_lf_substreams; sus++) {
+        //    if (get_bits1(gb)) {
+        //        ac4_substream_info_ajoc(substreams_present);
+        //        if (hsf_ext) {
+        //            ac4_hsf_ext_substream_info(substreams_present);
+        //        }
+        //    } else {
+        //        ac4_substream_info_obj(substreams_present);
+        //        if (hsf_ext)
+        //            ac4_hsf_ext_substream_info(substreams_present);
+        //    }
+        //}
+    }
+
+    if (get_bits1(gb))
+        content_type(s, NULL);
+
+    return 0;
+}
+
+static int ac4_sgi_specifier(AC4DecodeContext *s, PresentationInfo *p,
+                             SubstreamGroupInfo *g)
+{
+    GetBitContext *gb = &s->gbc;
+
+    if (s->version == 1) {
+        av_assert0(0);
+        //ac4_substream_group_info(s);
+    } else {
+        g->group_index = get_bits(gb, 3);
+        if (g->group_index == 7)
+            g->group_index += variable_bits(gb, 2);
+    }
+
+    s->total_groups = FFMAX(s->total_groups, g->group_index);
+
+    return 0;
+}
+
+static int ac4_presentation_v1_info(AC4DecodeContext *s, PresentationInfo *p)
+{
+    GetBitContext *gb = &s->gbc;
+    int single_substream_group;
+
+    single_substream_group = get_bits1(gb);
+    if (single_substream_group != 1) {
+        p->presentation_config = get_bits(gb, 3);
+        if (p->presentation_config == 7)
+            p->presentation_config += variable_bits(gb, 2);
+    }
+    if (s->version != 1)
+        p->presentation_version = get_unary(gb, 0, 31);
+
+    if (single_substream_group != 1 && p->presentation_config == 6) {
+        p->add_emdf_substreams = 1;
+    } else {
+        if (s->version != 1)
+            p->mdcompat = get_bits(gb, 3);
+
+        if (get_bits1(gb))
+            p->presentation_id = variable_bits(gb, 2);
+
+        frame_rate_multiply_info(s, p);
+        frame_rate_fractions_info(s, p);
+        emdf_info(s, &p->emdf[0]);
+
+        if (get_bits1(gb))
+            p->enable_presentation = get_bits1(gb);
+
+        if (single_substream_group == 1) {
+            ac4_sgi_specifier(s, p, &s->ssgroup[0]);
+            p->n_substream_groups = 1;
+        } else {
+            p->multi_pid = get_bits1(gb);
+            switch (p->presentation_config) {
+            case 0:
+                /* Music and Effects + Dialogue */
+                ac4_sgi_specifier(s, p, &s->ssgroup[0]);
+                ac4_sgi_specifier(s, p, &s->ssgroup[1]);
+                p->n_substream_groups = 2;
+                break;
+            case 1:
+                /* Main + DE */
+                ac4_sgi_specifier(s, p, &s->ssgroup[0]);
+                ac4_sgi_specifier(s, p, &s->ssgroup[1]);
+                p->n_substream_groups = 1;
+                break;
+            case 2:
+                /* Main + Associated Audio */
+                ac4_sgi_specifier(s, p, &s->ssgroup[0]);
+                ac4_sgi_specifier(s, p, &s->ssgroup[1]);
+                p->n_substream_groups = 2;
+                break;
+            case 3:
+                /* Music and Effects + Dialogue + Associated Audio */
+                ac4_sgi_specifier(s, p, &s->ssgroup[0]);
+                ac4_sgi_specifier(s, p, &s->ssgroup[1]);
+                ac4_sgi_specifier(s, p, &s->ssgroup[2]);
+                p->n_substream_groups = 3;
+                break;
+            case 4:
+                /* Main + DE + Associated Audio */
+                ac4_sgi_specifier(s, p, &s->ssgroup[0]);
+                ac4_sgi_specifier(s, p, &s->ssgroup[1]);
+                ac4_sgi_specifier(s, p, &s->ssgroup[2]);
+                p->n_substream_groups = 2;
+                break;
+            case 5:
+                /* Arbitrary number of roles and substream groups */
+                p->n_substream_groups = get_bits(gb, 2) + 2;
+                if (p->n_substream_groups == 5)
+                    p->n_substream_groups += variable_bits(gb, 2);
+
+                for (int sg = 0; sg < p->n_substream_groups; sg++)
+                    ac4_sgi_specifier(s, p, &s->ssgroup[sg]);
+                break;
+            default:
+                /* EMDF and other data */
+                presentation_config_ext_info(s);
+                break;
+            }
+        }
+        p->pre_virtualized = get_bits1(gb);
+        p->add_emdf_substreams = get_bits1(gb);
+        presentation_substream_info(s, &p->psinfo);
+    }
+
+    if (p->add_emdf_substreams) {
+        p->n_add_emdf_substreams = get_bits(gb, 2);
+        if (p->n_add_emdf_substreams == 0)
+            p->n_add_emdf_substreams = variable_bits(gb, 2) + 4;
+        for (int i = 0; i < p->n_add_emdf_substreams; i++)
+            emdf_info(s, &p->emdf[i]);
+    }
+
+    return 0;
+}
+
+static int get_num_ts_in_ats(int frame_length)
+{
+    if (frame_length <= 2048 && frame_length >= 1536)
+        return 2;
+
+    return 1;
+}
+
+static int ac4_toc(AC4DecodeContext *s)
+{
+    GetBitContext *gb = &s->gbc;
+    int ret;
+
+    s->version = get_bits(gb, 2);
+    if (s->version == 3)
+        s->version += variable_bits(gb, 2);
+    av_log(s->avctx, AV_LOG_DEBUG, "bitstream version: %d\n", s->version);
+    s->sequence_counter_prev = s->sequence_counter;
+    s->sequence_counter = get_bits(gb, 10);
+    av_log(s->avctx, AV_LOG_DEBUG, "sequence counter: %d\n", s->sequence_counter);
+
+    s->wait_frames = get_bits1(gb);
+    if (s->wait_frames) {
+        s->nb_wait_frames = get_bits(gb, 3);
+        if (s->nb_wait_frames > 0)
+            skip_bits(gb, 2);
+    }
+
+    s->fs_index = get_bits1(gb);
+    s->frame_rate_index = get_bits(gb, 4);
+    av_log(s->avctx, AV_LOG_DEBUG, "frame_rate_index: %d\n", s->frame_rate_index);
+    s->frame_len_base = frame_len_base_48khz[s->frame_rate_index];
+    s->num_ts_in_ats = get_num_ts_in_ats(s->frame_len_base);
+    s->frame_len_base_idx = frame_len_base_idx_48khz[s->frame_rate_index];
+    av_log(s->avctx, AV_LOG_DEBUG, "frame_len_base: %d\n", s->frame_len_base);
+    s->resampling_ratio = resampling_ratios[s->frame_rate_index];
+    s->num_qmf_timeslots = s->frame_len_base / 64;
+    s->num_aspx_timeslots = s->num_qmf_timeslots / s->num_ts_in_ats;
+    s->ts_offset_hfgen = 3 * s->num_ts_in_ats;
+    s->iframe_global = get_bits1(gb);
+    if (s->iframe_global) {
+        s->have_iframe = 1;
+    } else {
+        ret = check_sequence(s);
+        if (ret < 0)
+            return ret;
+    }
+    if (get_bits1(gb)) {
+        s->nb_presentations = 1;
+    } else {
+        if (get_bits1(gb)) {
+            s->nb_presentations = 2 + variable_bits(gb, 2);
+        } else {
+            s->nb_presentations = 0;
+        }
+    }
+
+    s->payload_base = 0;
+    if (get_bits1(gb)) {
+        s->payload_base = get_bits(gb, 5) + 1;
+        if (s->payload_base == 0x20) {
+            s->payload_base += variable_bits(gb, 3);
+        }
+    }
+
+    av_log(s->avctx, AV_LOG_DEBUG, "presentations: %d\n", s->nb_presentations);
+
+    if (s->version <= 1) {
+        for (int i = 0; i < s->nb_presentations; i++) {
+            ret = ac4_presentation_info(s, &s->pinfo[i]);
+            if (ret < 0)
+                return ret;
+        }
+    } else {
+        if (get_bits1(gb)) {
+            s->short_program_id = get_bits(gb, 16);
+            if (get_bits1(gb)) {
+                skip_bits_long(gb, 16 * 8);
+            }
+        }
+
+        for (int i = 0; i < s->nb_presentations; i++) {
+            ret = ac4_presentation_v1_info(s, &s->pinfo[i]);
+            if (ret < 0)
+                return ret;
+        }
+
+        for (int i = 0; i <= s->total_groups && s->nb_presentations; i++) {
+            ret = ac4_substream_group_info(s, &s->ssgroup[i], &s->pinfo[0]);
+            if (ret < 0)
+                return ret;
+        }
+    }
+
+    substream_index_table(s);
+
+    align_get_bits(gb);
+
+    av_log(s->avctx, AV_LOG_DEBUG, "TOC size: %d\n", get_bits_count(gb) >> 3);
+
+    return 0;
+}
+
+static int sb_to_pb(int acpl_num_param_bands_id, int acpl_qmf_band)
+{
+    if (acpl_qmf_band >= 0 &&
+        acpl_qmf_band <= 8)
+        return qmf_subbands[acpl_qmf_band][acpl_num_param_bands_id];
+    if (acpl_qmf_band >= 9 &&
+        acpl_qmf_band <= 10)
+        return qmf_subbands[9][acpl_num_param_bands_id];
+    if (acpl_qmf_band >= 11 &&
+        acpl_qmf_band <= 13)
+        return qmf_subbands[10][acpl_num_param_bands_id];
+    if (acpl_qmf_band >= 14 &&
+        acpl_qmf_band <= 17)
+        return qmf_subbands[11][acpl_num_param_bands_id];
+    if (acpl_qmf_band >= 18 &&
+        acpl_qmf_band <= 22)
+        return qmf_subbands[12][acpl_num_param_bands_id];
+    if (acpl_qmf_band >= 23 &&
+        acpl_qmf_band <= 34)
+        return qmf_subbands[13][acpl_num_param_bands_id];
+    if (acpl_qmf_band >= 35 &&
+        acpl_qmf_band <= 63)
+        return qmf_subbands[14][acpl_num_param_bands_id];
+    return 0;
+}
+
+static int acpl_config_1ch(AC4DecodeContext *s, Substream *ss, int mode)
+{
+    GetBitContext *gb = &s->gbc;
+
+    ss->acpl_qmf_band = 0;
+    ss->acpl_param_band = 0;
+    ss->acpl_num_param_bands_id = get_bits(gb, 2);
+    ss->acpl_quant_mode[0] = get_bits1(gb);
+    if (mode == ACPL_PARTIAL) {
+        ss->acpl_qmf_band = get_bits(gb, 3) + 1;
+        ss->acpl_param_band = sb_to_pb(ss->acpl_num_param_bands_id, ss->acpl_qmf_band);
+    }
+
+    return 0;
+}
+
+static int acpl_config_2ch(AC4DecodeContext *s, Substream *ss)
+{
+    GetBitContext *gb = &s->gbc;
+
+    ss->acpl_qmf_band = 0;
+    ss->acpl_param_band = 0;
+    ss->acpl_num_param_bands_id = get_bits(gb, 2);
+    ss->acpl_quant_mode[0] = get_bits1(gb);
+    ss->acpl_quant_mode[1] = get_bits1(gb);
+
+    return 0;
+}
+
+static int aspx_config(AC4DecodeContext *s, Substream *ss)
+{
+    GetBitContext *gb = &s->gbc;
+
+    ss->aspx_quant_mode_env = get_bits1(gb);
+    ss->prev_aspx_start_freq = ss->aspx_start_freq;
+    ss->aspx_start_freq = get_bits(gb, 3);
+    ss->prev_aspx_stop_freq = ss->aspx_stop_freq;
+    ss->aspx_stop_freq = get_bits(gb, 2);
+    ss->prev_aspx_master_freq_scale = ss->aspx_master_freq_scale;
+    ss->aspx_master_freq_scale = get_bits1(gb);
+    ss->aspx_interpolation = get_bits1(gb);
+    ss->aspx_preflat = get_bits1(gb);
+    ss->aspx_limiter = get_bits1(gb);
+    ss->aspx_noise_sbg = get_bits(gb, 2);
+    ss->aspx_num_env_bits_fixfix = get_bits1(gb);
+    ss->aspx_freq_res_mode = get_bits(gb, 2);
+
+    return 0;
+}
+
+static int get_transfer_length_from_idx(AC4DecodeContext *s, int idx)
+{
+    const uint16_t *transf_length_tab;
+
+    switch (s->frame_len_base) {
+    case 2048:
+        transf_length_tab = transf_length_48khz_2048;
+        break;
+    case 1920:
+        transf_length_tab = transf_length_48khz_1920;
+        break;
+    case 1536:
+        transf_length_tab = transf_length_48khz_1536;
+        break;
+    case 1024:
+        transf_length_tab = transf_length_48khz_1024;
+        break;
+    case 960:
+        transf_length_tab = transf_length_48khz_960;
+        break;
+    case 768:
+        transf_length_tab = transf_length_48khz_768;
+        break;
+    case 512:
+        transf_length_tab = transf_length_48khz_512;
+        break;
+    case 384:
+        transf_length_tab = transf_length_48khz_384;
+        break;
+    default:
+        av_assert0(0);
+    }
+
+    return transf_length_tab[idx];
+}
+
+static int asf_transform_info(AC4DecodeContext *s, Substream *ss,
+                              SubstreamChannel *ssch)
+{
+    GetBitContext *gb = &s->gbc;
+
+    if (s->frame_len_base >= 1536) {
+        ssch->scp.long_frame = get_bits1(gb);
+        if (ssch->scp.long_frame == 0) {
+            ssch->scp.transf_length_idx[0] = get_bits(gb, 2);
+            ssch->scp.transf_length_idx[1] = get_bits(gb, 2);
+            ssch->scp.transf_length[0] = get_transfer_length_from_idx(s, ssch->scp.transf_length_idx[0]);
+            ssch->scp.transf_length[1] = get_transfer_length_from_idx(s, ssch->scp.transf_length_idx[1]);
+        } else {
+            ssch->scp.transf_length[0] = s->frame_len_base;
+            ssch->scp.transf_length[1] = 0;
+        }
+    } else {
+        ssch->scp.transf_length_idx[0] = get_bits(gb, 2);
+        ssch->scp.transf_length[0] = get_transfer_length_from_idx(s, ssch->scp.transf_length_idx[0]);
+    }
+
+    return 0;
+}
+
+static int get_grp_bits(AC4DecodeContext *s, SubstreamChannel *ssch)
+{
+    if (s->frame_len_base >= 1536 && ssch->scp.long_frame == 1)
+        return 0;
+
+    if (s->frame_len_base >= 1536 && ssch->scp.long_frame == 0)
+        return n_grp_bits_a[ssch->scp.transf_length_idx[0]][ssch->scp.transf_length_idx[1]];
+
+    if (s->frame_len_base < 1536 && s->frame_len_base > 512)
+        return n_grp_bits_b[ssch->scp.transf_length_idx[0]];
+
+    if (s->frame_len_base <= 512)
+        return n_grp_bits_c[ssch->scp.transf_length_idx[0]];
+
+    return 0;
+}
+
+static int get_msfb_bits(int transf_length)
+{
+    if (transf_length <= 2048 && transf_length >= 384)
+        return 6;
+
+    if (transf_length <= 256 && transf_length >= 192)
+        return 5;
+
+    return 4;
+}
+
+static int get_side_bits(int transf_length)
+{
+    if (transf_length <= 2048 && transf_length >= 480)
+        return 5;
+
+    if (transf_length <= 384 && transf_length >= 240)
+        return 4;
+
+    return 3;
+}
+
+static int get_max_sfb(AC4DecodeContext *s, SubstreamChannel *ssch,
+                       int g)
+{
+    int idx = 0;
+
+    if (s->frame_len_base >= 1536 && (ssch->scp.long_frame == 0) &&
+        (ssch->scp.transf_length_idx[0] != ssch->scp.transf_length_idx[1])) {
+        int num_windows_0 = 1 << (3 - ssch->scp.transf_length_idx[0]);
+
+        if (g >= ssch->scp.window_to_group[num_windows_0])
+            idx = 1;
+    }
+
+    if ((ssch->scp.side_limited == 1) ||
+        (ssch->scp.dual_maxsfb == 1 && ssch->scp.side_channel == 1))  {
+        return ssch->scp.max_sfb_side[idx];
+    } else {
+        return ssch->scp.max_sfb[idx];
+    }
+}
+
+static int get_transf_length(AC4DecodeContext *s, SubstreamChannel *ssch, int g, int *idx)
+{
+    const uint16_t *transf_length_tab;
+
+    switch (s->frame_len_base) {
+    case 2048:
+        transf_length_tab = transf_length_48khz_2048;
+        break;
+    case 1920:
+        transf_length_tab = transf_length_48khz_1920;
+        break;
+    case 1536:
+        transf_length_tab = transf_length_48khz_1536;
+        break;
+    case 1024:
+        transf_length_tab = transf_length_48khz_1024;
+        break;
+    case 960:
+        transf_length_tab = transf_length_48khz_960;
+        break;
+    case 768:
+        transf_length_tab = transf_length_48khz_768;
+        break;
+    case 512:
+        transf_length_tab = transf_length_48khz_512;
+        break;
+    case 384:
+        transf_length_tab = transf_length_48khz_384;
+        break;
+    default:
+        av_assert0(0);
+    }
+
+    if (s->frame_len_base >= 1536) {
+        if (ssch->scp.long_frame == 0) {
+            int num_windows_0 = 1 << (3 - ssch->scp.transf_length_idx[0]);
+
+            if (g < ssch->scp.window_to_group[num_windows_0]) {
+                if (idx)
+                    *idx = ssch->scp.transf_length_idx[0];
+                return transf_length_tab[ssch->scp.transf_length_idx[0]];
+            } else {
+                if (idx)
+                    *idx = ssch->scp.transf_length_idx[1];
+                return transf_length_tab[ssch->scp.transf_length_idx[1]];
+            }
+        } else {
+            if (idx)
+                *idx = 4;
+            return s->frame_len_base; // long frame, the transform length equals to frame_length
+        }
+    } else {
+        if (idx)
+            *idx = ssch->scp.transf_length_idx[0];
+        return transf_length_tab[ssch->scp.transf_length_idx[0]];
+    }
+}
+
+static const int get_sfb_size(int transf_length)
+{
+    switch (transf_length) {
+    case 2048:
+        return FF_ARRAY_ELEMS(sfb_offset_48khz_2048);
+        break;
+    case 1920:
+        return FF_ARRAY_ELEMS(sfb_offset_48khz_1920);
+        break;
+    case 1536:
+        return FF_ARRAY_ELEMS(sfb_offset_48khz_1536);
+        break;
+    case 1024:
+        return FF_ARRAY_ELEMS(sfb_offset_48khz_1024);
+        break;
+    case 960:
+        return FF_ARRAY_ELEMS(sfb_offset_48khz_960);
+        break;
+    case 768:
+        return FF_ARRAY_ELEMS(sfb_offset_48khz_768);
+        break;
+    case 512:
+        return FF_ARRAY_ELEMS(sfb_offset_48khz_512);
+        break;
+    case 480:
+        return FF_ARRAY_ELEMS(sfb_offset_48khz_480);
+        break;
+    case 384:
+        return FF_ARRAY_ELEMS(sfb_offset_48khz_384);
+        break;
+    case 256:
+        return FF_ARRAY_ELEMS(sfb_offset_48khz_256);
+        break;
+    case 240:
+        return FF_ARRAY_ELEMS(sfb_offset_48khz_240);
+        break;
+    case 192:
+        return FF_ARRAY_ELEMS(sfb_offset_48khz_192);
+        break;
+    case 128:
+        return FF_ARRAY_ELEMS(sfb_offset_48khz_128);
+        break;
+    case 96:
+        return FF_ARRAY_ELEMS(sfb_offset_48khz_96);
+        break;
+    default:
+        av_assert0(0);
+    }
+    return 0;
+}
+
+static const uint16_t *get_sfb_offset(int transf_length)
+{
+    switch (transf_length) {
+    case 2048:
+        return sfb_offset_48khz_2048;
+        break;
+    case 1920:
+        return sfb_offset_48khz_1920;
+        break;
+    case 1536:
+        return sfb_offset_48khz_1536;
+        break;
+    case 1024:
+        return sfb_offset_48khz_1024;
+        break;
+    case 960:
+        return sfb_offset_48khz_960;
+        break;
+    case 768:
+        return sfb_offset_48khz_768;
+        break;
+    case 512:
+        return sfb_offset_48khz_512;
+        break;
+    case 480:
+        return sfb_offset_48khz_480;
+        break;
+    case 384:
+        return sfb_offset_48khz_384;
+        break;
+    case 256:
+        return sfb_offset_48khz_256;
+        break;
+    case 240:
+        return sfb_offset_48khz_240;
+        break;
+    case 192:
+        return sfb_offset_48khz_192;
+        break;
+    case 128:
+        return sfb_offset_48khz_128;
+        break;
+    case 96:
+        return sfb_offset_48khz_96;
+        break;
+    default:
+        av_assert0(0);
+    }
+
+    return 0;
+}
+
+static int num_sfb_96(int transf_length)
+{
+    if (transf_length >= 4096)
+        return 79;
+    else if (transf_length >= 3840)
+        return 76;
+    else if (transf_length >= 3072)
+        return 67;
+    else if (transf_length >= 2048)
+        return 57;
+    else if (transf_length >= 1920)
+        return 57;
+    else if (transf_length >= 1536)
+        return 49;
+    else if (transf_length >= 1024)
+        return 44;
+    else if (transf_length >= 920)
+        return 44;
+    else if (transf_length >= 768)
+        return 39;
+    else if (transf_length >= 512)
+        return 28;
+    else if (transf_length >= 480)
+        return 28;
+    else if (transf_length >= 384)
+        return 24;
+    else if (transf_length >= 256)
+        return 22;
+    else if (transf_length >= 240)
+        return 22;
+    else
+        return 18;
+}
+
+static int num_sfb_48(int transf_length)
+{
+    switch (transf_length) {
+    case 2048:
+        return 63; break;
+    case 1920:
+        return 61; break;
+    case 1536:
+        return 55; break;
+    case 1024:
+    case 960:
+        return 49; break;
+    case 768:
+        return 43; break;
+    case 512:
+    case 480:
+        return 36; break;
+    case 384:
+        return 33; break;
+    case 256:
+    case 240:
+        return 20; break;
+    case 192:
+        return 18; break;
+    case 128:
+    case 120:
+        return 14; break;
+    case 96:
+        return 12; break;
+    default:
+        av_assert0(0);
+    }
+
+    return 0;
+}
+
+static int asf_psy_elements(AC4DecodeContext *s, Substream *ss,
+                            SubstreamChannel *ssch, int n_grp_bits)
+{
+    int group_offset, win_offset, win;
+
+    ssch->scp.num_windows = 1;
+    ssch->scp.num_window_groups = 1;
+    ssch->scp.window_to_group[0] = 0;
+
+    if (ssch->scp.long_frame == 0) {
+        ssch->scp.num_windows = n_grp_bits + 1;
+        if (ssch->scp.different_framing) {
+            int num_windows_0 = 1 << (3 - ssch->scp.transf_length_idx[0]);
+
+            for (int i = n_grp_bits; i >= num_windows_0; i--) {
+                ssch->scp.scale_factor_grouping[i] = ssch->scp.scale_factor_grouping[i - 1];
+            }
+
+            ssch->scp.scale_factor_grouping[num_windows_0 - 1] = 0;
+            ssch->scp.num_windows++;
+        }
+
+        for (int i = 0; i < ssch->scp.num_windows - 1; i++) {
+            if (ssch->scp.scale_factor_grouping[i] == 0) {
+                ssch->scp.num_window_groups++;
+            }
+
+            ssch->scp.window_to_group[i + 1] = ssch->scp.num_window_groups - 1;
+        }
+    }
+
+    group_offset = 0;
+    win_offset = 0;
+    win = 0;
+    memset(ssch->offset2sfb, 0, sizeof(ssch->offset2sfb));
+    memset(ssch->offset2g, 0, sizeof(ssch->offset2g));
+    for (int g = 0; g < ssch->scp.num_window_groups; g++) {
+        int transf_length_g = get_transf_length(s, ssch, g, NULL);
+        const uint16_t *sfb_offset = get_sfb_offset(transf_length_g);
+        const int sfb_max_size = get_sfb_size(transf_length_g);
+        int max_sfb;
+
+        ssch->scp.num_win_in_group[g] = 0;
+        for (int w = 0; w < ssch->scp.num_windows; w++) {
+            if (ssch->scp.window_to_group[w] == g)
+                ssch->scp.num_win_in_group[g]++;
+        }
+
+        max_sfb = get_max_sfb(s, ssch, g);
+        if (max_sfb > sfb_max_size) {
+            av_log(s->avctx, AV_LOG_ERROR, "max_sfb=%d > sfb_max_size=%d\n", max_sfb, sfb_max_size);
+            return AVERROR_INVALIDDATA;
+        }
+        for (int sfb = 0; sfb < max_sfb; sfb++)
+            ssch->sect_sfb_offset[g][sfb] = group_offset + sfb_offset[sfb] * ssch->scp.num_win_in_group[g];
+        group_offset += sfb_offset[max_sfb] * ssch->scp.num_win_in_group[g];
+        ssch->sect_sfb_offset[g][max_sfb] = group_offset;
+        for (int sfb = 0; sfb < max_sfb; sfb++) {
+            for (int j = ssch->sect_sfb_offset[g][sfb]; j < ssch->sect_sfb_offset[g][sfb+1]; j++) {
+                ssch->offset2sfb[j] = sfb;
+                ssch->offset2g[j] = g;
+            }
+        }
+
+        for (int w = 0; w < ssch->scp.num_win_in_group[g]; w++) {
+            ssch->win_offset[win + w] = win_offset;
+            win_offset += transf_length_g;
+        }
+        win += ssch->scp.num_win_in_group[g];
+    }
+
+    av_log(s->avctx, AV_LOG_DEBUG, "long_frame: %d\n", ssch->scp.long_frame);
+    av_log(s->avctx, AV_LOG_DEBUG, "different_framing: %d\n", ssch->scp.different_framing);
+    av_log(s->avctx, AV_LOG_DEBUG, "num_windows: %d\n", ssch->scp.num_windows);
+    av_log(s->avctx, AV_LOG_DEBUG, "num_window_groups: %d\n", ssch->scp.num_window_groups);
+    av_log(s->avctx, AV_LOG_DEBUG, "transf_lengths:");
+    for (int g = 0; g < ssch->scp.num_window_groups; g++) {
+        av_log(s->avctx, AV_LOG_DEBUG, " %d", get_transf_length(s, ssch, g, NULL));
+    }
+    av_log(s->avctx, AV_LOG_DEBUG, "\n");
+    av_log(s->avctx, AV_LOG_DEBUG, "num_win_in_group:");
+    for (int g = 0; g < ssch->scp.num_window_groups; g++) {
+        av_log(s->avctx, AV_LOG_DEBUG, " %d", ssch->scp.num_win_in_group[g]);
+    }
+    av_log(s->avctx, AV_LOG_DEBUG, "\n");
+
+    return 0;
+}
+
+static int asf_psy_info(AC4DecodeContext *s, Substream *ss,
+                        SubstreamChannel *ssch,
+                        int dual_maxsfb, int side_limited)
+{
+    GetBitContext *gb = &s->gbc;
+    int n_side_bits = get_side_bits(ssch->scp.transf_length[0]);
+    int n_msfb_bits = get_msfb_bits(ssch->scp.transf_length[0]);
+    int n_grp_bits = get_grp_bits(s, ssch);
+
+    ssch->scp.different_framing = 0;
+    if ((s->frame_len_base >= 1536) && (ssch->scp.long_frame == 0) &&
+        (ssch->scp.transf_length_idx[0] != ssch->scp.transf_length_idx[1])) {
+        ssch->scp.different_framing = 1;
+    }
+
+    if (side_limited) {
+        ssch->scp.max_sfb_side[0] = get_bits(gb, n_side_bits);
+    } else {
+        ssch->scp.max_sfb[0] = get_bits(gb, n_msfb_bits);
+        if (dual_maxsfb)
+            ssch->scp.max_sfb_side[0] = get_bits(gb, n_msfb_bits);
+    }
+
+    if (ssch->scp.different_framing) {
+        n_side_bits = get_side_bits(ssch->scp.transf_length[1]);
+        n_msfb_bits = get_msfb_bits(ssch->scp.transf_length[1]);
+
+        if (side_limited) {
+            ssch->scp.max_sfb_side[1] = get_bits(gb, n_side_bits);
+        } else {
+            ssch->scp.max_sfb[1] = get_bits(gb, n_msfb_bits);
+            if (dual_maxsfb)
+                ssch->scp.max_sfb_side[1] = get_bits(gb, n_msfb_bits);
+        }
+    }
+
+    memset(ssch->scp.scale_factor_grouping, 0, sizeof(ssch->scp.scale_factor_grouping));
+    for (int i = 0; i < n_grp_bits; i++)
+        ssch->scp.scale_factor_grouping[i] = get_bits1(gb);
+
+    return asf_psy_elements(s, ss, ssch, n_grp_bits);
+}
+
+static int sf_info(AC4DecodeContext *s, Substream *ss,
+                   SubstreamChannel *ssch,
+                   int spec_frontend, int dual_maxsfb,
+                   int side_limited)
+{
+    int ret = 0;
+
+    ssch->scp.dual_maxsfb = dual_maxsfb;
+    ssch->scp.side_limited = side_limited;
+
+    if (spec_frontend == SF_ASF) {
+        asf_transform_info(s, ss, ssch);
+        ret = asf_psy_info(s, ss, ssch, dual_maxsfb, side_limited);
+    }
+
+    return ret;
+}
+
+static int sap_data(AC4DecodeContext *s, Substream *ss, SubstreamChannel *ssch)
+{
+    GetBitContext *gb = &s->gbc;
+
+    if (!get_bits1(gb)) {
+        for (int g = 0; g < ssch->scp.num_window_groups; g++) {
+            int max_sfb_g = get_max_sfb(s, ssch, g);
+
+            for (int sfb = 0; sfb < max_sfb_g; sfb += 2) {
+                ssch->sap_coeff_used[g][sfb] = get_bits1(gb);
+                if (sfb + 1 < max_sfb_g)
+                    ssch->sap_coeff_used[g][sfb + 1] = ssch->sap_coeff_used[g][sfb];
+            }
+        }
+    } else {
+        for (int g = 0; g < ssch->scp.num_window_groups; g++) {
+            int max_sfb_g = get_max_sfb(s, ssch, g);
+
+            for (int sfb = 0; sfb < max_sfb_g; sfb++)
+                ssch->sap_coeff_used[g][sfb] = 1;
+        }
+    }
+
+    ssch->delta_code_time = 0;
+    if (ssch->scp.num_window_groups != 1)
+        ssch->delta_code_time = get_bits1(gb);
+
+    for (int g = 0; g < ssch->scp.num_window_groups; g++) {
+        int max_sfb_g = get_max_sfb(s, ssch, g);
+
+        for (int sfb = 0; sfb < max_sfb_g; sfb += 2) {
+            if (ssch->sap_coeff_used[g][sfb]) {
+                ssch->dpcm_alpha_q[g][sfb] = get_vlc2(gb, scale_factors_vlc.table, scale_factors_vlc.bits, 3);
+                if (ssch->dpcm_alpha_q[g][sfb] < 0)
+                    return AVERROR_INVALIDDATA;
+            }
+        }
+    }
+
+    return 0;
+}
+
+static int ssf_data(AC4DecodeContext *s, Substream *ss,
+                    SubstreamChannel *ssch, int iframe)
+{
+    av_assert0(0);
+
+    return 0;
+}
+
+static int asf_section_data(AC4DecodeContext *s, Substream *ss, SubstreamChannel *ssch)
+{
+    GetBitContext *gb = &s->gbc;
+
+    memset(&ssch->sect_cb, 0, sizeof(ssch->sect_cb));
+    memset(&ssch->sfb_cb, 0, sizeof(ssch->sfb_cb));
+
+    for (int g = 0; g < ssch->scp.num_window_groups; g++) {
+        int transf_length_g = get_transf_length(s, ssch, g, NULL);
+        int sect_esc_val;
+        int n_sect_bits;
+        int k, i, max_sfb;
+
+        if (transf_length_g <= 512) {
+            sect_esc_val = (1 << 3) - 1;
+            n_sect_bits = 3;
+        } else {
+            sect_esc_val = (1 << 5) - 1;
+            n_sect_bits = 5;
+        }
+        k = 0;
+        i = 0;
+        ssch->num_sec_lsf[g] = 0;
+        max_sfb = get_max_sfb(s, ssch, g);
+        while (k < max_sfb) {
+            int sect_len_incr;
+            int sect_len;
+
+            ssch->sect_cb[g][i] = get_bits(gb, 4);
+            if (ssch->sect_cb[g][i] > 11) {
+                av_log(s->avctx, AV_LOG_ERROR, "sect_cb[%d][%d] > 11\n", g, i);
+                return AVERROR_INVALIDDATA;
+            }
+            sect_len = 1;
+            sect_len_incr = get_bits(gb, n_sect_bits);
+            while (sect_len_incr == sect_esc_val) {
+                sect_len += sect_esc_val;
+                sect_len_incr = get_bits(gb, n_sect_bits);
+            }
+
+            sect_len += sect_len_incr;
+            ssch->sect_start[g][i] = k;
+            ssch->sect_end[g][i] = k + sect_len;
+
+            if (ssch->sect_start[g][i] < num_sfb_48(transf_length_g) &&
+                ssch->sect_end[g][i] >= num_sfb_48(transf_length_g)) {
+                ssch->num_sec_lsf[g] = i + 1;
+                if (ssch->sect_end[g][i] > num_sfb_48(transf_length_g)) {
+                    ssch->sect_end[g][i] = num_sfb_48(transf_length_g);
+                    i++;
+                    ssch->sect_start[g][i] = num_sfb_48(transf_length_g);
+                    ssch->sect_end[g][i] = k + sect_len;
+                    ssch->sect_cb[g][i] = ssch->sect_cb[g][i-1];
+                }
+            }
+
+            for (int sfb = k; sfb < k + sect_len; sfb++)
+                ssch->sfb_cb[g][sfb] = ssch->sect_cb[g][i];
+            k += sect_len;
+            i++;
+        }
+
+        ssch->num_sec[g] = i;
+        if (ssch->num_sec_lsf[g] == 0)
+            ssch->num_sec_lsf[g] = ssch->num_sec[g];
+    }
+
+    return 0;
+}
+
+static int ext_decode(AC4DecodeContext *s)
+{
+    GetBitContext *gb = &s->gbc;
+    int b, ext_val, N_ext = 0;
+
+    b = get_bits1(gb);
+    while (b) {
+        N_ext++;
+        b = get_bits1(gb);
+    }
+
+    ext_val = get_bits(gb, N_ext + 4);
+
+    return (1 << (N_ext + 4)) + ext_val;
+}
+
+static int asf_spectral_data(AC4DecodeContext *s, Substream *ss, SubstreamChannel *ssch)
+{
+    GetBitContext *gb = &s->gbc;
+
+    memset(&ssch->max_quant_idx, 0, sizeof(ssch->max_quant_idx));
+    memset(&ssch->quant_spec, 0, sizeof(ssch->quant_spec));
+
+    for (int g = 0; g < ssch->scp.num_window_groups; g++) {
+        for (int i = 0; i < ssch->num_sec_lsf[g]; i++) {
+            int sect_start_line, sect_end_line, cb;
+
+            if (ssch->sect_cb[g][i] == 0 || ssch->sect_cb[g][i] > 11)
+                continue;
+
+            sect_start_line = ssch->sect_sfb_offset[g][ssch->sect_start[g][i]];
+            sect_end_line = ssch->sect_sfb_offset[g][ssch->sect_end[g][i]];
+            cb = ssch->sect_cb[g][i] - 1;
+
+            for (int k = sect_start_line; k < sect_end_line;) {
+                int cb_off = asf_codebook_off[cb];
+                int cb_mod = asf_codebook_mod[cb];
+                int x;
+
+                if (asf_codebook_dim[cb] == 4) {
+                    int cb_idx = get_vlc2(gb, asf_codebook_vlc[cb].table, asf_codebook_vlc[cb].bits, 3);
+                    int cb_mod2 = 9;
+                    int cb_mod3 = 27;
+
+                    if (cb_idx < 0)
+                        return AVERROR_INVALIDDATA;
+
+                    ssch->quant_spec[k]   = (cb_idx / cb_mod3) - cb_off;
+                    cb_idx -= (ssch->quant_spec[k]   + cb_off) * cb_mod3;
+                    ssch->quant_spec[k+1] = (cb_idx / cb_mod2) - cb_off;
+                    cb_idx -= (ssch->quant_spec[k+1] + cb_off) * cb_mod2;
+                    ssch->quant_spec[k+2] = (cb_idx / cb_mod)  - cb_off;
+                    cb_idx -= (ssch->quant_spec[k+2] + cb_off) * cb_mod;
+                    ssch->quant_spec[k+3] = cb_idx - cb_off;
+
+                    if (asf_codebook_unsigned[cb]) {
+                        if (ssch->quant_spec[k] && get_bits1(gb))
+                            ssch->quant_spec[k]   = -ssch->quant_spec[k];
+                        if (ssch->quant_spec[k+1] && get_bits1(gb))
+                            ssch->quant_spec[k+1] = -ssch->quant_spec[k+1];
+                        if (ssch->quant_spec[k+2] && get_bits1(gb))
+                            ssch->quant_spec[k+2] = -ssch->quant_spec[k+2];
+                        if (ssch->quant_spec[k+3] && get_bits1(gb))
+                            ssch->quant_spec[k+3] = -ssch->quant_spec[k+3];
+                    }
+                    x = ssch->offset2sfb[k];
+                    ssch->max_quant_idx[g][x] = FFMAX(ssch->max_quant_idx[g][x], FFABS(ssch->quant_spec[k]));
+                    x = ssch->offset2sfb[k+1];
+                    ssch->max_quant_idx[g][x] = FFMAX(ssch->max_quant_idx[g][x], FFABS(ssch->quant_spec[k+1]));
+                    x = ssch->offset2sfb[k+2];
+                    ssch->max_quant_idx[g][x] = FFMAX(ssch->max_quant_idx[g][x], FFABS(ssch->quant_spec[k+2]));
+                    x = ssch->offset2sfb[k+3];
+                    ssch->max_quant_idx[g][x] = FFMAX(ssch->max_quant_idx[g][x], FFABS(ssch->quant_spec[k+3]));
+                    k += 4;
+                } else { /* (asf_codebook_dim[ssch->sect_cb[g][i]] == 2) */
+                    int cb_idx = get_vlc2(gb, asf_codebook_vlc[cb].table, asf_codebook_vlc[cb].bits, 3);
+                    int sign0 = 0, sign1 = 0;
+
+                    if (cb_idx < 0)
+                        return AVERROR_INVALIDDATA;
+
+                    ssch->quant_spec[k]  = (cb_idx / cb_mod) - cb_off;
+                    cb_idx -= (ssch->quant_spec[k] + cb_off) * cb_mod;
+                    ssch->quant_spec[k+1] = cb_idx - cb_off;
+
+                    if (asf_codebook_unsigned[cb]) {
+                        if (ssch->quant_spec[k] && get_bits1(gb))
+                            sign0 = 1;
+                        if (ssch->quant_spec[k+1] && get_bits1(gb))
+                            sign1 = 1;
+                    }
+                    if (ssch->sect_cb[g][i] == 11) {
+                        if (ssch->quant_spec[k] == 16)
+                            ssch->quant_spec[k] = ext_decode(s);
+                        if (ssch->quant_spec[k+1] == 16)
+                            ssch->quant_spec[k+1] = ext_decode(s);
+                    }
+
+                    if (sign0)
+                        ssch->quant_spec[k] = -ssch->quant_spec[k];
+                    if (sign1)
+                        ssch->quant_spec[k+1] = -ssch->quant_spec[k+1];
+
+                    x = ssch->offset2sfb[k];
+                    ssch->max_quant_idx[g][x] = FFMAX(ssch->max_quant_idx[g][x], FFABS(ssch->quant_spec[k]));
+                    x = ssch->offset2sfb[k+1];
+                    ssch->max_quant_idx[g][x] = FFMAX(ssch->max_quant_idx[g][x], FFABS(ssch->quant_spec[k+1]));
+                    k += 2;
+                }
+            }
+        }
+    }
+
+    return 0;
+}
+
+static int asf_scalefac_data(AC4DecodeContext *s, Substream *ss, SubstreamChannel *ssch)
+{
+    GetBitContext *gb = &s->gbc;
+    int first_scf_found = 0;
+    int scale_factor;
+
+    scale_factor = get_bits(gb, 8);
+    memset(ssch->sf_gain, 0, sizeof(ssch->sf_gain));
+
+    for (int g = 0; g < ssch->scp.num_window_groups; g++) {
+        int max_sfb = FFMIN(get_max_sfb(s, ssch, g), num_sfb_48(get_transf_length(s, ssch, g, NULL)));
+
+        for (int sfb = 0; sfb < max_sfb; sfb++) {
+            if ((ssch->sfb_cb[g][sfb]) != 0 && (ssch->max_quant_idx[g][sfb] > 0)) {
+                if (first_scf_found == 1) {
+                    ssch->dpcm_sf[g][sfb] = get_vlc2(gb, scale_factors_vlc.table, scale_factors_vlc.bits, 3);
+                    if (ssch->dpcm_sf[g][sfb] < 0)
+                        return AVERROR_INVALIDDATA;
+                    scale_factor += ssch->dpcm_sf[g][sfb] - 60;
+                } else {
+                    first_scf_found = 1;
+                }
+
+                ssch->sf_gain[g][sfb] = powf(2.f, 0.25f * (scale_factor - 100));
+            }
+        }
+    }
+
+    return 0;
+}
+
+static int asf_snf_data(AC4DecodeContext *s, Substream *ss, SubstreamChannel *ssch)
+{
+    GetBitContext *gb = &s->gbc;
+
+    ssch->snf_data_exists = get_bits1(gb);
+    if (ssch->snf_data_exists) {
+        for (int g = 0; g < ssch->scp.num_window_groups; g++) {
+            int transf_length_g = get_transf_length(s, ssch, g, NULL);
+            int max_sfb = FFMIN(get_max_sfb(s, ssch, g), num_sfb_48(transf_length_g));
+
+            for (int sfb = 0; sfb < max_sfb; sfb++) {
+                if ((ssch->sfb_cb[g][sfb] == 0) || (ssch->max_quant_idx[g][sfb] == 0)) {
+                    ssch->dpcm_snf[g][sfb] = get_vlc2(gb, snf_vlc.table, snf_vlc.bits, 3);
+                    if (ssch->dpcm_snf[g][sfb] < 0)
+                        return AVERROR_INVALIDDATA;
+                }
+            }
+        }
+    }
+
+    return 0;
+}
+
+static int sf_data(AC4DecodeContext *s, Substream *ss, SubstreamChannel *ssch,
+                   int iframe, int spec_frontend)
+{
+    int ret;
+
+    if (spec_frontend == SF_ASF) {
+        ret = asf_section_data(s, ss, ssch);
+        if (ret < 0)
+            return ret;
+        ret = asf_spectral_data(s, ss, ssch);
+        if (ret < 0)
+            return ret;
+        ret = asf_scalefac_data(s, ss, ssch);
+        if (ret < 0)
+            return ret;
+        ret = asf_snf_data(s, ss, ssch);
+        if (ret < 0)
+            return ret;
+    } else {
+        ssf_data(s, ss, ssch, iframe);
+    }
+
+    return 0;
+}
+
+static int chparam_info(AC4DecodeContext *s, Substream *ss, SubstreamChannel *ssch)
+{
+    GetBitContext *gb = &s->gbc;
+    int ret;
+
+    ssch->sap_mode = get_bits(gb, 2);
+    av_log(s->avctx, AV_LOG_DEBUG, "sap_mode: %d\n", ssch->sap_mode);
+
+    if (ssch->sap_mode == 1) {
+        for (int g = 0; g < ssch->scp.num_window_groups; g++) {
+            int max_sfb_g = get_max_sfb(s, ssch, g);
+
+            for (int sfb = 0; sfb < max_sfb_g; sfb++) {
+                ssch->ms_used[g][sfb] = get_bits1(gb);
+            }
+        }
+    }
+
+    if (ssch->sap_mode == 3) {
+        ret = sap_data(s, ss, ssch);
+        if (ret < 0)
+            return ret;
+    }
+
+    return 0;
+}
+
+static int stereo_data(AC4DecodeContext *s, Substream *ss, int iframe)
+{
+    GetBitContext *gb = &s->gbc;
+    int ret;
+
+    ss->mdct_stereo_proc[0] = get_bits1(gb);
+    if (ss->mdct_stereo_proc[0]) {
+        ss->spec_frontend_l = SF_ASF;
+        ss->spec_frontend_r = SF_ASF;
+        ret = sf_info(s, ss, &ss->ssch[0], SF_ASF, 0, 0);
+        if (ret < 0)
+            return ret;
+
+        memcpy(&ss->ssch[1].scp, &ss->ssch[0].scp, sizeof(ss->ssch[0].scp));
+        memcpy(&ss->ssch[1].sect_sfb_offset, &ss->ssch[0].sect_sfb_offset, sizeof(ss->ssch[0].sect_sfb_offset));
+        memcpy(&ss->ssch[1].offset2sfb, &ss->ssch[0].offset2sfb, sizeof(ss->ssch[0].offset2sfb));
+        memcpy(&ss->ssch[1].offset2g, &ss->ssch[0].offset2g, sizeof(ss->ssch[0].offset2g));
+        memcpy(&ss->ssch[1].win_offset, &ss->ssch[0].win_offset, sizeof(ss->ssch[0].win_offset));
+
+        ret = chparam_info(s, ss, &ss->ssch[0]);
+        if (ret < 0)
+            return ret;
+    } else {
+        ss->spec_frontend_l = get_bits1(gb);
+        sf_info(s, ss, &ss->ssch[0], ss->spec_frontend_l, 0, 0);
+        ss->spec_frontend_r = get_bits1(gb);
+        sf_info(s, ss, &ss->ssch[1], ss->spec_frontend_r, 0, 0);
+    }
+
+    ret = sf_data(s, ss, &ss->ssch[0], iframe, ss->spec_frontend_l);
+    if (ret < 0)
+        return ret;
+    ret = sf_data(s, ss, &ss->ssch[1], iframe, ss->spec_frontend_r);
+    if (ret < 0)
+        return ret;
+
+    return 0;
+}
+
+static int companding_control(AC4DecodeContext *s, Substream *ss, int num_chan)
+{
+    GetBitContext *gb = &s->gbc;
+    int sync_flag = 0;
+    int need_avg = 0;
+    int nc;
+
+    if (num_chan > 1)
+        sync_flag = get_bits1(gb);
+
+    nc = sync_flag ? 1 : num_chan;
+
+    for (int i = 0; i < nc; i++) {
+        ss->compand_on[i] = get_bits1(gb);
+        if (!ss->compand_on[i])
+            need_avg = 1;
+    }
+
+    if (need_avg == 1)
+        ss->compand_avg = get_bits1(gb);
+
+    return 0;
+}
+
+static int noise_mid_border(int aspx_tsg_ptr, int aspx_int_class, int num_atsg_sig)
+{
+    if (aspx_tsg_ptr == -1) {
+       if (aspx_int_class == VARFIX)
+           return 1;
+       else
+           return num_atsg_sig - 1;
+    } else if (aspx_tsg_ptr >= 0) {
+       if (aspx_int_class == VARFIX)
+           return num_atsg_sig - 1;
+       else
+           return FFMAX(1, FFMIN(num_atsg_sig - 1, aspx_tsg_ptr));
+    } else {
+        av_assert0(0);
+    }
+
+    return 0;
+}
+
+static int freq_res(int *atsg_sig, int atsg, int aspx_tsg_ptr,
+                    int num_aspx_timeslots, int aspx_freq_res_mode,
+                    int *aspx_freq_res)
+{
+    int freq_res;
+
+    switch (aspx_freq_res_mode) {
+    case 0:
+        freq_res = aspx_freq_res[atsg];
+        break;
+    case 1:
+        freq_res = 0;
+        break;
+    case 2:
+        if ((atsg < aspx_tsg_ptr && num_aspx_timeslots > 8) ||
+            (atsg_sig[atsg+1]-atsg_sig[atsg]) > (num_aspx_timeslots/6.0+3.25))
+            freq_res = 1;
+        else
+            freq_res = 0;
+        break;
+    case 3:
+        freq_res = 1;
+        break;
+    default:
+        av_assert0(0);
+    }
+
+    return freq_res;
+}
+
+static void get_tab_border(int *atsg_sig, int num_aspx_timeslots, int num_atsg)
+{
+    switch (num_aspx_timeslots) {
+    case 6:
+        memcpy(atsg_sig, tab_border[0][num_atsg >> 1], sizeof(tab_border[0][0]));
+        break;
+    case 8:
+        memcpy(atsg_sig, tab_border[1][num_atsg >> 1], sizeof(tab_border[0][0]));
+        break;
+    case 12:
+        memcpy(atsg_sig, tab_border[2][num_atsg >> 1], sizeof(tab_border[0][0]));
+        break;
+    case 15:
+        memcpy(atsg_sig, tab_border[3][num_atsg >> 1], sizeof(tab_border[0][0]));
+        break;
+    case 16:
+        memcpy(atsg_sig, tab_border[4][num_atsg >> 1], sizeof(tab_border[0][0]));
+        break;
+    default:
+        av_assert0(0);
+    }
+}
+
+static int aspx_atsg(AC4DecodeContext *s, Substream *ss, SubstreamChannel *ssch, int iframe)
+{
+    int num_atsg_sig = ssch->aspx_num_env;
+    int num_atsg_noise = ssch->aspx_num_noise;
+
+    if (ssch->aspx_int_class == FIXFIX) {
+        get_tab_border(ssch->atsg_sig, s->num_aspx_timeslots, num_atsg_sig);
+        get_tab_border(ssch->atsg_noise, s->num_aspx_timeslots, num_atsg_noise);
+        ssch->atsg_freqres[0] = freq_res(ssch->atsg_sig, 0, 0, s->num_aspx_timeslots,
+                                         ss->aspx_freq_res_mode, ssch->aspx_freq_res);
+        for (int atsg = 1; atsg < num_atsg_sig; atsg++)
+            ssch->atsg_freqres[atsg] = ssch->atsg_freqres[0];
+    } else {
+        switch (ssch->aspx_int_class) {
+        case FIXVAR:
+            ssch->atsg_sig[0] = 0;
+            ssch->atsg_sig[num_atsg_sig] = ssch->aspx_var_bord_right + s->num_aspx_timeslots;
+            for (int tsg = 0; tsg < ssch->aspx_num_rel_right; tsg++)
+                ssch->atsg_sig[num_atsg_sig-tsg-1] = ssch->atsg_sig[num_atsg_sig-tsg] - ssch->aspx_rel_bord_right[tsg];
+            break;
+        case VARFIX:
+            if (iframe)
+                ssch->atsg_sig[0] = ssch->aspx_var_bord_left;
+            else
+                ssch->atsg_sig[0] = ssch->previous_stop_pos - s->num_aspx_timeslots;
+            ssch->atsg_sig[num_atsg_sig] = s->num_aspx_timeslots;
+            for (int tsg = 0; tsg < ssch->aspx_num_rel_left; tsg++)
+                ssch->atsg_sig[tsg+1] = ssch->atsg_sig[tsg] + ssch->aspx_rel_bord_left[tsg];
+            break;
+        case VARVAR:
+            if (iframe)
+                ssch->atsg_sig[0] = ssch->aspx_var_bord_left;
+            else
+                ssch->atsg_sig[0] = ssch->previous_stop_pos - s->num_aspx_timeslots;
+            ssch->atsg_sig[num_atsg_sig] = ssch->aspx_var_bord_right + s->num_aspx_timeslots;
+            for (int tsg = 0; tsg < ssch->aspx_num_rel_left; tsg++)
+                ssch->atsg_sig[tsg+1] = ssch->atsg_sig[tsg] + ssch->aspx_rel_bord_left[tsg];
+            for (int tsg = 0; tsg < ssch->aspx_num_rel_right; tsg++)
+                ssch->atsg_sig[num_atsg_sig-tsg-1] = ssch->atsg_sig[num_atsg_sig-tsg] - ssch->aspx_rel_bord_right[tsg];
+            break;
+        }
+
+        ssch->atsg_noise[0] = ssch->atsg_sig[0];
+        ssch->atsg_noise[num_atsg_noise] = ssch->atsg_sig[num_atsg_sig];
+        if (num_atsg_noise > 1)
+            ssch->atsg_noise[1] = ssch->atsg_sig[noise_mid_border(ssch->aspx_tsg_ptr,
+                                                                  ssch->aspx_int_class,
+                                                                  num_atsg_sig)];
+        for (int atsg = 0; atsg < num_atsg_sig; atsg++)
+            ssch->atsg_freqres[atsg] = freq_res(ssch->atsg_sig, atsg, ssch->aspx_tsg_ptr,
+                                                s->num_aspx_timeslots, ss->aspx_freq_res_mode,
+                                                ssch->aspx_freq_res);
+    }
+
+    ssch->previous_stop_pos = ssch->atsg_sig[num_atsg_sig];
+
+    for (int atsg = 0; atsg < num_atsg_sig; atsg++) {
+        if (ssch->atsg_freqres[atsg]) {
+            ssch->num_sbg_sig[atsg] = ssch->num_sbg_sig_highres;
+            memcpy(ssch->sbg_sig[atsg], ssch->sbg_sig_highres, 24 * 4);
+        } else {
+            ssch->num_sbg_sig[atsg] = ssch->num_sbg_sig_lowres;
+            memcpy(ssch->sbg_sig[atsg], ssch->sbg_sig_lowres, 24 * 4);
+        }
+    }
+
+    return 0;
+}
+
+static int aspx_framing(AC4DecodeContext *s, Substream *ss, SubstreamChannel *ssch, int iframe)
+{
+    GetBitContext *gb = &s->gbc;
+
+    ssch->aspx_num_rel_left = 0;
+    ssch->aspx_num_rel_right = 0;
+
+    ssch->aspx_int_class = get_vlc2(gb, aspx_int_class_vlc.table, aspx_int_class_vlc.bits, 1);
+    if (ssch->aspx_int_class < 0)
+        return AVERROR_INVALIDDATA;
+
+    ssch->aspx_num_env_prev = ssch->aspx_num_env;
+
+    switch (ssch->aspx_int_class) {
+    case FIXFIX:
+        ssch->aspx_num_env = 1 << get_bits(gb, 1 + ss->aspx_num_env_bits_fixfix);
+        if (ss->aspx_freq_res_mode == 0)
+            ssch->aspx_freq_res[0] = get_bits1(gb);
+        break;
+    case FIXVAR:
+        ssch->aspx_var_bord_right = get_bits(gb, 2);
+        ssch->aspx_num_rel_right = get_bits(gb, 1 + (s->num_aspx_timeslots > 8));
+        for (int i = 0; i < ssch->aspx_num_rel_right; i++)
+            ssch->aspx_rel_bord_right[i] = 2 * get_bits(gb, 1 + (s->num_aspx_timeslots > 8)) + 2;
+        break;
+    case VARFIX:
+        if (iframe)
+            ssch->aspx_var_bord_left = get_bits(gb, 2);
+        ssch->aspx_num_rel_left = get_bits(gb, 1 + (s->num_aspx_timeslots > 8));
+        for (int i = 0; i < ssch->aspx_num_rel_left; i++)
+            ssch->aspx_rel_bord_left[i] = 2 * get_bits(gb, 1 + (s->num_aspx_timeslots > 8)) + 2;
+        break;
+    case VARVAR:
+        if (iframe)
+            ssch->aspx_var_bord_left = get_bits(gb, 2);
+        ssch->aspx_num_rel_left = get_bits(gb, 1 + (s->num_aspx_timeslots > 8));
+        for (int i = 0; i < ssch->aspx_num_rel_left; i++)
+            ssch->aspx_rel_bord_left[i] = 2 * get_bits(gb, 1 + (s->num_aspx_timeslots > 8)) + 2;
+        ssch->aspx_var_bord_right = get_bits(gb, 2);
+        ssch->aspx_num_rel_right = get_bits(gb, 1 + (s->num_aspx_timeslots > 8));
+        for (int i = 0; i < ssch->aspx_num_rel_right; i++)
+            ssch->aspx_rel_bord_right[i] = 2 * get_bits(gb, 1 + (s->num_aspx_timeslots > 8)) + 2;
+        break;
+    }
+
+    if (ssch->aspx_int_class != FIXFIX) {
+        int ptr_bits;
+
+        ssch->aspx_num_env = ssch->aspx_num_rel_left + ssch->aspx_num_rel_right + 1;
+        ptr_bits = ceilf(logf(ssch->aspx_num_env + 2) / logf(2));
+        ssch->aspx_tsg_ptr_prev = ssch->aspx_tsg_ptr;
+        ssch->aspx_tsg_ptr = (int)get_bits(gb, ptr_bits) - 1;
+        if (ss->aspx_freq_res_mode == 0)
+            for (int env = 0; env < ssch->aspx_num_env; env++)
+                ssch->aspx_freq_res[env] = get_bits1(gb);
+    }
+
+    ssch->aspx_num_noise_prev = ssch->aspx_num_noise;
+
+    if (ssch->aspx_num_env > 1)
+        ssch->aspx_num_noise = 2;
+    else
+        ssch->aspx_num_noise = 1;
+
+    if (!ssch->aspx_num_env_prev)
+        ssch->aspx_num_env_prev = ssch->aspx_num_env;
+    if (!ssch->aspx_num_noise_prev)
+        ssch->aspx_num_noise_prev = ssch->aspx_num_noise;
+
+    return aspx_atsg(s, ss, ssch, iframe);
+}
+
+static void aspx_delta_dir(AC4DecodeContext *s, SubstreamChannel *ssch)
+{
+    GetBitContext *gb = &s->gbc;
+
+    for (int env = 0; env < ssch->aspx_num_env; env++)
+        ssch->aspx_sig_delta_dir[env] = get_bits1(gb);
+    for (int env = 0; env < ssch->aspx_num_noise; env++)
+        ssch->aspx_noise_delta_dir[env] = get_bits1(gb);
+}
+
+static int aspx_hfgen_iwc_2ch(AC4DecodeContext *s, Substream *ss,
+                              SubstreamChannel *ssch0,
+                              SubstreamChannel *ssch1,
+                              int aspx_balance)
+{
+    GetBitContext *gb = &s->gbc;
+    int aspx_tic_left = 0, aspx_tic_right = 0;
+
+    memcpy(ssch0->aspx_tna_mode_prev, ssch0->aspx_tna_mode, sizeof(ssch0->aspx_tna_mode));
+    memcpy(ssch1->aspx_tna_mode_prev, ssch1->aspx_tna_mode, sizeof(ssch1->aspx_tna_mode));
+
+    for (int n = 0; n < ssch0->num_sbg_noise; n++)
+        ssch0->aspx_tna_mode[n] = get_bits(gb, 2);
+    if (aspx_balance == 0) {
+        for (int n = 0; n < ssch0->num_sbg_noise; n++)
+            ssch1->aspx_tna_mode[n] = get_bits(gb, 2);
+    } else {
+        for (int n = 0; n < ssch0->num_sbg_noise; n++)
+            ssch1->aspx_tna_mode[n] = ssch0->aspx_tna_mode[n];
+    }
+    if (get_bits1(gb)) {
+        for (int n = 0; n < ssch0->num_sbg_sig_highres; n++)
+            ssch0->aspx_add_harmonic[n] = get_bits1(gb);
+    }
+    if (get_bits1(gb)) {
+        for (int n = 0; n < ssch0->num_sbg_sig_highres; n++)
+            ssch1->aspx_add_harmonic[n] = get_bits1(gb);
+    }
+
+    for (int n = 0; n < ssch0->num_sbg_sig_highres; n++)
+        ssch0->aspx_fic_used_in_sfb[n] = ssch1->aspx_fic_used_in_sfb[n] = 0;
+
+    if (get_bits1(gb)) {
+        if (get_bits1(gb)) {
+            for (int n = 0; n < ssch0->num_sbg_sig_highres; n++)
+                ssch0->aspx_fic_used_in_sfb[n] = get_bits1(gb);
+        }
+
+        if (get_bits1(gb)) {
+            for (int n = 0; n < ssch0->num_sbg_sig_highres; n++)
+                ssch1->aspx_fic_used_in_sfb[n] = get_bits1(gb);
+        }
+    }
+
+    for (int n = 0; n < s->num_aspx_timeslots; n++)
+        ssch0->aspx_tic_used_in_slot[n] = ssch1->aspx_tic_used_in_slot[n] = 0;
+
+    if (get_bits1(gb)) {
+        int aspx_tic_copy = get_bits1(gb);
+
+        if (aspx_tic_copy == 0) {
+            aspx_tic_left = get_bits1(gb);
+            aspx_tic_right = get_bits1(gb);
+        }
+
+        if (aspx_tic_copy || aspx_tic_left) {
+            for (int n = 0; n < s->num_aspx_timeslots; n++)
+                ssch0->aspx_tic_used_in_slot[n] = get_bits1(gb);
+        }
+
+        if (aspx_tic_right) {
+            for (int n = 0; n < s->num_aspx_timeslots; n++)
+                ssch1->aspx_tic_used_in_slot[n] = get_bits1(gb);
+        }
+
+        if (aspx_tic_copy) {
+            for (int n = 0; n < s->num_aspx_timeslots; n++)
+                ssch1->aspx_tic_used_in_slot[n] = ssch0->aspx_tic_used_in_slot[n];
+        }
+    }
+
+    return 0;
+}
+
+static VLC *get_aspx_hcb(int data_type, int quant_mode, int stereo_mode, int hcb_type)
+{
+    VLC *aspx_cb;
+
+    if (data_type == DT_SIGNAL)
+        aspx_cb = &aspx_codebook_signal_vlc[stereo_mode][quant_mode][hcb_type];
+    else // NOISE
+        aspx_cb = &aspx_codebook_noise_vlc[stereo_mode][hcb_type];
+
+    return aspx_cb;
+}
+
+static int get_aspx_off(int data_type, int quant_mode, int stereo_mode, int hcb_type)
+{
+    int off;
+
+    if (data_type == DT_SIGNAL)
+        off = aspx_codebook_signal_off[stereo_mode][quant_mode][hcb_type];
+    else // NOISE
+        off = aspx_codebook_noise_off[stereo_mode][hcb_type];
+
+    return off;
+}
+
+static int aspx_huff_data(AC4DecodeContext *s,
+                          int data_type, int num_sbg,
+                          int quant_mode, int stereo_mode,
+                          int direction, int *data)
+{
+    GetBitContext *gb = &s->gbc;
+    VLC *aspx_cb;
+    int aspx_off;
+
+    if (direction == 0) { // FREQ
+        aspx_cb = get_aspx_hcb(data_type, quant_mode, stereo_mode, F0);
+        aspx_off = get_aspx_off(data_type, quant_mode, stereo_mode, F0);
+        data[0] = get_vlc2(gb, aspx_cb->table, aspx_cb->bits, 3);
+        if (data[0] < 0)
+            return AVERROR_INVALIDDATA;
+        data[0] -= aspx_off;
+        aspx_cb = get_aspx_hcb(data_type, quant_mode, stereo_mode, DF);
+        aspx_off = get_aspx_off(data_type, quant_mode, stereo_mode, DF);
+        for (int i = 1; i < num_sbg; i++) {
+            data[i] = get_vlc2(gb, aspx_cb->table, aspx_cb->bits, 3);
+            if (data[i] < 0)
+                return AVERROR_INVALIDDATA;
+            data[i] -= aspx_off;
+        }
+    } else { // TIME
+        aspx_cb = get_aspx_hcb(data_type, quant_mode, stereo_mode, DT);
+        aspx_off = get_aspx_off(data_type, quant_mode, stereo_mode, DT);
+        for (int i = 0; i < num_sbg; i++) {
+            data[i] = get_vlc2(gb, aspx_cb->table, aspx_cb->bits, 3);
+            if (data[i] < 0)
+                return AVERROR_INVALIDDATA;
+            data[i] -= aspx_off;
+        }
+    }
+
+    return 0;
+}
+
+static int aspx_ec_data(AC4DecodeContext *s,
+                        Substream *ss,
+                        SubstreamChannel *ssch,
+                        int data_type, int num_env,
+                        uint8_t *freq_res, int quant_mode,
+                        int stereo_mode, int *direction)
+{
+    int dir, num_sbg, ret;
+
+    for (int env = 0; env < num_env; env++) {
+        if (data_type == DT_SIGNAL) {
+            if (freq_res[env])
+                num_sbg = ssch->num_sbg_sig_highres;
+            else
+                num_sbg = ssch->num_sbg_sig_lowres;
+        } else {
+            num_sbg = ssch->num_sbg_noise;
+        }
+        dir = direction[env];
+        ret = aspx_huff_data(s, data_type, num_sbg, quant_mode, stereo_mode, dir,
+                             ssch->aspx_data[data_type][env]);
+        if (ret < 0)
+            return ret;
+    }
+
+    return 0;
+}
+
+static int is_element_of_sbg_patches(int sbg_lim_sbg, int *sbg_patches,
+                                     int num_sbg_patches)
+{
+    for (int i = 0; i <= num_sbg_patches; i++) {
+        if (sbg_patches[i] == sbg_lim_sbg)
+            return 1;
+    }
+
+    return 0;
+}
+
+static void remove_element(int *sbg_lim, int num_sbg_lim, int sbg)
+{
+    for (int i = sbg; i < num_sbg_lim; i++)
+        sbg_lim[i] = sbg_lim[i + 1];
+}
+
+static int cmpints(const void *p1, const void *p2)
+{
+    int left  = *(const int *)p1;
+    int right = *(const int *)p2;
+    return FFDIFFSIGN(left, right);
+}
+
+static int aspx_elements(AC4DecodeContext *s, Substream *ss, SubstreamChannel *ssch)
+{
+    int master_reset = (ss->prev_aspx_start_freq != ss->aspx_start_freq) +
+                       (ss->prev_aspx_stop_freq != ss->aspx_stop_freq) +
+                       (ss->prev_aspx_master_freq_scale != ss->aspx_master_freq_scale);
+    int sb, sbg = 0, goal_sb, msb, usb;
+    int source_band_low;
+    int idx[6];
+
+    if (master_reset) {
+        if (ss->aspx_master_freq_scale == 1) {
+            ssch->num_sbg_master = 22 - 2 * ss->aspx_start_freq - 2 * ss->aspx_stop_freq;
+            for (int sbg = 0; sbg <= ssch->num_sbg_master; sbg++) {
+                ssch->sbg_master[sbg] = sbg_template_highres[2 * ss->aspx_start_freq + sbg];
+            }
+        } else {
+            ssch->num_sbg_master = 20 - 2 * ss->aspx_start_freq - 2 * ss->aspx_stop_freq;
+            for (int sbg = 0; sbg <= ssch->num_sbg_master; sbg++) {
+                ssch->sbg_master[sbg] = sbg_template_lowres[2 * ss->aspx_start_freq + sbg];
+            }
+        }
+    }
+
+    ssch->sba = ssch->sbg_master[0];
+    ssch->sbz = ssch->sbg_master[ssch->num_sbg_master];
+
+    ssch->num_sbg_sig_highres = ssch->num_sbg_master - ssch->aspx_xover_subband_offset;
+    for (int sbg = 0; sbg <= ssch->num_sbg_sig_highres; sbg++)
+        ssch->sbg_sig_highres[sbg] = ssch->sbg_master[sbg + ssch->aspx_xover_subband_offset];
+
+    ssch->sbx = ssch->sbg_sig_highres[0];
+    ssch->num_sb_aspx = ssch->sbg_sig_highres[ssch->num_sbg_sig_highres] - ssch->sbx;
+
+    ssch->num_sbg_sig_lowres = ssch->num_sbg_sig_highres - floorf(ssch->num_sbg_sig_highres / 2.);
+    ssch->sbg_sig_lowres[0] = ssch->sbg_sig_highres[0];
+    if ((ssch->num_sbg_sig_highres & 1) == 0) {
+        for (int sbg = 1; sbg <= ssch->num_sbg_sig_lowres; sbg++)
+            ssch->sbg_sig_lowres[sbg] = ssch->sbg_sig_highres[2*sbg];
+    } else {
+        for (int sbg = 1; sbg <= ssch->num_sbg_sig_lowres; sbg++)
+            ssch->sbg_sig_lowres[sbg] = ssch->sbg_sig_highres[2*sbg-1];
+    }
+
+    ssch->num_sbg_sig[0] = ssch->num_sbg_sig_lowres;
+    ssch->num_sbg_sig[1] = ssch->num_sbg_sig_highres;
+
+    ssch->num_sbg_noise = FFMAX(1, floorf(ss->aspx_noise_sbg * log2f(ssch->sbz / (float)ssch->sbx) + 0.5));
+    idx[0] = 0;
+    ssch->sbg_noise[0] = ssch->sbg_sig_lowres[0];
+    for (int sbg = 1; sbg <= ssch->num_sbg_noise; sbg++) {
+        idx[sbg] = idx[sbg-1];
+        idx[sbg] += floorf((ssch->num_sbg_sig_lowres - idx[sbg - 1]) / (float)(ssch->num_sbg_noise + 1 - sbg));
+        ssch->sbg_noise[sbg] = ssch->sbg_sig_lowres[idx[sbg]];
+    }
+
+    msb = ssch->sba;
+    usb = ssch->sbx;
+    ssch->num_sbg_patches = 0;
+    if (s->fs_index)
+        goal_sb = 43;
+    else
+        goal_sb = 46;
+    if (ss->aspx_master_freq_scale == 1)
+        source_band_low = 4;
+    else
+        source_band_low = 2;
+
+    if (goal_sb < ssch->sbx + ssch->num_sb_aspx) {
+        for (int i = 0, sbg = 0; ssch->sbg_master[i] < goal_sb; i++)
+            sbg = i + 1;
+    } else {
+        sbg = ssch->num_sbg_master;
+    }
+
+    do {
+        int odd, j = sbg;
+        sb = ssch->sbg_master[j];
+        odd = (sb - 2 + ssch->sba) % 2;
+
+        while (sb > ( ssch->sba - source_band_low + msb - odd )) {
+            j--;
+            sb = ssch->sbg_master[j];
+            odd = (sb - 2 + ssch->sba) % 2;
+        }
+
+        ssch->sbg_patch_num_sb[ssch->num_sbg_patches] = FFMAX(sb - usb, 0);
+        ssch->sbg_patch_start_sb[ssch->num_sbg_patches] = ssch->sba - odd - FFMAX(sb - usb, 0);
+        if (ssch->sbg_patch_num_sb[ssch->num_sbg_patches] > 0) {
+            usb = sb;
+            msb = sb;
+            ssch->num_sbg_patches++;
+        } else {
+            msb = ssch->sbx;
+        }
+
+        if (ssch->sbg_master[sbg] - sb < 3)
+            sbg = ssch->num_sbg_master;
+    } while (sb != (ssch->sbx + ssch->num_sb_aspx));
+
+    if ((ssch->sbg_patch_num_sb[ssch->num_sbg_patches - 1] < 3) && (ssch->num_sbg_patches > 1))
+        ssch->num_sbg_patches--;
+
+    ssch->sbg_patches[0] = ssch->sbx;
+    for (int i = 1; i <= ssch->num_sbg_patches; i++)
+        ssch->sbg_patches[i] = ssch->sbg_patches[i-1] + ssch->sbg_patch_num_sb[i-1];
+
+    /* Copy sbg_sig_lowres into lower part of limiter table */
+    for (int sbg = 0; sbg <= ssch->num_sbg_sig_lowres; sbg++)
+        ssch->sbg_lim[sbg] = ssch->sbg_sig_lowres[sbg];
+
+    /* Copy patch borders into higher part of limiter table */
+    for (int sbg = 1; sbg < ssch->num_sbg_patches; sbg++)
+        ssch->sbg_lim[sbg + ssch->num_sbg_sig_lowres] = ssch->sbg_patches[sbg];
+
+    /* Sort patch borders + low res sbg into temporary limiter table */
+    ssch->num_sbg_lim = ssch->num_sbg_sig_lowres + ssch->num_sbg_patches - 1;
+    AV_QSORT(ssch->sbg_lim, ssch->num_sbg_lim + 1, int, cmpints);
+    sbg = 1;
+
+    while (sbg <= ssch->num_sbg_lim) {
+        float num_octaves = log2(ssch->sbg_lim[sbg] / (float)ssch->sbg_lim[sbg - 1]);
+
+        if (num_octaves < 0.245) {
+            if (ssch->sbg_lim[sbg] == ssch->sbg_lim[sbg-1]) {
+                remove_element(ssch->sbg_lim, ssch->num_sbg_lim, sbg);
+                ssch->num_sbg_lim--;
+                continue;
+            } else {
+                if (is_element_of_sbg_patches(ssch->sbg_lim[sbg],
+                                              ssch->sbg_patches,
+                                              ssch->num_sbg_patches)) {
+                    if (is_element_of_sbg_patches(ssch->sbg_lim[sbg - 1],
+                                                  ssch->sbg_patches,
+                                                  ssch->num_sbg_patches)) {
+                        sbg++;
+                        continue;
+                    } else {
+                        remove_element(ssch->sbg_lim, ssch->num_sbg_lim, sbg - 1);
+                        ssch->num_sbg_lim--;
+                        continue;
+                    }
+                } else {
+                    remove_element(ssch->sbg_lim, ssch->num_sbg_lim, sbg);
+                    ssch->num_sbg_lim--;
+                    continue;
+                }
+            }
+        } else {
+            sbg++;
+            continue;
+        }
+    }
+
+    return 0;
+}
+
+static int aspx_data_2ch(AC4DecodeContext *s, Substream *ss,
+                         SubstreamChannel *ssch0, SubstreamChannel *ssch1,
+                         int iframe)
+{
+    GetBitContext *gb = &s->gbc;
+    int ret;
+
+    if (iframe) {
+        ssch0->aspx_xover_subband_offset = get_bits(gb, 3);
+        ssch1->aspx_xover_subband_offset = ssch0->aspx_xover_subband_offset;
+    }
+
+    aspx_elements(s, ss, ssch0);
+    aspx_elements(s, ss, ssch1);
+
+    ret = aspx_framing(s, ss, ssch0, iframe);
+    if (ret < 0)
+        return ret;
+
+    ssch0->aspx_qmode_env = ssch1->aspx_qmode_env = ss->aspx_quant_mode_env;
+    if (ssch0->aspx_int_class == FIXFIX && ssch0->aspx_num_env == 1)
+        ssch0->aspx_qmode_env = ssch1->aspx_qmode_env = 0;
+
+    ssch0->aspx_balance = ssch1->aspx_balance = get_bits1(gb);
+
+    if (ssch0->aspx_balance == 0) {
+        ret = aspx_framing(s, ss, ssch1, iframe);
+        if (ret < 0)
+            return ret;
+        ssch1->aspx_qmode_env = ss->aspx_quant_mode_env;
+        if (ssch1->aspx_int_class == FIXFIX && ssch1->aspx_num_env == 1)
+            ssch1->aspx_qmode_env = 0;
+    } else {
+        ssch1->aspx_num_env = ssch0->aspx_num_env;
+        ssch1->aspx_num_noise = ssch0->aspx_num_noise;
+        memcpy(&ssch1->atsg_freqres, &ssch0->atsg_freqres, sizeof(ssch0->atsg_freqres));
+    }
+
+    aspx_delta_dir(s, ssch0);
+    aspx_delta_dir(s, ssch1);
+    aspx_hfgen_iwc_2ch(s, ss, ssch0, ssch1, ssch0->aspx_balance);
+
+    ret = aspx_ec_data(s, ss, ssch0, DT_SIGNAL,
+                       ssch0->aspx_num_env,
+                       ssch0->atsg_freqres,
+                       ssch0->aspx_qmode_env,
+                       SM_LEVEL,
+                       ssch0->aspx_sig_delta_dir);
+    if (ret < 0)
+        return ret;
+    ret = aspx_ec_data(s, ss, ssch1, DT_SIGNAL,
+                       ssch1->aspx_num_env,
+                       ssch1->atsg_freqres,
+                       ssch1->aspx_qmode_env,
+                       ssch0->aspx_balance ? SM_BALANCE : SM_LEVEL,
+                       ssch1->aspx_sig_delta_dir);
+    if (ret < 0)
+        return ret;
+    ret = aspx_ec_data(s, ss, ssch0, DT_NOISE,
+                       ssch0->aspx_num_noise,
+                       0,
+                       0,
+                       SM_LEVEL,
+                       ssch0->aspx_noise_delta_dir);
+    if (ret < 0)
+        return ret;
+    ret = aspx_ec_data(s, ss, ssch1, DT_NOISE,
+                       ssch1->aspx_num_noise,
+                       0,
+                       0,
+                       ssch0->aspx_balance ? SM_BALANCE : SM_LEVEL,
+                       ssch1->aspx_noise_delta_dir);
+
+    return ret;
+}
+
+static int aspx_hfgen_iwc_1ch(AC4DecodeContext *s, Substream *ss,
+                              SubstreamChannel *ssch)
+{
+    GetBitContext *gb = &s->gbc;
+
+    memcpy(ssch->aspx_tna_mode_prev, ssch->aspx_tna_mode, sizeof(ssch->aspx_tna_mode));
+
+    for (int n = 0; n < ssch->num_sbg_noise; n++)
+        ssch->aspx_tna_mode[n] = get_bits(gb, 2);
+    if (get_bits1(gb)) {
+        for (int n = 0; n < ssch->num_sbg_sig_highres; n++)
+            ssch->aspx_add_harmonic[n] = get_bits1(gb);
+    }
+
+    for (int n = 0; n < ssch->num_sbg_sig_highres; n++)
+        ssch->aspx_fic_used_in_sfb[n] = 0;
+
+    if (get_bits1(gb)) {
+        for (int n = 0; n < ssch->num_sbg_sig_highres; n++)
+            ssch->aspx_fic_used_in_sfb[n] = get_bits1(gb);
+    }
+
+    for (int n = 0; n < s->num_aspx_timeslots; n++)
+        ssch->aspx_tic_used_in_slot[n] = 0;
+
+    if (get_bits1(gb)) {
+        for (int n = 0; n < s->num_aspx_timeslots; n++)
+            ssch->aspx_tic_used_in_slot[n] = get_bits1(gb);
+    }
+
+    return 0;
+}
+
+static int aspx_data_1ch(AC4DecodeContext *s, Substream *ss,
+                         SubstreamChannel *ssch, int iframe)
+{
+    GetBitContext *gb = &s->gbc;
+    int ret;
+
+    if (iframe)
+        ssch->aspx_xover_subband_offset = get_bits(gb, 3);
+
+    ssch->aspx_balance = 0;
+
+    aspx_elements(s, ss, ssch);
+
+    ret = aspx_framing(s, ss, ssch, iframe);
+    if (ret < 0)
+        return ret;
+
+    ssch->aspx_qmode_env = ss->aspx_quant_mode_env;
+    if (ssch->aspx_int_class == FIXFIX && ssch->aspx_num_env == 1)
+        ssch->aspx_qmode_env = 0;
+
+    aspx_delta_dir(s, ssch);
+    aspx_hfgen_iwc_1ch(s, ss, ssch);
+
+    ret = aspx_ec_data(s, ss, ssch, DT_SIGNAL,
+                       ssch->aspx_num_env,
+                       ssch->atsg_freqres,
+                       ssch->aspx_qmode_env,
+                       0,
+                       ssch->aspx_sig_delta_dir);
+    if (ret < 0)
+        return ret;
+    ret = aspx_ec_data(s, ss, ssch, DT_NOISE,
+                       ssch->aspx_num_noise,
+                       0,
+                       0,
+                       0,
+                       ssch->aspx_noise_delta_dir);
+    return ret;
+}
+
+static int acpl_framing_data(AC4DecodeContext *s, Substream *ss,
+                             SubstreamChannel *ssch)
+{
+    GetBitContext *gb = &s->gbc;
+
+    ssch->acpl_interpolation_type = get_bits1(gb);
+    ssch->acpl_num_param_sets_cod = get_bits1(gb);
+    if (ssch->acpl_interpolation_type) {
+        for (int ps = 0; ps < ssch->acpl_num_param_sets_cod + 1; ps++)
+            ssch->acpl_param_timeslot[ps] = get_bits(gb, 5);
+    }
+
+    return 0;
+}
+
+static VLC *get_acpl_hcb(int data_type, int quant_mode, int hcb_type)
+{
+    VLC *acpl_cb;
+
+    acpl_cb = &acpl_codebook_vlc[data_type][quant_mode][hcb_type];
+
+    return acpl_cb;
+}
+
+static int acpl_huff_data(AC4DecodeContext *s,
+                          int data_type, int data_bands,
+                          int start_band, int quant_mode,
+                          int *data)
+{
+    GetBitContext *gb = &s->gbc;
+    int diff_type;
+    VLC *acpl_cb;
+
+    switch (data_type) {
+    case ALPHA1:
+    case ALPHA2:
+        data_type = 0;
+        break;
+    case BETA1:
+    case BETA2:
+        data_type = 1;
+        break;
+    case BETA3:
+        data_type = 2;
+        break;
+    default:
+        data_type = 3;
+        break;
+    };
+
+    diff_type = get_bits1(gb);
+    if (diff_type == 0) { // DIFF_FREQ
+        acpl_cb = get_acpl_hcb(data_type, quant_mode, F0);
+        data[start_band] = get_vlc2(gb, acpl_cb->table, acpl_cb->bits, 3);
+        if (data[start_band] < 0)
+            return AVERROR_INVALIDDATA;
+        acpl_cb = get_acpl_hcb(data_type, quant_mode, DF);
+        for (int i = start_band + 1; i < data_bands; i++) {
+            data[i] = get_vlc2(gb, acpl_cb->table, acpl_cb->bits, 3);
+            if (data[i] < 0)
+                return AVERROR_INVALIDDATA;
+        }
+    } else { // DIFF_TIME
+        acpl_cb = get_acpl_hcb(data_type, quant_mode, DT);
+        for (int i = start_band; i < data_bands; i++) {
+            data[i] = get_vlc2(gb, acpl_cb->table, acpl_cb->bits, 3);
+            if (data[i] < 0)
+                return AVERROR_INVALIDDATA;
+        }
+    }
+
+    return 0;
+}
+
+static int acpl_ec_data(AC4DecodeContext *s, Substream *ss,
+                        SubstreamChannel *ssch,
+                        int data_type, int data_bands,
+                        int start_band, int quant_mode)
+{
+    int ret;
+
+    for (int ps = 0; ps < ssch->acpl_num_param_sets_cod + 1; ps++) {
+        ret = acpl_huff_data(s, data_type, data_bands,
+                             start_band, quant_mode,
+                             ssch->acpl_data[data_type]);
+        if (ret < 0)
+            return ret;
+    }
+
+    return 0;
+}
+
+static int acpl_data_2ch(AC4DecodeContext *s, Substream *ss,
+                         SubstreamChannel *ssch0,
+                         SubstreamChannel *ssch1)
+{
+    int ret, num_bands, st;
+
+    acpl_framing_data(s, ss, ssch0);
+
+    num_bands = acpl_num_param_bands[ss->acpl_num_param_bands_id];
+    st = ss->acpl_param_band;
+
+    ret = acpl_ec_data(s, ss, ssch0, ALPHA1, num_bands, st, ss->acpl_quant_mode[0]);
+    if (ret < 0)
+        return ret;
+    ret = acpl_ec_data(s, ss, ssch0, ALPHA2, num_bands, st, ss->acpl_quant_mode[0]);
+    if (ret < 0)
+        return ret;
+    ret = acpl_ec_data(s, ss, ssch0, BETA1, num_bands, st, ss->acpl_quant_mode[0]);
+    if (ret < 0)
+        return ret;
+    ret = acpl_ec_data(s, ss, ssch0, BETA2, num_bands, st, ss->acpl_quant_mode[0]);
+    if (ret < 0)
+        return ret;
+    ret = acpl_ec_data(s, ss, ssch0, BETA3, num_bands, st, ss->acpl_quant_mode[0]);
+    if (ret < 0)
+        return ret;
+    ret = acpl_ec_data(s, ss, ssch1, GAMMA1, num_bands, st, ss->acpl_quant_mode[1]);
+    if (ret < 0)
+        return ret;
+    ret = acpl_ec_data(s, ss, ssch1, GAMMA2, num_bands, st, ss->acpl_quant_mode[1]);
+    if (ret < 0)
+        return ret;
+    ret = acpl_ec_data(s, ss, ssch1, GAMMA3, num_bands, st, ss->acpl_quant_mode[1]);
+    if (ret < 0)
+        return ret;
+    ret = acpl_ec_data(s, ss, ssch1, GAMMA4, num_bands, st, ss->acpl_quant_mode[1]);
+    if (ret < 0)
+        return ret;
+    ret = acpl_ec_data(s, ss, ssch1, GAMMA5, num_bands, st, ss->acpl_quant_mode[1]);
+    if (ret < 0)
+        return ret;
+    ret = acpl_ec_data(s, ss, ssch1, GAMMA6, num_bands, st, ss->acpl_quant_mode[1]);
+    if (ret < 0)
+        return ret;
+
+    return 0;
+}
+
+static int acpl_data_1ch(AC4DecodeContext *s, Substream *ss,
+                         SubstreamChannel *ssch)
+{
+    int ret, num_bands, start;
+
+    acpl_framing_data(s, ss, ssch);
+
+    num_bands = acpl_num_param_bands[ss->acpl_num_param_bands_id];
+    start = ss->acpl_param_band;
+
+    ret = acpl_ec_data(s, ss, ssch, ALPHA1, num_bands, start, ss->acpl_quant_mode[0]);
+    if (ret < 0)
+        return ret;
+
+    ret = acpl_ec_data(s, ss, ssch, BETA1, num_bands, start, ss->acpl_quant_mode[0]);
+    if (ret < 0)
+        return ret;
+
+    return 0;
+}
+
+static int channel_pair_element(AC4DecodeContext *s, int iframe)
+{
+    GetBitContext *gb = &s->gbc;
+    Substream *ss = &s->substream;
+    int spec_frontend;
+    int ret;
+
+    ss->codec_mode = get_bits(gb, 2);
+    if (iframe) {
+        if (ss->codec_mode != CM_SIMPLE)
+            aspx_config(s, ss);
+        if (ss->codec_mode == CM_ASPX_ACPL_1)
+            acpl_config_1ch(s, ss, ACPL_PARTIAL);
+        if (ss->codec_mode == CM_ASPX_ACPL_2)
+            acpl_config_1ch(s, ss, ACPL_FULL);
+    }
+
+    switch (ss->codec_mode) {
+    case CM_SIMPLE:
+        ret = stereo_data(s, ss, iframe);
+        if (ret < 0)
+            return ret;
+        break;
+    case CM_ASPX:
+        companding_control(s, ss, 2);
+        ret = stereo_data(s, ss, iframe);
+        if (ret < 0)
+            return ret;
+        ret = aspx_data_2ch(s, ss, &ss->ssch[0], &ss->ssch[1], iframe);
+        if (ret < 0)
+            return ret;
+        break;
+    case CM_ASPX_ACPL_1:
+        companding_control(s, ss, 1);
+        ss->mdct_stereo_proc[0] = get_bits1(gb);
+        if (ss->mdct_stereo_proc[0]) {
+            ss->spec_frontend_m = SF_ASF;
+            ss->spec_frontend_s = SF_ASF;
+            ret = sf_info(s, ss, &ss->ssch[0], SF_ASF, 1, 0);
+            if (ret < 0)
+                return ret;
+
+            memcpy(&ss->ssch[1].scp, &ss->ssch[0].scp, sizeof(ss->ssch[0].scp));
+            memcpy(&ss->ssch[1].sect_sfb_offset, &ss->ssch[0].sect_sfb_offset, sizeof(ss->ssch[0].sect_sfb_offset));
+            memcpy(&ss->ssch[1].offset2sfb, &ss->ssch[0].offset2sfb, sizeof(ss->ssch[0].offset2sfb));
+            memcpy(&ss->ssch[1].offset2g, &ss->ssch[0].offset2g, sizeof(ss->ssch[0].offset2g));
+            memcpy(&ss->ssch[1].win_offset, &ss->ssch[0].win_offset, sizeof(ss->ssch[0].win_offset));
+
+            ret = chparam_info(s, ss, &ss->ssch[0]);
+            if (ret < 0)
+                return ret;
+        } else {
+            ss->spec_frontend_m = get_bits1(gb);
+            ret = sf_info(s, ss, &ss->ssch[0], ss->spec_frontend_m, 0, 0);
+            if (ret < 0)
+                return ret;
+            ss->spec_frontend_s = get_bits1(gb);
+            ret = sf_info(s, ss, &ss->ssch[1], ss->spec_frontend_s, 0, 1);
+            if (ret < 0)
+                return ret;
+        }
+        ret = sf_data(s, ss, &ss->ssch[0], iframe, ss->spec_frontend_m);
+        if (ret < 0)
+            return ret;
+        ret = sf_data(s, ss, &ss->ssch[1], iframe, ss->spec_frontend_m);
+        if (ret < 0)
+            return ret;
+        ret = aspx_data_1ch(s, ss, &ss->ssch[0], iframe);
+        if (ret < 0)
+            return ret;
+        ret = acpl_data_1ch(s, ss, &ss->ssch[0]);
+        if (ret < 0)
+            return ret;
+        break;
+    case CM_ASPX_ACPL_2:
+        companding_control(s, ss, 1);
+        spec_frontend = get_bits1(gb);
+        ret = sf_info(s, ss, &ss->ssch[0], spec_frontend, 0, 0);
+        if (ret < 0)
+            return ret;
+        ret = sf_data(s, ss, &ss->ssch[0], iframe, spec_frontend);
+        if (ret < 0)
+            return ret;
+        ret = aspx_data_1ch(s, ss, &ss->ssch[0], iframe);
+        if (ret < 0)
+            return ret;
+        ret = acpl_data_1ch(s, ss, &ss->ssch[0]);
+        if (ret < 0)
+            return ret;
+        break;
+    }
+
+    return 0;
+}
+
+static int four_channel_data(AC4DecodeContext *s, Substream *ss, int iframe)
+{
+    int ret;
+
+    ret = sf_info(s, ss, &ss->ssch[0], SF_ASF, 0, 0);
+    if (ret < 0)
+        return ret;
+
+    for (int i = 1; i < 4; i++) {
+        memcpy(&ss->ssch[i], &ss->ssch[0], sizeof(ss->ssch[0]));
+    }
+
+    for (int i = 0; i < 4; i++) {
+        ret = chparam_info(s, ss, &ss->ssch[i]);
+        if (ret < 0)
+            return ret;
+    }
+
+    for (int i = 0; i < 4; i++) {
+        ret = sf_data(s, ss, &ss->ssch[i], iframe, SF_ASF);
+        if (ret < 0)
+            return ret;
+    }
+
+    return 0;
+}
+
+static int channel_element_7x(AC4DecodeContext *s, int channel_mode, int iframe)
+{
+    GetBitContext *gb = &s->gbc;
+    Substream *ss = &s->substream;
+    int ret = 0;
+
+    ss->codec_mode = get_bits(gb, 2);
+    if (iframe) {
+        if (ss->codec_mode != CM_SIMPLE)
+            aspx_config(s, ss);
+        if (ss->codec_mode == CM_ASPX_ACPL_1)
+            acpl_config_1ch(s, ss, ACPL_PARTIAL);
+        if (ss->codec_mode == CM_ASPX_ACPL_2)
+            acpl_config_1ch(s, ss, ACPL_FULL);
+    }
+
+    if (channel_mode == 6) {
+        av_assert0(0);
+    }
+
+    if (ss->codec_mode == CM_ASPX_ACPL_1 ||
+        ss->codec_mode == CM_ASPX_ACPL_2)
+        companding_control(s, ss, 5);
+
+    ss->coding_config = get_bits(gb, 2);
+    switch (ss->coding_config) {
+    case 0:
+        break;
+    case 1:
+        break;
+    case 2:
+        ret = four_channel_data(s, ss, iframe);
+        break;
+    default:
+        av_assert0(0);
+    }
+
+    return ret;
+}
+
+static int get_msfbl_bits(int transf_length)
+{
+    if (transf_length <= 2048 && transf_length >= 1536)
+        return 3;
+
+    return 2;
+}
+
+static int sf_info_lfe(AC4DecodeContext *s, Substream *ss,
+                        SubstreamChannel *ssch)
+{
+    GetBitContext *gb = &s->gbc;
+    int n_msfbl_bits = get_msfbl_bits(s->frame_len_base);
+
+    ssch->scp.long_frame = 1;
+    ssch->scp.max_sfb[0] = get_bits(gb, n_msfbl_bits);
+    ssch->scp.num_window_groups = 1;
+
+    return asf_psy_elements(s, ss, ssch, 0);
+}
+
+static int mono_data(AC4DecodeContext *s, Substream *ss,
+                     SubstreamChannel *ssch, int lfe, int iframe)
+{
+    GetBitContext *gb = &s->gbc;
+    int spec_frontend;
+    int ret;
+
+    if (lfe) {
+        spec_frontend = SF_ASF;
+        ret = sf_info_lfe(s, ss, ssch);
+    } else {
+        spec_frontend = get_bits1(gb);
+        ret = sf_info(s, ss, ssch, spec_frontend, 0, 0);
+    }
+    if (ret < 0)
+        return ret;
+    return sf_data(s, ss, ssch, iframe, spec_frontend);
+}
+
+static int three_channel_info(AC4DecodeContext *s, Substream *ss,
+                              SubstreamChannel *ssch0,
+                              SubstreamChannel *ssch1,
+                              SubstreamChannel *ssch2)
+{
+    GetBitContext *gb = &s->gbc;
+    int ret;
+
+    ss->chel_matsel = get_bits(gb, 4);
+    ret = chparam_info(s, ss, ssch0);
+    if (ret < 0)
+        return ret;
+    return chparam_info(s, ss, ssch1);
+}
+
+static int three_channel_data(AC4DecodeContext *s, Substream *ss,
+                              SubstreamChannel *ssch0,
+                              SubstreamChannel *ssch1,
+                              SubstreamChannel *ssch2)
+{
+    int ret;
+
+    ret = sf_info(s, ss, ssch0, SF_ASF, 0, 0);
+    if (ret < 0)
+        return ret;
+
+    memcpy(&ssch1->scp, &ssch0->scp, sizeof(ss->ssch[0].scp));
+    memcpy(&ssch1->sect_sfb_offset, &ssch0->sect_sfb_offset, sizeof(ss->ssch[0].sect_sfb_offset));
+    memcpy(&ssch1->offset2sfb, &ssch0->offset2sfb, sizeof(ss->ssch[0].offset2sfb));
+    memcpy(&ssch1->offset2g, &ssch0->offset2g, sizeof(ss->ssch[0].offset2g));
+    memcpy(&ssch1->win_offset, &ssch0->win_offset, sizeof(ss->ssch[0].win_offset));
+
+    memcpy(&ssch2->scp, &ssch0->scp, sizeof(ss->ssch[0].scp));
+    memcpy(&ssch2->sect_sfb_offset, &ssch0->sect_sfb_offset, sizeof(ss->ssch[0].sect_sfb_offset));
+    memcpy(&ssch2->offset2sfb, &ssch0->offset2sfb, sizeof(ss->ssch[0].offset2sfb));
+    memcpy(&ssch2->offset2g, &ssch0->offset2g, sizeof(ss->ssch[0].offset2g));
+    memcpy(&ssch2->win_offset, &ssch0->win_offset, sizeof(ss->ssch[0].win_offset));
+
+    ret = three_channel_info(s, ss, ssch0, ssch1, ssch2);
+    if (ret < 0)
+        return ret;
+    ret = sf_data(s, ss, ssch0, 0, SF_ASF);
+    if (ret < 0)
+        return ret;
+    ret = sf_data(s, ss, ssch1, 0, SF_ASF);
+    if (ret < 0)
+        return ret;
+    ret = sf_data(s, ss, ssch2, 0, SF_ASF);
+    if (ret < 0)
+        return ret;
+
+    return 0;
+}
+
+static int two_channel_data(AC4DecodeContext *s, Substream *ss,
+                            SubstreamChannel *ssch0,
+                            SubstreamChannel *ssch1,
+                            int x)
+{
+    GetBitContext *gb = &s->gbc;
+    int ret;
+
+    ss->mdct_stereo_proc[x] = get_bits1(gb);
+    if (ss->mdct_stereo_proc[x]) {
+        ret = sf_info(s, ss, ssch0, SF_ASF, 0, 0);
+        if (ret < 0)
+            return ret;
+
+        memcpy(&ssch1->scp, &ssch0->scp, sizeof(ss->ssch[0].scp));
+        memcpy(&ssch1->sect_sfb_offset, &ssch0->sect_sfb_offset, sizeof(ss->ssch[0].sect_sfb_offset));
+        memcpy(&ssch1->offset2sfb, &ssch0->offset2sfb, sizeof(ss->ssch[0].offset2sfb));
+        memcpy(&ssch1->offset2g, &ssch0->offset2g, sizeof(ss->ssch[0].offset2g));
+        memcpy(&ssch1->win_offset, &ssch0->win_offset, sizeof(ss->ssch[0].win_offset));
+
+        ret = chparam_info(s, ss, ssch0);
+        if (ret < 0)
+            return ret;
+    } else {
+        ret = sf_info(s, ss, ssch0, SF_ASF, 0, 0);
+        if (ret < 0)
+            return ret;
+        ret = sf_info(s, ss, ssch1, SF_ASF, 0, 0);
+        if (ret < 0)
+            return ret;
+    }
+    ret = sf_data(s, ss, ssch0, 0, SF_ASF);
+    if (ret < 0)
+        return ret;
+    ret = sf_data(s, ss, ssch1, 0, SF_ASF);
+    if (ret < 0)
+        return ret;
+
+    return 0;
+}
+
+static int five_channel_info(AC4DecodeContext *s, Substream *ss)
+{
+    GetBitContext *gb = &s->gbc;
+    int ret;
+
+    ss->chel_matsel = get_bits(gb, 4);
+
+    for (int i = 0; i < 5; i++) {
+        ret = chparam_info(s, ss, &ss->ssch[i]);
+        if (ret < 0)
+            return ret;
+    }
+
+    return 0;
+}
+
+static int five_channel_data(AC4DecodeContext *s, Substream *ss, int iframe)
+{
+    int ret;
+
+    ret = sf_info(s, ss, &ss->ssch[0], SF_ASF, 0, 0);
+    if (ret < 0)
+        return ret;
+
+    for (int i = 1; i < 5; i++) {
+        memcpy(&ss->ssch[i], &ss->ssch[0], sizeof(ss->ssch[0]));
+    }
+
+    ret = five_channel_info(s, ss);
+    if (ret < 0)
+        return ret;
+
+    for (int i = 0; i < 5; i++) {
+        ret = sf_data(s, ss, &ss->ssch[i], 0, SF_ASF);
+        if (ret < 0)
+            return ret;
+    }
+
+    return 0;
+}
+
+static int channel_element_3x(AC4DecodeContext *s, int iframe)
+{
+    GetBitContext *gb = &s->gbc;
+    Substream *ss = &s->substream;
+    int ret;
+
+    ss->codec_mode = get_bits1(gb);
+    if (ss->codec_mode == CM_ASPX) {
+        if (iframe)
+            aspx_config(s, ss);
+        companding_control(s, ss, 3);
+    }
+
+    ss->coding_config = get_bits1(gb);
+    switch (ss->coding_config) {
+    case 0:
+        ret = stereo_data(s, ss, iframe);
+        if (ret < 0)
+            return ret;
+        ret = mono_data(s, ss, &ss->ssch[2], 0, iframe);
+        if (ret < 0)
+            return ret;
+        break;
+    case 1:
+        ret = three_channel_data(s, ss,
+                                 &ss->ssch[0],
+                                 &ss->ssch[1],
+                                 &ss->ssch[2]);
+        if (ret < 0)
+            return ret;
+        break;
+    }
+
+    if (ss->codec_mode == CM_ASPX) {
+        ret = aspx_data_2ch(s, ss, &ss->ssch[0], &ss->ssch[1], iframe);
+        if (ret < 0)
+            return ret;
+        ret = aspx_data_1ch(s, ss, &ss->ssch[2], iframe);
+        if (ret < 0)
+            return ret;
+    }
+
+    return 0;
+}
+
+static int channel_element_5x(AC4DecodeContext *s, int lfe, int iframe)
+{
+    GetBitContext *gb = &s->gbc;
+    Substream *ss = &s->substream;
+    int ret = 0;
+
+    ss->codec_mode = get_bits(gb, 3);
+    if (iframe) {
+        if (ss->codec_mode != CM_SIMPLE)
+            aspx_config(s, ss);
+        if (ss->codec_mode == CM_ASPX_ACPL_1)
+            acpl_config_1ch(s, ss, ACPL_PARTIAL);
+        if (ss->codec_mode == CM_ASPX_ACPL_2)
+            acpl_config_1ch(s, ss, ACPL_FULL);
+        if (ss->codec_mode == CM_ASPX_ACPL_3)
+            acpl_config_2ch(s, ss);
+    }
+
+    if (lfe) {
+        ret = mono_data(s, ss, &ss->ssch[5], 1, iframe);
+        if (ret < 0)
+            return ret;
+    }
+
+    switch (ss->codec_mode) {
+    case CM_SIMPLE:
+    case CM_ASPX:
+        if (ss->codec_mode == CM_ASPX)
+            companding_control(s, ss, 5);
+
+        ss->coding_config = get_bits(gb, 2);
+        switch (ss->coding_config) {
+        case 0:
+            ss->mode_2ch = get_bits1(gb);
+            ret = two_channel_data(s, ss, &ss->ssch[0], &ss->ssch[1], 0);
+            if (ret < 0)
+                return ret;
+            ret = two_channel_data(s, ss, &ss->ssch[2], &ss->ssch[3], 1);
+            if (ret < 0)
+                return ret;
+            ret = mono_data(s, ss, &ss->ssch[4], 0, iframe);
+            if (ret < 0)
+                return ret;
+            break;
+        case 1:
+            ret = three_channel_data(s, ss, &ss->ssch[0], &ss->ssch[1], &ss->ssch[2]);
+            if (ret < 0)
+                return ret;
+            ret = two_channel_data(s, ss, &ss->ssch[3], &ss->ssch[4], 0);
+            if (ret < 0)
+                return ret;
+            break;
+        case 2:
+            ret = four_channel_data(s, ss, iframe);
+            if (ret < 0)
+                return ret;
+            ret = mono_data(s, ss, &ss->ssch[4], 0, iframe);
+            if (ret < 0)
+                return ret;
+            break;
+        case 3:
+            ret = five_channel_data(s, ss, iframe);
+            if (ret < 0)
+                return ret;
+            break;
+        }
+
+        if (ss->codec_mode == CM_ASPX) {
+            ret = aspx_data_2ch(s, ss, &ss->ssch[0], &ss->ssch[1], iframe);
+            if (ret < 0)
+                return ret;
+            ret = aspx_data_2ch(s, ss, &ss->ssch[2], &ss->ssch[3], iframe);
+            if (ret < 0)
+                return ret;
+            ret = aspx_data_1ch(s, ss, &ss->ssch[4], iframe);
+            if (ret < 0)
+                return ret;
+        }
+        break;
+    case CM_ASPX_ACPL_1:
+    case CM_ASPX_ACPL_2:
+        companding_control(s, ss, 3);
+        ss->coding_config = get_bits1(gb);
+        if (ss->coding_config)
+            ret = three_channel_data(s, ss, &ss->ssch[0], &ss->ssch[1], &ss->ssch[2]);
+        else
+            ret = two_channel_data(s, ss, &ss->ssch[0], &ss->ssch[1], 0);
+        if (ret < 0)
+            return ret;
+
+        if (ss->codec_mode == CM_ASPX_ACPL_1) {
+            ss->max_sfb_master = get_bits(gb, 5); // XXX
+            ret = chparam_info(s, ss, &ss->ssch[3]);
+            if (ret < 0)
+                return ret;
+            ret = chparam_info(s, ss, &ss->ssch[4]);
+            if (ret < 0)
+                return ret;
+            ret = sf_data(s, ss, &ss->ssch[3], iframe, SF_ASF);
+            if (ret < 0)
+                return ret;
+            ret = sf_data(s, ss, &ss->ssch[4], iframe, SF_ASF);
+            if (ret < 0)
+                return ret;
+        }
+        if (ss->coding_config == 0) {
+           ret = mono_data(s, ss, &ss->ssch[2], 0, iframe);
+           if (ret < 0)
+               return ret;
+        }
+
+        ret = aspx_data_2ch(s, ss, &ss->ssch[0], &ss->ssch[1], iframe);
+        if (ret < 0)
+            return ret;
+        ret = aspx_data_1ch(s, ss, &ss->ssch[2], iframe);
+        if (ret < 0)
+            return ret;
+        ret = acpl_data_1ch(s, ss, &ss->ssch[0]);
+        if (ret < 0)
+            return ret;
+        ret = acpl_data_1ch(s, ss, &ss->ssch[1]);
+        if (ret < 0)
+            return ret;
+        break;
+    case CM_ASPX_ACPL_3:
+        companding_control(s, ss, 2);
+        ret = stereo_data(s, ss, iframe);
+        if (ret < 0)
+            return ret;
+        ret = aspx_data_2ch(s, ss, &ss->ssch[0], &ss->ssch[1], iframe);
+        if (ret < 0)
+            return ret;
+        ret = acpl_data_2ch(s, ss, &ss->ssch[0], &ss->ssch[1]);
+        if (ret < 0)
+            return ret;
+        break;
+    default:
+        av_assert0(0);
+    }
+
+    return ret;
+}
+
+static int single_channel_element(AC4DecodeContext *s, int iframe)
+{
+    GetBitContext *gb = &s->gbc;
+    Substream *ss = &s->substream;
+    int ret = 0;
+
+    ss->codec_mode = get_bits1(gb);
+    if (iframe) {
+        if (ss->codec_mode == CM_ASPX)
+            aspx_config(s, ss);
+    }
+    if (ss->codec_mode == CM_SIMPLE) {
+        ret = mono_data(s, ss, &ss->ssch[0], 0, iframe);
+    } else {
+        companding_control(s, ss, 1);
+        ret = mono_data(s, ss, &ss->ssch[0], 0, iframe);
+        if (ret < 0)
+            return ret;
+        ret = aspx_data_1ch(s, ss, &ss->ssch[0], iframe);
+    }
+
+    return ret;
+}
+
+static int audio_data(AC4DecodeContext *s, int channel_mode, int iframe)
+{
+    int ret = 0;
+
+    switch (channel_mode) {
+    case 0:
+        ret = single_channel_element(s, iframe);
+        break;
+    case 1:
+        ret = channel_pair_element(s, iframe);
+        break;
+    case 2:
+        ret = channel_element_3x(s, iframe);
+        break;
+    case 3:
+        ret = channel_element_5x(s, 0, iframe);
+        break;
+    case 4:
+        ret = channel_element_5x(s, 1, iframe);
+        break;
+    case 5:
+        ret = channel_element_7x(s, channel_mode, iframe);
+        break;
+    default:
+        av_assert0(0);
+        break;
+    }
+
+    return ret;
+}
+
+static int further_loudness_info(AC4DecodeContext *s, SubstreamInfo *ssi)
+{
+    GetBitContext *gb = &s->gbc;
+    Metadata *m = &ssi->meta;
+
+    m->loudness_version = get_bits(gb, 2);
+    if (m->loudness_version == 3)
+        m->loudness_version += get_bits(gb, 4);
+
+    m->loud_prac_type = get_bits(gb, 4);
+    if (m->loud_prac_type != 0) {
+        if (get_bits1(gb))
+            m->dialgate_prac_type = get_bits(gb, 3);
+        m->loudcorr_type = get_bits1(gb);
+    }
+
+    if (get_bits1(gb))
+        m->loudrelgat = get_bits(gb, 11);
+
+    if (get_bits1(gb)) {
+        m->loudspchgat = get_bits(gb, 11);
+        m->dialgate_prac_type = get_bits(gb, 3);
+    }
+
+    if (get_bits1(gb))
+        m->loudstrm3s = get_bits(gb, 11);
+
+    if (get_bits1(gb))
+        m->max_loudstrm3s = get_bits(gb, 11);
+
+    if (get_bits1(gb))
+        m->truepk = get_bits(gb, 11);
+
+    if (get_bits1(gb))
+        m->max_truepk = get_bits(gb, 11);
+
+    if (get_bits1(gb)) {
+        int prgmbndy_bit = 0;
+
+        m->prgmbndy = 1;
+        while (prgmbndy_bit == 0) {
+            m->prgmbndy <<= 1;
+            prgmbndy_bit = get_bits1(gb);
+        }
+
+        m->end_or_start = get_bits1(gb);
+        if (get_bits1(gb))
+            m->prgmbndy_offset = get_bits(gb, 11);
+    }
+
+    if (get_bits1(gb)) {
+        m->lra = get_bits(gb, 10);
+        m->lra_prac_type = get_bits(gb, 3);
+    }
+
+    if (get_bits1(gb))
+        m->loudmntry = get_bits(gb, 11);
+
+    if (get_bits1(gb))
+        m->max_loudmntry = get_bits(gb, 11);
+
+    if (get_bits1(gb)) {
+        int e_bits_size = get_bits(gb, 5);
+        if (e_bits_size == 31)
+            e_bits_size += variable_bits(gb, 4);
+        skip_bits_long(gb, e_bits_size);
+    }
+
+    return 0;
+}
+
+static int channel_mode_contains_lfe(int channel_mode)
+{
+    if (channel_mode == 4 ||
+        channel_mode == 6 ||
+        channel_mode == 8 ||
+        channel_mode == 10)
+        return 1;
+    return 0;
+}
+
+static int basic_metadata(AC4DecodeContext *s, SubstreamInfo *ssi)
+{
+    GetBitContext *gb = &s->gbc;
+    Metadata *m = &ssi->meta;
+
+    if (ssi->sus_ver == 0)
+        m->dialnorm_bits = get_bits(gb, 7);
+
+    if (get_bits1(gb)) {
+        if (get_bits1(gb))
+            further_loudness_info(s, ssi);
+        if (ssi->channel_mode == 1) {
+            if (get_bits1(gb)) {
+                m->pre_dmixtyp_2ch = get_bits(gb, 3);
+                m->phase90_info_2ch = get_bits(gb, 2);
+            }
+        }
+
+        if (ssi->channel_mode > 1) {
+            if (get_bits1(gb)) {
+                m->loro_center_mixgain = get_bits(gb, 3);
+                m->loro_surround_mixgain = get_bits(gb, 3);
+                if (get_bits1(gb))
+                    m->loro_dmx_loud_corr = get_bits(gb, 5);
+                if (get_bits1(gb)) {
+                    m->ltrt_center_mixgain = get_bits(gb, 3);
+                    m->ltrt_surround_mixgain = get_bits(gb, 3);
+                }
+                if (get_bits1(gb))
+                    m->ltrt_dmx_loud_corr = get_bits(gb, 5);
+                if (channel_mode_contains_lfe(ssi->channel_mode)) {
+                    if (get_bits1(gb))
+                        m->lfe_mixgain = get_bits(gb, 5);
+                }
+                m->preferred_dmx_method = get_bits(gb, 2);
+            }
+            if (ssi->channel_mode == 3 ||
+                ssi->channel_mode == 4) {
+                if (get_bits1(gb))
+                    m->pre_dmixtyp_5ch = get_bits(gb, 3);
+                if (get_bits1(gb))
+                    m->pre_upmixtyp_5ch = get_bits(gb, 4);
+            }
+
+            if (ssi->channel_mode >= 5 && ssi->channel_mode <= 10) {
+                if (get_bits1(gb)) {
+                    if (ssi->channel_mode >= 5 && ssi->channel_mode <= 6) {
+                        m->pre_upmixtyp_3_4 = get_bits(gb, 2);
+                    } else if (ssi->channel_mode >= 9 && ssi->channel_mode <= 10) {
+                        m->pre_upmixtyp_3_2_2 = get_bits(gb, 1);
+                    }
+                }
+            }
+            m->phase90_info_mc = get_bits(gb, 2);
+            m->surround_attenuation_known = get_bits1(gb);
+            m->lfe_attenuation_known = get_bits1(gb);
+        }
+
+        if (get_bits1(gb))
+            m->dc_block_on = get_bits1(gb);
+    }
+    return 0;
+}
+
+static int extended_metadata(AC4DecodeContext *s)
+{
+    return 0;
+}
+
+static int drc_decoder_mode_config(AC4DecodeContext *s, SubstreamInfo *ssi)
+{
+    return 0;
+}
+
+static int drc_config(AC4DecodeContext *s, SubstreamInfo *ssi)
+{
+    GetBitContext *gb = &s->gbc;
+    Metadata *m = &ssi->meta;
+
+    m->drc_decoder_nr_modes = get_bits(gb, 3);
+    for (int i = 0; i <= m->drc_decoder_nr_modes; i++)
+        drc_decoder_mode_config(s, ssi);
+    m->drc_eac3_profile = get_bits(gb, 3);
+
+    return 0;
+}
+
+static int drc_data(AC4DecodeContext *s, SubstreamInfo *ssi)
+{
+    return 0;
+}
+
+static int drc_frame(AC4DecodeContext *s, SubstreamInfo *ssi, int iframe)
+{
+    GetBitContext *gb = &s->gbc;
+
+    if (get_bits1(gb)) {
+        if (iframe)
+            drc_config(s, ssi);
+
+        drc_data(s, ssi);
+    }
+
+    return 0;
+}
+
+static int dialog_enhancement(AC4DecodeContext *s, int iframe)
+{
+    return 0;
+}
+
+static int emdf_payloads_substream(AC4DecodeContext *s)
+{
+    return 0;
+}
+
+static int metadata(AC4DecodeContext *s, SubstreamInfo *ssi, int iframe)
+{
+    GetBitContext *gb = &s->gbc;
+    int tools_metadata_size;
+
+    basic_metadata(s, ssi);
+    extended_metadata(s);
+    tools_metadata_size = get_bits(gb, 7);
+    if (get_bits1(gb))
+        tools_metadata_size += variable_bits(gb, 3) << 7;
+
+    drc_frame(s, ssi, iframe);
+
+    dialog_enhancement(s, iframe);
+
+    if (get_bits1(gb))
+        emdf_payloads_substream(s);
+
+    return 0;
+}
+
+static int ac4_substream(AC4DecodeContext *s)
+{
+    GetBitContext *gb = &s->gbc;
+    int audio_size, offset, consumed;
+    int ret;
+
+    audio_size = get_bits(gb, 15);
+    if (get_bits1(gb))
+        audio_size += variable_bits(gb, 7) << 15;
+    if (audio_size > 131072)
+        return AVERROR_INVALIDDATA;
+
+    av_log(s->avctx, AV_LOG_DEBUG, "audio_size: %d\n", audio_size);
+
+    align_get_bits(gb);
+
+    offset = get_bits_count(gb) >> 3;
+    ret = audio_data(s, s->pinfo[0].ssinfo.channel_mode, s->pinfo[0].ssinfo.iframe[0]);
+    if (ret < 0)
+        return ret;
+
+    align_get_bits(gb);
+    consumed = (get_bits_count(gb) >> 3) - offset;
+    if (consumed > audio_size) {
+        av_log(s->avctx, AV_LOG_ERROR, "substream audio data overread: %d\n", consumed - audio_size);
+        return AVERROR_INVALIDDATA;
+    }
+    if (consumed < audio_size) {
+        int non_zero = 0;
+
+        for (int i = consumed; i < audio_size; i++)
+            non_zero += !!get_bits(gb, 8);
+        if (non_zero)
+            av_log(s->avctx, AV_LOG_WARNING, "substream audio data underread: %d\n", non_zero);
+    }
+
+    metadata(s, &s->pinfo[0].ssinfo, s->iframe_global);
+
+    align_get_bits(gb);
+
+    return 0;
+}
+
+static void spectral_reordering(AC4DecodeContext *s, SubstreamChannel *ssch)
+{
+    float *scaled_spec = ssch->scaled_spec;
+    float *spec_reord = ssch->spec_reord;
+    int *win_offset = ssch->win_offset;
+    int k, win;
+
+    k = 0;
+    win = 0;
+    memset(ssch->spec_reord, 0, sizeof(ssch->spec_reord));
+
+    for (int g = 0; g < ssch->scp.num_window_groups; g++) {
+        int transf_length_g = get_transf_length(s, ssch, g, NULL);
+        const uint16_t *sfb_offset = get_sfb_offset(transf_length_g);
+        int max_sfb = get_max_sfb(s, ssch, g);
+
+        for (int sfb = 0; sfb < max_sfb; sfb++) {
+            for (int w = 0; w < ssch->scp.num_win_in_group[g]; w++) {
+                for (int l = sfb_offset[sfb]; l < sfb_offset[sfb+1]; l++)
+                    spec_reord[win_offset[win+w] + l] = scaled_spec[k++];
+            }
+        }
+        win += ssch->scp.num_win_in_group[g];
+    }
+}
+
+static int compute_window(AC4DecodeContext *s, float *w, int N,
+                          int N_prev, int Nfull, int dir)
+{
+    const uint16_t *transf_lengths = transf_length_48khz[s->frame_len_base_idx];
+    float *kernel;
+    int i, idx, N_w, N_skip;
+
+    if (N <= N_prev)
+        N_w = N;
+    if (N > N_prev)
+        N_w = N_prev;
+
+    for (i = 0; i < 5; i++) {
+        if (transf_lengths[i] == N_w) {
+            idx = i;
+            break;
+        }
+    }
+
+    av_assert0(i < 5);
+
+    N_skip = (N - N_w) / 2;
+    kernel = s->kbd_window[s->frame_len_base_idx][idx];
+
+    for (int n = 0; n < N; n++) {
+        if (n >= 0 && n < N_skip)
+            w[n] =  dir;
+        else if (n >= N_skip && n < N_w + N_skip)
+            w[n] = !dir ? kernel[n - N_skip] : kernel[N_w - n + N_skip - 1];
+        else if (n >= N_w + N_skip && n < N_w + 2 * N_skip)
+            w[n] = !dir;
+        else
+            av_assert0(0);
+    }
+
+    return 0;
+}
+
+static void scale_spec(AC4DecodeContext *s, int ch)
+{
+    Substream *ss = &s->substream;
+    SubstreamChannel *ssch = &ss->ssch[ch];
+    const float *quant_lut = s->quant_lut;
+
+    memset(ssch->scaled_spec, 0, sizeof(ssch->scaled_spec));
+
+    for (int k = 0; k < s->frame_len_base; k++) {
+        int x = ssch->quant_spec[k];
+        int sfb = ssch->offset2sfb[k];
+        int g = ssch->offset2g[k];
+
+        ssch->scaled_spec[k] = ssch->sf_gain[g][sfb] * copysignf(quant_lut[FFABS(x)], x) / 32768.f;
+    }
+}
+
+static int two_channel_processing(AC4DecodeContext *s, Substream *ss,
+                                  SubstreamChannel *ssch0,
+                                  SubstreamChannel *ssch1)
+{
+    int max_sfb_prev;
+    float sap_gain;
+
+    memset(&ss->alpha_q, 0, sizeof(ss->alpha_q));
+
+    max_sfb_prev = get_max_sfb(s, ssch0, 0);
+    for (int g = 0; g < ssch0->scp.num_window_groups; g++) {
+        int max_sfb_g = get_max_sfb(s, ssch0, g);
+
+        for (int sfb = 0; sfb < max_sfb_g; sfb++) {
+            float m[2][2];
+
+            if (ssch0->sap_mode == 0 ||
+                (ssch0->sap_mode == 1 && ssch0->ms_used[g][sfb] == 0)) {
+                m[0][0] = m[1][1] = 1;
+                m[0][1] = m[1][0] = 0;
+            } else if (ssch0->sap_mode == 2 ||
+                       ((ssch0->sap_mode == 1 && ssch0->ms_used[g][sfb] == 1))) {
+                m[0][0] =
+                m[0][1] =
+                m[1][0] =  1;
+                m[1][1] = -1;
+            } else { // sap_mode == 3
+                if (ssch0->sap_coeff_used[g][sfb]) { // setup alpha_q[g][sfb]
+                    if (sfb & 1) {
+                        ss->alpha_q[g][sfb] = ss->alpha_q[g][sfb-1];
+                    } else {
+                        float delta = ssch0->dpcm_alpha_q[g][sfb] - 60;
+                        int code_delta;
+
+                        if ((g == 0) || (max_sfb_g != max_sfb_prev)) {
+                            code_delta = 0;
+                        } else {
+                            code_delta = ssch0->delta_code_time;
+                        }
+
+                        if (code_delta) {
+                            ss->alpha_q[g][sfb] = ss->alpha_q[g-1][sfb] + delta;
+                        } else if (sfb == 0) {
+                            ss->alpha_q[g][sfb] = delta;
+                        } else {
+                            ss->alpha_q[g][sfb] = ss->alpha_q[g][sfb-2] + delta;
+                        }
+                    }
+                    // inverse quantize alpha_q[g][sfb]
+                    sap_gain = ss->alpha_q[g][sfb] * 0.1f;
+                    m[0][0] =  1 + sap_gain;
+                    m[0][1] =  1;
+                    m[1][0] =  1 - sap_gain;
+                    m[1][1] = -1;
+                } else {
+                    m[0][0] = 1;
+                    m[0][1] = 0;
+                    m[1][0] = 0;
+                    m[1][1] = 1;
+                }
+            }
+
+            memcpy(&ss->matrix_stereo[g][sfb], m, sizeof(m));
+        }
+
+        max_sfb_prev = max_sfb_g;
+    }
+
+    for (int k = 0; k < s->frame_len_base; k++) {
+        int sfb = ssch0->offset2sfb[k];
+        int g = ssch0->offset2g[k];
+        float a = ss->matrix_stereo[g][sfb][0][0];
+        float b = ss->matrix_stereo[g][sfb][0][1];
+        float c = ss->matrix_stereo[g][sfb][1][0];
+        float d = ss->matrix_stereo[g][sfb][1][1];
+        float i0 = ssch0->scaled_spec[k];
+        float i1 = ssch1->scaled_spec[k];
+        float o0, o1;
+
+        o0 = i0 * a + i1 * b;
+        o1 = i0 * c + i1 * d;
+
+        ssch0->scaled_spec[k] = o0;
+        ssch1->scaled_spec[k] = o1;
+    }
+
+    return 0;
+}
+
+static int stereo_processing(AC4DecodeContext *s, Substream *ss)
+{
+    if (ss->mdct_stereo_proc[0])
+        two_channel_processing(s, ss, &ss->ssch[0], &ss->ssch[1]);
+
+    return 0;
+}
+
+static int m5channel_processing(AC4DecodeContext *s, Substream *ss)
+{
+    switch (ss->codec_mode) {
+    case CM_SIMPLE:
+    case CM_ASPX:
+        switch (ss->coding_config) {
+        case 0:
+            if (ss->mdct_stereo_proc[0])
+                two_channel_processing(s, ss, &ss->ssch[0], &ss->ssch[1]);
+            if (ss->mdct_stereo_proc[1])
+                two_channel_processing(s, ss, &ss->ssch[2], &ss->ssch[3]);
+            break;
+        }
+        break;
+    case CM_ASPX_ACPL_1:
+    case CM_ASPX_ACPL_2:
+        switch (ss->coding_config) {
+        case 0:
+            if (ss->mdct_stereo_proc[0])
+                two_channel_processing(s, ss, &ss->ssch[0], &ss->ssch[1]);
+            break;
+        }
+        break;
+    }
+
+    return 0;
+}
+
+static void qmf_analysis(AC4DecodeContext *s, SubstreamChannel *ssch)
+{
+    float *qmf_filt = ssch->qmf_filt;
+    float *pcm = ssch->pcm;
+    LOCAL_ALIGNED_32(float, u, [128]);
+    LOCAL_ALIGNED_32(float, z, [640]);
+
+    for (int ts = 0; ts < s->num_qmf_timeslots; ts++) {
+        /* shift time-domain input samples by 64 */
+        memmove(qmf_filt + 64, qmf_filt, sizeof(*qmf_filt) * (640 - 64));
+
+        /* feed new audio samples */
+        for (int sb = 63; sb >= 0; sb--)
+            qmf_filt[sb] = pcm[ts * 64 + 63 - sb];
+
+        /* multiply input samples by window coefficients */
+        s->fdsp->vector_fmul(z, qmf_filt, qwin, 640);
+
+        /* sum the samples to create vector u */
+        for (int n = 0; n < 128; n++) {
+            u[n] = z[n];
+            for (int k = 1; k < 5; k++)
+                u[n] += z[n + k * 128];
+        }
+
+        /* compute 64 new subband samples */
+        for (int sb = 0; sb < 64; sb++) {
+            float *cos_atab = s->cos_atab[sb];
+            float *sin_atab = s->sin_atab[sb];
+
+            ssch->Q[0][ts][sb] = s->fdsp->scalarproduct_float(u, cos_atab, 128);
+            ssch->Q[1][ts][sb] = s->fdsp->scalarproduct_float(u, sin_atab, 128);
+        }
+    }
+}
+
+static void qmf_synthesis(AC4DecodeContext *s, SubstreamChannel *ssch, float *pcm)
+{
+    float *qsyn_filt = ssch->qsyn_filt;
+    LOCAL_ALIGNED_32(float, g, [640]);
+    LOCAL_ALIGNED_32(float, w, [640]);
+
+    for (int ts = 0; ts < s->num_qmf_timeslots; ts++) {
+        /* shift samples by 128 */
+        memmove(qsyn_filt + 128, qsyn_filt, sizeof(*qsyn_filt) * (1280 - 128));
+
+        for (int n = 0; n < 128; n++) {
+            float *cos_stab = s->cos_stab[n];
+            float *sin_stab = s->sin_stab[n];
+
+            qsyn_filt[n] = s->fdsp->scalarproduct_float(ssch->Q[0][ts], cos_stab, 64) -
+                           s->fdsp->scalarproduct_float(ssch->Q[1][ts], sin_stab, 64);
+        }
+
+        for (int n = 0; n < 5; n++) {
+            for (int sb = 0; sb < 64; sb++) {
+                g[128*n + sb]      = qsyn_filt[256*n + sb];
+                g[128*n + 64 + sb] = qsyn_filt[256*n + 192 + sb];
+            }
+        }
+        /* multiply by window coefficients */
+        s->fdsp->vector_fmul(w, g, qwin, 640);
+
+        /* compute 64 new time-domain output samples */
+        for (int sb = 0; sb < 64; sb++) {
+            float temp = 0;
+
+            for (int n = 0; n < 10; n++)
+                temp += w[64*n + sb];
+            pcm[ts*64 + sb] = temp;
+        }
+    }
+}
+
+static void spectral_synthesis(AC4DecodeContext *s, SubstreamChannel *ssch)
+{
+    LOCAL_ALIGNED_32(float, in, [2048]);
+    LOCAL_ALIGNED_32(float, x, [4096]);
+    const int *win_offset = ssch->win_offset;
+    float *overlap = ssch->overlap;
+    float *winl = s->winl;
+    float *winr = s->winr;
+    float *pcm = ssch->pcm;
+    int Nfull = s->frame_len_base;
+    int nskip, nskip_prev;
+    int win = 0;
+
+    for (int g = 0; g < ssch->scp.num_window_groups; g++) {
+        int midx = s->frame_len_base_idx;
+        int idx;
+        int N = get_transf_length(s, ssch, g, &idx);
+
+        if (!ssch->N_prev)
+            ssch->N_prev = Nfull;
+
+        compute_window(s, winl, N, ssch->N_prev, Nfull, 0);
+        compute_window(s, winr, ssch->N_prev, N, Nfull, 1);
+
+        for (int w = 0; w < ssch->scp.num_win_in_group[g]; w++) {
+            nskip = (Nfull - N) / 2;
+            nskip_prev = (Nfull - ssch->N_prev) / 2;
+
+            memcpy(in, ssch->spec_reord + win_offset[win + w], N * 4);
+
+#if 0
+            s->tx_fn[midx][idx](s->tx_ctx[midx][idx], x, in, sizeof(float));
+
+            s->fdsp->vector_fmul_window(pcm + win_offset[win + w], overlap + nskip, x,
+                                        s->kbd_window[midx][idx], N >> 1);
+            memcpy(overlap + nskip, x + (N >> 1), sizeof(float)*N >> 1);
+#else
+            s->tx_fn[midx][idx](s->tx_ctx[midx][idx], x + (N >> 1), in, sizeof(float));
+
+            for (int n = 0; n < N >> 1; n++) {
+                x[n]       = -x[N-n-1];
+                x[N*2-n-1] =  x[N+n];
+            }
+
+            for (int n = 0; n < N / 4; n++) {
+                x[2*n  ]     *= winl[2*n  ];
+                x[2*n+1]     *= winl[2*n+1];
+                x[N/2+2*n  ] *= winl[N/2+2*n  ];
+                x[N/2+2*n+1] *= winl[N/2+2*n+1];
+            }
+
+            /* window second half of previous block */
+            for (int n = 0; n < ssch->N_prev; n++)
+                overlap[nskip_prev + n] *= winr[n];
+
+            /* overlap/add using first N samples from x[n] */
+            for (int n = 0; n < N; n++)
+                overlap[nskip + n] += x[n];
+
+            /* output pcm */
+            for (int n = 0; n < N; n++)
+                pcm[win_offset[win + w] + n] = overlap[n];
+            /* move samples in overlap[] not stored in pcm[] */
+            for (int n = 0; n < nskip; n++)
+                overlap[n] = overlap[N+n];
+
+            /* store second N samples from x[n] for next overlap/add */
+            for (int n = 0; n < N; n++)
+                overlap[nskip + n] = x[N+n];
+#endif
+        }
+
+        ssch->N_prev = N;
+
+        win += ssch->scp.num_win_in_group[g];
+    }
+}
+
+static int polyfit(int order,
+                   int countOfElements,
+                   const float *const dependentValues,
+                   const float *const independentValues,
+                   float *coefficients)
+{
+    enum {maxOrder = 5};
+    float B[maxOrder+1] = {0.0f};
+    float P[((maxOrder+1) * 2)+1] = {0.0f};
+    float A[(maxOrder + 1)*2*(maxOrder + 1)] = {0.0f};
+    float x, y, powx;
+    int ii, jj, kk;
+
+    // This method requires that the countOfElements >
+    // (order+1)
+    if (countOfElements <= order)
+        return -1;
+
+    // This method has imposed an arbitrary bound of
+    // order <= maxOrder.  Increase maxOrder if necessary.
+    if (order > maxOrder)
+        return -1;
+
+    // Identify the column vector
+    for (ii = 0; ii < countOfElements; ii++) {
+        x    = dependentValues[ii];
+        y    = independentValues[ii];
+        powx = 1;
+
+        for (jj = 0; jj < (order + 1); jj++) {
+            B[jj] = B[jj] + (y * powx);
+            powx  = powx * x;
+        }
+    }
+
+    // Initialize the PowX array
+    P[0] = countOfElements;
+    // Compute the sum of the Powers of X
+    for (ii = 0; ii < countOfElements; ii++) {
+        x    = dependentValues[ii];
+        powx = dependentValues[ii];
+
+        for (jj = 1; jj < (2 * (order + 1)) + 1; jj++) {
+            P[jj] = P[jj] + powx;
+            powx  = powx * x;
+        }
+    }
+
+    // Initialize the reduction matrix
+    //
+    for (ii = 0; ii < (order + 1); ii++) {
+        for (jj = 0; jj < (order + 1); jj++) {
+            A[(ii * (2 * (order + 1))) + jj] = P[ii+jj];
+        }
+        A[(ii*(2 * (order + 1))) + (ii + (order + 1))] = 1;
+    }
+
+    // Move the Identity matrix portion of the redux matrix
+    // to the left side (find the inverse of the left side
+    // of the redux matrix
+    for (ii = 0; ii < (order + 1); ii++) {
+        x = A[(ii * (2 * (order + 1))) + ii];
+        if (x != 0) {
+            for (kk = 0; kk < (2 * (order + 1)); kk++) {
+                A[(ii * (2 * (order + 1))) + kk] =
+                    A[(ii * (2 * (order + 1))) + kk] / x;
+            }
+
+            for (jj = 0; jj < (order + 1); jj++) {
+                if ((jj - ii) != 0) {
+                    y = A[(jj * (2 * (order + 1))) + ii];
+                    for (kk = 0; kk < (2 * (order + 1)); kk++) {
+                        A[(jj * (2 * (order + 1))) + kk] =
+                            A[(jj * (2 * (order + 1))) + kk] -
+                            y * A[(ii * (2 * (order + 1))) + kk];
+                    }
+                }
+            }
+        } else { // Cannot work with singular matrices
+            return -1;
+        }
+    }
+
+    // Calculate and Identify the coefficients
+    for (ii = 0; ii < order + 1; ii++) {
+        for (jj = 0; jj < order + 1; jj++) {
+            x = 0;
+            for (kk = 0; kk < (order + 1); kk++) {
+                x = x + (A[(ii * (2 * (order + 1))) + (kk + (order + 1))] *
+                         B[kk]);
+            }
+            coefficients[ii] = x;
+        }
+    }
+
+    return 0;
+}
+
+static int get_qsignal_scale_factors(AC4DecodeContext *s, SubstreamChannel *ssch, int ch)
+{
+    int sbg_idx_high2low[24] = { 0 };
+    int sbg_idx_low2high[24] = { 0 };
+    int sbg_low = 0;
+    int delta;
+
+    for (int sbg = 0; sbg < ssch->num_sbg_sig_highres; sbg++) {
+        if (ssch->sbg_sig_lowres[sbg_low+1] == ssch->sbg_sig_highres[sbg]) {
+            sbg_low++;
+            sbg_idx_low2high[sbg_low] = sbg;
+        }
+        sbg_idx_high2low[sbg] = sbg_low;
+    }
+
+    delta = ((ch == 1) && (ssch->aspx_balance == 1)) + 1;
+
+    memcpy(ssch->qscf_sig_sbg_prev, ssch->qscf_sig_sbg, sizeof(ssch->qscf_sig_sbg));
+
+    /* Loop over Envelopes */
+    for (int atsg = 0; atsg < ssch->aspx_num_env; atsg++) {
+        /* Loop over scale factor subband groups */
+        for (int sbg = 0; sbg < ssch->num_sbg_sig[atsg]; sbg++) {
+            if (atsg == 0) {
+                ssch->atsg_freqres_prev[atsg] = ssch->atsg_freqres[ssch->aspx_num_env_prev - 1];
+                ssch->qscf_prev[sbg][atsg] = ssch->qscf_sig_sbg_prev[sbg][ssch->aspx_num_env_prev - 1];
+            } else {
+                ssch->atsg_freqres_prev[atsg] = ssch->atsg_freqres[atsg-1];
+                ssch->qscf_prev[sbg][atsg] = ssch->qscf_sig_sbg[sbg][atsg-1];
+            }
+            if (ssch->aspx_sig_delta_dir[atsg] == 0) { /* FREQ */
+                ssch->qscf_sig_sbg[sbg][atsg] = 0;
+                for (int i = 0; i <= sbg; i++) {
+                    ssch->qscf_sig_sbg[sbg][atsg] += delta * ssch->aspx_data[0][atsg][i];
+                }
+            } else { /* TIME */
+                if (ssch->atsg_freqres[atsg] == ssch->atsg_freqres_prev[atsg]) {
+                    ssch->qscf_sig_sbg[sbg][atsg]  = ssch->qscf_prev[sbg][atsg];
+                    ssch->qscf_sig_sbg[sbg][atsg] += delta * ssch->aspx_data[0][atsg][sbg];
+                } else if ((ssch->atsg_freqres[atsg] == 0) && (ssch->atsg_freqres_prev[atsg] == 1)) {
+                    ssch->qscf_sig_sbg[sbg][atsg]  = ssch->qscf_prev[sbg_idx_low2high[sbg]][atsg];
+                    ssch->qscf_sig_sbg[sbg][atsg] += delta * ssch->aspx_data[0][atsg][sbg];
+                } else if ((ssch->atsg_freqres[atsg] == 1) && (ssch->atsg_freqres_prev[atsg] == 0)) {
+                    ssch->qscf_sig_sbg[sbg][atsg]  = ssch->qscf_prev[sbg_idx_high2low[sbg]][atsg];
+                    ssch->qscf_sig_sbg[sbg][atsg] += delta * ssch->aspx_data[0][atsg][sbg];
+                }
+            }
+        }
+    }
+
+    return 0;
+}
+
+static int get_qnoise_scale_factors(AC4DecodeContext *s, SubstreamChannel *ssch, int ch)
+{
+    int delta;
+
+    if ((ch == 1) && (ssch->aspx_balance == 1)) {
+        delta = 2;
+    } else {
+        delta = 1;
+    }
+
+    /* Loop over envelopes */
+    for (int atsg = 0; atsg < ssch->aspx_num_noise; atsg++) {
+        /* Loop over noise subband groups */
+        for (int sbg = 0; sbg < ssch->num_sbg_noise; sbg++) {
+            ssch->qscf_noise_sbg[sbg][atsg] = 0;
+            if (ssch->aspx_noise_delta_dir[atsg] == 0) { /* FREQ */
+                for (int i = 0; i <= sbg; i++) {
+                    ssch->qscf_noise_sbg[sbg][atsg] += delta * ssch->aspx_data[1][atsg][sbg];
+                }
+            } else { /* TIME */
+                if (atsg == 0) {
+                    ssch->qscf_noise_sbg[sbg][atsg]  = ssch->qscf_prev[sbg][ssch->aspx_num_noise_prev-1];
+                    ssch->qscf_noise_sbg[sbg][atsg] += delta * ssch->aspx_data[1][atsg][sbg];
+                } else {
+                    ssch->qscf_noise_sbg[sbg][atsg]  = ssch->qscf_noise_sbg[sbg][atsg-1];
+                    ssch->qscf_noise_sbg[sbg][atsg] += delta * ssch->aspx_data[1][atsg][sbg];
+                }
+            }
+        }
+    }
+
+    return 0;
+}
+
+static void prepare_channel(AC4DecodeContext *s, int ch)
+{
+    Substream *ss = &s->substream;
+    SubstreamChannel *ssch = &ss->ssch[ch];
+
+    spectral_reordering(s, ssch);
+    spectral_synthesis(s, ssch);
+
+    qmf_analysis(s, ssch);
+}
+
+static void aspx_processing(AC4DecodeContext *s, SubstreamChannel *ssch)
+{
+    memcpy(ssch->Q_low_prev, ssch->Q_low, sizeof(ssch->Q_low));
+
+    for (int ts = 0; ts < s->ts_offset_hfgen; ts++) {
+        for (int sb = 0; sb < 64; sb++) {
+            if (sb < ssch->sbx) {
+                ssch->Q_low[0][ts][sb] = ssch->Q_prev[0][ts + s->num_qmf_timeslots - s->ts_offset_hfgen][sb];
+                ssch->Q_low[1][ts][sb] = ssch->Q_prev[1][ts + s->num_qmf_timeslots - s->ts_offset_hfgen][sb];
+            }
+        }
+    }
+
+    for (int ts = s->ts_offset_hfgen; ts < s->num_qmf_timeslots + s->ts_offset_hfgen; ts++) {
+        for (int sb = 0; sb < 64; sb++) {
+            if (sb < ssch->sbx) {
+                ssch->Q_low[0][ts][sb] = ssch->Q[0][ts - s->ts_offset_hfgen][sb];
+                ssch->Q_low[1][ts][sb] = ssch->Q[1][ts - s->ts_offset_hfgen][sb];
+            }
+        }
+    }
+}
+
+static void mono_deq_signal_factors(AC4DecodeContext *s, SubstreamChannel *ssch)
+{
+    float a = (ssch->aspx_qmode_env == 0) + 1;
+
+    for (int atsg = 0; atsg < ssch->aspx_num_env; atsg++) {
+        for (int sbg = 0; sbg < ssch->num_sbg_sig[atsg]; sbg++)
+            ssch->scf_sig_sbg[sbg][atsg] = powf(2, ssch->qscf_sig_sbg[sbg][atsg] / a) / 512.f;
+
+        if (ssch->aspx_sig_delta_dir[atsg] == 0 &&
+            ssch->qscf_sig_sbg[0][atsg] == 0 &&
+            ssch->scf_sig_sbg[1][atsg] < 0) {
+            ssch->scf_sig_sbg[0][atsg] = ssch->scf_sig_sbg[1][atsg];
+        }
+    }
+}
+
+static void mono_deq_noise_factors(AC4DecodeContext *s, SubstreamChannel *ssch)
+{
+#define NOISE_FLOOR_OFFSET 6
+
+    for (int atsg = 0; atsg < ssch->aspx_num_noise; atsg++) {
+        for (int sbg = 0; sbg < ssch->num_sbg_noise; sbg++)
+            ssch->scf_noise_sbg[sbg][atsg] = powf(2, NOISE_FLOOR_OFFSET - ssch->qscf_noise_sbg[sbg][atsg]);
+    }
+}
+
+static void stereo_deq_signoise_factors(AC4DecodeContext *s,
+                                        SubstreamChannel *ssch0,
+                                        SubstreamChannel *ssch1)
+{
+#define PAN_OFFSET 12
+
+    float a = 1 + (ssch0->aspx_qmode_env == 0);
+
+    for (int atsg = 0; atsg < ssch0->aspx_num_env; atsg++) {
+        for (int sbg = 0; sbg < ssch0->num_sbg_sig[atsg]; sbg++) {
+            float nom = powf(2, ssch0->qscf_sig_sbg[sbg][atsg] / a + 1) / 512.f;
+            float denom_a = 1 + powf(2, PAN_OFFSET - ssch1->qscf_sig_sbg[sbg][atsg] / a);
+            float denom_b = 1 + powf(2, ssch1->qscf_sig_sbg[sbg][atsg] / a - PAN_OFFSET);
+
+            ssch0->scf_sig_sbg[sbg][atsg] = nom / denom_a;
+            ssch1->scf_sig_sbg[sbg][atsg] = nom / denom_b;
+        }
+    }
+
+    for (int atsg = 0; atsg < ssch0->aspx_num_noise; atsg++) {
+        for (int sbg = 0; sbg < ssch0->num_sbg_noise; sbg++) {
+            float nom = powf(2, NOISE_FLOOR_OFFSET - ssch0->qscf_noise_sbg[sbg][atsg] + 1);
+            float denom_a = 1 + powf(2, PAN_OFFSET - ssch1->qscf_noise_sbg[sbg][atsg]);
+            float denom_b = 1 + powf(2, ssch1->qscf_noise_sbg[sbg][atsg] - PAN_OFFSET);
+
+            ssch0->scf_noise_sbg[sbg][atsg] = nom / denom_a;
+            ssch1->scf_noise_sbg[sbg][atsg] = nom / denom_b;
+        }
+    }
+}
+
+static void preflattening(AC4DecodeContext *s, SubstreamChannel *ssch)
+{
+    float mean_energy = 0;
+    int polynomial_order = 3;
+    int num_qmf_subbands = ssch->sbx;
+    float x[32]; // XXX
+    float slope[32]; // XXX
+    float pow_env[32]; // XXX
+    float poly_array[32]; // XXX
+
+    for (int i = 0; i < num_qmf_subbands; i++) {
+        x[i] = i;
+        slope[i] = 0;
+    }
+    /* Calculate the spectral signal envelope in dB over the current interval. */
+    for (int sb = 0; sb < num_qmf_subbands; sb++) {
+        pow_env[sb] = 0;
+        for (int ts = ssch->atsg_sig[0] * s->num_ts_in_ats; ts < ssch->atsg_sig[ssch->aspx_num_env] * s->num_ts_in_ats; ts++) {
+            pow_env[sb] += powf(ssch->Q_low[0][ts][sb], 2);
+            pow_env[sb] += powf(ssch->Q_low[1][ts][sb], 2);
+        }
+        pow_env[sb] /= (ssch->atsg_sig[ssch->aspx_num_env] - ssch->atsg_sig[0]) * s->num_ts_in_ats;
+        pow_env[sb] = 10 * log10f(pow_env[sb] + 1);
+        mean_energy += pow_env[sb];
+    }
+
+    mean_energy /= num_qmf_subbands;
+    polyfit(polynomial_order, num_qmf_subbands, x, pow_env, poly_array);
+
+    /* Transform polynomial into slope */
+    for (int k = polynomial_order; k >= 0; k--) {
+        for (int sb = 0; sb < num_qmf_subbands; sb++)
+            slope[sb] += powf(x[sb], k) * poly_array[k];
+    }
+
+    /* Derive a gain vector from the slope */
+    for (int sb = 0; sb < num_qmf_subbands; sb++) {
+        ssch->gain_vec[sb] = powf(10, (mean_energy - slope[sb]) / 20.f);
+    }
+}
+
+static void get_chirps(AC4DecodeContext *s, SubstreamChannel *ssch)
+{
+    memcpy(ssch->chirp_arr_prev, ssch->chirp_arr, sizeof(ssch->chirp_arr));
+
+    for (int sbg = 0; sbg < ssch->num_sbg_noise; sbg++) {
+        float new_chirp = new_chirp_tab[ssch->aspx_tna_mode[sbg]][ssch->aspx_tna_mode_prev[sbg]];
+
+        if (new_chirp < ssch->chirp_arr_prev[sbg]) {
+            new_chirp = 0.75000f * new_chirp + 0.25000f * ssch->chirp_arr_prev[sbg];
+        } else {
+            new_chirp = 0.90625f * new_chirp + 0.09375f * ssch->chirp_arr_prev[sbg];
+        }
+
+        if (new_chirp < 0.015625f) {
+            ssch->chirp_arr[sbg] = 0.f;
+        } else {
+            ssch->chirp_arr[sbg] = new_chirp;
+        }
+    }
+}
+
+static void get_covariance(AC4DecodeContext *s, SubstreamChannel *ssch)
+{
+    int num_ts_ext;
+    int ts_offset_hfadj = 4;
+
+    /* Create an additional delay of ts_offset_hfadj QMF time slots */
+    for (int sb = 0; sb < ssch->sba; sb++) {
+        int ts_offset_prev = s->num_qmf_timeslots - ts_offset_hfadj;
+
+        for (int ts = 0; ts < ts_offset_hfadj; ts++) {
+            ssch->Q_low_ext[0][ts][sb] = ssch->Q_low_prev[0][ts + ts_offset_prev][sb];
+            ssch->Q_low_ext[1][ts][sb] = ssch->Q_low_prev[1][ts + ts_offset_prev][sb];
+        }
+
+        for (int ts = 0; ts < s->num_qmf_timeslots + s->ts_offset_hfgen; ts++) {
+            ssch->Q_low_ext[0][ts + ts_offset_hfadj][sb] = ssch->Q_low[0][ts][sb];
+            ssch->Q_low_ext[1][ts + ts_offset_hfadj][sb] = ssch->Q_low[1][ts][sb];
+        }
+    }
+
+    num_ts_ext = s->num_qmf_timeslots + s->ts_offset_hfgen + ts_offset_hfadj;
+    /* Loop over QMF subbands */
+    for (int sb = 0; sb < ssch->sba; sb++) {
+        for (int i = 0; i < 3; i++) {
+            for (int j = 1; j < 3; j++) {
+                ssch->cov[sb][i][j][0] = 0;
+                ssch->cov[sb][i][j][1] = 0;
+                /* Loop over QMF time slots */
+                for (int ts = ts_offset_hfadj; ts < num_ts_ext; ts += 2) {
+                    ssch->cov[sb][i][j][0] += ssch->Q_low_ext[0][ts - 2*i][sb] * ssch->Q_low_ext[0][ts - 2*j][sb];
+                    ssch->cov[sb][i][j][0] += ssch->Q_low_ext[1][ts - 2*i][sb] * ssch->Q_low_ext[1][ts - 2*j][sb];
+                    ssch->cov[sb][i][j][1] -= ssch->Q_low_ext[0][ts - 2*i][sb] * ssch->Q_low_ext[1][ts - 2*j][sb];
+                    ssch->cov[sb][i][j][1] += ssch->Q_low_ext[1][ts - 2*i][sb] * ssch->Q_low_ext[0][ts - 2*j][sb];
+                }
+            }
+        }
+    }
+}
+
+static void complex_div(float *r, float *i, float x, float yi, float u, float vi)
+{
+    *r = (x*u + yi*vi) / (u * u + vi * vi);
+    *i = (x*vi - u*yi) / (u * u + vi * vi);
+}
+
+static void complex_mul(float *r, float *i, float x, float yi, float u, float vi)
+{
+    *r = x*u - yi*vi;
+    *i = x*vi + u*yi;
+}
+
+static void get_alphas(AC4DecodeContext *s, SubstreamChannel *ssch)
+{
+    float EPSILON_INV = powf(2,-20);
+
+    for (int sb = 0; sb < ssch->sba; sb++) {
+        float denom[2];
+
+        complex_mul(&denom[0], &denom[1], ssch->cov[sb][2][2][0], ssch->cov[sb][2][2][1], ssch->cov[sb][1][1][0], ssch->cov[sb][1][1][1]);
+        denom[0] -= (ssch->cov[sb][1][2][0] * ssch->cov[sb][1][2][0] + ssch->cov[sb][1][2][1] * ssch->cov[sb][1][2][1]) * 1/(1+EPSILON_INV);
+        if (denom[0] == 0 && denom[1] == 0) {
+            ssch->alpha1[sb][0] = 0;
+            ssch->alpha1[sb][1] = 0;
+        } else {
+            ssch->alpha1[sb][0]  = (ssch->cov[sb][0][1][0] * ssch->cov[sb][1][2][0] - ssch->cov[sb][0][1][1] * ssch->cov[sb][1][2][1]) -
+                                   (ssch->cov[sb][0][2][0] * ssch->cov[sb][1][1][0] - ssch->cov[sb][0][2][1] * ssch->cov[sb][1][1][1]);
+            ssch->alpha1[sb][1]  = (ssch->cov[sb][0][1][0] * ssch->cov[sb][1][2][1] + ssch->cov[sb][0][1][1] * ssch->cov[sb][1][2][0]) -
+                                   (ssch->cov[sb][0][2][0] * ssch->cov[sb][1][1][1] + ssch->cov[sb][0][2][1] * ssch->cov[sb][1][1][0]);
+            complex_div(&ssch->alpha1[sb][0], &ssch->alpha1[sb][1], ssch->alpha1[sb][0], ssch->alpha1[sb][1], denom[0], denom[1]);
+        }
+
+        if (ssch->cov[sb][1][1][0] == 0 &&
+            ssch->cov[sb][1][1][1] == 0) {
+            ssch->alpha0[sb][0] = 0;
+            ssch->alpha0[sb][1] = 0;
+        } else {
+            ssch->alpha0[sb][0]  = -ssch->cov[sb][0][1][0] + ssch->alpha1[sb][0] * ssch->cov[sb][1][2][0] + ssch->alpha1[sb][1] * ssch->cov[sb][1][2][1];
+            ssch->alpha0[sb][1]  = -ssch->cov[sb][0][1][1] + ssch->alpha1[sb][1] * ssch->cov[sb][1][2][0] - ssch->alpha1[sb][0] * ssch->cov[sb][1][2][1];
+            complex_div(&ssch->alpha0[sb][0], &ssch->alpha0[sb][1], ssch->alpha0[sb][0], ssch->alpha0[sb][1], ssch->cov[sb][1][1][0], ssch->cov[sb][1][1][1]);
+        }
+
+        if (hypotf(ssch->alpha0[sb][0], ssch->alpha0[sb][1]) >= 4.f ||
+            hypotf(ssch->alpha1[sb][0], ssch->alpha1[sb][1]) >= 4.f) {
+            ssch->alpha0[sb][0] = ssch->alpha0[sb][1] = 0;
+            ssch->alpha1[sb][0] = ssch->alpha1[sb][1] = 0;
+        }
+    }
+}
+
+static void create_high_signal(AC4DecodeContext *s, Substream *ss, SubstreamChannel *ssch)
+{
+    int ts_offset_hfadj = 4;
+
+    /* Loop over QMF time slots */
+    for (int ts = ssch->atsg_sig[0]*s->num_ts_in_ats; ts < ssch->atsg_sig[ssch->aspx_num_env] * s->num_ts_in_ats; ts++) {
+        int sum_sb_patches = 0;
+        int g = 0;
+        /* Loop over number of patches */
+        for (int i = 0; i < ssch->num_sbg_patches; i++) {
+            /* Loop over number of subbands per patch */
+            for (int sb = 0; sb < ssch->sbg_patch_num_sb[i]; sb++) {
+                float cplx[2] = { 0 };
+                /* Map to High QMF Subband */
+                int n, p;
+                int sb_high = ssch->sbx + sum_sb_patches + sb;
+
+                /* Map to current noise envelope */
+                if (ssch->sbg_noise[g+1] == sb_high)
+                    g++;
+
+                n = ts + ts_offset_hfadj;
+                /* Current low QMF Subband */
+                p = ssch->sbg_patch_start_sb[i] + sb;
+                ssch->Q_high[0][ts][sb_high] = ssch->Q_low_ext[0][n][p];
+                ssch->Q_high[1][ts][sb_high] = ssch->Q_low_ext[1][n][p];
+
+                complex_mul(&cplx[0], &cplx[1], ssch->alpha0[p][0], ssch->alpha0[p][1], ssch->Q_low_ext[0][n-2][p], ssch->Q_low_ext[1][n-2][p]);
+                complex_mul(&cplx[0], &cplx[1], cplx[0], cplx[1], ssch->chirp_arr[g], 0);
+                ssch->Q_high[0][ts][sb_high] += cplx[0];
+                ssch->Q_high[1][ts][sb_high] += cplx[1];
+                complex_mul(&cplx[0], &cplx[1], ssch->alpha1[p][0], ssch->alpha1[p][1], ssch->Q_low_ext[0][n-4][p], ssch->Q_low_ext[1][n-4][p]);
+                complex_mul(&cplx[0], &cplx[1], cplx[0], cplx[1], powf(ssch->chirp_arr[g], 2), 0);
+                ssch->Q_high[0][ts][sb_high] += cplx[0];
+                ssch->Q_high[1][ts][sb_high] += cplx[1];
+                if (ss->aspx_preflat == 1)
+                    complex_mul(&ssch->Q_high[0][ts][sb_high], &ssch->Q_high[1][ts][sb_high], ssch->Q_high[0][ts][sb_high], ssch->Q_high[1][ts][sb_high], 1.f / ssch->gain_vec[p], 0);
+            }
+            sum_sb_patches += ssch->sbg_patch_num_sb[i];
+        }
+    }
+}
+
+static void estimate_spectral_envelopes(AC4DecodeContext *s, Substream *ss, SubstreamChannel *ssch)
+{
+    int ts_offset_hfadj = 4;
+
+    for (int atsg = 0; atsg < ssch->aspx_num_env; atsg++) {
+        int sbg = 0;
+        /* Loop over QMF subbands in A-SPX range */
+        for (int sb = 0; sb < ssch->num_sb_aspx; sb++) {
+            int tsa, tsz;
+            float est_sig = 0;
+
+            /* Update current subband group */
+            if (sb == ssch->sbg_sig[atsg][sbg+1])
+                sbg++;
+
+            tsa = ssch->atsg_sig[atsg]*s->num_ts_in_ats + ts_offset_hfadj;
+            tsz = ssch->atsg_sig[atsg+1]*s->num_ts_in_ats + ts_offset_hfadj;
+            for (int ts = tsa; ts < tsz; ts++) {
+                if (ss->aspx_interpolation == 0) {
+                    for (int j = ssch->sbg_sig[atsg][sbg]; j < ssch->sbg_sig[atsg][sbg+1]; j++) {
+                        est_sig += powf(ssch->Q_high[0][ts][j], 2) +
+                                   powf(ssch->Q_high[1][ts][j], 2);
+                    }
+                } else {
+                    est_sig += powf(ssch->Q_high[0][ts][sb+ssch->sbx], 2) +
+                               powf(ssch->Q_high[1][ts][sb+ssch->sbx], 2);
+                }
+            }
+
+            if (ss->aspx_interpolation == 0) {
+                est_sig /= ssch->sbg_sig[atsg][sbg+1] - ssch->sbg_sig[atsg][sbg];
+                est_sig /= ssch->atsg_sig[atsg+1] - ssch->atsg_sig[atsg];
+            } else {
+                est_sig /= ssch->atsg_sig[atsg+1] - ssch->atsg_sig[atsg];
+            }
+            ssch->est_sig_sb[sb][atsg] = est_sig;
+        }
+    }
+}
+
+static void map_signoise(AC4DecodeContext *s, SubstreamChannel *ssch)
+{
+    int atsg_noise = 0;
+
+    /* Loop over Signal Envelopes */
+    for (int atsg = 0; atsg < ssch->aspx_num_env; atsg++) {
+        /* Map Signal Envelopes from subband groups to QMF subbands */
+
+        for (int sbg = 0; sbg < ssch->num_sbg_sig[atsg]; sbg++) {
+            for (int sb = ssch->sbg_sig[atsg][sbg]-ssch->sbx; sb < ssch->sbg_sig[atsg][sbg+1]-ssch->sbx; sb++)
+                ssch->scf_sig_sb[sb][atsg] = ssch->scf_sig_sbg[sbg][atsg];
+
+        }
+
+        if (ssch->atsg_sig[atsg] == ssch->atsg_noise[atsg_noise + 1])
+            atsg_noise++;
+
+        /* Map Noise Floors from subband groups to QMF subbands, and to signal envelopes */
+        for (int sbg = 0; sbg < ssch->num_sbg_noise; sbg++) {
+            for (int sb = ssch->sbg_noise[sbg]-ssch->sbx; sb < ssch->sbg_noise[sbg+1]-ssch->sbx; sb++)
+                ssch->scf_noise_sb[sb][atsg] = ssch->scf_noise_sbg[sbg][atsg_noise];
+        }
+    }
+}
+
+static void add_sinusoids(AC4DecodeContext *s, SubstreamChannel *ssch)
+{
+    int p_sine_at_end;
+
+    if (ssch->aspx_tsg_ptr_prev == ssch->aspx_num_env_prev)
+        p_sine_at_end = 0;
+    else
+        p_sine_at_end = -1;
+
+    memcpy(ssch->sine_idx_sb_prev, ssch->sine_idx_sb, sizeof(ssch->sine_idx_sb));
+
+    /* Loop over envelopes */
+    for (int atsg = 0; atsg < ssch->aspx_num_env; atsg++) {
+        /* Loop over high resolution signal envelope subband groups */
+        for (int sbg = 0; sbg < ssch->num_sbg_sig_highres; sbg++) {
+            int sba = ssch->sbg_sig_highres[sbg] - ssch->sbx;
+            int sbz = ssch->sbg_sig_highres[sbg+1] - ssch->sbx;
+            int sb_mid = (int)0.5*(sbz+sba);
+            /* Map sinusoid markers to QMF subbands */
+            for (int sb = ssch->sbg_sig_highres[sbg]-ssch->sbx; sb < ssch->sbg_sig_highres[sbg+1]-ssch->sbx; sb++) {
+                if ((sb == sb_mid) && ((atsg >= ssch->aspx_tsg_ptr) || (p_sine_at_end == 0)
+                                       || ssch->sine_idx_sb_prev[sb][ssch->aspx_num_env_prev-1])) {
+                    ssch->sine_idx_sb[sb][atsg] = ssch->aspx_add_harmonic[sbg];
+                } else {
+                    ssch->sine_idx_sb[sb][atsg] = 0;
+                }
+            }
+        }
+    }
+
+    for (int atsg = 0; atsg < ssch->aspx_num_env; atsg++) {
+        /* Loop over subband groups */
+        for (int sbg = 0; sbg < ssch->num_sbg_sig[atsg]; sbg++) {
+            int sine_present = 0;
+            /* Additional sinusoid present in SF band? */
+            for (int sb = ssch->sbg_sig[atsg][sbg]-ssch->sbx; sb < ssch->sbg_sig[atsg][sbg+1]-ssch->sbx; sb++) {
+                if (ssch->sine_idx_sb[sb][atsg] == 1)
+                    sine_present = 1;
+            }
+
+            /* Mark all subbands in current subband group accordingly */
+            for (int sb = ssch->sbg_sig[atsg][sbg]-ssch->sbx; sb < ssch->sbg_sig[atsg][sbg+1]-ssch->sbx; sb++) {
+                ssch->sine_area_sb[sb][atsg] = sine_present;
+            }
+        }
+    }
+
+    /* Loop over envelopes */
+    for (int atsg = 0; atsg < ssch->aspx_num_env; atsg++) {
+        /* Loop over QMF subbands in A-SPX range */
+        for (int sb = 0; sb < ssch->num_sb_aspx; sb++) {
+            float sig_noise_fact = ssch->scf_sig_sb[sb][atsg] / (1+ssch->scf_noise_sb[sb][atsg]);
+
+            ssch->sine_lev_sb[sb][atsg] = sqrtf(sig_noise_fact * ssch->sine_idx_sb[sb][atsg]);
+            ssch->noise_lev_sb[sb][atsg] = sqrtf(sig_noise_fact * ssch->scf_noise_sb[sb][atsg]);
+        }
+    }
+
+    float EPSILON = 1.0;
+
+    /* Loop over envelopes */
+    for (int atsg = 0; atsg < ssch->aspx_num_env; atsg++) {
+        /* Loop over QMF subbands in A-SPX range */
+        for (int sb = 0; sb < ssch->num_sb_aspx; sb++) {
+            if (ssch->sine_area_sb[sb][atsg] == 0) {
+                float denom = EPSILON + ssch->est_sig_sb[sb][atsg];
+                if (!(atsg == ssch->aspx_tsg_ptr || atsg == p_sine_at_end))
+                    denom *= (1 + ssch->scf_noise_sb[sb][atsg]);
+                ssch->sig_gain_sb[sb][atsg] = sqrtf(ssch->scf_sig_sb[sb][atsg] / denom);
+            } else {
+                float denom = EPSILON + ssch->est_sig_sb[sb][atsg];
+                denom *= 1 + ssch->scf_noise_sb[sb][atsg];
+                ssch->sig_gain_sb[sb][atsg] = sqrtf(ssch->scf_sig_sb[sb][atsg]*ssch->scf_noise_sb[sb][atsg] / denom);
+            }
+        }
+    }
+
+    float LIM_GAIN = 1.41254;
+    float EPSILON0 = powf(10, -12);
+    float MAX_SIG_GAIN = powf(10, 5);
+
+    /* Loop over envelopes */
+    for (int atsg = 0; atsg < ssch->aspx_num_env; atsg++) {
+        /* Loop over limiter subband groups */
+        for (int sbg = 0; sbg < ssch->num_sbg_lim; sbg++) {
+            float nom = 0;
+            float denom = EPSILON0;
+            for (int sb = ssch->sbg_lim[sbg]-ssch->sbx; sb < ssch->sbg_lim[sbg+1]-1-ssch->sbx; sb++) {
+                nom += ssch->scf_sig_sb[sb][atsg];
+                denom += ssch->est_sig_sb[sb][atsg];
+            }
+
+            ssch->max_sig_gain_sbg[sbg][atsg] = sqrtf(nom/denom) * LIM_GAIN;
+        }
+
+        int sbg = 0;
+        /* Map to QMF subbands */
+        for (int sb = 0; sb < ssch->num_sb_aspx; sb++) {
+            if (sb == ssch->sbg_lim[sbg+1]-ssch->sbx)
+                sbg++;
+            ssch->max_sig_gain_sb[sb][atsg] = FFMIN(ssch->max_sig_gain_sbg[sbg][atsg], MAX_SIG_GAIN);
+        }
+    }
+
+    /* Loop over envelopes */
+    for (int atsg = 0; atsg < ssch->aspx_num_env; atsg++) {
+        /* Loop over QMF subbands */
+        for (int sb = 0; sb < ssch->num_sb_aspx; sb++) {
+            float tmp = ssch->noise_lev_sb[sb][atsg];
+
+            tmp *= ssch->max_sig_gain_sb[sb][atsg] / ssch->sig_gain_sb[sb][atsg];
+            ssch->noise_lev_sb_lim[sb][atsg] = FFMIN(ssch->noise_lev_sb[sb][atsg], tmp);
+        }
+    }
+
+    /* Loop over envelopes */
+    for (int atsg = 0; atsg < ssch->aspx_num_env; atsg++) {
+        /* Loop over QMF subbands */
+        for (int sb = 0; sb < ssch->num_sb_aspx; sb++) {
+            ssch->sig_gain_sb_lim[sb][atsg] = FFMIN(ssch->sig_gain_sb[sb][atsg],
+                                                    ssch->max_sig_gain_sb[sb][atsg]);
+        }
+    }
+
+    /* Loop over envelopes */
+    for (int atsg = 0; atsg < ssch->aspx_num_env; atsg++) {
+        /* Loop over limiter subband groups */
+        for (int sbg = 0; sbg < ssch->num_sbg_lim; sbg++) {
+            float nom, denom;
+
+            nom = denom = EPSILON0;
+            /* Loop over subbands */
+            for (int sb = ssch->sbg_lim[sbg]-ssch->sbx; sb < ssch->sbg_lim[sbg+1]-1-ssch->sbx; sb++) {
+                nom   += ssch->scf_sig_sb[sb][atsg];
+                denom += ssch->est_sig_sb[sb][atsg] * powf(ssch->sig_gain_sb_lim[sb][atsg], 2);
+                denom += powf(ssch->sine_lev_sb[sb][atsg], 2);
+                if (!((ssch->sine_lev_sb[sb][atsg] != 0)
+                      || (atsg == ssch->aspx_tsg_ptr) || (atsg == p_sine_at_end)))
+                    denom += powf(ssch->noise_lev_sb_lim[sb][atsg], 2);
+            }
+            ssch->boost_fact_sbg[sbg][atsg] = sqrtf(nom/denom);
+        }
+    }
+
+    float MAX_BOOST_FACT = 1.584893192;
+    /* Loop over envelopes */
+    for (int atsg = 0; atsg < ssch->aspx_num_env; atsg++) {
+        int sbg = 0;
+        /* Loop over QMF subbands */
+        for (int sb = 0; sb < ssch->num_sb_aspx; sb++) {
+            if (sb == ssch->sbg_lim[sbg+1]-ssch->sbx)
+                sbg++;
+            ssch->boost_fact_sb[sb][atsg] = FFMIN(ssch->boost_fact_sbg[sbg][atsg], MAX_BOOST_FACT);
+        }
+    }
+
+    /* Loop over envelopes */
+    for (int atsg = 0; atsg < ssch->aspx_num_env; atsg++) {
+        /* Loop over QMF subbands */
+        for (int sb = 0; sb < ssch->num_sb_aspx; sb++) {
+            float boost_fact                 = ssch->boost_fact_sb[sb][atsg];
+            ssch->sig_gain_sb_adj[sb][atsg]  = ssch->sig_gain_sb_lim[sb][atsg] * boost_fact;
+            ssch->noise_lev_sb_adj[sb][atsg] = ssch->noise_lev_sb_lim[sb][atsg] * boost_fact;
+            ssch->sine_lev_sb_adj[sb][atsg]  = ssch->sine_lev_sb[sb][atsg] * boost_fact;
+        }
+    }
+}
+
+static int sine_idx(int sb, int ts, AC4DecodeContext *s, SubstreamChannel *ssch)
+{
+    int index;
+
+    if (s->have_iframe) {
+        index = 1;
+    } else {
+        index = (ssch->sine_idx_prev[sb][ts] + 1) % 4;
+    }
+    index += ts - ssch->atsg_sig[0];
+
+    return index % 4;
+}
+
+static void generate_tones(AC4DecodeContext *s, SubstreamChannel *ssch)
+{
+    int atsg = 0;
+    /* Loop over QMF time slots */
+    for (int ts = ssch->atsg_sig[0] * s->num_ts_in_ats;
+         ts < ssch->atsg_sig[ssch->aspx_num_env] * s->num_ts_in_ats; ts++) {
+        if (ts == ssch->atsg_sig[atsg+1] * s->num_ts_in_ats)
+            atsg++;
+        /* Loop over QMF subbands in A-SPX */
+        for (int sb = 0; sb < ssch->num_sb_aspx; sb++) {
+            int idx;
+
+            ssch->sine_idx[sb][ts] = idx = sine_idx(sb, ts, s, ssch);
+            ssch->qmf_sine[0][ts][sb]  = ssch->sine_lev_sb_adj[sb][atsg];
+            ssch->qmf_sine[0][ts][sb] *= SineTable[0][idx];
+            ssch->qmf_sine[1][ts][sb]  = ssch->sine_lev_sb_adj[sb][atsg] * powf(-1, sb + ssch->sbx);
+            ssch->qmf_sine[1][ts][sb] *= SineTable[1][idx];
+        }
+    }
+}
+
+static void assemble_hf_signal(AC4DecodeContext *s, SubstreamChannel *ssch)
+{
+    int ts_offset_hfadj = 4;
+    int atsg = 0;
+    /* Get delayed QMF subsamples from delay buffer */
+    for (int ts = 0; ts < ssch->atsg_sig[0] * s->num_ts_in_ats; ts++) {
+        for (int sb = 0; sb < ssch->num_sb_aspx; sb++) {
+            ssch->Y[0][ts][sb] = ssch->Y_prev[0][s->num_qmf_timeslots + ts][sb];
+            ssch->Y[1][ts][sb] = ssch->Y_prev[1][s->num_qmf_timeslots + ts][sb];
+        }
+    }
+
+    /* Loop over QMF time slots */
+    for (int ts = ssch->atsg_sig[0] * s->num_ts_in_ats;
+         ts < ssch->atsg_sig[ssch->aspx_num_env] * s->num_ts_in_ats; ts++) {
+        if (ts == ssch->atsg_sig[atsg+1] * s->num_ts_in_ats)
+            atsg++;
+        /* Loop over QMF subbands */
+        for (int sb = 0; sb < ssch->num_sb_aspx; sb++) {
+            ssch->Y[0][ts][sb]  = ssch->sig_gain_sb_adj[sb][atsg];
+            ssch->Y[1][ts][sb]  = 0;
+            complex_mul(&ssch->Y[0][ts][sb], &ssch->Y[1][ts][sb],
+                        ssch->Y[0][ts][sb], ssch->Y[1][ts][sb],
+                        ssch->Q_high[0][ts + ts_offset_hfadj][sb + ssch->sbx],
+                        ssch->Q_high[1][ts + ts_offset_hfadj][sb + ssch->sbx]);
+        }
+    }
+
+    memcpy(ssch->Y_prev, ssch->Y, sizeof(ssch->Y));
+
+    /* Loop over time slots */
+    for (int ts = ssch->atsg_sig[0]; ts < ssch->atsg_sig[ssch->aspx_num_env]; ts++) {
+        /* Loop over QMF subbands */
+        for (int sb = 0; sb < ssch->num_sb_aspx; sb++) {
+            ssch->Y[0][ts][sb] += ssch->qmf_sine[0][ts][sb];
+            ssch->Y[1][ts][sb] += ssch->qmf_sine[1][ts][sb];
+        }
+    }
+
+    memcpy(ssch->Q_prev, ssch->Q, sizeof(ssch->Q));
+
+    for (int ts = 0; ts < s->num_qmf_timeslots; ts++) {
+        /* Loop over QMF subbands */
+        for (int sb = 0; sb < 64; sb++) {
+            ssch->Q[0][ts][sb] += ssch->Y[0][ts+s->ts_offset_hfgen][sb];
+            ssch->Q[1][ts][sb] += ssch->Y[1][ts+s->ts_offset_hfgen][sb];
+        }
+    }
+}
+
+static int stereo_aspx_processing(AC4DecodeContext *s, Substream *ss)
+{
+    if (ss->codec_mode == CM_ASPX) {
+        aspx_processing(s, &ss->ssch[0]);
+        aspx_processing(s, &ss->ssch[1]);
+        get_qsignal_scale_factors(s, &ss->ssch[0], 0);
+        get_qsignal_scale_factors(s, &ss->ssch[1], 1);
+        get_qnoise_scale_factors(s, &ss->ssch[0], 0);
+        get_qnoise_scale_factors(s, &ss->ssch[1], 1);
+        if (ss->ssch[0].aspx_balance == 0) {
+            mono_deq_signal_factors(s, &ss->ssch[0]);
+            mono_deq_signal_factors(s, &ss->ssch[1]);
+            mono_deq_noise_factors(s, &ss->ssch[0]);
+            mono_deq_noise_factors(s, &ss->ssch[1]);
+        } else {
+            stereo_deq_signoise_factors(s, &ss->ssch[0], &ss->ssch[1]);
+        }
+        preflattening(s, &ss->ssch[0]);
+        preflattening(s, &ss->ssch[1]);
+        get_covariance(s, &ss->ssch[0]);
+        get_covariance(s, &ss->ssch[1]);
+        get_alphas(s, &ss->ssch[0]);
+        get_alphas(s, &ss->ssch[1]);
+        get_chirps(s, &ss->ssch[0]);
+        get_chirps(s, &ss->ssch[1]);
+        create_high_signal(s, ss, &ss->ssch[0]);
+        create_high_signal(s, ss, &ss->ssch[1]);
+        estimate_spectral_envelopes(s, ss, &ss->ssch[0]);
+        estimate_spectral_envelopes(s, ss, &ss->ssch[1]);
+        map_signoise(s, &ss->ssch[0]);
+        map_signoise(s, &ss->ssch[1]);
+        add_sinusoids(s, &ss->ssch[0]);
+        add_sinusoids(s, &ss->ssch[1]);
+        generate_tones(s, &ss->ssch[0]);
+        generate_tones(s, &ss->ssch[1]);
+        assemble_hf_signal(s, &ss->ssch[0]);
+        assemble_hf_signal(s, &ss->ssch[1]);
+    }
+
+    return 0;
+}
+
+static void decode_channel(AC4DecodeContext *s, int ch, float *pcm)
+{
+    Substream *ss = &s->substream;
+    SubstreamChannel *ssch = &ss->ssch[ch];
+
+    qmf_synthesis(s, ssch, pcm);
+}
+
+static int ac4_decode_frame(AVCodecContext *avctx, void *data,
+                            int *got_frame_ptr, AVPacket *avpkt)
+{
+    AC4DecodeContext *s = avctx->priv_data;
+    AVFrame *frame = data;
+    GetBitContext *gb = &s->gbc;
+    int ret, start_offset = 0;
+    uint32_t header;
+
+    if (avpkt->size < 8)
+        return AVERROR_INVALIDDATA;
+
+    header = AV_RB16(avpkt->data);
+    if (header == 0xAC40 || header == 0xAC41) {
+        int size = AV_RB16(avpkt->data + 2);
+
+        start_offset = 4;
+        if (size == 0xFFFF)
+            start_offset += 3;
+    }
+
+    if ((ret = init_get_bits8(gb, avpkt->data, avpkt->size)) < 0)
+        return ret;
+    skip_bits_long(gb, start_offset * 8);
+
+    ret = ac4_toc(s);
+    if (ret < 0)
+        return ret;
+
+    if (!s->have_iframe)
+        return avpkt->size;
+
+    avctx->sample_rate = s->fs_index ? 48000 : 44100;
+    avctx->channels = channel_mode_nb_channels[s->pinfo[0].ssinfo.channel_mode];
+    avctx->channel_layout = channel_mode_layouts[s->pinfo[0].ssinfo.channel_mode];
+    frame->nb_samples = av_rescale(s->frame_len_base,
+                                   s->resampling_ratio.num,
+                                   s->resampling_ratio.den);
+    frame->nb_samples = s->frame_len_base;
+    if ((ret = ff_get_buffer(avctx, frame, 0)) < 0)
+        return ret;
+
+    skip_bits_long(gb, s->payload_base * 8);
+
+    for (int i = 0; i < s->nb_substreams; i++) {
+        int substream_type = s->substream_type[i];
+
+        switch (substream_type) {
+        case ST_SUBSTREAM:
+            ret = ac4_substream(s);
+            break;
+        case ST_PRESENTATION:
+            skip_bits_long(gb, s->substream_size[i] * 8);
+            break;
+        default:
+            av_assert0(0);
+        }
+
+        if (ret < 0)
+            return ret;
+    }
+
+    if (get_bits_left(gb) < 0)
+        av_log(s->avctx, AV_LOG_WARNING, "overread\n");
+
+    for (int ch = 0; ch < avctx->channels; ch++)
+        scale_spec(s, ch);
+
+    switch (s->pinfo[0].ssinfo.channel_mode) {
+    case 0:
+        /* nothing to do */
+        break;
+    case 1:
+        stereo_processing(s, &s->substream);
+        break;
+    case 3:
+    case 4:
+        m5channel_processing(s, &s->substream);
+        break;
+    }
+
+    for (int ch = 0; ch < avctx->channels; ch++)
+        prepare_channel(s, ch);
+
+    switch (s->pinfo[0].ssinfo.channel_mode) {
+    case 0:
+        break;
+    case 1:
+        break;
+        stereo_aspx_processing(s, &s->substream);
+        break;
+    case 3:
+    case 4:
+        break;
+    }
+
+    for (int ch = 0; ch < avctx->channels; ch++)
+        decode_channel(s, ch, (float *)frame->extended_data[ch]);
+
+    frame->key_frame = s->iframe_global;
+
+    *got_frame_ptr = 1;
+
+    return avpkt->size;
+}
+
+static av_cold void ac4_flush(AVCodecContext *avctx)
+{
+    AC4DecodeContext *s = avctx->priv_data;
+
+    s->have_iframe = 0;
+    s->sequence_counter_prev = 0;
+}
+
+static av_cold int ac4_decode_end(AVCodecContext *avctx)
+{
+    AC4DecodeContext *s = avctx->priv_data;
+
+    av_freep(&s->fdsp);
+
+    for (int j = 0; j < 8; j++)
+        for (int i = 0; i < 5; i++)
+            av_tx_uninit(&s->tx_ctx[j][i]);
+
+    return 0;
+}
+
+AVCodec ff_ac4_decoder = {
+    .name           = "ac4",
+    .type           = AVMEDIA_TYPE_AUDIO,
+    .id             = AV_CODEC_ID_AC4,
+    .priv_data_size = sizeof (AC4DecodeContext),
+    .init           = ac4_decode_init,
+    .close          = ac4_decode_end,
+    .decode         = ac4_decode_frame,
+    .flush          = ac4_flush,
+    .capabilities   = AV_CODEC_CAP_DR1,
+    .long_name      = NULL_IF_CONFIG_SMALL("AC-4"),
+    .sample_fmts    = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_FLTP,
+                                                      AV_SAMPLE_FMT_NONE },
+};
diff --git a/libavcodec/ac4dec_data.h b/libavcodec/ac4dec_data.h
new file mode 100644
index 0000000000..e200525399
--- /dev/null
+++ b/libavcodec/ac4dec_data.h
@@ -0,0 +1,1484 @@
+/*
+ * AC-4 Audio Decoder
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef AVCODEC_AC4DECDATA_H
+#define AVCODEC_AC4DECDATA_H
+
+static const uint8_t aspx_hcb_env_level_15_f0_bits[71] = {
+     7,  9,  9,  9,  9,  8,  8,  7,  7,  7,  7,  7,  6,  6,  6,  6,
+     6,  6,  6,  6,  6,  6,  5,  5,  5,  5,  5,  5,  5,  5,  4,  5,
+     5,  5,  5,  5,  5,  5,  4,  5,  5,  5,  5,  6,  6,  6,  7,  8,
+     9, 10, 11, 12, 14, 14, 16, 16, 17, 17, 18, 18, 18, 18, 18, 18,
+    18, 18, 17, 17, 17, 17, 16,
+};
+
+static const uint32_t aspx_hcb_env_level_15_f0_codes[71] = {
+    0x0003e, 0x0007e, 0x0007f, 0x000be, 0x000bf, 0x0003e, 0x0005e, 0x00016,
+    0x00017, 0x0001e, 0x0002e, 0x0005e, 0x00012, 0x0000a, 0x0000c, 0x0000e,
+    0x00013, 0x00016, 0x0001a, 0x0001b, 0x00022, 0x00023, 0x00004, 0x00008,
+    0x0000c, 0x0000e, 0x00012, 0x00014, 0x00015, 0x0001a, 0x00000, 0x00016,
+    0x00018, 0x0001e, 0x0001c, 0x00019, 0x0001d, 0x0001f, 0x00001, 0x0001b,
+    0x00013, 0x00010, 0x0000a, 0x0002e, 0x0001e, 0x0000d, 0x0003f, 0x000be,
+    0x0017e, 0x002fe, 0x005fe, 0x00bfe, 0x02ffe, 0x02ffc, 0x0bffc, 0x0bff6,
+    0x17ffa, 0x17ffb, 0x2fff8, 0x2fff9, 0x2fffa, 0x2fffb, 0x2fffc, 0x2fffd,
+    0x2fffe, 0x2ffff, 0x17fe8, 0x17fe9, 0x17fea, 0x17feb, 0x0bff7,
+};
+
+static const uint8_t aspx_hcb_env_level_15_df_bits[141] = {
+    21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+    21, 21, 17, 18, 19, 19, 21, 19, 19, 19, 21, 20, 20, 20, 16, 17,
+    19, 19, 18, 18, 17, 15, 15, 15, 15, 14, 14, 14, 14, 13, 13, 13,
+    13, 13, 13, 13, 12, 12, 12, 12, 12, 11, 10, 10,  9,  8,  8,  7,
+     6,  6,  5,  4,  3,  2,  2,  3,  4,  6,  7,  7,  8,  9, 10, 11,
+    11, 12, 13, 13, 14, 14, 15, 15, 15, 16, 16, 16, 17, 17, 17, 17,
+    17, 18, 17, 17, 16, 17, 18, 19, 20, 21, 19, 19, 18, 16, 19, 21,
+    16, 20, 20, 21, 21, 20, 20, 19, 20, 19, 17, 21, 21, 21, 21, 21,
+    21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+};
+
+static const uint32_t aspx_hcb_env_level_15_df_codes[141] = {
+    0xfeff2, 0xfeff3, 0xfeff4, 0xfeff5, 0xfeff6, 0xfeff7, 0xfeff8, 0xfeff9,
+    0xfeffa, 0xfeffb, 0xfeffc, 0xfeffd, 0xfeffe, 0xfefff, 0xff5e4, 0xff5e5,
+    0xff5e6, 0xff5e7, 0x0fef4, 0x1fefe, 0x3fdea, 0x3ffde, 0xff7b6, 0x3fdec,
+    0x3fdee, 0x3fd78, 0xff5ee, 0x7f798, 0x7faf6, 0x7f799, 0x07ffa, 0x0fef6,
+    0x3fdef, 0x3ffdf, 0x1fdee, 0x1ffee, 0x0ff7e, 0x03d7e, 0x03fba, 0x03fbe,
+    0x03ffe, 0x01ebe, 0x01fdc, 0x01fee, 0x01ff6, 0x00f5c, 0x00f5d, 0x00f7e,
+    0x00f7f, 0x00ff4, 0x00ff6, 0x00ffe, 0x007bc, 0x007bd, 0x007f6, 0x007fc,
+    0x007fe, 0x003fa, 0x001ea, 0x001fc, 0x000f6, 0x00076, 0x0007e, 0x0003c,
+    0x0001c, 0x0003e, 0x0001e, 0x0000e, 0x00006, 0x00002, 0x00000, 0x00002,
+    0x00006, 0x0003f, 0x0003e, 0x0003a, 0x00077, 0x000f4, 0x001ee, 0x003fc,
+    0x003d6, 0x007be, 0x00ffa, 0x00f5e, 0x01ff7, 0x01fea, 0x03ffc, 0x03fd6,
+    0x03fbb, 0x07fbe, 0x07fae, 0x07f7e, 0x0fff6, 0x0fffe, 0x0fef5, 0x0fef2,
+    0x0f5fe, 0x1fffe, 0x0ff78, 0x0fefe, 0x07afe, 0x0ff79, 0x1fef4, 0x3fd7a,
+    0x7f79a, 0xff5ef, 0x3fdfe, 0x3fffe, 0x1fdef, 0x07ffe, 0x3fdff, 0xff5f2,
+    0x07f78, 0x7f79b, 0x7f79e, 0xff5f3, 0xff5f4, 0x7f79f, 0x7faf8, 0x3ffff,
+    0x7f7f8, 0x3fbce, 0x0f5ff, 0xff5f5, 0xff5f6, 0xff5f7, 0xff5f8, 0xff5f9,
+    0xff5fa, 0xff5fb, 0xff5fc, 0xff5fd, 0xff5fe, 0xff5ff, 0xff7ac, 0xff7ad,
+    0xff7ae, 0xff7af, 0xff7b4, 0xff7b5, 0xff7b7,
+};
+
+static const uint8_t aspx_hcb_env_level_15_dt_bits[141] = {
+    19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+    19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+    19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 18, 18, 18, 18, 18,
+    17, 19, 17, 16, 17, 17, 17, 16, 15, 16, 15, 15, 14, 14, 14, 13,
+    12, 10,  8,  6,  4,  2,  1,  3,  5,  7, 10, 11, 12, 14, 14, 15,
+    15, 16, 16, 17, 16, 17, 17, 18, 16, 17, 18, 18, 19, 18, 19, 19,
+    17, 18, 18, 19, 19, 19, 19, 19, 19, 19, 19, 19, 18, 19, 19, 19,
+    19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+    19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+};
+
+static const uint32_t aspx_hcb_env_level_15_dt_codes[141] = {
+    0x7ffa0, 0x7ffa1, 0x7ffa2, 0x7ffa3, 0x7ffa4, 0x7ffa5, 0x7ffa6, 0x7ffa7,
+    0x7ffa8, 0x7ffa9, 0x7ffaa, 0x7ffab, 0x7ffac, 0x7ffad, 0x7ffae, 0x7ffaf,
+    0x7ffb0, 0x7ffb1, 0x7ffb2, 0x7ffb3, 0x7ffb4, 0x7ffb5, 0x7ffb6, 0x7ffb7,
+    0x7ffb8, 0x7ffb9, 0x7ffba, 0x7ffbb, 0x7ffbc, 0x7ffbd, 0x7ffbe, 0x7ffbf,
+    0x7ffc0, 0x7ffc1, 0x7ffc2, 0x7ffc3, 0x7ffc4, 0x7ffc5, 0x7ffc6, 0x7ffc7,
+    0x7ffcc, 0x7ffcd, 0x7ffce, 0x3ff16, 0x3ff17, 0x3ff1e, 0x3ff1f, 0x3ff3c,
+    0x1fefa, 0x7ffcf, 0x1ffb6, 0x0ff7c, 0x1ff8e, 0x1ffbe, 0x1fefb, 0x0ffc4,
+    0x07fba, 0x0ffc6, 0x07fbb, 0x07fee, 0x03fdc, 0x03ff0, 0x03ff2, 0x01ffa,
+    0x00ffe, 0x003fc, 0x000fe, 0x0003e, 0x0000e, 0x00002, 0x00000, 0x00006,
+    0x0001e, 0x0007e, 0x003fe, 0x007fa, 0x00ff6, 0x03ffc, 0x03fde, 0x07fe6,
+    0x07fec, 0x0ffda, 0x0ffde, 0x1fefe, 0x0ffce, 0x1fff2, 0x1ffbf, 0x3ff3d,
+    0x0ff7e, 0x1feff, 0x3ff3e, 0x3ff3f, 0x7ffd2, 0x3ffe8, 0x7ffd3, 0x7ffd4,
+    0x1ff8a, 0x3ff6e, 0x3ff6f, 0x7ffd5, 0x7ffd6, 0x7ffd7, 0x7ffd8, 0x7ffd9,
+    0x7ffda, 0x7ffdb, 0x7ffde, 0x7ffdf, 0x3ffee, 0x7ffe0, 0x7ffe1, 0x7ffe2,
+    0x7ffe3, 0x7ffe4, 0x7ffe5, 0x7ffe6, 0x7ffe7, 0x7ffe8, 0x7ffe9, 0x7ffea,
+    0x7ffeb, 0x7ffec, 0x7ffed, 0x7ffee, 0x7ffef, 0x7fff0, 0x7fff1, 0x7fff2,
+    0x7fff3, 0x7fff4, 0x7fff5, 0x7fff6, 0x7fff7, 0x7fff8, 0x7fff9, 0x7fffa,
+    0x7fffb, 0x7fffc, 0x7fffd, 0x7fffe, 0x7ffff,
+};
+
+static const uint8_t aspx_hcb_env_balance_15_f0_bits[25] = {
+    13, 16, 15, 15, 13, 12, 11,  9,  8,  7,  5,  3,  1,  2,  4,  7,
+     8,  9, 10, 10, 11, 12, 13, 15, 16,
+};
+
+static const uint32_t aspx_hcb_env_balance_15_f0_codes[25] = {
+    0x01ffe, 0x0ffea, 0x07ff6, 0x07ff7, 0x01fff, 0x00ffc, 0x007de, 0x001f6,
+    0x000fa, 0x0007c, 0x0001e, 0x00006, 0x00000, 0x00002, 0x0000e, 0x0007e,
+    0x000fe, 0x001fe, 0x003fe, 0x003ee, 0x007df, 0x00ffd, 0x01ffc, 0x07ff4,
+    0x0ffeb,
+};
+
+static const uint8_t aspx_hcb_env_balance_15_df_bits[49] = {
+    19, 19, 19, 19, 19, 18, 18, 17, 16, 16, 16, 15, 13, 13, 12, 12,
+    12, 11, 10,  9,  8,  7,  5,  3,  1,  2,  4,  7,  8, 10, 10, 11,
+    12, 12, 13, 13, 14, 15, 16, 18, 18, 17, 18, 18, 18, 19, 19, 18,
+    19,
+};
+
+static const uint32_t aspx_hcb_env_balance_15_df_codes[49] = {
+    0x7def6, 0x7def7, 0x7defa, 0x7defb, 0x7dffe, 0x3ef7c, 0x3ef7e, 0x1f7b2,
+    0x0fbd8, 0x0fbda, 0x0fbfe, 0x07dfe, 0x01f6e, 0x01f7a, 0x00f9e, 0x00fb6,
+    0x00fbc, 0x007da, 0x003ec, 0x001f2, 0x000fa, 0x0007e, 0x0001e, 0x00006,
+    0x00000, 0x00002, 0x0000e, 0x0007f, 0x000f8, 0x003ee, 0x003e6, 0x007ce,
+    0x00fbe, 0x00f9f, 0x01f7e, 0x01f6f, 0x03efe, 0x07dee, 0x0fbdb, 0x3ef78,
+    0x3ef7f, 0x1f7b3, 0x3effc, 0x3effd, 0x3ef79, 0x7dffc, 0x7dffd, 0x3ef7a,
+    0x7dfff,
+};
+
+static const uint8_t aspx_hcb_env_balance_15_dt_bits[49] = {
+    15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 14, 13, 13, 12, 12,
+    11, 12, 11,  9,  8,  7,  4,  2,  1,  3,  5,  7,  9,  9, 10, 11,
+    11, 12, 12, 12, 12, 13, 15, 14, 15, 14, 15, 15, 15, 14, 14, 15,
+    15,
+};
+
+static const uint32_t aspx_hcb_env_balance_15_dt_codes[49] = {
+    0x07dce, 0x07dcf, 0x07ddc, 0x07ddd, 0x07dde, 0x07ddf, 0x07dec, 0x07ded,
+    0x07dee, 0x07def, 0x07df8, 0x03ebe, 0x01f5e, 0x01f7a, 0x00fb8, 0x00fba,
+    0x007cc, 0x00fbe, 0x007d6, 0x001f2, 0x000f8, 0x0007e, 0x0000e, 0x00002,
+    0x00000, 0x00006, 0x0001e, 0x0007f, 0x001f6, 0x001f4, 0x003ea, 0x007cd,
+    0x007ce, 0x00f9e, 0x00fae, 0x00fbc, 0x00f9f, 0x01f76, 0x07df9, 0x03ebf,
+    0x07dfa, 0x03ee4, 0x07dfb, 0x07dfc, 0x07dfd, 0x03ee5, 0x03ee6, 0x07dfe,
+    0x07dff,
+};
+
+static const uint8_t aspx_hcb_env_level_30_f0_bits[36] = {
+    11, 13, 11, 11, 10, 10,  9,  8,  8,  7,  7,  7,  6,  6,  5,  5,
+     4,  4,  4,  4,  3,  3,  3,  3,  4,  5,  6,  7,  9, 12, 14, 16,
+    17, 16, 17, 16,
+};
+
+static const uint32_t aspx_hcb_env_level_30_f0_codes[36] = {
+    0x007fe, 0x01ffe, 0x001de, 0x001df, 0x000ee, 0x003fe, 0x001fe, 0x0003a,
+    0x000fe, 0x0001c, 0x0001e, 0x0007e, 0x0002e, 0x0003e, 0x00006, 0x00016,
+    0x00002, 0x0000a, 0x0000c, 0x0000e, 0x00002, 0x00003, 0x00004, 0x00000,
+    0x0000d, 0x0001e, 0x0002f, 0x0001f, 0x00076, 0x00ffe, 0x03ffe, 0x0fffc,
+    0x1fffe, 0x0fffe, 0x1ffff, 0x0fffd,
+};
+
+static const uint8_t aspx_hcb_env_level_30_df_bits[71] = {
+    23, 23, 23, 23, 22, 22, 22, 22, 20, 19, 19, 20, 19, 18, 17, 16,
+    16, 15, 14, 14, 14, 13, 13, 13, 13, 12, 12, 12, 11, 10,  9,  8,
+     5,  4,  2,  1,  3,  6,  8,  9, 11, 12, 14, 14, 15, 16, 17, 17,
+    17, 18, 18, 19, 21, 19, 17, 20, 19, 20, 20, 20, 19, 19, 19, 22,
+    22, 22, 22, 22, 22, 22, 22,
+};
+
+static const uint32_t aspx_hcb_env_level_30_df_codes[71] = {
+    0x7ffbfc, 0x7ffbfd, 0x7ffbfe, 0x7ffbff, 0x3f7f6c, 0x3f7f6d, 0x3f7f6e,
+    0x3f7f6f, 0x0fdfee, 0x07effe, 0x07efec, 0x0fff7e, 0x07ffbe, 0x03f7fe,
+    0x01fbfe, 0x00fdfc, 0x00fff6, 0x007ffa, 0x003f7e, 0x003ffc, 0x003ffe,
+    0x001fba, 0x001fbe, 0x001ffa, 0x001ffb, 0x000fdc, 0x000ffc, 0x000ffe,
+    0x0007fc, 0x0003f6, 0x0001fe, 0x0000fe, 0x00001e, 0x00000e, 0x000002,
+    0x000000, 0x000006, 0x00003e, 0x0000fc, 0x0001fa, 0x0007fd, 0x000fde,
+    0x003fff, 0x003f76, 0x007eee, 0x00fdde, 0x01ffee, 0x01fbfc, 0x01fbfa,
+    0x03ffde, 0x03f77e, 0x07efee, 0x1ffefe, 0x07eefe, 0x01fbbe, 0x0fdfea,
+    0x07eff6, 0x0fdfda, 0x0fdfde, 0x0fdfef, 0x07eff4, 0x07efff, 0x07eeff,
+    0x3f7fae, 0x3f7f7c, 0x3f7f7d, 0x3f7f7e, 0x3f7f7f, 0x3f7fac, 0x3f7fad,
+    0x3f7faf,
+};
+
+static const uint8_t aspx_hcb_env_level_30_dt_bits[71] = {
+    20, 20, 20, 20, 20, 20, 20, 20, 20, 19, 19, 20, 20, 18, 16, 16,
+    15, 16, 15, 14, 14, 14, 13, 13, 13, 12, 12, 11, 11, 10, 10,  8,
+     6,  4,  2,  1,  3,  5,  8,  9, 11, 11, 12, 13, 13, 14, 14, 14,
+    15, 15, 16, 17, 18, 19, 18, 18, 18, 18, 20, 19, 20, 20, 20, 20,
+    20, 20, 20, 20, 20, 20, 19,
+};
+
+static const uint32_t aspx_hcb_env_level_30_dt_codes[71] = {
+    0x0ff7d6, 0x0ff7d7, 0x0ff7d8, 0x0ff7d9, 0x0ff7da, 0x0ff7db, 0x0ff7dc,
+    0x0ff7dd, 0x0ff7de, 0x07fbfe, 0x07ed7a, 0x0ff7df, 0x0ff7f2, 0x03fdf4,
+    0x00ff7c, 0x00fdae, 0x007ede, 0x00ff7e, 0x007ed2, 0x003f68, 0x003f6e,
+    0x003ffa, 0x001fb6, 0x001ffe, 0x001fff, 0x000fde, 0x000ff6, 0x0007ec,
+    0x0007fa, 0x0003fc, 0x0003fe, 0x0000fc, 0x00003e, 0x00000e, 0x000002,
+    0x000000, 0x000006, 0x00001e, 0x0000fe, 0x0001fa, 0x0007fe, 0x0007ee,
+    0x000fdf, 0x001ffc, 0x001fee, 0x003ffb, 0x003fde, 0x003f6a, 0x007ed6,
+    0x007ed3, 0x00fdbe, 0x01fb7e, 0x03f6bc, 0x07fbf8, 0x03f6be, 0x03f6bf,
+    0x03f6fe, 0x03f6ff, 0x0ff7f3, 0x07fbea, 0x0ff7f4, 0x0ff7f5, 0x0ff7f6,
+    0x0ff7f7, 0x0ff7f8, 0x0ff7f9, 0x0ff7fa, 0x0ff7fb, 0x0ff7fe, 0x0ff7ff,
+    0x07ed7b,
+};
+
+static const uint8_t aspx_hcb_env_balance_30_f0_bits[13] = {
+    12, 11,  9,  7,  4,  3,  1,  2,  5,  6,  8, 10, 12,
+};
+
+static const uint16_t aspx_hcb_env_balance_30_f0_codes[13] = {
+    0x000ffe, 0x0007fe, 0x0001fe, 0x00007e, 0x00000e, 0x000006, 0x000000,
+    0x000002, 0x00001e, 0x00003e, 0x0000fe, 0x0003fe, 0x000fff,
+};
+
+static const uint8_t aspx_hcb_env_balance_30_df_bits[25] = {
+    17, 17, 17, 15, 14, 12,  9,  9,  8,  7,  5,  2,  1,  3,  4,  7,
+     8,  9, 10, 11, 14, 15, 16, 16, 17,
+};
+
+static const uint32_t aspx_hcb_env_balance_30_df_codes[25] = {
+    0x01fffc, 0x01fffd, 0x01fffe, 0x007ffa, 0x003ffc, 0x000ffe, 0x0001fc,
+    0x0001fe, 0x0000fa, 0x00007e, 0x00001e, 0x000002, 0x000000, 0x000006,
+    0x00000e, 0x00007c, 0x0000fb, 0x0001fd, 0x0003fe, 0x0007fe, 0x003ffe,
+    0x007ffb, 0x00fffc, 0x00fffd, 0x01ffff,
+};
+
+static const uint8_t aspx_hcb_env_balance_30_dt_bits[25] = {
+    15, 15, 15, 14, 13, 13, 10,  8,  8,  7,  4,  2,  1,  3,  5,  7,
+     9,  9,  9, 12, 14, 13, 14, 15, 14,
+};
+
+static const uint16_t aspx_hcb_env_balance_30_dt_codes[25] = {
+    0x007ff2, 0x007ff3, 0x007ff6, 0x003ff6, 0x001ffe, 0x001fff, 0x0003fe,
+    0x0000fa, 0x0000fe, 0x00007e, 0x00000e, 0x000002, 0x000000, 0x000006,
+    0x00001e, 0x00007c, 0x0001fe, 0x0001f6, 0x0001f7, 0x000ffc, 0x003ffa,
+    0x001ffa, 0x003ff7, 0x007ff7, 0x003ff8,
+};
+
+static const uint8_t aspx_hcb_noise_level_f0_bits[30] = {
+    12, 12,  9,  7,  6,  6,  5,  1,  2,  3,  5,  7,  8,  8,  9, 10,
+    11, 12, 12, 12, 13, 13, 14, 12, 14, 14, 11, 16, 16, 15,
+};
+
+static const uint16_t aspx_hcb_noise_level_f0_codes[30] = {
+    0x000efe, 0x000eff, 0x0001fe, 0x000076, 0x00003a, 0x00003e, 0x00001e,
+    0x000000, 0x000002, 0x000006, 0x00001c, 0x00007e, 0x0000fe, 0x0000ee,
+    0x0001ff, 0x0003bc, 0x00077c, 0x000efa, 0x000ef4, 0x000ef6, 0x001df6,
+    0x001dee, 0x003bee, 0x000ef5, 0x003bde, 0x003bef, 0x00077e, 0x00ef7e,
+    0x00ef7f, 0x0077be,
+};
+
+static const uint8_t aspx_hcb_noise_level_df_bits[59] = {
+    17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 13, 14, 16, 16, 15, 15,
+    16, 15, 14, 14, 14, 14, 13, 11, 10,  9,  8,  7,  3,  1,  2,  4,
+     5,  7,  8,  9, 10, 12, 13, 13, 14, 16, 17, 17, 17, 17, 17, 17,
+    16, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
+};
+
+static const uint32_t aspx_hcb_noise_level_df_codes[59] = {
+    0x01f19e, 0x01f19f, 0x01f1dc, 0x01f1dd, 0x01f1de, 0x01f1df, 0x01f1e8,
+    0x01f1e9, 0x01f1ea, 0x01f1eb, 0x001f1a, 0x003e7e, 0x00f9fe, 0x00f8f6,
+    0x007c76, 0x007c66, 0x00f8f7, 0x007c7c, 0x003e3c, 0x003e36, 0x003e37,
+    0x003e3a, 0x001f3e, 0x0007ce, 0x0003e6, 0x0001f0, 0x0000fa, 0x00007e,
+    0x000006, 0x000000, 0x000002, 0x00000e, 0x00001e, 0x00007f, 0x0000fb,
+    0x0001f2, 0x0003e2, 0x000f9e, 0x001f1c, 0x001f18, 0x003e32, 0x00f8fa,
+    0x01f3fe, 0x01f1f6, 0x01f1f7, 0x01f1f8, 0x01f1f9, 0x01f1fa, 0x00f8ce,
+    0x01f1fb, 0x01f1fc, 0x01f1fd, 0x01f1fe, 0x01f1ff, 0x01f3f8, 0x01f3f9,
+    0x01f3fa, 0x01f3fb, 0x01f3ff,
+};
+
+static const uint8_t aspx_hcb_noise_level_dt_bits[59] = {
+    16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
+    16, 16, 16, 16, 16, 14, 16, 13, 11,  8,  6,  4,  3,  1,  2,  5,
+     7, 10, 10, 12, 13, 13, 14, 15, 14, 15, 15, 16, 16, 16, 16, 16,
+    16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
+};
+
+static const uint16_t aspx_hcb_noise_level_dt_codes[59] = {
+    0x00ff70, 0x00ff71, 0x00ff72, 0x00ff73, 0x00ff74, 0x00ff75, 0x00ff76,
+    0x00ff77, 0x00ff78, 0x00ff79, 0x00ff7a, 0x00ff7b, 0x00ff7c, 0x00ff7d,
+    0x00ff7e, 0x00ff7f, 0x00ffe0, 0x00ffe1, 0x00ffe2, 0x00ffe3, 0x00ffe6,
+    0x003fd6, 0x00ffe7, 0x001ffe, 0x0007fe, 0x0000fe, 0x00003e, 0x00000e,
+    0x000006, 0x000000, 0x000002, 0x00001e, 0x00007e, 0x0003fe, 0x0003fc,
+    0x000ff6, 0x001fe8, 0x001fea, 0x003fd2, 0x007fae, 0x003fd3, 0x007ff2,
+    0x007faf, 0x00ffe8, 0x00ffe9, 0x00ffea, 0x00ffeb, 0x00ffec, 0x00ffed,
+    0x00ffee, 0x00ffef, 0x00fff8, 0x00fff9, 0x00fffa, 0x00fffb, 0x00fffc,
+    0x00fffd, 0x00fffe, 0x00ffff,
+};
+
+static const uint8_t aspx_hcb_noise_balance_f0_bits[13] = {
+    10, 10,  9,  7,  5,  3,  2,  1,  4,  6,  9, 10, 10,
+};
+
+static const uint16_t aspx_hcb_noise_balance_f0_codes[13] = {
+    0x0003fa, 0x0003fe, 0x0001fc, 0x00007e, 0x00001e, 0x000006,
+    0x000002, 0x000000, 0x00000e, 0x00003e, 0x0001fe, 0x0003ff,
+    0x0003fb,
+};
+
+static const uint8_t aspx_hcb_noise_balance_df_bits[25] = {
+    13, 13, 13, 13, 13, 12, 13, 10,  9,  7,  4,  2,  1,  3,  5,  6,
+     9, 11, 13, 13, 12, 12, 12, 12, 12,
+};
+
+static const uint16_t aspx_hcb_noise_balance_df_codes[25] = {
+    0x001fd8, 0x001fd9, 0x001fda, 0x001fdb, 0x001fdc, 0x000fea, 0x001fdd,
+    0x0003f8, 0x0001fe, 0x00007e, 0x00000e, 0x000002, 0x000000, 0x000006,
+    0x00001e, 0x00003e, 0x0001ff, 0x0007f4, 0x001fde, 0x001fdf, 0x000fe4,
+    0x000fe5, 0x000fe6, 0x000fe7, 0x000feb,
+};
+
+static const uint8_t aspx_hcb_noise_balance_dt_bits[25] = {
+    11, 11, 11, 11, 11, 11, 11, 10, 10,  6,  4,  3,  1,  2,  5,  8,
+     9, 11, 10, 11, 11, 11, 11, 11, 11,
+};
+
+static const uint16_t aspx_hcb_noise_balance_dt_codes[25] = {
+    0x0007e6, 0x0007e7, 0x0007e8, 0x0007e9, 0x0007ea, 0x0007eb, 0x0007ec,
+    0x0003fe, 0x0003ff, 0x00003e, 0x00000e, 0x000006, 0x000000, 0x000002,
+    0x00001e, 0x0000fe, 0x0001f8, 0x0007ed, 0x0003f2, 0x0007ee, 0x0007ef,
+    0x0007f8, 0x0007f9, 0x0007fa, 0x0007fb,
+};
+
+static uint8_t aspx_codebook_signal_off[2][2][3] = {
+    {
+        {  0, 70, 70, },
+        { 36, 35, 35, },
+    },
+    {
+        { 25, 24, 24, },
+        { 13, 12, 12, },
+    },
+};
+
+static uint8_t aspx_codebook_noise_off[2][3] = {
+        { 30, 29, 29, },
+        { 13, 12, 12, },
+};
+
+static const uint8_t scale_factors_bits[121] = {
+    17, 14, 14, 14, 14, 14, 14, 15, 14, 14, 14, 14, 14, 14, 14, 14,
+    13, 13, 14, 14, 14, 14, 14, 13, 14, 13, 13, 14, 14, 13, 14, 13,
+    13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 12, 12, 12, 12, 11,
+    11, 11, 10,  9,  9,  8,  8,  6,  6,  4,  4,  3,  1,  4,  4,  5,
+     6,  7,  8,  8,  9,  9, 10, 10, 11, 11, 11, 11, 12, 11, 12, 12,
+    12, 12, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14,
+    14, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+    14, 14, 14, 14, 14, 16, 14, 14, 17,
+};
+
+static const uint8_t scale_factors_codes[121] = {
+    0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x01,
+    0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
+    0x19, 0x1a, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x1b,
+    0x14, 0x1c, 0x1d, 0x15, 0x16, 0x1e, 0x17, 0x1f,
+    0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
+    0x28, 0x29, 0x2a, 0x1b, 0x1c, 0x1d, 0x1e, 0x12,
+    0x13, 0x14, 0x0d, 0x08, 0x09, 0x06, 0x07, 0x03,
+    0x04, 0x02, 0x03, 0x03, 0x01, 0x04, 0x05, 0x03,
+    0x05, 0x05, 0x08, 0x09, 0x0a, 0x0b, 0x0e, 0x0f,
+    0x15, 0x16, 0x17, 0x18, 0x1f, 0x19, 0x20, 0x21,
+    0x22, 0x23, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30,
+    0x31, 0x32, 0x33, 0x34, 0x18, 0x19, 0x1a, 0x1b,
+    0x1c, 0x35, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22,
+    0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a,
+    0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x01, 0x30, 0x31,
+    0x01,
+};
+
+static const uint16_t frame_len_base_48khz[] = {
+    1920, 1920, 2048, 1536, 1536, 960, 960, 1024,
+    768, 768, 512, 384, 384, 2048, 0, 0,
+};
+
+static const uint8_t frame_len_base_idx_48khz[] = {
+    1, 1, 0, 2, 2, 4, 4, 3, 5, 5, 6, 7, 7, 0, 0, 0,
+};
+
+static const uint16_t transf_length_48khz_2048[] = {
+    128, 256, 512, 1024, 2048,
+};
+
+static const uint16_t transf_length_48khz_1920[] = {
+    120, 240, 480, 960, 1920,
+};
+
+static const uint16_t transf_length_48khz_1536[] = {
+    96, 192, 384, 768, 1536,
+};
+
+static const uint16_t transf_length_48khz_1024[] = {
+    128, 256, 512, 1024, 1024,
+};
+
+static const uint16_t transf_length_48khz_960[] = {
+    120, 240, 480, 960, 960,
+};
+
+static const uint16_t transf_length_48khz_768[] = {
+    96, 192, 384, 768, 768,
+};
+
+static const uint16_t transf_length_48khz_512[] = {
+    128, 256, 512, 512, 512,
+};
+
+static const uint16_t transf_length_48khz_384[] = {
+    96, 192, 384, 384, 384,
+};
+
+static const uint16_t *transf_length_48khz[8] = {
+    transf_length_48khz_2048,
+    transf_length_48khz_1920,
+    transf_length_48khz_1536,
+    transf_length_48khz_1024,
+    transf_length_48khz_960,
+    transf_length_48khz_768,
+    transf_length_48khz_512,
+    transf_length_48khz_384,
+};
+
+static const float kbd_window_alpha[8][5] = {
+    { 6.f, 5.f, 4.5f, 4.f, 3.0f },
+    { 6.f, 5.f, 4.5f, 4.f, 3.0f },
+    { 6.f, 5.f, 4.5f, 4.f, 3.0f },
+    { 6.f, 5.f, 4.5f, 4.f, 4.0f },
+    { 6.f, 5.f, 4.5f, 4.f, 4.0f },
+    { 6.f, 5.f, 4.5f, 4.f, 4.0f },
+    { 6.f, 5.f, 4.5f, 0.f, 4.5f },
+    { 6.f, 5.f, 4.5f, 0.f, 4.5f },
+};
+
+static const uint8_t n_grp_bits_a[4][4] = {
+    { 15, 10, 8, 7 },
+    { 10,  7, 4, 3 },
+    {  8,  4, 3, 1 },
+    {  7,  3, 1, 1 },
+};
+
+static const uint8_t n_grp_bits_b[4] = {
+    7, 3, 1, 0,
+};
+
+static const uint8_t n_grp_bits_c[4] = {
+    3, 1, 0, 0,
+};
+
+static const uint8_t channel_mode_bits[] = {
+    1, 2, 4, 4, 4, 7, 7, 7, 7, 7, 7, 8, 8, 9, 9, 9, 9,
+};
+
+static const uint16_t channel_mode_codes[] = {
+    0, 2, 12, 13, 14, 120, 121, 122, 123, 124, 125, 252, 253, 508, 509, 510, 511,
+};
+
+static const uint8_t bitrate_indicator_bits[] = {
+    3, 3, 3, 3, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+};
+
+static const uint8_t bitrate_indicator_codes[] = {
+    0, 2, 4, 6, 4, 5, 6, 7, 12, 13, 14, 15, 20, 21, 22, 23, 28, 29, 30, 31,
+};
+
+static const uint8_t asf_codebook_dim[] = {
+    4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 2,
+};
+
+static const uint8_t asf_codebook_unsigned[] = {
+    0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1,
+};
+
+static const uint8_t asf_codebook_off[] = {
+    1, 1, 0, 0, 4, 4, 0, 0, 0, 0, 0,
+};
+
+static const uint8_t asf_codebook_mod[] = {
+    3, 3, 3, 3, 9, 9, 8, 8, 13, 13, 17,
+};
+
+static const uint8_t asf_codebook_1_bits[81] = {
+     9,  9, 12, 10,  7, 10, 12, 10, 11, 10,  7, 10,  7,  5,  7,  9,
+     7, 10, 11,  8,  9,  9,  7,  9, 11, 10, 12,  9,  7, 10,  7,  5,
+     7,  9,  7, 10,  7,  5,  7,  5,  1,  5,  7,  5,  7, 10,  7,  8,
+     7,  5,  7, 10,  7,  9, 12, 10, 11,  9,  7, 10,  9,  8, 12, 10,
+     7,  9,  7,  5,  7,  9,  7, 10, 12, 10, 12, 10,  7, 10, 12,  9,
+     9,
+};
+
+static const uint8_t asf_codebook_1_codes[81] = {
+    0x0b, 0x0c, 0x00, 0x04, 0x08, 0x05, 0x01, 0x06, 0x04, 0x07, 0x09, 0x08, 0x0a, 0x08, 0x0b, 0x0d,
+    0x0c, 0x09, 0x05, 0x0d, 0x0e, 0x0f, 0x0d, 0x10, 0x06, 0x0a, 0x02, 0x11, 0x0e, 0x0b, 0x0f, 0x09,
+    0x10, 0x12, 0x11, 0x0c, 0x12, 0x0a, 0x13, 0x0b, 0x01, 0x0c, 0x14, 0x0d, 0x15, 0x0d, 0x16, 0x0e,
+    0x17, 0x0e, 0x18, 0x0e, 0x19, 0x13, 0x03, 0x0f, 0x07, 0x14, 0x1a, 0x10, 0x15, 0x0f, 0x04, 0x11,
+    0x1b, 0x16, 0x1c, 0x0f, 0x1d, 0x17, 0x1e, 0x12, 0x05, 0x13, 0x06, 0x14, 0x1f, 0x15, 0x07, 0x18,
+    0x19,
+};
+
+static const uint8_t asf_codebook_2_bits[81] = {
+     8,  7,  9,  8,  6,  8,  9,  8,  9,  8,  6,  7,  6,  5,  6,  7,
+     6,  8,  9,  7,  7,  7,  6,  7,  9,  8,  9,  8,  6,  8,  6,  5,
+     6,  7,  6,  8,  6,  5,  6,  5,  3,  5,  6,  5,  6,  8,  6,  7,
+     6,  5,  6,  8,  6,  8,  9,  8,  9,  8,  6,  7,  7,  7,  9,  8,
+     6,  7,  6,  4,  6,  8,  6,  8,  9,  8,  9,  8,  6,  8,  9,  7,
+     8,
+};
+
+static const uint8_t asf_codebook_2_codes[81] = {
+    0x06, 0x0e, 0x00, 0x07, 0x0e, 0x08, 0x01, 0x09, 0x02, 0x0a, 0x0f, 0x0f, 0x10, 0x13, 0x11, 0x10,
+    0x12, 0x0b, 0x03, 0x11, 0x12, 0x13, 0x13, 0x14, 0x04, 0x0c, 0x05, 0x0d, 0x14, 0x0e, 0x15, 0x14,
+    0x16, 0x15, 0x17, 0x0f, 0x18, 0x15, 0x19, 0x16, 0x07, 0x17, 0x1a, 0x18, 0x1b, 0x10, 0x1c, 0x16,
+    0x1d, 0x19, 0x1e, 0x11, 0x1f, 0x12, 0x06, 0x13, 0x07, 0x14, 0x20, 0x17, 0x18, 0x19, 0x08, 0x15,
+    0x21, 0x1a, 0x22, 0x0d, 0x23, 0x16, 0x24, 0x17, 0x09, 0x18, 0x0a, 0x19, 0x25, 0x1a, 0x0b, 0x1b,
+    0x1b,
+};
+
+static const uint8_t asf_codebook_3_bits[81] = {
+     1,  4,  9,  4,  5,  9, 10, 10, 12,  4,  6, 10,  5,  6,  9, 10,
+     9, 11, 10, 11, 14, 10, 10, 12, 12, 11, 13,  4,  6, 11,  6,  7,
+    10, 11, 10, 12,  5,  7, 11,  6,  6, 10, 10,  9, 11,  9, 10, 13,
+     9,  9, 12, 11, 11, 12,  9, 10, 15, 10, 11, 15, 14, 13, 15,  9,
+    10, 14,  9, 10, 13, 13, 12, 14, 11, 12, 15, 11, 11, 14, 13, 12,
+    14,
+};
+
+static const uint8_t asf_codebook_3_codes[81] = {
+    0x01, 0x04, 0x0d, 0x05, 0x05, 0x0e, 0x0a, 0x0b, 0x05, 0x06, 0x04, 0x0c, 0x06, 0x05, 0x0f, 0x0d,
+    0x10, 0x07, 0x0e, 0x08, 0x02, 0x0f, 0x10, 0x06, 0x07, 0x09, 0x04, 0x07, 0x06, 0x0a, 0x07, 0x06,
+    0x11, 0x0b, 0x12, 0x08, 0x07, 0x07, 0x0c, 0x08, 0x09, 0x13, 0x14, 0x11, 0x0d, 0x12, 0x15, 0x05,
+    0x13, 0x14, 0x09, 0x0e, 0x0f, 0x0a, 0x15, 0x16, 0x00, 0x17, 0x10, 0x01, 0x03, 0x06, 0x02, 0x16,
+    0x18, 0x04, 0x17, 0x19, 0x07, 0x08, 0x0b, 0x05, 0x11, 0x0c, 0x03, 0x12, 0x13, 0x06, 0x09, 0x0d,
+    0x07,
+};
+
+static const uint8_t asf_codebook_4_bits[81] = {
+     4,  4,  9,  5,  4,  8,  9,  8, 11,  4,  5,  8,  5,  4,  8,  8,
+     8, 10,  9,  9, 11,  8,  8, 10, 11, 10, 12,  4,  5,  8,  5,  4,
+     8,  9,  8, 10,  4,  4,  8,  4,  4,  7,  8,  7,  9,  8,  8, 11,
+     8,  7, 10, 10,  9, 10,  9,  8, 11,  8,  8, 11, 11, 10, 12,  8,
+     8, 11,  8,  7, 10, 10,  9, 11, 11, 10, 12, 10,  9, 11, 12, 10,
+    11,
+};
+
+static const uint8_t asf_codebook_4_codes[81] = {
+    0x05, 0x06, 0x0a, 0x05, 0x07, 0x0a, 0x0b, 0x0b, 0x02, 0x08, 0x06, 0x0c, 0x07, 0x09, 0x0d, 0x0e,
+    0x0f, 0x07, 0x0c, 0x0d, 0x03, 0x10, 0x11, 0x08, 0x04, 0x09, 0x00, 0x0a, 0x08, 0x12, 0x09, 0x0b,
+    0x13, 0x0e, 0x14, 0x0a, 0x0c, 0x0d, 0x15, 0x0e, 0x0f, 0x10, 0x16, 0x11, 0x0f, 0x17, 0x18, 0x05,
+    0x19, 0x12, 0x0b, 0x0c, 0x10, 0x0d, 0x11, 0x1a, 0x06, 0x1b, 0x1c, 0x07, 0x08, 0x0e, 0x01, 0x1d,
+    0x1e, 0x09, 0x1f, 0x13, 0x0f, 0x10, 0x12, 0x0a, 0x0b, 0x11, 0x02, 0x12, 0x13, 0x0c, 0x03, 0x13,
+    0x0d,
+};
+
+static const uint8_t asf_codebook_5_bits[81] = {
+    14, 13, 12, 12, 11, 11, 12, 13, 14, 13, 12, 10,  9,  9,  9, 10,
+    11, 13, 13, 10,  9,  8,  7,  7,  9, 10, 12, 12,  9,  8,  5,  4,
+     5,  7,  9, 12, 12,  9,  7,  4,  1,  4,  7,  9, 12, 11,  9,  7,
+     5,  4,  5,  8,  9, 12, 12, 10,  9,  7,  7,  8,  9, 10, 12, 13,
+    11, 10,  9,  9, 10, 10, 12, 13, 14, 12, 12, 12, 11, 11, 12, 13,
+    14,
+};
+
+static const uint8_t asf_codebook_5_codes[81] = {
+    0x00, 0x02, 0x05, 0x06, 0x0b, 0x0c, 0x07, 0x03, 0x01, 0x04, 0x08, 0x09, 0x09, 0x0a, 0x0b, 0x0a,
+    0x0d, 0x05, 0x06, 0x0b, 0x0c, 0x0c, 0x08, 0x09, 0x0d, 0x0c, 0x09, 0x0a, 0x0e, 0x0d, 0x04, 0x04,
+    0x05, 0x0a, 0x0f, 0x0b, 0x0c, 0x10, 0x0b, 0x05, 0x01, 0x06, 0x0c, 0x11, 0x0d, 0x0e, 0x12, 0x0d,
+    0x06, 0x07, 0x07, 0x0e, 0x13, 0x0e, 0x0f, 0x0d, 0x14, 0x0e, 0x0f, 0x0f, 0x15, 0x0e, 0x10, 0x07,
+    0x0f, 0x0f, 0x16, 0x17, 0x10, 0x11, 0x11, 0x08, 0x02, 0x12, 0x13, 0x14, 0x10, 0x11, 0x15, 0x09,
+    0x03,
+};
+
+static const uint8_t asf_codebook_6_bits[81] = {
+    12, 11, 10, 10, 10, 10, 10, 11, 12, 11,  9,  8,  8,  8,  8,  8,
+     9, 11, 10,  8,  6,  6,  6,  5,  6,  8, 10, 10,  8,  6,  4,  4,
+     4,  5,  8, 10, 10,  8,  6,  4,  4,  4,  6,  8, 10, 10,  8,  5,
+     4,  4,  4,  6,  8, 10, 10,  8,  6,  5,  6,  5,  6,  8, 11, 11,
+     9,  8,  8,  8,  8,  8,  9, 11, 12, 11, 10, 10, 11, 10, 10, 11,
+    12,
+};
+
+static const uint8_t asf_codebook_6_codes[81] = {
+    0x00, 0x02, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x03, 0x01, 0x04, 0x0c, 0x08, 0x09, 0x0a, 0x0b, 0x0c,
+    0x0d, 0x05, 0x0b, 0x0d, 0x07, 0x08, 0x09, 0x09, 0x0a, 0x0e, 0x0c, 0x0d, 0x0f, 0x0b, 0x07, 0x08,
+    0x09, 0x0a, 0x10, 0x0e, 0x0f, 0x11, 0x0c, 0x0a, 0x0b, 0x0c, 0x0d, 0x12, 0x10, 0x11, 0x13, 0x0b,
+    0x0d, 0x0e, 0x0f, 0x0e, 0x14, 0x12, 0x13, 0x15, 0x0f, 0x0c, 0x10, 0x0d, 0x11, 0x16, 0x06, 0x07,
+    0x0e, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x0f, 0x08, 0x02, 0x09, 0x14, 0x15, 0x0a, 0x16, 0x17, 0x0b,
+    0x03,
+};
+
+static const uint8_t asf_codebook_7_bits[64] = {
+     1,  3,  6,  8,  9,  9, 10, 11,  3,  4,  6,  7,  8,  8,  9, 10,
+     6,  5,  7,  8,  8,  9, 10, 11,  8,  7,  8,  8,  9,  9, 10, 11,
+     9,  8,  8,  9, 10, 10, 10, 11,  9,  8,  9,  9, 10, 10, 11, 12,
+    10,  9, 10, 10, 10, 11, 12, 12, 12, 10, 11, 11, 12, 12, 12, 12,
+};
+
+static const uint8_t asf_codebook_7_codes[64] = {
+    0x01, 0x02, 0x07, 0x0b, 0x0a, 0x0b, 0x06, 0x04, 0x03, 0x03, 0x08, 0x0b, 0x0c, 0x0d, 0x0c, 0x07,
+    0x09, 0x05, 0x0c, 0x0e, 0x0f, 0x0d, 0x08, 0x05, 0x10, 0x0d, 0x11, 0x12, 0x0e, 0x0f, 0x09, 0x06,
+    0x10, 0x13, 0x14, 0x11, 0x0a, 0x0b, 0x0c, 0x07, 0x12, 0x15, 0x13, 0x14, 0x0d, 0x0e, 0x08, 0x00,
+    0x0f, 0x15, 0x10, 0x11, 0x12, 0x09, 0x01, 0x02, 0x03, 0x13, 0x0a, 0x0b, 0x04, 0x05, 0x06, 0x07,
+};
+
+static const uint8_t asf_codebook_8_bits[64] = {
+     4,  4,  5,  6,  7,  8,  9, 10,  4,  3,  4,  5,  6,  7,  8,  9,
+     5,  4,  4,  5,  6,  7,  8,  9,  6,  5,  5,  5,  6,  7,  8,  9,
+     7,  6,  6,  6,  7,  7,  9, 10,  8,  7,  7,  7,  7,  8,  9, 10,
+     9,  8,  8,  8,  8,  9,  9, 10, 11,  9,  9,  9, 10, 10, 10, 11,
+};
+
+static const uint8_t asf_codebook_8_codes[64] = {
+    0x08, 0x09, 0x09, 0x0a, 0x09, 0x08, 0x04, 0x01, 0x0a, 0x07, 0x0b, 0x0a, 0x0b, 0x0a, 0x09, 0x05,
+    0x0b, 0x0c, 0x0d, 0x0c, 0x0c, 0x0b, 0x0a, 0x06, 0x0d, 0x0d, 0x0e, 0x0f, 0x0e, 0x0c, 0x0b, 0x07,
+    0x0d, 0x0f, 0x10, 0x11, 0x0e, 0x0f, 0x08, 0x02, 0x0c, 0x10, 0x11, 0x12, 0x13, 0x0d, 0x09, 0x03,
+    0x0a, 0x0e, 0x0f, 0x10, 0x11, 0x0b, 0x0c, 0x04, 0x00, 0x0d, 0x0e, 0x0f, 0x05, 0x06, 0x07, 0x01,
+};
+
+static const uint8_t asf_codebook_9_bits[169] = {
+     1,  3,  6,  8,  9, 10, 10, 11, 11, 12, 12, 12, 13,  3,  4,  6,
+     7,  8,  9,  9, 10, 10, 11, 11, 11, 12,  6,  6,  7,  8,  9,  9,
+    10, 10, 10, 11, 11, 12, 12,  8,  7,  8,  9,  9, 10, 10, 11, 11,
+    11, 12, 12, 12,  9,  8,  9,  9, 10, 10, 11, 11, 11, 12, 12, 12,
+    13, 10,  9,  9, 10, 10, 10, 11, 11, 11, 12, 12, 12, 13, 10,  9,
+    10, 10, 11, 11, 11, 12, 12, 12, 12, 13, 13, 11, 10, 10, 11, 11,
+    12, 12, 12, 12, 12, 13, 13, 13, 11, 10, 10, 11, 11, 11, 12, 12,
+    12, 13, 13, 13, 14, 12, 11, 11, 11, 11, 12, 12, 12, 13, 13, 13,
+    14, 14, 12, 11, 11, 12, 12, 12, 12, 13, 13, 13, 13, 14, 14, 12,
+    11, 11, 12, 12, 12, 13, 13, 13, 13, 13, 14, 14, 13, 12, 12, 12,
+    13, 13, 13, 13, 14, 14, 14, 14, 14,
+};
+
+static const uint8_t asf_codebook_9_codes[169] = {
+    0x01, 0x02, 0x08, 0x14, 0x1b, 0x20, 0x21, 0x1e, 0x1f, 0x11, 0x12, 0x13, 0x06, 0x03, 0x03, 0x09,
+    0x0d, 0x15, 0x1c, 0x1d, 0x22, 0x23, 0x20, 0x21, 0x22, 0x14, 0x0a, 0x0b, 0x0e, 0x16, 0x1e, 0x1f,
+    0x24, 0x25, 0x26, 0x23, 0x24, 0x15, 0x16, 0x17, 0x0f, 0x18, 0x20, 0x21, 0x27, 0x28, 0x25, 0x26,
+    0x27, 0x17, 0x18, 0x19, 0x22, 0x19, 0x23, 0x24, 0x29, 0x2a, 0x28, 0x29, 0x2a, 0x1a, 0x1b, 0x1c,
+    0x07, 0x2b, 0x25, 0x26, 0x2c, 0x2d, 0x2e, 0x2b, 0x2c, 0x2d, 0x1d, 0x1e, 0x1f, 0x08, 0x2f, 0x27,
+    0x30, 0x31, 0x2e, 0x2f, 0x30, 0x20, 0x21, 0x22, 0x23, 0x09, 0x0a, 0x31, 0x32, 0x33, 0x32, 0x33,
+    0x24, 0x25, 0x26, 0x27, 0x28, 0x0b, 0x0c, 0x0d, 0x34, 0x34, 0x35, 0x35, 0x36, 0x37, 0x29, 0x2a,
+    0x2b, 0x0e, 0x0f, 0x10, 0x00, 0x2c, 0x38, 0x39, 0x3a, 0x3b, 0x2d, 0x2e, 0x2f, 0x11, 0x12, 0x13,
+    0x01, 0x02, 0x30, 0x3c, 0x3d, 0x31, 0x32, 0x33, 0x34, 0x14, 0x15, 0x16, 0x17, 0x03, 0x04, 0x35,
+    0x3e, 0x3f, 0x36, 0x37, 0x38, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x05, 0x06, 0x1d, 0x39, 0x3a, 0x3b,
+    0x1e, 0x1f, 0x20, 0x21, 0x07, 0x08, 0x09, 0x0a, 0x0b,
+};
+
+static const uint8_t asf_codebook_10_bits[169] = {
+     6,  5,  6,  6,  7,  8,  9, 10, 10, 11, 11, 12, 12,  5,  4,  4,
+     5,  6,  7,  7,  8,  9, 10, 10, 10, 11,  6,  4,  4,  5,  6,  6,
+     7,  8,  9,  9, 10, 10, 11,  6,  5,  5,  5,  6,  7,  7,  8,  8,
+     9, 10, 10, 11,  7,  6,  6,  6,  6,  7,  7,  8,  9,  9, 10, 10,
+    11,  8,  7,  6,  7,  7,  7,  8,  8,  9,  9, 10, 10, 11,  9,  7,
+     7,  7,  7,  8,  8,  9,  9, 10, 10, 10, 12, 10,  8,  8,  8,  8,
+     8,  9,  9,  9, 10, 10, 11, 12, 10,  8,  8,  8,  8,  9,  9,  9,
+    10, 10, 10, 11, 12, 11,  9,  9,  9,  9,  9, 10, 10, 10, 10, 11,
+    11, 13, 11, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 13, 12,
+    10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 12, 12, 12, 11, 11, 11,
+    11, 11, 11, 11, 12, 12, 13, 12, 13,
+};
+
+static const uint8_t asf_codebook_10_codes[169] = {
+    0x14, 0x11, 0x15, 0x16, 0x17, 0x1a, 0x1d, 0x11, 0x12, 0x07, 0x08, 0x02, 0x03, 0x12, 0x0c, 0x0d,
+    0x13, 0x17, 0x18, 0x19, 0x1b, 0x1e, 0x13, 0x14, 0x15, 0x09, 0x18, 0x0e, 0x0f, 0x14, 0x19, 0x1a,
+    0x1a, 0x1c, 0x1f, 0x20, 0x16, 0x17, 0x0a, 0x1b, 0x15, 0x16, 0x17, 0x1c, 0x1b, 0x1c, 0x1d, 0x1e,
+    0x21, 0x18, 0x19, 0x0b, 0x1d, 0x1d, 0x1e, 0x1f, 0x20, 0x1e, 0x1f, 0x1f, 0x22, 0x23, 0x1a, 0x1b,
+    0x0c, 0x20, 0x20, 0x21, 0x21, 0x22, 0x23, 0x21, 0x22, 0x24, 0x25, 0x1c, 0x1d, 0x0d, 0x26, 0x24,
+    0x25, 0x26, 0x27, 0x23, 0x24, 0x27, 0x28, 0x1e, 0x1f, 0x20, 0x04, 0x21, 0x25, 0x26, 0x27, 0x28,
+    0x29, 0x29, 0x2a, 0x2b, 0x22, 0x23, 0x0e, 0x05, 0x24, 0x2a, 0x2b, 0x2c, 0x2d, 0x2c, 0x2d, 0x2e,
+    0x25, 0x26, 0x27, 0x0f, 0x06, 0x10, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x28, 0x29, 0x2a, 0x2b, 0x11,
+    0x12, 0x00, 0x13, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x14, 0x15, 0x16, 0x17, 0x01, 0x07,
+    0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x18, 0x19, 0x1a, 0x08, 0x09, 0x0a, 0x1b, 0x1c, 0x1d,
+    0x1e, 0x1f, 0x20, 0x21, 0x0b, 0x0c, 0x02, 0x0d, 0x03,
+};
+
+static const uint8_t asf_codebook_11_bits[289] = {
+     3,  4,  6,  7,  8,  9,  9, 10, 10, 11, 11, 11, 12, 12, 12, 12,
+    10,  4,  4,  5,  6,  7,  8,  8,  9,  9,  9,  9, 10, 10, 10, 11,
+    11,  9,  6,  5,  6,  6,  7,  7,  8,  8,  9,  9,  9,  9, 10, 10,
+    10, 11,  8,  7,  6,  6,  7,  7,  7,  8,  8,  9,  9,  9,  9, 10,
+    10, 10, 11,  8,  8,  7,  7,  7,  7,  8,  8,  9,  9,  9,  9, 10,
+    10, 10, 10, 11,  8,  9,  7,  7,  7,  8,  8,  8,  9,  9,  9, 10,
+    10, 10, 10, 11, 11,  8,  9,  8,  8,  8,  8,  8,  9,  9,  9, 10,
+    10, 10, 10, 10, 11, 11,  8, 10,  9,  8,  8,  8,  9,  9,  9,  9,
+    10, 10, 10, 11, 11, 11, 11,  9, 10,  9,  9,  9,  9,  9,  9,  9,
+    10, 10, 10, 10, 11, 11, 11, 11,  9, 11,  9,  9,  9,  9,  9, 10,
+    10, 10, 10, 10, 10, 11, 11, 11, 12,  9, 11,  9,  9,  9,  9, 10,
+    10, 10, 10, 10, 10, 11, 11, 11, 11, 12,  9, 11, 10,  9,  9,  9,
+    10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 12,  9, 12, 10, 10, 10,
+    10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 12, 12,  9, 11, 10, 10,
+    10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 12, 12, 12,  9, 12, 11,
+    10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12,  9, 12,
+    11, 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12,  9,
+    10,  8,  8,  8,  8,  8,  8,  8,  9,  9,  9,  9,  9,  9,  9,  9,
+     5,
+};
+
+static const uint8_t asf_codebook_11_codes[289] = {
+    0x07, 0x0b, 0x1f, 0x2f, 0x3d, 0x36, 0x37, 0x26, 0x27, 0x0d, 0x0e, 0x0f, 0x00, 0x01, 0x02, 0x03,
+    0x28, 0x0c, 0x0d, 0x13, 0x20, 0x30, 0x3e, 0x3f, 0x38, 0x39, 0x3a, 0x3b, 0x29, 0x2a, 0x2b, 0x10,
+    0x11, 0x3c, 0x21, 0x14, 0x22, 0x23, 0x31, 0x32, 0x40, 0x41, 0x3d, 0x3e, 0x3f, 0x40, 0x2c, 0x2d,
+    0x2e, 0x12, 0x42, 0x33, 0x24, 0x25, 0x34, 0x35, 0x36, 0x43, 0x44, 0x41, 0x42, 0x43, 0x44, 0x2f,
+    0x30, 0x31, 0x13, 0x45, 0x46, 0x37, 0x38, 0x39, 0x3a, 0x47, 0x48, 0x45, 0x46, 0x47, 0x48, 0x32,
+    0x33, 0x34, 0x35, 0x14, 0x49, 0x49, 0x3b, 0x3c, 0x3d, 0x4a, 0x4b, 0x4c, 0x4a, 0x4b, 0x4c, 0x36,
+    0x37, 0x38, 0x39, 0x15, 0x16, 0x4d, 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x52, 0x4e, 0x4f, 0x50, 0x3a,
+    0x3b, 0x3c, 0x3d, 0x3e, 0x17, 0x18, 0x53, 0x3f, 0x51, 0x54, 0x55, 0x56, 0x52, 0x53, 0x54, 0x55,
+    0x40, 0x41, 0x42, 0x19, 0x1a, 0x1b, 0x1c, 0x56, 0x43, 0x57, 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d,
+    0x44, 0x45, 0x46, 0x47, 0x1d, 0x1e, 0x1f, 0x20, 0x5e, 0x21, 0x5f, 0x60, 0x61, 0x62, 0x63, 0x48,
+    0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x22, 0x23, 0x24, 0x04, 0x64, 0x25, 0x65, 0x66, 0x67, 0x68, 0x4e,
+    0x4f, 0x50, 0x51, 0x52, 0x53, 0x26, 0x27, 0x28, 0x29, 0x05, 0x69, 0x2a, 0x54, 0x6a, 0x6b, 0x6c,
+    0x55, 0x56, 0x57, 0x58, 0x59, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x06, 0x6d, 0x07, 0x5a, 0x5b, 0x5c,
+    0x5d, 0x5e, 0x5f, 0x60, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x08, 0x09, 0x6e, 0x36, 0x61, 0x62,
+    0x63, 0x64, 0x65, 0x66, 0x67, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x0a, 0x0b, 0x0c, 0x6f, 0x0d, 0x3c,
+    0x68, 0x69, 0x6a, 0x3d, 0x3e, 0x3f, 0x40, 0x41, 0x42, 0x43, 0x0e, 0x0f, 0x10, 0x11, 0x70, 0x12,
+    0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x71,
+    0x6b, 0x57, 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79,
+    0x15,
+};
+
+static const uint16_t sfb_offset_48khz_2048[] = {
+    0, 4, 8, 12, 16, 20, 24, 28, 32, 36, 40,
+    44, 52, 60, 68, 76, 84, 92, 100, 108, 116,
+    124, 136, 148, 160, 172, 188, 204, 220, 240,
+    260, 284, 308, 336, 364, 396, 432, 468, 508,
+    552, 600, 652, 704, 768, 832, 896, 960, 1024,
+    1088, 1152, 1216, 1280, 1344, 1408, 1472, 1536,
+    1600, 1664, 1728, 1792, 1856, 1920, 1984, 2048,
+    2176, 2304, 2432, 2560, 2688, 2816, 2944, 3072,
+    3200, 3328, 3456, 3584, 3712, 3840, 3968, 4096,
+    4224, 4352, 4480, 4608, 4736, 4864, 4992, 5120,
+    5248, 5376, 5504, 5632, 5760, 5888, 6016, 6144,
+    6272, 6400, 6528, 6656, 6784, 6912, 7040, 7168,
+    7296, 7424, 7552, 7680, 7808, 7936, 8064, 8192,
+};
+
+static const uint16_t sfb_offset_48khz_1920[] = {
+    0, 4, 8, 12, 16, 20, 24, 28, 32, 36, 40, 44, 52, 60, 68,
+    76, 84, 92, 100, 108, 116, 124, 136, 148, 160, 172, 188,
+    204, 220, 240, 260, 284, 308, 336, 364, 396, 432, 468,
+    508, 552, 600, 652, 704, 768, 832, 896, 960, 1024, 1088,
+    1152, 1216, 1280, 1344, 1408, 1472, 1536, 1600, 1664, 1728,
+    1792, 1856, 1920, 2048, 2176, 2304, 2432, 2560, 2688, 2816,
+    2944, 3072, 3200, 3328, 3456, 3584, 3712, 3840, 3968, 4096,
+    4224, 4352, 4480, 4608, 4736, 4864, 4992, 5120, 5248, 5376,
+    5504, 5632, 5760, 5888, 6016, 6144, 6272, 6400, 6528, 6656,
+    6784, 6912, 7040, 7168, 7296, 7424, 7552, 7680,
+};
+
+static const uint16_t sfb_offset_48khz_1536[] = {
+    0, 4, 8, 12, 16, 20, 24, 28, 32, 36, 40,
+    44, 52, 60, 68, 76, 84, 92, 100, 108, 116,
+    124, 136, 148, 160, 172, 188, 204, 220, 240,
+    260, 284, 308, 336, 364, 396, 432, 468, 508,
+    552, 600, 652, 704, 768, 832, 896, 960, 1024,
+    1088, 1152, 1216, 1280, 1344, 1408, 1472, 1536,
+    1664, 1792, 1920, 2048, 2176, 2304, 2432, 2560,
+    2688, 2816, 2944, 3072, 3200, 3328, 3456, 3584,
+    3712, 3840, 3968, 4096, 4224, 4352, 4480, 4608,
+    4736, 4864, 4992, 5120, 5248, 5376, 5504, 5632,
+    5760, 5888, 6016, 6144,
+};
+
+static const uint16_t sfb_offset_48khz_1024[] = {
+    0, 4, 8, 12, 16, 20, 24, 28, 32, 36, 40, 48,
+    56, 64, 72, 80, 88, 96, 108, 120, 132, 144,
+    160, 176, 196, 216, 240, 264, 292, 320, 352,
+    384, 416, 448, 480, 512, 544, 576, 608, 640,
+    672, 704, 736, 768, 800, 832, 864, 896, 928,
+    1024, 1152, 1280, 1408, 1536, 1664, 1792, 1920,
+    2048, 2176, 2304, 2432, 2560, 2688, 2816, 2944,
+    3072, 3200, 3328, 3456, 3584, 3712, 3840, 3968,
+    4096,
+};
+
+static const uint16_t sfb_offset_48khz_960[] = {
+    0, 4, 8, 12, 16, 20, 24, 28, 32, 36, 40, 48, 56, 64, 72,
+    80, 88, 96, 108, 120, 132, 144, 160, 176, 196, 216, 240,
+    264, 292, 320, 352, 384, 416, 448, 480, 512, 544,
+    576, 608, 640, 672, 704, 736, 768, 800, 832, 864, 896,
+    928, 960, 1024, 1152, 1280, 1408, 1536, 1664, 1792, 1920,
+    2048, 2176, 2304, 2432, 2560, 2688, 2816, 2944, 3072,
+    3200, 3328, 3456, 3584, 3712, 3840,
+};
+
+static const uint16_t sfb_offset_48khz_768[] = {
+    0, 4, 8, 12, 16, 20, 24, 28, 32, 36, 40, 48,
+    56, 64, 72, 80, 88, 96, 108, 120, 132, 144,
+    160, 176, 196, 216, 240, 264, 292, 320, 352,
+    384, 416, 448, 480, 512, 544, 576, 608, 640,
+    672, 704, 736, 768, 896, 1024, 1152, 1280, 1408,
+    1536, 1664, 1792, 1920, 2048, 2176, 2304, 2432,
+    2560, 2688, 2816, 2944, 3072,
+};
+
+static const uint16_t sfb_offset_48khz_512[] = {
+    0, 4, 8, 12, 16, 20, 24, 28, 32, 36, 40, 44, 48, 52,
+    56, 60, 68, 76, 84, 92, 100, 112, 124, 136, 148, 164,
+    184, 208, 236, 268, 300, 332, 364, 396, 428, 460, 512,
+    576, 640, 704, 768, 832, 896, 960, 1024, 1088, 1152,
+    1216, 1280, 1344, 1408, 1472, 1536, 1600, 1664, 1728,
+    1792, 1856, 1920, 1984, 2048,
+};
+
+static const uint16_t sfb_offset_48khz_480[] = {
+    0, 4, 8, 12, 16, 20, 24, 28, 32, 36, 40, 44, 48, 52, 56,
+    60, 68, 76, 84, 92, 100, 112, 124, 136, 148, 164, 184,
+    208, 236, 268, 300, 332, 364, 396, 428, 460, 480, 512,
+    576, 640, 704, 768, 832, 896, 960, 1024, 1088, 1152,
+    1216, 1280, 1344, 1408, 1472, 1536, 1600, 1664, 1728,
+    1792, 1856, 1920,
+};
+
+static const uint16_t sfb_offset_48khz_384[] = {
+    0, 4, 8, 12, 16, 20, 24, 28, 32, 36, 40, 44, 48, 52,
+    56, 60, 68, 76, 84, 92, 100, 112, 124, 136, 148, 164,
+    184, 208, 236, 268, 300, 332, 364, 384, 448, 512, 576,
+    640, 704, 768, 832, 896, 960, 1024, 1088, 1152,
+    1216, 1280, 1344, 1408, 1472, 1536,
+};
+
+static const uint16_t sfb_offset_48khz_256[] = {
+    0, 4, 8, 12, 16, 20, 24, 28, 36, 44, 52, 64, 76,
+    92, 108, 128, 148, 172, 196, 224, 256, 288, 320,
+    352, 384, 416, 448, 480, 512, 576, 640, 704, 768,
+    832, 896, 960, 1024,
+};
+
+static const uint16_t sfb_offset_48khz_240[] = {
+    0, 4, 8, 12, 16, 20, 24, 28, 36, 44, 52, 64, 76, 92, 108,
+    128, 148, 172, 196, 224, 240, 256, 288, 320, 352, 384, 416,
+    448, 480, 512, 576, 640, 704, 768, 832, 896, 960,
+};
+
+static const uint16_t sfb_offset_48khz_192[] = {
+    0, 4, 8, 12, 16, 20, 24, 28, 36, 44, 52, 64, 76,
+    92, 108, 128, 148, 172, 192, 224, 256, 288, 320,
+    352, 384, 448, 512, 576, 640, 704, 768,
+};
+
+static const uint16_t sfb_offset_48khz_128[] = {
+    0, 4, 8, 12, 16, 20, 28, 36, 44, 56, 68, 80, 96, 112,
+    128, 144, 160, 176, 192, 208, 224, 240, 256, 288, 320,
+    352, 384, 416, 448, 480, 512,
+};
+
+static const uint16_t sfb_offset_48khz_96[] = {
+    0, 4, 8, 12, 16, 20, 28, 36, 44, 56, 68, 80, 96, 112,
+    128, 144, 160, 176, 192, 224, 256, 288, 320, 352, 384,
+};
+
+static const uint8_t snf_bits[22] = {
+    4, 7, 8, 8, 7, 6, 6, 6, 6, 5, 5, 4, 4, 3, 3, 3, 3, 4, 4, 6, 7, 6,
+};
+
+static const uint8_t snf_codes[22] = {
+    0x03, 0x01, 0x00, 0x01, 0x02, 0x02, 0x03, 0x04,
+    0x05, 0x04, 0x05, 0x04, 0x05, 0x04, 0x05, 0x06,
+    0x07, 0x06, 0x07, 0x06, 0x03, 0x07,
+};
+
+static const uint8_t aspx_int_class_bits[4] = {
+    1, 2, 3, 3,
+};
+
+static const uint8_t aspx_int_class_codes[4] = {
+    0, 2, 6, 7,
+};
+
+static const uint8_t sbg_template_lowres[] = {
+    10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
+    22, 24, 26, 28, 30, 32, 35, 38, 42, 46,
+};
+
+static const uint8_t sbg_template_highres[] = {
+    18, 19, 20, 21, 22, 23, 24, 26, 28, 30, 32, 34,
+    36, 38, 40, 42, 44, 47, 50, 53, 56, 59, 62,
+};
+
+static const int tab_border[5][3][5] = {
+    {
+        { 0, 6, 0, 0, 0, },
+        { 0, 3, 6, 0, 0, },
+        { 0, 2, 3, 4, 6, },
+    },
+    {
+        { 0, 8, 0, 0, 0, },
+        { 0, 4, 8, 0, 0, },
+        { 0, 2, 4, 6, 8, },
+    },
+    {
+        { 0,12, 0, 0, 0, },
+        { 0, 6,12, 0, 0, },
+        { 0, 3, 6, 9,12, },
+    },
+    {
+        { 0,15, 0, 0, 0, },
+        { 0, 8,15, 0, 0, },
+        { 0, 4, 8,12,15, },
+    },
+    {
+        { 0,16, 0, 0, 0, },
+        { 0, 8,16, 0, 0, },
+        { 0, 4, 8,12,16, },
+    },
+};
+
+static const uint8_t qmf_subbands[][4] = {
+    { 0, 0, 0, 0 },
+    { 1, 1, 1, 1 },
+    { 2, 2, 2, 2 },
+    { 3, 3, 3, 2 },
+    { 4, 4, 3, 3 },
+    { 5, 4, 4, 3 },
+    { 6, 5, 4, 3 },
+    { 7, 5, 5, 3 },
+    { 8, 6, 5, 4 },
+    { 9, 6, 6, 4 },
+    {10, 7, 6, 4 },
+    {11, 8, 7, 5 },
+    {12, 9, 7, 5 },
+    {13,10, 8, 6 },
+    {14,11, 8, 6 },
+};
+
+static const uint8_t acpl_num_param_bands[] = {
+    15, 12, 9, 7,
+};
+
+static const uint8_t acpl_hcb_alpha_coarse_f0_bits[17] = {
+    10, 10,  9,  8,  6,  6,  5,  2,  1,  3,  5,  7,  7,  8,  9, 10,
+    10,
+};
+
+static const uint16_t acpl_hcb_alpha_coarse_f0_codes[17] = {
+    0x0003be, 0x0003fe, 0x0001fe, 0x0000fe, 0x00003e, 0x00003a,
+    0x00001e, 0x000002, 0x000000, 0x000006, 0x00001c, 0x00007e,
+    0x000076, 0x0000ee, 0x0001de, 0x0003ff, 0x0003bf,
+};
+
+static const uint8_t acpl_hcb_alpha_fine_f0_bits[33] = {
+    10, 12, 11, 11, 10, 10,  9,  8,  7,  7,  8,  7,  6,  6,  4,  3,
+     1,  3,  4,  6,  6,  7,  8,  8,  9,  9, 10, 10, 10, 10, 11, 12,
+    10,
+};
+
+static const uint16_t acpl_hcb_alpha_fine_f0_codes[33] = {
+    0x0002ce, 0x000b5e, 0x0004fe, 0x0005ae, 0x00027e, 0x0002de,
+    0x00016a, 0x0000b2, 0x00004a, 0x00004b, 0x0000b6, 0x00004e,
+    0x000024, 0x00002e, 0x00000a, 0x000006, 0x000000, 0x000007,
+    0x000008, 0x00002f, 0x000026, 0x000058, 0x0000b4, 0x00009e,
+    0x00016e, 0x000166, 0x0002df, 0x0002cf, 0x00027c, 0x00027d,
+    0x0004ff, 0x000b5f, 0x0002d6,
+};
+
+static const uint8_t acpl_hcb_alpha_coarse_df_bits[33] = {
+    15, 18, 17, 17, 16, 15, 15, 13, 12, 11, 10,  9,  8,  7,  4,  3,
+     1,  2,  5,  7,  8,  9, 10, 11, 12, 13, 15, 16, 16, 17, 16, 18,
+    15,
+};
+
+static const uint32_t acpl_hcb_alpha_coarse_df_codes[33] = {
+    0x007c76, 0x03e3fe, 0x01f1f6, 0x01f1f7, 0x00f8ea, 0x007c74, 0x007c7c,
+    0x001f1c, 0x000f9e, 0x0007ce, 0x0003e2, 0x0001f0, 0x0000fa, 0x00007e,
+    0x00000e, 0x000006, 0x000000, 0x000002, 0x00001e, 0x00007f, 0x0000fb,
+    0x0001f2, 0x0003e6, 0x0007c6, 0x000f9f, 0x001f1e, 0x007c7e, 0x00f8fe,
+    0x00f8fa, 0x01f1fe, 0x00f8eb, 0x03e3ff, 0x007c77,
+};
+
+static const uint8_t acpl_hcb_alpha_fine_df_bits[65] = {
+    13, 17, 17, 17, 16, 17, 17, 17, 17, 16, 16, 16, 15, 15, 14, 13,
+    13, 12, 12, 11, 11, 11, 10, 10, 10,  9,  8,  7,  7,  5,  4,  3,
+     1,  3,  4,  5,  6,  7,  8,  9,  9, 10, 10, 11, 11, 12, 12, 12,
+    13, 13, 14, 15, 15, 16, 16, 17, 16, 16, 17, 16, 16, 17, 17, 17,
+    13,
+};
+
+static const uint32_t acpl_hcb_alpha_fine_df_codes[65] = {
+    0x0011de, 0x011ffe, 0x013dea, 0x013df6, 0x008eea, 0x013df7, 0x013dee,
+    0x013deb, 0x013dec, 0x008eee, 0x008ffe, 0x009efe, 0x0047fe, 0x004f7c,
+    0x0023fe, 0x0011fe, 0x0013fe, 0x0008f6, 0x0009ee, 0x000476, 0x00047a,
+    0x0004f6, 0x00023a, 0x00027a, 0x00027e, 0x00013e, 0x00009a, 0x00004c,
+    0x00004e, 0x000012, 0x00000a, 0x000006, 0x000000, 0x000007, 0x00000b,
+    0x000010, 0x000022, 0x000046, 0x00009b, 0x00013c, 0x00011c, 0x00023e,
+    0x00023c, 0x0004fe, 0x00047e, 0x0009fe, 0x0008fe, 0x0008f7, 0x0013ff,
+    0x0011df, 0x0027bc, 0x004f7e, 0x004776, 0x009efa, 0x009ef4, 0x013dfe,
+    0x008eeb, 0x008ee8, 0x013dff, 0x008ee9, 0x008eef, 0x011fff, 0x013ded,
+    0x013def, 0x0011dc,
+};
+
+static const uint8_t acpl_hcb_alpha_coarse_dt_bits[33] = {
+    14, 16, 15, 16, 15, 15, 14, 13, 12, 12, 10,  9,  8,  7,  5,  3,
+     1,  2,  4,  7,  8,  9, 10, 11, 12, 13, 14, 15, 15, 16, 15, 16,
+    14,
+};
+
+static const uint32_t acpl_hcb_alpha_coarse_dt_codes[33] = {
+    0x003efc, 0x00fbfa, 0x007ddc, 0x00fbfe, 0x007dde, 0x007dfc, 0x003ef6,
+    0x001f76, 0x000fba, 0x000fbe, 0x0003ec, 0x0001f2, 0x0000f8, 0x00007e,
+    0x00001e, 0x000006, 0x000000, 0x000002, 0x00000e, 0x00007f, 0x0000fa,
+    0x0001f3, 0x0003ed, 0x0007dc, 0x000fbc, 0x001f7a, 0x003ef7, 0x007dfe,
+    0x007ddf, 0x00fbff, 0x007ddd, 0x00fbfb, 0x003efd,
+};
+
+static const uint8_t acpl_hcb_alpha_fine_dt_bits[65] = {
+    16, 18, 18, 18, 17, 17, 17, 18, 17, 17, 17, 16, 16, 16, 15, 15,
+    14, 14, 13, 13, 13, 12, 11, 11, 10, 10,  9,  9,  7,  6,  5,  3,
+     1,  2,  5,  6,  7,  9,  9, 10, 10, 11, 11, 12, 12, 13, 13, 14,
+    14, 15, 15, 16, 16, 16, 17, 17, 17, 17, 17, 18, 17, 18, 18, 18,
+    16,
+};
+
+static const uint32_t acpl_hcb_alpha_fine_dt_codes[65] = {
+    0x00eeee, 0x03b3ee, 0x03b3f6, 0x03b3fc, 0x01d9bc, 0x01d9bd, 0x01d9b2,
+    0x03b3fe, 0x01d9be, 0x01d9f6, 0x01d9fc, 0x00ecda, 0x00ecfa, 0x00eeef,
+    0x00766e, 0x007776, 0x003b3a, 0x003bba, 0x001d9a, 0x001ddc, 0x001dde,
+    0x000eec, 0x000764, 0x000772, 0x0003b0, 0x0003b8, 0x0001da, 0x0001de,
+    0x000072, 0x000038, 0x00001e, 0x000006, 0x000000, 0x000002, 0x00001f,
+    0x00003a, 0x000073, 0x0001df, 0x0001db, 0x0003ba, 0x0003b1, 0x000773,
+    0x000765, 0x000eed, 0x000ecc, 0x001d9e, 0x001d9c, 0x003bbe, 0x003b3b,
+    0x00777e, 0x00767c, 0x00eefe, 0x00ecfc, 0x00ecd8, 0x01d9fd, 0x01d9fa,
+    0x01d9bf, 0x01d9b6, 0x01d9b3, 0x03b3fd, 0x01d9b7, 0x03b3ff, 0x03b3ef,
+    0x03b3f7, 0x00eeff,
+};
+
+static const uint8_t acpl_hcb_beta_coarse_f0_bits[5] = {
+     1,  2,  3,  4,  4,
+};
+
+static const uint8_t acpl_hcb_beta_coarse_f0_codes[5] = {
+    0x000000, 0x000002, 0x000006, 0x00000e, 0x00000f,
+};
+
+static const uint8_t acpl_hcb_beta_fine_f0_bits[9] = {
+     1,  2,  3,  4,  5,  6,  7,  8,  8,
+};
+
+static const uint8_t acpl_hcb_beta_fine_f0_codes[9] = {
+    0x000000, 0x000002, 0x000006, 0x00000e, 0x00001e, 0x00003e, 0x00007e, 0x0000fe, 0x0000ff,
+};
+
+static const uint8_t acpl_hcb_beta_coarse_df_bits[9] = {
+     8,  6,  4,  3,  1,  2,  5,  7,  8,
+};
+
+static const uint8_t acpl_hcb_beta_coarse_df_codes[9] = {
+    0x0000fe, 0x00003e, 0x00000e, 0x000006, 0x000000, 0x000002, 0x00001e, 0x00007e, 0x0000ff,
+};
+
+static const uint8_t acpl_hcb_beta_fine_df_bits[17] = {
+    13, 12, 10,  9,  8,  7,  5,  3,  1,  2,  4,  7,  8,  9,  9, 11,
+    13,
+};
+
+static const uint32_t acpl_hcb_beta_fine_df_codes[17] = {
+    0x001f1e, 0x000f8e, 0x0003e2, 0x0001f2, 0x0000fa, 0x00007e,
+    0x00001e, 0x000006, 0x000000, 0x000002, 0x00000e, 0x00007f,
+    0x0000fb, 0x0001f3, 0x0001f0, 0x0007c6, 0x001f1f,
+};
+
+static const uint8_t acpl_hcb_beta_coarse_dt_bits[9] = {
+     8,  7,  5,  3,  1,  2,  4,  6,  8,
+};
+
+static const uint8_t acpl_hcb_beta_coarse_dt_codes[9] = {
+    0x0000fe, 0x00007e, 0x00001e, 0x000006, 0x000000, 0x000002, 0x00000e, 0x00003e, 0x0000ff,
+};
+
+static const uint8_t acpl_hcb_beta_fine_dt_bits[17] = {
+    15, 14, 12, 10,  8,  7,  5,  3,  1,  2,  4,  7,  7,  9, 11, 13,
+    15,
+};
+
+static const uint32_t acpl_hcb_beta_fine_dt_codes[17] = {
+    0x007dfe, 0x003efe, 0x000fbe, 0x0003ee, 0x0000fa,
+    0x00007e, 0x00001e, 0x000006, 0x000000, 0x000002,
+    0x00000e, 0x00007f, 0x00007c, 0x0001f6, 0x0007de,
+    0x001f7e, 0x007dff,
+};
+
+static const uint8_t acpl_hcb_beta3_coarse_f0_bits[9] = {
+     5,  3,  3,  2,  2,  3,  4,  6,  6,
+};
+
+static const uint8_t acpl_hcb_beta3_coarse_f0_codes[9] = {
+    0x000001, 0x000006, 0x000007, 0x000001, 0x000002, 0x000001, 0x000001, 0x000001, 0x000000,
+};
+
+static const uint8_t acpl_hcb_beta3_fine_f0_bits[17] = {
+     7,  5,  4,  4,  4,  3,  3,  3,  3,  3,  4,  5,  6,  6,  7,  7,
+     7,
+};
+
+static const uint8_t acpl_hcb_beta3_fine_f0_codes[17] = {
+    0x00000d, 0x000002, 0x000000, 0x00000c, 0x00000e, 0x000001, 0x000003,
+    0x000005, 0x000004, 0x000002, 0x00000d, 0x00001f, 0x00003d, 0x000007,
+    0x000078, 0x00000c, 0x000079,
+};
+
+static const uint8_t acpl_hcb_beta3_coarse_df_bits[17] = {
+    13, 12, 12, 11,  9,  6,  4,  2,  1,  3,  5,  7,  9, 11, 12, 13,
+     9,
+};
+
+static const uint32_t acpl_hcb_beta3_coarse_df_codes[17] = {
+    0x000a93, 0x000548, 0x00054b, 0x0002a7, 0x0000ab, 0x000014,
+    0x000004, 0x000000, 0x000001, 0x000003, 0x00000b, 0x00002b,
+    0x0000aa, 0x0002a6, 0x00054a, 0x000a92, 0x0000a8,
+};
+
+static const uint8_t acpl_hcb_beta3_fine_df_bits[33] = {
+    14, 15, 14, 13, 13, 12, 11, 11,  9,  8,  7,  6,  5,  4,  3,  2,
+     2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 12, 13, 14, 14, 14,
+    15,
+};
+
+static const uint32_t acpl_hcb_beta3_fine_df_codes[33] = {
+    0x0019e9, 0x0033f7, 0x0019f3, 0x000cf5, 0x000cfc, 0x00067d, 0x00033c,
+    0x0007ff, 0x0000ce, 0x000066, 0x000032, 0x000018, 0x00000d, 0x000007,
+    0x000002, 0x000000, 0x000002, 0x000006, 0x00000e, 0x00001e, 0x00003e,
+    0x00007e, 0x0000fe, 0x0001fe, 0x0003fe, 0x0007fe, 0x00067f, 0x00067b,
+    0x000cf8, 0x0019fa, 0x0019f2, 0x0019e8, 0x0033f6,
+};
+
+static const uint8_t acpl_hcb_beta3_coarse_dt_bits[17] = {
+    15, 15, 14, 12, 10,  7,  5,  3,  1,  2,  4,  6,  8, 11, 14, 14,
+     9,
+};
+
+static const uint16_t acpl_hcb_beta3_coarse_dt_codes[17] = {
+    0x000adc, 0x000add, 0x00056c, 0x00015a, 0x000057, 0x00000b, 0x000003,
+    0x000001, 0x000001, 0x000001, 0x000000, 0x000004, 0x000014, 0x0000ac,
+    0x00056f, 0x00056d, 0x00002a,
+};
+
+static const uint8_t acpl_hcb_beta3_fine_dt_bits[33] = {
+    16, 16, 16, 16, 16, 16, 15, 14, 12, 11, 10,  9,  8,  7,  5,  3,
+     1,  2,  4,  7,  8,  9, 10, 11, 12, 13, 14, 15, 15, 16, 16, 16,
+    16,
+};
+
+static const uint32_t acpl_hcb_beta3_fine_dt_codes[33] = {
+    0x00501e, 0x00501d, 0x00501c, 0x00501b, 0x00510e, 0x00510d, 0x002809,
+    0x001442, 0x000500, 0x000281, 0x000141, 0x0000a1, 0x000052, 0x00002a,
+    0x00000b, 0x000003, 0x000001, 0x000000, 0x000004, 0x00002b, 0x000053,
+    0x0000a3, 0x000145, 0x000289, 0x000511, 0x000a20, 0x001405, 0x00280c,
+    0x002808, 0x00510f, 0x00510c, 0x00501f, 0x00501a,
+};
+
+static const uint8_t acpl_hcb_gamma_coarse_f0_bits[21] = {
+    13, 13, 13, 13, 11,  9,  7,  6,  5,  3,  2,  3,  3,  4,  3,  3,
+     8, 11, 12, 13, 13,
+};
+
+static const uint16_t acpl_hcb_gamma_coarse_f0_codes[21] = {
+    0x000af4, 0x000af8, 0x000af9, 0x000afb, 0x0002bc, 0x0000ae, 0x00002a, 0x000014,
+    0x00000b, 0x000001, 0x000003, 0x000005, 0x000000, 0x000004, 0x000004, 0x000003,
+    0x000056, 0x0002bf, 0x00057b, 0x000af5, 0x000afa,
+};
+
+static const uint8_t acpl_hcb_gamma_fine_f0_bits[41] = {
+    12, 13, 13, 12, 12, 12, 12, 11,  9, 10,  9,  8,  8,  7,  7,  6,
+     5,  5,  4,  4,  3,  3,  4,  4,  5,  5,  5,  5,  4,  3,  4,  7,
+     8,  9, 10, 11, 11, 12, 12, 12, 12,
+};
+
+static const uint32_t acpl_hcb_gamma_fine_f0_codes[41] = {
+    0x0004b6, 0x001c6d, 0x001c6c, 0x00049b, 0x0004b5, 0x0004b7, 0x000e35, 0x00024e,
+    0x0001c7, 0x00038c, 0x000097, 0x000048, 0x0000e2, 0x000070, 0x000073, 0x000013,
+    0x000008, 0x000017, 0x000005, 0x00000c, 0x000004, 0x000001, 0x00000d, 0x00000a,
+    0x00001f, 0x00001e, 0x000016, 0x00001d, 0x000006, 0x000000, 0x000007, 0x000072,
+    0x00004a, 0x000092, 0x00012c, 0x00024f, 0x00024c, 0x000e34, 0x0004b4, 0x00049a,
+    0x000e37,
+};
+
+static const uint8_t acpl_hcb_gamma_coarse_df_bits[41] = {
+    16, 16, 16, 16, 16, 16, 16, 16, 16, 15, 15, 14, 13, 13, 11, 10,
+     8,  7,  4,  2,  1,  3,  5,  7,  8, 10, 11, 13, 13, 14, 15, 16,
+    16, 16, 16, 16, 16, 16, 16, 16,  8,
+};
+
+static const uint32_t acpl_hcb_gamma_coarse_df_codes[41] = {
+    0x0053e1, 0x0053e0, 0x0053db, 0x0053da, 0x0053d9, 0x0053e2, 0x0053e4, 0x0053ea,
+    0x0053eb, 0x0029ea, 0x0029f4, 0x0014f4, 0x000a78, 0x000a7f, 0x000299, 0x00014d,
+    0x000051, 0x00002a, 0x000004, 0x000000, 0x000001, 0x000003, 0x00000b, 0x00002b,
+    0x000052, 0x00014e, 0x000298, 0x000a7e, 0x000a79, 0x0014f7, 0x0029f6, 0x0053ef,
+    0x0053ee, 0x0053e7, 0x0053e6, 0x0053e3, 0x0053e5, 0x0053d8, 0x0053d7, 0x0053d6,
+    0x000050,
+};
+
+static const uint8_t acpl_hcb_gamma_fine_df_bits[81] = {
+    17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
+    17, 17, 16, 16, 16, 15, 15, 15, 14, 14, 13, 13, 13, 12, 11, 11,
+    10,  9,  8,  7,  6,  5,  4,  3,  1,  3,  4,  5,  6,  7,  9,  9,
+    10, 11, 11, 12, 13, 13, 14, 14, 14, 15, 15, 15, 16, 16, 16, 17,
+    17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
+    17,
+};
+
+static const uint32_t acpl_hcb_gamma_fine_df_codes[81] = {
+    0x013e1f, 0x013e35, 0x013e1e, 0x013e1d, 0x013e1c, 0x013e1b, 0x013e1a, 0x013e19,
+    0x013e34, 0x013e33, 0x013e18, 0x013ec2, 0x013ec1, 0x013ece, 0x013edf, 0x013e17,
+    0x013ede, 0x013edd, 0x009d52, 0x009f18, 0x009f1b, 0x004eaa, 0x004ea8, 0x004fb1,
+    0x002753, 0x002757, 0x0013a8, 0x0013e0, 0x0013ee, 0x0009d6, 0x0004e9, 0x0004fa,
+    0x00027b, 0x00013c, 0x00009c, 0x00004d, 0x000021, 0x000012, 0x00000b, 0x000007,
+    0x000000, 0x000006, 0x00000a, 0x000011, 0x000020, 0x00004c, 0x00013f, 0x00013b,
+    0x00027a, 0x0004f9, 0x0004e8, 0x0009d7, 0x0013ef, 0x0013e2, 0x0027da, 0x0027c7,
+    0x002752, 0x004fb6, 0x004eac, 0x004eab, 0x009f65, 0x009d5a, 0x009d53, 0x013ecd,
+    0x013edc, 0x013ecc, 0x013ecf, 0x013ec9, 0x013e32, 0x013ec3, 0x013e16, 0x013ec0,
+    0x013ec8, 0x013e15, 0x013e14, 0x013e13, 0x013e12, 0x013e11, 0x013e10, 0x013ab7,
+    0x013ab6,
+};
+
+static const uint8_t acpl_hcb_gamma_coarse_dt_bits[41] = {
+    17, 17, 17, 17, 16, 17, 16, 16, 16, 15, 14, 13, 12, 12, 10,  9,
+     8,  7,  5,  3,  1,  2,  4,  7,  8, 10, 11, 12, 13, 13, 14, 15,
+    16, 16, 16, 17, 17, 17, 17, 17,  9,
+};
+
+static const uint32_t acpl_hcb_gamma_coarse_dt_codes[41] = {
+    0x00a7f3, 0x00a7f1, 0x00a7f9, 0x00a7f8, 0x0050e1, 0x00a7fe, 0x0050e8, 0x0050eb,
+    0x0053fe, 0x0029fd, 0x00143b, 0x000a1b, 0x00050c, 0x00053e, 0x000142, 0x0000a0,
+    0x000052, 0x00002b, 0x00000b, 0x000003, 0x000001, 0x000000, 0x000004, 0x00002a,
+    0x000051, 0x00014e, 0x00029e, 0x00050f, 0x000a7e, 0x000a1a, 0x001439, 0x002871,
+    0x0050ea, 0x0050e9, 0x0050e0, 0x00a7ff, 0x00a7fb, 0x00a7fa, 0x00a7f2, 0x00a7f0,
+    0x0000a6,
+};
+
+static const uint8_t acpl_hcb_gamma_fine_dt_bits[81] = {
+    18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 17,
+    17, 17, 17, 17, 16, 16, 16, 15, 15, 15, 14, 14, 13, 13, 12, 12,
+    11, 10,  9,  8,  7,  6,  5,  2,  1,  3,  5,  6,  7,  8, 10, 10,
+    11, 12, 13, 13, 14, 14, 15, 15, 15, 15, 16, 16, 17, 17, 17, 17,
+    17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18,
+    18,
+};
+
+static const uint32_t acpl_hcb_gamma_fine_dt_codes[81] = {
+    0x031e44, 0x031d1d, 0x031e42, 0x031e16, 0x031e41, 0x031e47, 0x031d1c, 0x031e43,
+    0x031e73, 0x031e72, 0x031e15, 0x031e70, 0x031e75, 0x031e7f, 0x031e7e, 0x018e88,
+    0x018d8b, 0x018e8f, 0x018f0e, 0x018f3e, 0x00c746, 0x00c796, 0x00c79e, 0x006361,
+    0x0063c9, 0x0063d8, 0x0031d0, 0x0031e6, 0x0018d9, 0x0018f1, 0x000c6d, 0x000c7a,
+    0x00063b, 0x00031c, 0x00018c, 0x0000c1, 0x000062, 0x000033, 0x00001b, 0x000002,
+    0x000000, 0x000007, 0x00001a, 0x000032, 0x000061, 0x0000c0, 0x00031f, 0x00031a,
+    0x000637, 0x000c75, 0x0018f7, 0x0018e9, 0x0031ed, 0x0031e0, 0x0063d9, 0x0063ca,
+    0x006363, 0x006360, 0x00c786, 0x00c745, 0x018f3b, 0x018f2e, 0x018e89, 0x018d88,
+    0x018d8a, 0x018d89, 0x031e5f, 0x031e74, 0x031e40, 0x031e71, 0x031e46, 0x031e5e,
+    0x031e1f, 0x031e45, 0x031e1e, 0x031e14, 0x031e17, 0x031e13, 0x031e12, 0x031e11,
+    0x031e10,
+};
+
+static const float qwin[640] = {
+    0,
+    1.990318758627504e-004,  2.494762615491542e-004,  3.021769445225078e-004,
+    3.548460080857985e-004,  4.058915811480806e-004,  4.546408052001889e-004,
+    5.012680176678405e-004,  5.464958142195282e-004,  5.912073950641334e-004,
+    6.361178026937039e-004,  6.816060488244358e-004,  7.277257095064290e-004,
+    7.743418255606097e-004,  8.212990636826637e-004,  8.685363488152327e-004,
+    9.161071539925993e-004,  9.641168291303352e-004,  1.012630507392736e-003,
+    1.061605258108620e-003,  1.110882587090581e-003,  1.160236901298543e-003,
+    1.209448942573337e-003,  1.258362795150757e-003,  1.306902381715039e-003,
+    1.355046337751365e-003,  1.402784629568410e-003,  1.450086694843816e-003,
+    1.496898951224534e-003,  1.543170821958483e-003,  1.588889089195869e-003,
+    1.634098242730728e-003,  1.678892372493930e-003,  1.723381173920660e-003,
+    1.767651163797991e-003,  1.811741998614740e-003,  1.855650606587200e-003,
+    1.899360915083620e-003,  1.942876625831283e-003,  1.986241654706626e-003,
+    2.029534125962055e-003,  2.072840712410525e-003,  2.116229103721749e-003,
+    2.159738034390673e-003,  2.203392976200947e-003,  2.247239773881968e-003,
+    2.291373966775394e-003,  2.335946110021889e-003,  2.381132815654862e-003,
+    2.427086732976290e-003,  2.473891839822582e-003,  2.521550367974952e-003,
+    2.570013995199655e-003,  2.619244058999978e-003,  2.669265893796866e-003,
+    2.720177146231281e-003,  2.772088849679780e-003,  2.825009494162980e-003,
+    2.878716544061140e-003,  2.932677076291194e-003,  2.986067366389476e-003,
+    3.037905983043366e-003,  3.087269477594307e-003,  3.133519274378684e-003,
+    3.176460810085721e-003,  3.216374095471449e-003,  3.253902493849856e-003,
+    3.289837867273167e-003,  3.324873276103132e-003,  3.359407689115599e-003,
+    3.393454084675361e-003,  3.426668323773391e-003,  3.458465815999750e-003,
+    3.488171121469781e-003,  3.515141351338780e-003,  3.538827383683883e-003,
+    3.558767785536742e-003,  3.574539247363964e-003,  3.585697968628984e-003,
+    3.591743339500398e-003,  3.592116764752254e-003,  3.586228204993297e-003,
+    3.573492966885132e-003,  3.553356715665694e-003,  3.525300399274114e-003,
+    3.488824092931520e-003,  3.443423145747434e-003,  3.388568319085867e-003,
+    3.323699442173841e-003,  3.248231770523395e-003,  3.161568930730635e-003,
+    3.063113666967670e-003,  2.952270973359112e-003,  2.828441943181057e-003,
+    2.691016173288500e-003,  2.539366102140493e-003,  2.372848583221744e-003,
+    2.190814088754598e-003,  1.992618085548526e-003,  1.777631090142623e-003,
+    1.545242163079598e-003,  1.294855985911958e-003,  1.025885587325796e-003,
+    7.377456851538827e-004,  4.298496740962311e-004,  1.016113723823784e-004,
+   -2.475493814535340e-004, -6.181972580227641e-004, -1.010876063031582e-003,
+   -1.426108207321696e-003, -1.864392667409557e-003, -2.326207721179968e-003,
+   -2.812013688448634e-003, -3.322252633537029e-003, -3.857344314546718e-003,
+   -4.417678415707104e-003, -5.003604409245843e-003, -5.615422427540850e-003,
+   -6.253382198869787e-003, -6.917691380307223e-003, -7.608536937561301e-003,
+   -8.326113472848559e-003, -9.070651572928327e-003, -9.842433610911637e-003,
+   -1.064178450184536e-002, -1.146903570409307e-002, -1.232446526717138e-002,
+   -1.320822893615923e-002,  1.412030102138547e-002,  1.506045143737221e-002,
+    1.602824700934038e-002,  1.702310507234504e-002,  1.804435938034114e-002,
+    1.909132707403387e-002,  2.016335321815832e-002,  2.125982139139435e-002,
+    2.238013015948307e-002,  2.352365148441367e-002,  2.468968228813486e-002,
+    2.587741357605385e-002,  2.708591966384863e-002,  2.831416731612567e-002,
+    2.956103453432552e-002,  3.082532788511644e-002,  3.210578787607558e-002,
+    3.340108247607704e-002,  3.470979250147262e-002,  3.603039785904666e-002,
+    3.736126987823528e-002,  3.870067428980750e-002,  4.004677994303860e-002,
+    4.139766786359423e-002,  4.275134353925827e-002,  4.410572893128047e-002,
+    4.545866171224587e-002,  4.680788921400311e-002,  4.815106534667384e-002,
+    4.948575188369231e-002,  5.080942296260306e-002,  5.211947012173918e-002,
+    5.341320372603929e-002,  5.468785186395163e-002,  5.594055607104873e-002,
+    5.716836923188953e-002,  5.836825629443718e-002,  5.953709945765930e-002,
+    6.067170625396996e-002,  6.176881705202805e-002,  6.282510999827461e-002,
+    6.383720245755561e-002,  6.480165083585107e-002,  6.571495100350305e-002,
+    6.657354346196487e-002,  6.737381445564891e-002,  6.811211000439976e-002,
+    6.878473991370719e-002,  6.938797895654626e-002,  6.991806618580000e-002,
+    7.037120381110623e-002,  7.074355866301176e-002,  7.103126866531538e-002,
+    7.123045563399449e-002,  7.133723888151840e-002,  7.134774334517399e-002,
+    7.125810128129656e-002,  7.106444395777428e-002,  7.076288963679085e-002,
+    7.034953453342756e-002,  6.982045490146145e-002,  6.917172452383333e-002,
+    6.839944399575645e-002,  6.749977716975542e-002,  6.646898181809889e-002,
+    6.530342654389224e-002,  6.399958984339946e-002,  6.255404354954748e-002,
+    6.096342863203985e-002,  5.922443337469448e-002,  5.733378365410422e-002,
+    5.528824660015738e-002,  5.308464739461209e-002,  5.071989148277166e-002,
+    4.819098634672628e-002,  4.549505579582869e-002,  4.262934676625042e-002,
+    3.959122947020497e-002,  3.637819581239452e-002,  3.298786054608736e-002,
+    2.941796954479800e-002,  2.566640058060906e-002,  2.173117939155709e-002,
+    1.761048656968719e-002,  1.330266415707108e-002,  8.806217289921706e-003,
+    4.119815918461287e-003, -7.577038291607129e-004, -5.827337082489678e-003,
+   -1.108990619665782e-002, -1.654605559674886e-002, -2.219624707735291e-002,
+   -2.804075556277473e-002, -3.407966641908426e-002, -4.031287253355741e-002,
+   -4.674007190475649e-002, -5.336076390182971e-002, -6.017424526940620e-002,
+   -6.717960594283154e-002, -7.437572538762392e-002, -8.176127022450692e-002,
+   -8.933469320120192e-002, -9.709423309043450e-002, -1.050379143754414e-001,
+   -1.131635475471188e-001, -1.214687284677367e-001, -1.299508386078101e-001,
+   -1.386070430802319e-001, -1.474342913196958e-001, -1.564293167898782e-001,
+   -1.655886374953163e-001, -1.749085568711785e-001, -1.843851642116290e-001,
+   -1.940143360850268e-001, -2.037917371113644e-001, -2.137128217101543e-001,
+   -2.237728356363325e-001, -2.339668182208061e-001, -2.442896055908444e-001,
+   -2.547358344658102e-001, -2.652999476893712e-001, -2.759762003673840e-001,
+   -2.867586659726799e-001, -2.976412485679301e-001, -3.086176827721830e-001,
+   -3.196815399704708e-001, -3.308262316588501e-001, -3.420450091826495e-001,
+    3.533309414505971e-001,  3.646770149404552e-001,  3.760759747758828e-001,
+    3.875204555118187e-001,  3.990029533969267e-001,  4.105158411581483e-001,
+    4.220513789540003e-001,  4.336017251305980e-001,  4.451589452332786e-001,
+    4.567150149423557e-001,  4.682618290579831e-001,  4.797912086537587e-001,
+    4.912949058677955e-001,  5.027646134968753e-001,  5.141919746376279e-001,
+    5.255685924518015e-001,  5.368860394090674e-001,  5.481358656081351e-001,
+    5.593096071830315e-001,  5.703987947306394e-001,  5.813949615434598e-001,
+    5.922896536434017e-001,  6.030744392774144e-001,  6.137409201916185e-001,
+    6.242807411441345e-001,  6.346855991963545e-001,  6.449472531836600e-001,
+    6.550575323798634e-001,  6.650083455855346e-001,  6.747916901830467e-001,
+    6.843996616799759e-001,  6.938244627003839e-001,  7.030584122393319e-001,
+    7.120939537241190e-001,  7.209236637533725e-001,  7.295402599029810e-001,
+    7.379366091028713e-001,  7.461057359576386e-001,  7.540408314942230e-001,
+    7.617352611504460e-001,  7.691825714586890e-001,  7.763765020733762e-001,
+    7.833109874824341e-001,  7.899801646390305e-001,  7.963783815797485e-001,
+    8.025002033685581e-001,  8.083404191294724e-001,  8.138940486031526e-001,
+    8.191563476989879e-001,  8.241228138607196e-001,  8.287891904413357e-001,
+    8.331514714928793e-001,  8.372059062705359e-001,  8.409490040631689e-001,
+    8.443775395556067e-001,  8.474885573145614e-001,  8.502793750759253e-001,
+    8.527475863595390e-001,  8.548910606594570e-001,  8.567079441260879e-001,
+    8.581966597760032e-001,  8.593559096378087e-001,  8.601846769933608e-001,
+    8.606822313166693e-001,  8.608481078185764e-001,  8.606822313166693e-001,
+    8.601846769933608e-001,  8.593559096378087e-001,  8.581966597760032e-001,
+    8.567079441260879e-001,  8.548910606594570e-001,  8.527475863595390e-001,
+    8.502793750759253e-001,  8.474885573145614e-001,  8.443775395556067e-001,
+    8.409490040631689e-001,  8.372059062705359e-001,  8.331514714928793e-001,
+    8.287891904413357e-001,  8.241228138607196e-001,  8.191563476989879e-001,
+    8.138940486031526e-001,  8.083404191294724e-001,  8.025002033685581e-001,
+    7.963783815797485e-001,  7.899801646390305e-001,  7.833109874824341e-001,
+    7.763765020733762e-001,  7.691825714586890e-001,  7.617352611504460e-001,
+    7.540408314942230e-001,  7.461057359576386e-001,  7.379366091028713e-001,
+    7.295402599029810e-001,  7.209236637533725e-001,  7.120939537241190e-001,
+    7.030584122393319e-001,  6.938244627003839e-001,  6.843996616799759e-001,
+    6.747916901830467e-001,  6.650083455855346e-001,  6.550575323798634e-001,
+    6.449472531836600e-001,  6.346855991963545e-001,  6.242807411441345e-001,
+    6.137409201916185e-001,  6.030744392774144e-001,  5.922896536434017e-001,
+    5.813949615434598e-001,  5.703987947306394e-001,  5.593096071830315e-001,
+    5.481358656081351e-001,  5.368860394090674e-001,  5.255685924518015e-001,
+    5.141919746376279e-001,  5.027646134968753e-001,  4.912949058677955e-001,
+    4.797912086537587e-001,  4.682618290579831e-001,  4.567150149423557e-001,
+    4.451589452332786e-001,  4.336017251305980e-001,  4.220513789540003e-001,
+    4.105158411581483e-001,  3.990029533969267e-001,  3.875204555118187e-001,
+    3.760759747758828e-001,  3.646770149404552e-001, -3.533309414505971e-001,
+   -3.420450091826495e-001, -3.308262316588501e-001, -3.196815399704708e-001,
+   -3.086176827721830e-001, -2.976412485679301e-001, -2.867586659726799e-001,
+   -2.759762003673840e-001, -2.652999476893712e-001, -2.547358344658102e-001,
+   -2.442896055908444e-001, -2.339668182208061e-001, -2.237728356363325e-001,
+   -2.137128217101543e-001, -2.037917371113644e-001, -1.940143360850268e-001,
+   -1.843851642116290e-001, -1.749085568711785e-001, -1.655886374953163e-001,
+   -1.564293167898782e-001, -1.474342913196958e-001, -1.386070430802319e-001,
+   -1.299508386078101e-001, -1.214687284677367e-001, -1.131635475471188e-001,
+   -1.050379143754414e-001, -9.709423309043450e-002, -8.933469320120192e-002,
+   -8.176127022450692e-002, -7.437572538762392e-002, -6.717960594283154e-002,
+   -6.017424526940620e-002, -5.336076390182971e-002, -4.674007190475649e-002,
+   -4.031287253355741e-002, -3.407966641908426e-002, -2.804075556277473e-002,
+   -2.219624707735291e-002, -1.654605559674886e-002, -1.108990619665782e-002,
+   -5.827337082489678e-003, -7.577038291607129e-004,  4.119815918461287e-003,
+    8.806217289921706e-003,  1.330266415707108e-002,  1.761048656968719e-002,
+    2.173117939155709e-002,  2.566640058060906e-002,  2.941796954479800e-002,
+    3.298786054608736e-002,  3.637819581239452e-002,  3.959122947020497e-002,
+    4.262934676625042e-002,  4.549505579582869e-002,  4.819098634672628e-002,
+    5.071989148277166e-002,  5.308464739461209e-002,  5.528824660015738e-002,
+    5.733378365410422e-002,  5.922443337469448e-002,  6.096342863203985e-002,
+    6.255404354954748e-002,  6.399958984339946e-002,  6.530342654389224e-002,
+    6.646898181809889e-002,  6.749977716975542e-002,  6.839944399575645e-002,
+    6.917172452383333e-002,  6.982045490146145e-002,  7.034953453342756e-002,
+    7.076288963679085e-002,  7.106444395777428e-002,  7.125810128129656e-002,
+    7.134774334517399e-002,  7.133723888151840e-002,  7.123045563399449e-002,
+    7.103126866531538e-002,  7.074355866301176e-002,  7.037120381110623e-002,
+    6.991806618580000e-002,  6.938797895654626e-002,  6.878473991370719e-002,
+    6.811211000439976e-002,  6.737381445564891e-002,  6.657354346196487e-002,
+    6.571495100350305e-002,  6.480165083585107e-002,  6.383720245755561e-002,
+    6.282510999827461e-002,  6.176881705202805e-002,  6.067170625396996e-002,
+    5.953709945765930e-002,  5.836825629443718e-002,  5.716836923188953e-002,
+    5.594055607104873e-002,  5.468785186395163e-002,  5.341320372603929e-002,
+    5.211947012173918e-002,  5.080942296260306e-002,  4.948575188369231e-002,
+    4.815106534667384e-002,  4.680788921400311e-002,  4.545866171224587e-002,
+    4.410572893128047e-002,  4.275134353925827e-002,  4.139766786359423e-002,
+    4.004677994303860e-002,  3.870067428980750e-002,  3.736126987823528e-002,
+    3.603039785904666e-002,  3.470979250147262e-002,  3.340108247607704e-002,
+    3.210578787607558e-002,  3.082532788511644e-002,  2.956103453432552e-002,
+    2.831416731612567e-002,  2.708591966384863e-002,  2.587741357605385e-002,
+    2.468968228813486e-002,  2.352365148441367e-002,  2.238013015948307e-002,
+    2.125982139139435e-002,  2.016335321815832e-002,  1.909132707403387e-002,
+    1.804435938034114e-002,  1.702310507234504e-002,  1.602824700934038e-002,
+    1.506045143737221e-002, -1.412030102138547e-002, -1.320822893615923e-002,
+   -1.232446526717138e-002, -1.146903570409307e-002, -1.064178450184536e-002,
+   -9.842433610911637e-003, -9.070651572928327e-003, -8.326113472848559e-003,
+   -7.608536937561301e-003, -6.917691380307223e-003, -6.253382198869787e-003,
+   -5.615422427540850e-003, -5.003604409245843e-003, -4.417678415707104e-003,
+   -3.857344314546718e-003, -3.322252633537029e-003, -2.812013688448634e-003,
+   -2.326207721179968e-003, -1.864392667409557e-003, -1.426108207321696e-003,
+   -1.010876063031582e-003, -6.181972580227641e-004, -2.475493814535340e-004,
+    1.016113723823784e-004,  4.298496740962311e-004,  7.377456851538827e-004,
+    1.025885587325796e-003,  1.294855985911958e-003,  1.545242163079598e-003,
+    1.777631090142623e-003,  1.992618085548526e-003,  2.190814088754598e-003,
+    2.372848583221744e-003,  2.539366102140493e-003,  2.691016173288500e-003,
+    2.828441943181057e-003,  2.952270973359112e-003,  3.063113666967670e-003,
+    3.161568930730635e-003,  3.248231770523395e-003,  3.323699442173841e-003,
+    3.388568319085867e-003,  3.443423145747434e-003,  3.488824092931520e-003,
+    3.525300399274114e-003,  3.553356715665694e-003,  3.573492966885132e-003,
+    3.586228204993297e-003,  3.592116764752254e-003,  3.591743339500398e-003,
+    3.585697968628984e-003,  3.574539247363964e-003,  3.558767785536742e-003,
+    3.538827383683883e-003,  3.515141351338780e-003,  3.488171121469781e-003,
+    3.458465815999750e-003,  3.426668323773391e-003,  3.393454084675361e-003,
+    3.359407689115599e-003,  3.324873276103132e-003,  3.289837867273167e-003,
+    3.253902493849856e-003,  3.216374095471449e-003,  3.176460810085721e-003,
+    3.133519274378684e-003,  3.087269477594307e-003,  3.037905983043366e-003,
+    2.986067366389476e-003,  2.932677076291194e-003,  2.878716544061140e-003,
+    2.825009494162980e-003,  2.772088849679780e-003,  2.720177146231281e-003,
+    2.669265893796866e-003,  2.619244058999978e-003,  2.570013995199655e-003,
+    2.521550367974952e-003,  2.473891839822582e-003,  2.427086732976290e-003,
+    2.381132815654862e-003,  2.335946110021889e-003,  2.291373966775394e-003,
+    2.247239773881968e-003,  2.203392976200947e-003,  2.159738034390673e-003,
+    2.116229103721749e-003,  2.072840712410525e-003,  2.029534125962055e-003,
+    1.986241654706626e-003,  1.942876625831283e-003,  1.899360915083620e-003,
+    1.855650606587200e-003,  1.811741998614740e-003,  1.767651163797991e-003,
+    1.723381173920660e-003,  1.678892372493930e-003,  1.634098242730728e-003,
+    1.588889089195869e-003,  1.543170821958483e-003,  1.496898951224534e-003,
+    1.450086694843816e-003,  1.402784629568410e-003,  1.355046337751365e-003,
+    1.306902381715039e-003,  1.258362795150757e-003,  1.209448942573337e-003,
+    1.160236901298543e-003,  1.110882587090581e-003,  1.061605258108620e-003,
+    1.012630507392736e-003,  9.641168291303352e-004,  9.161071539925993e-004,
+    8.685363488152327e-004,  8.212990636826637e-004,  7.743418255606097e-004,
+    7.277257095064290e-004,  6.816060488244358e-004,  6.361178026937039e-004,
+    5.912073950641334e-004,  5.464958142195282e-004,  5.012680176678405e-004,
+    4.546408052001889e-004,  4.058915811480806e-004,  3.548460080857985e-004,
+    3.021769445225078e-004,  2.494762615491542e-004,  1.990318758627504e-004,
+};
+
+static const float new_chirp_tab[4][4] = {
+    { 0.0,  0.6,  0.0,  0.0,  },
+    { 0.6,  0.75, 0.75, 0.75, },
+    { 0.9,  0.9,  0.9,  0.9,  },
+    { 0.98, 0.98, 0.98, 0.98, },
+};
+
+static const int8_t SineTable[2][4] = {
+    { 1, 0, -1,  0 },
+    { 0, 1,  0, -1 },
+};
+
+#endif /* AVCODEC_AC4DECDATA_H */
diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c
index 674995df72..a2d867abc6 100644
--- a/libavcodec/allcodecs.c
+++ b/libavcodec/allcodecs.c
@@ -391,6 +391,7 @@ extern AVCodec ff_ac3_encoder;
 extern AVCodec ff_ac3_decoder;
 extern AVCodec ff_ac3_fixed_encoder;
 extern AVCodec ff_ac3_fixed_decoder;
+extern AVCodec ff_ac4_decoder;
 extern AVCodec ff_acelp_kelvin_decoder;
 extern AVCodec ff_alac_encoder;
 extern AVCodec ff_alac_decoder;
diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h
index 5a0fc3405c..1420db26b6 100644
--- a/libavcodec/avcodec.h
+++ b/libavcodec/avcodec.h
@@ -665,6 +665,7 @@ enum AVCodecID {
     AV_CODEC_ID_ACELP_KELVIN,
     AV_CODEC_ID_MPEGH_3D_AUDIO,
     AV_CODEC_ID_SIREN,
+    AV_CODEC_ID_AC4,
 
     /* subtitle codecs */
     AV_CODEC_ID_FIRST_SUBTITLE = 0x17000,          ///< A dummy ID pointing at the start of subtitle codecs.
diff --git a/libavcodec/codec_desc.c b/libavcodec/codec_desc.c
index 52178e7afe..b01733c924 100644
--- a/libavcodec/codec_desc.c
+++ b/libavcodec/codec_desc.c
@@ -3058,6 +3058,13 @@ static const AVCodecDescriptor codec_descriptors[] = {
         .long_name = NULL_IF_CONFIG_SMALL("Siren"),
         .props     = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSY,
     },
+    {
+        .id        = AV_CODEC_ID_AC4,
+        .type      = AVMEDIA_TYPE_AUDIO,
+        .name      = "ac4",
+        .long_name = NULL_IF_CONFIG_SMALL("AC-4"),
+        .props     = AV_CODEC_PROP_LOSSY,
+    },
 
     /* subtitle codecs */
     {
diff --git a/libavcodec/kbdwin.h b/libavcodec/kbdwin.h
index 4185c4206f..2ea35e1bd5 100644
--- a/libavcodec/kbdwin.h
+++ b/libavcodec/kbdwin.h
@@ -24,7 +24,7 @@
 /**
  * Maximum window size for ff_kbd_window_init.
  */
-#define FF_KBD_WINDOW_MAX 1024
+#define FF_KBD_WINDOW_MAX 2048
 
 /**
  * Generate a Kaiser-Bessel Derived Window.
diff --git a/libavformat/isom.c b/libavformat/isom.c
index eefe9277b4..6f4990a90c 100644
--- a/libavformat/isom.c
+++ b/libavformat/isom.c
@@ -373,6 +373,7 @@ const AVCodecTag ff_codec_movaudio_tags[] = {
     { AV_CODEC_ID_TRUEHD,          MKTAG('m', 'l', 'p', 'a') }, /* mp4ra.org */
     { AV_CODEC_ID_OPUS,            MKTAG('O', 'p', 'u', 's') }, /* mp4ra.org */
     { AV_CODEC_ID_MPEGH_3D_AUDIO,  MKTAG('m', 'h', 'm', '1') }, /* MPEG-H 3D Audio bitstream */
+    { AV_CODEC_ID_AC4,             MKTAG('a', 'c', '-', '4') }, /* ETSI TS 103 190 */
     { AV_CODEC_ID_NONE, 0 },
 };
 
