All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.vacco.libmpghip.Jlayer3 Maven / Gradle / Ivy

The newest version!
package io.vacco.libmpghip;

import io.vacco.libmpghip.JIII_sideinfo.Jch;

/*
 * layer3.c: Mpeg Layer-3 audio decoder
 *
 * Copyright (C) 1999-2010 The L.A.M.E. project
 *
 * Initially written by Michael Hipp, see also AUTHORS and README.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library 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
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
 */
/* $Id: layer3.c,v 1.69 2017/08/20 20:06:57 robert Exp $ */

// layer3.c

final class Jlayer3 {

  private static boolean gd_are_hip_tables_layer3_initialized = false;

  private static final float ispow[] = new float[8207];
  private static final float aa_ca[] = new float[8];
  private static final float aa_cs[] = new float[8];
  private static final float COS1[][] = new float[12][6];
  private static final float win[][] = new float[4][36];
  private static final float win1[][] = new float[4][36];
  private static final float gainpow2[] = new float[256 + 118 + 4];
  private static final float COS9[] = new float[9];
  private static float COS6_1, COS6_2;
  private static final float tfcos36[] = new float[9];
  private static final float tfcos12[] = new float[3];

  private static final class JbandInfoStruct {
    private final short longIdx[]; // = new short[23];
    private final short longDiff[]; // = new short[22];
    private final short shortIdx[]; // = new short[14];
    private final short shortDiff[]; // = new short[13];
    //
    private JbandInfoStruct(
        final short[] lidx, final short[] ldiff, final short[] sidx, final short[] sdiff) {
      this.longIdx = lidx;
      this.longDiff = ldiff;
      this.shortIdx = sidx;
      this.shortDiff = sdiff;
    }
  }

  private static final int longLimit[][] = new int[9][23];
  private static final int shortLimit[][] = new int[9][14];

  private static final JbandInfoStruct bandInfo[] = { // [9] = {

    /* MPEG 1.0 */
    new JbandInfoStruct(
        new short[] {
          0, 4, 8, 12, 16, 20, 24, 30, 36, 44, 52, 62, 74, 90, 110, 134, 162, 196, 238, 288, 342,
          418, 576
        },
        new short[] {4, 4, 4, 4, 4, 4, 6, 6, 8, 8, 10, 12, 16, 20, 24, 28, 34, 42, 50, 54, 76, 158},
        new short[] {
          0, 4 * 3, 8 * 3, 12 * 3, 16 * 3, 22 * 3, 30 * 3, 40 * 3, 52 * 3, 66 * 3, 84 * 3, 106 * 3,
          136 * 3, 192 * 3
        },
        new short[] {4, 4, 4, 4, 6, 8, 10, 12, 14, 18, 22, 30, 56}),
    new JbandInfoStruct(
        new short[] {
          0, 4, 8, 12, 16, 20, 24, 30, 36, 42, 50, 60, 72, 88, 106, 128, 156, 190, 230, 276, 330,
          384, 576
        },
        new short[] {4, 4, 4, 4, 4, 4, 6, 6, 6, 8, 10, 12, 16, 18, 22, 28, 34, 40, 46, 54, 54, 192},
        new short[] {
          0, 4 * 3, 8 * 3, 12 * 3, 16 * 3, 22 * 3, 28 * 3, 38 * 3, 50 * 3, 64 * 3, 80 * 3, 100 * 3,
          126 * 3, 192 * 3
        },
        new short[] {4, 4, 4, 4, 6, 6, 10, 12, 14, 16, 20, 26, 66}),
    new JbandInfoStruct(
        new short[] {
          0, 4, 8, 12, 16, 20, 24, 30, 36, 44, 54, 66, 82, 102, 126, 156, 194, 240, 296, 364, 448,
          550, 576
        },
        new short[] {
          4, 4, 4, 4, 4, 4, 6, 6, 8, 10, 12, 16, 20, 24, 30, 38, 46, 56, 68, 84, 102, 26
        },
        new short[] {
          0, 4 * 3, 8 * 3, 12 * 3, 16 * 3, 22 * 3, 30 * 3, 42 * 3, 58 * 3, 78 * 3, 104 * 3, 138 * 3,
          180 * 3, 192 * 3
        },
        new short[] {4, 4, 4, 4, 6, 8, 12, 16, 20, 26, 34, 42, 12}),

    /* MPEG 2.0 */
    new JbandInfoStruct(
        new short[] {
          0, 6, 12, 18, 24, 30, 36, 44, 54, 66, 80, 96, 116, 140, 168, 200, 238, 284, 336, 396, 464,
          522, 576
        },
        new short[] {
          6, 6, 6, 6, 6, 6, 8, 10, 12, 14, 16, 20, 24, 28, 32, 38, 46, 52, 60, 68, 58, 54
        },
        new short[] {
          0, 4 * 3, 8 * 3, 12 * 3, 18 * 3, 24 * 3, 32 * 3, 42 * 3, 56 * 3, 74 * 3, 100 * 3, 132 * 3,
          174 * 3, 192 * 3
        },
        new short[] {4, 4, 4, 6, 6, 8, 10, 14, 18, 26, 32, 42, 18}),
    /* docs: 332. mpg123: 330 */
    new JbandInfoStruct(
        new short[] {
          0, 6, 12, 18, 24, 30, 36, 44, 54, 66, 80, 96, 114, 136, 162, 194, 232, 278, 332, 394, 464,
          540, 576
        },
        new short[] {
          6, 6, 6, 6, 6, 6, 8, 10, 12, 14, 16, 18, 22, 26, 32, 38, 46, 54, 62, 70, 76, 36
        },
        new short[] {
          0, 4 * 3, 8 * 3, 12 * 3, 18 * 3, 26 * 3, 36 * 3, 48 * 3, 62 * 3, 80 * 3, 104 * 3, 136 * 3,
          180 * 3, 192 * 3
        },
        new short[] {4, 4, 4, 6, 8, 10, 12, 14, 18, 24, 32, 44, 12}),
    new JbandInfoStruct(
        new short[] {
          0, 6, 12, 18, 24, 30, 36, 44, 54, 66, 80, 96, 116, 140, 168, 200, 238, 284, 336, 396, 464,
          522, 576
        },
        new short[] {
          6, 6, 6, 6, 6, 6, 8, 10, 12, 14, 16, 20, 24, 28, 32, 38, 46, 52, 60, 68, 58, 54
        },
        new short[] {
          0, 4 * 3, 8 * 3, 12 * 3, 18 * 3, 26 * 3, 36 * 3, 48 * 3, 62 * 3, 80 * 3, 104 * 3, 134 * 3,
          174 * 3, 192 * 3
        },
        new short[] {4, 4, 4, 6, 8, 10, 12, 14, 18, 24, 30, 40, 18}),
    /* MPEG 2.5 */
    new JbandInfoStruct(
        new short[] {
          0, 6, 12, 18, 24, 30, 36, 44, 54, 66, 80, 96, 116, 140, 168, 200, 238, 284, 336, 396, 464,
          522, 576
        },
        new short[] {
          6, 6, 6, 6, 6, 6, 8, 10, 12, 14, 16, 20, 24, 28, 32, 38, 46, 52, 60, 68, 58, 54
        },
        new short[] {0, 12, 24, 36, 54, 78, 108, 144, 186, 240, 312, 402, 522, 576},
        new short[] {4, 4, 4, 6, 8, 10, 12, 14, 18, 24, 30, 40, 18}),
    new JbandInfoStruct(
        new short[] {
          0, 6, 12, 18, 24, 30, 36, 44, 54, 66, 80, 96, 116, 140, 168, 200, 238, 284, 336, 396, 464,
          522, 576
        },
        new short[] {
          6, 6, 6, 6, 6, 6, 8, 10, 12, 14, 16, 20, 24, 28, 32, 38, 46, 52, 60, 68, 58, 54
        },
        new short[] {0, 12, 24, 36, 54, 78, 108, 144, 186, 240, 312, 402, 522, 576},
        new short[] {4, 4, 4, 6, 8, 10, 12, 14, 18, 24, 30, 40, 18}),
    new JbandInfoStruct(
        new short[] {
          0, 12, 24, 36, 48, 60, 72, 88, 108, 132, 160, 192, 232, 280, 336, 400, 476, 566, 568, 570,
          572, 574, 576
        },
        new short[] {
          12, 12, 12, 12, 12, 12, 16, 20, 24, 28, 32, 40, 48, 56, 64, 76, 90, 2, 2, 2, 2, 2
        },
        new short[] {0, 24, 48, 72, 108, 156, 216, 288, 372, 480, 486, 492, 498, 576},
        new short[] {8, 8, 8, 12, 16, 20, 24, 28, 36, 2, 2, 2, 26})
  };

  private static final int mapbuf0[][] = new int[9][152];
  private static final int mapbuf1[][] = new int[9][156];
  private static final int mapbuf2[][] = new int[9][44];
  private static final int map[][][] = new int[9][3][];
  private static final int mapend[][] = new int[9][3];

  private static final int n_slen2[] = new int[512]; /* MPEG 2.0 slen for 'normal' mode */
  private static final int i_slen2[] = new int[256]; /* MPEG 2.0 slen for intensity stereo */

  private static final float tan1_1[] = new float[16];
  private static final float tan2_1[] = new float[16];
  private static final float tan1_2[] = new float[16];
  private static final float tan2_2[] = new float[16];
  private static final float pow1_1[][] = new float[2][16];
  private static final float pow2_1[][] = new float[2][16];
  private static final float pow1_2[][] = new float[2][16];
  private static final float pow2_2[][] = new float[2][16];

  private static final int get1bit(final Jmpstr_tag mp) {
    final int rval = (int) mp.wordbuf[mp.wordpointer] << mp.bitindex;

    mp.bitindex++;
    mp.wordpointer += (mp.bitindex >> 3);
    mp.bitindex &= 7;

    return (rval >> 7) & 1;
  }

  /* FIXME ugly code.
  // java: replaced by ArrayIndexException
  private static final float get_gain(float[] gain_ptr, int idx, int[] overflow)
  {
  	static float[] gainpow2_end_ptr = gainpow2 + gainpow2.length - 1;
  	float[] ptr = &gain_ptr[idx];
  	if( &gain_ptr[idx] > gainpow2_end_ptr ) {
  		ptr = gainpow2_end_ptr;
  		if( overflow != null ) overflow[0] = 1;
  	}
  	return *ptr;
  }*/

  /** init tables for layer-3 */
  static final void hip_init_tables_layer3() {

    if (gd_are_hip_tables_layer3_initialized) {
      return;
    }
    gd_are_hip_tables_layer3_initialized = true;

    for (int i = -256; i < 118 + 4; i++) {
      gainpow2[i + 256] = (float) Math.pow(2.0, -0.25 * (double) (i + 210));
    }

    for (int i = 0; i < 8207; i++) {
      ispow[i] = (float) Math.pow((double) i, 4.0 / 3.0);
    }

    final double Ci[] = {-0.6, -0.535, -0.33, -0.185, -0.095, -0.041, -0.0142, -0.0037};
    for (int i = 0; i < 8; i++) {
      final double c = Ci[i];
      final double sq = Math.sqrt(1.0 + c * c);
      aa_cs[i] = (float) (1.0 / sq);
      aa_ca[i] = (float) (c / sq);
    }

    for (int i = 0; i < 18; i++) {
      int i2 = i << 1;
      win[0][i] =
          win[1][i] =
              (float)
                  (0.5
                      * Math.sin(Math.PI / 72.0 * (double) (i2 + 1))
                      / Math.cos(Math.PI * (double) (i2 + 19) / 72.0));
      i2 += 2 * 18;
      win[0][i + 18] =
          win[3][i + 18] =
              (float)
                  (0.5
                      * Math.sin(Math.PI / 72.0 * (double) (i2 + 1))
                      / Math.cos(Math.PI * (double) (i2 + 19) / 72.0));
    }
    for (int i = 0; i < 6; i++) {
      win[1][i + 18] = (float) (0.5 / Math.cos(Math.PI * (double) (2 * (i + 18) + 19) / 72.0));
      win[3][i + 12] = (float) (0.5 / Math.cos(Math.PI * (double) (2 * (i + 12) + 19) / 72.0));
      win[1][i + 24] =
          (float)
              (0.5
                  * Math.sin(Math.PI / 24.0 * (double) (2 * i + 13))
                  / Math.cos(Math.PI * (double) (2 * (i + 24) + 19) / 72.0));
      win[1][i + 30] = win[3][i] = 0.0f;
      win[3][i + 6] =
          (float)
              (0.5
                  * Math.sin(Math.PI / 24.0 * (double) (2 * i + 1))
                  / Math.cos(Math.PI * (double) (2 * (i + 6) + 19) / 72.0));
    }

    for (int i = 0; i < 9; i++) {
      COS9[i] = (float) Math.cos(Math.PI / 18.0 * (double) i);
    }

    for (int i = 0; i < 9; i++) {
      tfcos36[i] = (float) (0.5 / Math.cos(Math.PI * (double) ((i << 1) + 1) / 36.0));
    }
    for (int i = 0; i < 3; i++) {
      tfcos12[i] = (float) (0.5 / Math.cos(Math.PI * (double) ((i << 1) + 1) / 12.0));
    }

    COS6_1 = (float) Math.cos(Math.PI / 6.0 * (double) 1);
    COS6_2 = (float) Math.cos(Math.PI / 6.0 * (double) 2);

    for (int i = 0; i < 12; i++) {
      final int i2 = i << 1;
      win[2][i] =
          (float)
              (0.5
                  * Math.sin(Math.PI / 24.0 * (double) (i2 + 1))
                  / Math.cos(Math.PI * (double) (i2 + 7) / 24.0));
      for (int j = 0; j < 6; j++) {
        COS1[i][j] = (float) (Math.cos(Math.PI / 24.0 * (double) ((i2 + 7) * ((j << 1) + 1))));
      }
    }

    final int len[] = {36, 36, 12, 36};
    for (int j = 0; j < 4; j++) {
      for (int i = 0; i < len[j]; i += 2) {
        win1[j][i] = +win[j][i];
      }
      for (int i = 1; i < len[j]; i += 2) {
        win1[j][i] = -win[j][i];
      }
    }

    for (int i = 0; i < 16; i++) {
      final double t = Math.tan((double) i * Math.PI / 12.0);
      tan1_1[i] = (float) (t / (1.0 + t));
      tan2_1[i] = (float) (1.0 / (1.0 + t));
      tan1_2[i] = (float) (Jmpg123.M_SQRT2 * t / (1.0 + t));
      tan2_2[i] = (float) (Jmpg123.M_SQRT2 / (1.0 + t));

      for (int j = 0; j < 2; j++) {
        final double base = Math.pow(2.0, -0.25 * (j + 1.0));
        double p1 = 1.0, p2 = 1.0;
        if (i > 0) {
          if ((i & 1) != 0) {
            p1 = Math.pow(base, (i + 1.0) * 0.5);
          } else {
            p2 = Math.pow(base, i * 0.5);
          }
        }
        pow1_1[j][i] = (float) p1;
        pow2_1[j][i] = (float) p2;
        pow1_2[j][i] = (float) (Jmpg123.M_SQRT2 * p1);
        pow2_2[j][i] = (float) (Jmpg123.M_SQRT2 * p2);
      }
    }

    for (int j = 0; j < 9; j++) {
      final JbandInfoStruct bi = bandInfo[j];
      final int switch_idx = (j < 3) ? 8 : 6;

      int[] mp = map[j][0] = mapbuf0[j];
      int mpi = 0; // mp [ mpi ]
      short[] diff = bi.longDiff;
      int bdf = 0; // long_diff[ bdf ]
      int i = 0, cb;
      for (cb = 0; cb < switch_idx; cb++, i += diff[bdf++]) {
        mp[mpi++] = diff[bdf] >> 1;
        mp[mpi++] = i;
        mp[mpi++] = 3;
        mp[mpi++] = cb;
      }
      diff = bi.shortDiff;
      bdf = 3;
      for (cb = 3; cb < 13; cb++) {
        final int l = diff[bdf++] >> 1;
        for (int lwin = 0; lwin < 3; lwin++) {
          mp[mpi++] = l;
          mp[mpi++] = i + lwin;
          mp[mpi++] = lwin;
          mp[mpi++] = cb;
        }
        i += 6 * l;
      }
      mapend[j][0] = mpi;

      mp = map[j][1] = mapbuf1[j];
      mpi = 0;
      diff = bi.shortDiff;
      bdf = 0;
      for (i = 0, cb = 0; cb < 13; cb++) {
        final int l = diff[bdf++] >> 1;
        for (int lwin = 0; lwin < 3; lwin++) {
          mp[mpi++] = l;
          mp[mpi++] = i + lwin;
          mp[mpi++] = lwin;
          mp[mpi++] = cb;
        }
        i += 6 * l;
      }
      mapend[j][1] = mpi;

      mp = map[j][2] = mapbuf2[j];
      mpi = 0;
      diff = bi.longDiff;
      bdf = 0;
      for (cb = 0; cb < 22; cb++) {
        mp[mpi++] = diff[bdf++] >> 1;
        mp[mpi++] = cb;
      }
      mapend[j][2] = mpi;
    }

    for (int j = 0; j < 9; j++) {
      for (int i = 0; i < 23; i++) {
        longLimit[j][i] = (bandInfo[j].longIdx[i] - 1 + 8) / 18 + 1;
        if (longLimit[j][i] > Jmpg123.SBLIMIT) {
          longLimit[j][i] = Jmpg123.SBLIMIT;
        }
      }
      for (int i = 0; i < 14; i++) {
        shortLimit[j][i] = (bandInfo[j].shortIdx[i] - 1) / 18 + 1;
        if (shortLimit[j][i] > Jmpg123.SBLIMIT) {
          shortLimit[j][i] = Jmpg123.SBLIMIT;
        }
      }
    }

    for (int i = 0; i < 5; i++) {
      for (int j = 0; j < 6; j++) {
        for (int k = 0; k < 6; k++) {
          final int n = k + j * 6 + i * 36;
          i_slen2[n] = i | (j << 3) | (k << 6) | (3 << 12);
        }
      }
    }
    for (int i = 0; i < 4; i++) {
      for (int j = 0; j < 4; j++) {
        for (int k = 0; k < 4; k++) {
          final int n = k + j * 4 + i * 16;
          i_slen2[n + 180] = i | (j << 3) | (k << 6) | (4 << 12);
        }
      }
    }
    for (int i = 0; i < 4; i++) {
      for (int j = 0; j < 3; j++) {
        final int n = j + i * 3;
        i_slen2[n + 244] = i | (j << 3) | (5 << 12);
        n_slen2[n + 500] = i | (j << 3) | (2 << 12) | (1 << 15);
      }
    }

    for (int i = 0; i < 5; i++) {
      for (int j = 0; j < 5; j++) {
        for (int k = 0; k < 4; k++) {
          for (int l = 0; l < 4; l++) {
            final int n = l + k * 4 + j * 16 + i * 80;
            n_slen2[n] = i | (j << 3) | (k << 6) | (l << 9) | (0 << 12);
          }
        }
      }
    }
    for (int i = 0; i < 5; i++) {
      for (int j = 0; j < 5; j++) {
        for (int k = 0; k < 4; k++) {
          final int n = k + j * 4 + i * 20;
          n_slen2[n + 400] = i | (j << 3) | (k << 6) | (1 << 12);
        }
      }
    }
  }

  /** read additional side information */
  @SuppressWarnings("boxing")
  private static final void III_get_side_info_1(
      final Jmpstr_tag mp,
      final int stereo,
      final boolean ms_stereo,
      final int sfreq,
      final int single) {
    final int powdiff = (single == 3) ? 4 + 256 : 0 + 256;

    mp.sideinfo.main_data_begin = mp.getbits(9);
    mp.sideinfo.private_bits = mp.getbits_fast(stereo == 1 ? 5 : 3);

    final Jch[] chs = mp.sideinfo.ch; // java
    for (int ch = 0; ch < stereo; ch++) {
      chs[ch].gr[0].scfsi = -1;
      chs[ch].gr[1].scfsi = mp.getbits_fast(4);
    }

    for (int gr = 0; gr < 2; gr++) {
      for (int ch = 0; ch < stereo; ch++) {
        final Jgr_info gr_infos = chs[ch].gr[gr];

        gr_infos.part2_3_length = mp.getbits(12);
        gr_infos.big_values = mp.getbits_fast(9);
        if (gr_infos.big_values > 288) {
          System.err.printf("big_values too large! %d\n", gr_infos.big_values);
          gr_infos.big_values = 288;
        }
        {
          final int qss = mp.getbits_fast(8);
          gr_infos.pow2gain = /*256 +*/ powdiff - qss;
          gr_infos.pow2gain_base = gainpow2;
        }
        if (ms_stereo) {
          gr_infos.pow2gain += 2;
        }
        gr_infos.scalefac_compress = mp.getbits_fast(4);
        /* window-switching flag == 1 for block_Type != 0 .. and block-type == 0 . win-sw-flag = 0 */
        if (get1bit(mp) != 0) {
          gr_infos.block_type = mp.getbits_fast(2);
          gr_infos.mixed_block_flag = get1bit(mp);
          gr_infos.table_select[0] = mp.getbits_fast(5);
          gr_infos.table_select[1] = mp.getbits_fast(5);

          /*
           * table_select[2] not needed, because there is no region2,
           * but to satisfy some verifications tools we set it either.
           */
          gr_infos.table_select[2] = 0;
          int i = 0;
          do {
            final int sbg = (mp.getbits_fast(3) << 3);
            gr_infos.full_gain[i] = gr_infos.pow2gain_base;
            gr_infos.full_gain_pos[i] = gr_infos.pow2gain + sbg;
          } while (++i < 3);

          if (gr_infos.block_type == 0) {
            System.err.printf("Blocktype == 0 and window-switching == 1 not allowed.\n");
            /* error seems to be very good recoverable, so don't exit */
            /* exit(1); */
          }
          /* region_count/start parameters are implicit in this case. */
          gr_infos.region1start = 36 >> 1;
          gr_infos.region2start = 576 >> 1;
        } else {
          gr_infos.table_select[0] = mp.getbits_fast(5);
          gr_infos.table_select[1] = mp.getbits_fast(5);
          gr_infos.table_select[2] = mp.getbits_fast(5);
          int region0index = mp.getbits_fast(4);
          region0index++;
          int region1index = region0index;
          region1index += mp.getbits_fast(3);
          region1index++;
          if (region0index > 22) {
            System.err.printf("region0index=%d > 22\n", region0index);
            region0index = 22;
          }
          if (region1index > 22) {
            System.err.printf("region1index=%d > 22\n", region1index);
            region1index = 22;
          }
          gr_infos.region1start = bandInfo[sfreq].longIdx[region0index] >> 1;
          gr_infos.region2start = bandInfo[sfreq].longIdx[region1index] >> 1;
          gr_infos.block_type = 0;
          gr_infos.mixed_block_flag = 0;
        }
        gr_infos.preflag = get1bit(mp) != 0;
        gr_infos.scalefac_scale = get1bit(mp);
        gr_infos.count1table_select = get1bit(mp);
      }
    }
  }

  /** Side Info for MPEG 2.0 / LSF */
  @SuppressWarnings("boxing")
  private static final void III_get_side_info_2(
      final Jmpstr_tag mp,
      final int stereo,
      final boolean ms_stereo,
      final int sfreq,
      final int single) {
    final int powdiff = (single == 3) ? 4 + 256 : 0 + 256;

    mp.sideinfo.main_data_begin = mp.getbits(8);

    if (stereo == 1) {
      mp.sideinfo.private_bits = get1bit(mp);
    } else {
      mp.sideinfo.private_bits = mp.getbits_fast(2);
    }

    final JbandInfoStruct bi = bandInfo[sfreq]; // java
    for (int ch = 0; ch < stereo; ch++) {
      final Jgr_info gr_infos = mp.sideinfo.ch[ch].gr[0];
      gr_infos.part2_3_length = mp.getbits(12);
      gr_infos.big_values = mp.getbits_fast(9);
      if (gr_infos.big_values > 288) {
        System.err.printf("big_values too large! %d\n", gr_infos.big_values);
        gr_infos.big_values = 288;
      }
      final int qss = mp.getbits_fast(8);
      gr_infos.pow2gain_base = gainpow2;
      gr_infos.pow2gain = /*256 +*/ powdiff - qss;

      if (ms_stereo) {
        gr_infos.pow2gain += 2;
      }
      gr_infos.scalefac_compress = mp.getbits(9);
      /* window-switching flag == 1 for block_Type != 0 .. and block-type == 0 . win-sw-flag = 0 */
      if (get1bit(mp) != 0) {
        gr_infos.block_type = mp.getbits_fast(2);
        gr_infos.mixed_block_flag = get1bit(mp);
        gr_infos.table_select[0] = mp.getbits_fast(5);
        gr_infos.table_select[1] = mp.getbits_fast(5);
        /*
         * table_select[2] not needed, because there is no region2,
         * but to satisfy some verifications tools we set it either.
         */
        gr_infos.table_select[2] = 0;
        int i = 0;
        do {
          final int sbg = (mp.getbits_fast(3) << 3);
          gr_infos.full_gain[i] = gr_infos.pow2gain_base;
          gr_infos.full_gain_pos[i] = gr_infos.pow2gain + sbg;
        } while (++i < 3);

        if (gr_infos.block_type == 0) {
          System.err.printf("Blocktype == 0 and window-switching == 1 not allowed.\n");
          /* error seems to be very good recoverable, so don't exit */
          /* exit(1); */
        }
        /* region_count/start parameters are implicit in this case. */
        if (gr_infos.block_type == 2) {
          if (gr_infos.mixed_block_flag == 0) {
            gr_infos.region1start = 36 >> 1;
          } else {
            gr_infos.region1start = 48 >> 1;
          }
        } else {
          gr_infos.region1start = 54 >> 1;
        }
        if (sfreq == 8) {
          gr_infos.region1start <<= 1;
        }
        gr_infos.region2start = 576 >> 1;
      } else {
        gr_infos.table_select[0] = mp.getbits_fast(5);
        gr_infos.table_select[1] = mp.getbits_fast(5);
        gr_infos.table_select[2] = mp.getbits_fast(5);
        int region0index = mp.getbits_fast(4);
        region0index++;
        int region1index = region0index;
        region1index += mp.getbits_fast(3);
        region1index++;
        if (region0index > 22) {
          System.err.printf("region0index=%d > 22\n", region0index);
          region0index = 22;
        }
        if (region1index > 22) {
          System.err.printf("region1index=%d > 22\n", region0index);
          region1index = 22;
        }
        gr_infos.region1start = bi.longIdx[region0index] >> 1;
        gr_infos.region2start = bi.longIdx[region1index] >> 1;
        gr_infos.block_type = 0;
        gr_infos.mixed_block_flag = 0;
      }
      gr_infos.scalefac_scale = get1bit(mp);
      gr_infos.count1table_select = get1bit(mp);
    }
  }

  private static final byte slen[][] = { // [2][16] = {
    {0, 0, 0, 0, 3, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4},
    {0, 1, 2, 3, 0, 1, 2, 3, 1, 2, 3, 1, 2, 3, 2, 3}
  };

  /** read scalefactors */
  private static final int III_get_scale_factors_1(
      final Jmpstr_tag mp, final int[] scf, final Jgr_info gr_infos) {
    int scfoffset = 0;
    final int num0 = slen[0][gr_infos.scalefac_compress];
    final int num1 = slen[1][gr_infos.scalefac_compress];
    int numbits;

    if (gr_infos.block_type == 2) {
      int i = 18;
      numbits = (num0 + num1) * 18;

      if (gr_infos.mixed_block_flag != 0) {
        i = scfoffset + 8;
        do {
          scf[scfoffset++] = mp.getbits_fast(num0);
        } while (scfoffset < i);
        i = 9;
        numbits -= num0; /* num0 * 17 + num1 * 18 */
      }

      i += scfoffset;
      do {
        scf[scfoffset++] = mp.getbits_fast(num0);
      } while (scfoffset < i);
      i = scfoffset + 18;
      do {
        scf[scfoffset++] = mp.getbits_fast(num1);
      } while (scfoffset < i);
      scf[scfoffset++] = 0;
      scf[scfoffset++] = 0;
      scf[scfoffset++] = 0; /* short[13][0..2] = 0 */
      return numbits;
    } // else {
    final int scfsi = gr_infos.scfsi;
    if (scfsi < 0) {
      /* scfsi < 0 => granule == 0 */
      int i = 11 + scfoffset;
      do {
        scf[scfoffset++] = mp.getbits_fast(num0);
      } while (scfoffset < i);
      i = 10 + scfoffset;
      do {
        scf[scfoffset++] = mp.getbits_fast(num1);
      } while (scfoffset < i);
      numbits = (num0 + num1) * 10 + num0;
    } else {
      numbits = 0;
      if (0 == (scfsi & 0x8)) {
        final int i = 6 + scfoffset;
        do {
          scf[scfoffset++] = mp.getbits_fast(num0);
        } while (scfoffset < i);
        numbits += num0 * 6;
      } else {
        scfoffset += 6;
      }

      if (0 == (scfsi & 0x4)) {
        final int i = 5 + scfoffset;
        do {
          scf[scfoffset++] = mp.getbits_fast(num0);
        } while (scfoffset < i);
        numbits += num0 * 5;
      } else {
        scfoffset += 5;
      }

      if (0 == (scfsi & 0x2)) {
        final int i = 5 + scfoffset;
        do {
          scf[scfoffset++] = mp.getbits_fast(num1);
        } while (scfoffset < i);
        numbits += num1 * 5;
      } else {
        scfoffset += 5;
      }

      if (0 == (scfsi & 0x1)) {
        final int i = 5 + scfoffset;
        do {
          scf[scfoffset++] = mp.getbits_fast(num1);
        } while (scfoffset < i);
        numbits += num1 * 5;
      } else {
        scfoffset += 5;
      }
    }

    scf[scfoffset++] = 0; /* no l[21] in original sources */
    // }
    return numbits;
  }

  private static final byte stab[][][] = { // [3][6][4] = {
    {{6, 5, 5, 5}, {6, 5, 7, 3}, {11, 10, 0, 0}, {7, 7, 7, 0}, {6, 6, 6, 3}, {8, 8, 5, 0}},
    {{9, 9, 9, 9}, {9, 9, 12, 6}, {18, 18, 0, 0}, {12, 12, 12, 0}, {12, 9, 9, 6}, {15, 12, 9, 0}},
    {{6, 9, 9, 9}, {6, 9, 12, 6}, {15, 18, 0, 0}, {6, 15, 12, 0}, {6, 12, 9, 6}, {6, 18, 9, 0}}
  };

  private static final int III_get_scale_factors_2(
      final Jmpstr_tag mp, final int[] scf, final Jgr_info gr_infos, final boolean i_stereo) {
    int slen2;
    if (i_stereo) {
      slen2 = i_slen2[gr_infos.scalefac_compress >> 1];
    } else {
      slen2 = n_slen2[gr_infos.scalefac_compress];
    }

    gr_infos.preflag = ((slen2 >>> 15) & 0x1) != 0;

    int n = 0;
    if (gr_infos.block_type == 2) {
      n++;
      if (gr_infos.mixed_block_flag != 0) {
        n++;
      }
    }

    final byte[] pnt = stab[n][(slen2 >>> 12) & 0x7];
    int numbits = 0;
    int scfoffset = 0;
    int i = 0;
    do {
      final int num = slen2 & 0x7;
      slen2 >>>= 3;
      if (num != 0) {
        for (int j = 0, je = (int) pnt[i]; j < je; j++) {
          scf[scfoffset++] = mp.getbits_fast(num);
        }
        numbits += pnt[i] * num;
      } else {
        for (int j = 0, je = (int) pnt[i]; j < je; j++) {
          scf[scfoffset++] = 0;
        }
      }
    } while (++i < 4);

    n <<= 1;
    for (i = 0; i <= n; i++) {
      scf[scfoffset++] = 0;
    }

    return numbits;
  }

  private static final short tab0[] = {0};

  private static final short tab1[] = {-5, -3, -1, 17, 1, 16, 0};

  private static final short tab2[] = {
    -15, -11, -9, -5, -3, -1, 34, 2, 18, -1, 33, 32, 17, -1, 1, 16, 0
  };

  private static final short tab3[] = {
    -13, -11, -9, -5, -3, -1, 34, 2, 18, -1, 33, 32, 16, 17, -1, 1, 0
  };

  private static final short tab5[] = {
    -29, -25, -23, -15, -7, -5, -3, -1, 51, 35, 50, 49, -3, -1, 19, 3, -1, 48, 34, -3, -1, 18, 33,
    -1, 2, 32, 17, -1, 1, 16, 0
  };

  private static final short tab6[] = {
    -25, -19, -13, -9, -5, -3, -1, 51, 3, 35, -1, 50, 48, -1, 19,
    49, -3, -1, 34, 2, 18, -3, -1, 33, 32, 1, -1, 17, -1, 16,
    0
  };

  private static final short tab7[] = {
    -69, -65, -57, -39, -29, -17, -11, -7, -3, -1, 85, 69, -1, 84, 83,
    -1, 53, 68, -3, -1, 37, 82, 21, -5, -1, 81, -1, 5, 52, -1,
    80, -1, 67, 51, -5, -3, -1, 36, 66, 20, -1, 65, 64, -11, -7,
    -3, -1, 4, 35, -1, 50, 3, -1, 19, 49, -3, -1, 48, 34, 18,
    -5, -1, 33, -1, 2, 32, 17, -1, 1, 16, 0
  };

  private static final short tab8[] = {
    -65, -63, -59, -45, -31, -19, -13, -7, -5, -3, -1, 85, 84, 69, 83,
    -3, -1, 53, 68, 37, -3, -1, 82, 5, 21, -5, -1, 81, -1, 52,
    67, -3, -1, 80, 51, 36, -5, -3, -1, 66, 20, 65, -3, -1, 4,
    64, -1, 35, 50, -9, -7, -3, -1, 19, 49, -1, 3, 48, 34, -1,
    2, 32, -1, 18, 33, 17, -3, -1, 1, 16, 0
  };

  private static final short tab9[] = {
    -63, -53, -41, -29, -19, -11, -5, -3, -1, 85, 69, 53, -1, 83, -1,
    84, 5, -3, -1, 68, 37, -1, 82, 21, -3, -1, 81, 52, -1, 67,
    -1, 80, 4, -7, -3, -1, 36, 66, -1, 51, 64, -1, 20, 65, -5,
    -3, -1, 35, 50, 19, -1, 49, -1, 3, 48, -5, -3, -1, 34, 2,
    18, -1, 33, 32, -3, -1, 17, 1, -1, 16, 0
  };

  private static final short tab10[] = {
    -125, -121, -111, -83, -55, -35, -21, -13, -7, -3, -1, 119, 103, -1, 118,
    87, -3, -1, 117, 102, 71, -3, -1, 116, 86, -1, 101, 55, -9, -3,
    -1, 115, 70, -3, -1, 85, 84, 99, -1, 39, 114, -11, -5, -3, -1,
    100, 7, 112, -1, 98, -1, 69, 53, -5, -1, 6, -1, 83, 68, 23,
    -17, -5, -1, 113, -1, 54, 38, -5, -3, -1, 37, 82, 21, -1, 81,
    -1, 52, 67, -3, -1, 22, 97, -1, 96, -1, 5, 80, -19, -11, -7,
    -3, -1, 36, 66, -1, 51, 4, -1, 20, 65, -3, -1, 64, 35, -1,
    50, 3, -3, -1, 19, 49, -1, 48, 34, -7, -3, -1, 18, 33, -1,
    2, 32, 17, -1, 1, 16, 0
  };

  private static final short tab11[] = {
    -121, -113, -89, -59, -43, -27, -17, -7, -3, -1, 119, 103, -1, 118, 117,
    -3, -1, 102, 71, -1, 116, -1, 87, 85, -5, -3, -1, 86, 101, 55,
    -1, 115, 70, -9, -7, -3, -1, 69, 84, -1, 53, 83, 39, -1, 114,
    -1, 100, 7, -5, -1, 113, -1, 23, 112, -3, -1, 54, 99, -1, 96,
    -1, 68, 37, -13, -7, -5, -3, -1, 82, 5, 21, 98, -3, -1, 38,
    6, 22, -5, -1, 97, -1, 81, 52, -5, -1, 80, -1, 67, 51, -1,
    36, 66, -15, -11, -7, -3, -1, 20, 65, -1, 4, 64, -1, 35, 50,
    -1, 19, 49, -5, -3, -1, 3, 48, 34, 33, -5, -1, 18, -1, 2,
    32, 17, -3, -1, 1, 16, 0
  };

  private static final short tab12[] = {
    -115, -99, -73, -45, -27, -17, -9, -5, -3, -1, 119, 103, 118, -1, 87,
    117, -3, -1, 102, 71, -1, 116, 101, -3, -1, 86, 55, -3, -1, 115,
    85, 39, -7, -3, -1, 114, 70, -1, 100, 23, -5, -1, 113, -1, 7,
    112, -1, 54, 99, -13, -9, -3, -1, 69, 84, -1, 68, -1, 6, 5,
    -1, 38, 98, -5, -1, 97, -1, 22, 96, -3, -1, 53, 83, -1, 37,
    82, -17, -7, -3, -1, 21, 81, -1, 52, 67, -5, -3, -1, 80, 4,
    36, -1, 66, 20, -3, -1, 51, 65, -1, 35, 50, -11, -7, -5, -3,
    -1, 64, 3, 48, 19, -1, 49, 34, -1, 18, 33, -7, -5, -3, -1,
    2, 32, 0, 17, -1, 1, 16
  };

  private static final short tab13[] = {
    -509, -503, -475, -405, -333, -265, -205, -153, -115, -83, -53, -35, -21, -13, -9,
    -7, -5, -3, -1, 254, 252, 253, 237, 255, -1, 239, 223, -3, -1, 238,
    207, -1, 222, 191, -9, -3, -1, 251, 206, -1, 220, -1, 175, 233, -1,
    236, 221, -9, -5, -3, -1, 250, 205, 190, -1, 235, 159, -3, -1, 249,
    234, -1, 189, 219, -17, -9, -3, -1, 143, 248, -1, 204, -1, 174, 158,
    -5, -1, 142, -1, 127, 126, 247, -5, -1, 218, -1, 173, 188, -3, -1,
    203, 246, 111, -15, -7, -3, -1, 232, 95, -1, 157, 217, -3, -1, 245,
    231, -1, 172, 187, -9, -3, -1, 79, 244, -3, -1, 202, 230, 243, -1,
    63, -1, 141, 216, -21, -9, -3, -1, 47, 242, -3, -1, 110, 156, 15,
    -5, -3, -1, 201, 94, 171, -3, -1, 125, 215, 78, -11, -5, -3, -1,
    200, 214, 62, -1, 185, -1, 155, 170, -1, 31, 241, -23, -13, -5, -1,
    240, -1, 186, 229, -3, -1, 228, 140, -1, 109, 227, -5, -1, 226, -1,
    46, 14, -1, 30, 225, -15, -7, -3, -1, 224, 93, -1, 213, 124, -3,
    -1, 199, 77, -1, 139, 184, -7, -3, -1, 212, 154, -1, 169, 108, -1,
    198, 61, -37, -21, -9, -5, -3, -1, 211, 123, 45, -1, 210, 29, -5,
    -1, 183, -1, 92, 197, -3, -1, 153, 122, 195, -7, -5, -3, -1, 167,
    151, 75, 209, -3, -1, 13, 208, -1, 138, 168, -11, -7, -3, -1, 76,
    196, -1, 107, 182, -1, 60, 44, -3, -1, 194, 91, -3, -1, 181, 137,
    28, -43, -23, -11, -5, -1, 193, -1, 152, 12, -1, 192, -1, 180, 106,
    -5, -3, -1, 166, 121, 59, -1, 179, -1, 136, 90, -11, -5, -1, 43,
    -1, 165, 105, -1, 164, -1, 120, 135, -5, -1, 148, -1, 119, 118, 178,
    -11, -3, -1, 27, 177, -3, -1, 11, 176, -1, 150, 74, -7, -3, -1,
    58, 163, -1, 89, 149, -1, 42, 162, -47, -23, -9, -3, -1, 26, 161,
    -3, -1, 10, 104, 160, -5, -3, -1, 134, 73, 147, -3, -1, 57, 88,
    -1, 133, 103, -9, -3, -1, 41, 146, -3, -1, 87, 117, 56, -5, -1,
    131, -1, 102, 71, -3, -1, 116, 86, -1, 101, 115, -11, -3, -1, 25,
    145, -3, -1, 9, 144, -1, 72, 132, -7, -5, -1, 114, -1, 70, 100,
    40, -1, 130, 24, -41, -27, -11, -5, -3, -1, 55, 39, 23, -1, 113,
    -1, 85, 7, -7, -3, -1, 112, 54, -1, 99, 69, -3, -1, 84, 38,
    -1, 98, 53, -5, -1, 129, -1, 8, 128, -3, -1, 22, 97, -1, 6,
    96, -13, -9, -5, -3, -1, 83, 68, 37, -1, 82, 5, -1, 21, 81,
    -7, -3, -1, 52, 67, -1, 80, 36, -3, -1, 66, 51, 20, -19, -11,
    -5, -1, 65, -1, 4, 64, -3, -1, 35, 50, 19, -3, -1, 49, 3,
    -1, 48, 34, -3, -1, 18, 33, -1, 2, 32, -3, -1, 17, 1, 16,
    0
  };

  private static final short tab15[] = {
    -495, -445, -355, -263, -183, -115, -77, -43, -27, -13, -7, -3, -1, 255, 239,
    -1, 254, 223, -1, 238, -1, 253, 207, -7, -3, -1, 252, 222, -1, 237,
    191, -1, 251, -1, 206, 236, -7, -3, -1, 221, 175, -1, 250, 190, -3,
    -1, 235, 205, -1, 220, 159, -15, -7, -3, -1, 249, 234, -1, 189, 219,
    -3, -1, 143, 248, -1, 204, 158, -7, -3, -1, 233, 127, -1, 247, 173,
    -3, -1, 218, 188, -1, 111, -1, 174, 15, -19, -11, -3, -1, 203, 246,
    -3, -1, 142, 232, -1, 95, 157, -3, -1, 245, 126, -1, 231, 172, -9,
    -3, -1, 202, 187, -3, -1, 217, 141, 79, -3, -1, 244, 63, -1, 243,
    216, -33, -17, -9, -3, -1, 230, 47, -1, 242, -1, 110, 240, -3, -1,
    31, 241, -1, 156, 201, -7, -3, -1, 94, 171, -1, 186, 229, -3, -1,
    125, 215, -1, 78, 228, -15, -7, -3, -1, 140, 200, -1, 62, 109, -3,
    -1, 214, 227, -1, 155, 185, -7, -3, -1, 46, 170, -1, 226, 30, -5,
    -1, 225, -1, 14, 224, -1, 93, 213, -45, -25, -13, -7, -3, -1, 124,
    199, -1, 77, 139, -1, 212, -1, 184, 154, -7, -3, -1, 169, 108, -1,
    198, 61, -1, 211, 210, -9, -5, -3, -1, 45, 13, 29, -1, 123, 183,
    -5, -1, 209, -1, 92, 208, -1, 197, 138, -17, -7, -3, -1, 168, 76,
    -1, 196, 107, -5, -1, 182, -1, 153, 12, -1, 60, 195, -9, -3, -1,
    122, 167, -1, 166, -1, 192, 11, -1, 194, -1, 44, 91, -55, -29, -15,
    -7, -3, -1, 181, 28, -1, 137, 152, -3, -1, 193, 75, -1, 180, 106,
    -5, -3, -1, 59, 121, 179, -3, -1, 151, 136, -1, 43, 90, -11, -5,
    -1, 178, -1, 165, 27, -1, 177, -1, 176, 105, -7, -3, -1, 150, 74,
    -1, 164, 120, -3, -1, 135, 58, 163, -17, -7, -3, -1, 89, 149, -1,
    42, 162, -3, -1, 26, 161, -3, -1, 10, 160, 104, -7, -3, -1, 134,
    73, -1, 148, 57, -5, -1, 147, -1, 119, 9, -1, 88, 133, -53, -29,
    -13, -7, -3, -1, 41, 103, -1, 118, 146, -1, 145, -1, 25, 144, -7,
    -3, -1, 72, 132, -1, 87, 117, -3, -1, 56, 131, -1, 102, 71, -7,
    -3, -1, 40, 130, -1, 24, 129, -7, -3, -1, 116, 8, -1, 128, 86,
    -3, -1, 101, 55, -1, 115, 70, -17, -7, -3, -1, 39, 114, -1, 100,
    23, -3, -1, 85, 113, -3, -1, 7, 112, 54, -7, -3, -1, 99, 69,
    -1, 84, 38, -3, -1, 98, 22, -3, -1, 6, 96, 53, -33, -19, -9,
    -5, -1, 97, -1, 83, 68, -1, 37, 82, -3, -1, 21, 81, -3, -1,
    5, 80, 52, -7, -3, -1, 67, 36, -1, 66, 51, -1, 65, -1, 20,
    4, -9, -3, -1, 35, 50, -3, -1, 64, 3, 19, -3, -1, 49, 48,
    34, -9, -7, -3, -1, 18, 33, -1, 2, 32, 17, -3, -1, 1, 16,
    0
  };

  private static final short tab16[] = {
    -509, -503, -461, -323, -103, -37, -27, -15, -7, -3, -1, 239, 254, -1, 223,
    253, -3, -1, 207, 252, -1, 191, 251, -5, -1, 175, -1, 250, 159, -3,
    -1, 249, 248, 143, -7, -3, -1, 127, 247, -1, 111, 246, 255, -9, -5,
    -3, -1, 95, 245, 79, -1, 244, 243, -53, -1, 240, -1, 63, -29, -19,
    -13, -7, -5, -1, 206, -1, 236, 221, 222, -1, 233, -1, 234, 217, -1,
    238, -1, 237, 235, -3, -1, 190, 205, -3, -1, 220, 219, 174, -11, -5,
    -1, 204, -1, 173, 218, -3, -1, 126, 172, 202, -5, -3, -1, 201, 125,
    94, 189, 242, -93, -5, -3, -1, 47, 15, 31, -1, 241, -49, -25, -13,
    -5, -1, 158, -1, 188, 203, -3, -1, 142, 232, -1, 157, 231, -7, -3,
    -1, 187, 141, -1, 216, 110, -1, 230, 156, -13, -7, -3, -1, 171, 186,
    -1, 229, 215, -1, 78, -1, 228, 140, -3, -1, 200, 62, -1, 109, -1,
    214, 155, -19, -11, -5, -3, -1, 185, 170, 225, -1, 212, -1, 184, 169,
    -5, -1, 123, -1, 183, 208, 227, -7, -3, -1, 14, 224, -1, 93, 213,
    -3, -1, 124, 199, -1, 77, 139, -75, -45, -27, -13, -7, -3, -1, 154,
    108, -1, 198, 61, -3, -1, 92, 197, 13, -7, -3, -1, 138, 168, -1,
    153, 76, -3, -1, 182, 122, 60, -11, -5, -3, -1, 91, 137, 28, -1,
    192, -1, 152, 121, -1, 226, -1, 46, 30, -15, -7, -3, -1, 211, 45,
    -1, 210, 209, -5, -1, 59, -1, 151, 136, 29, -7, -3, -1, 196, 107,
    -1, 195, 167, -1, 44, -1, 194, 181, -23, -13, -7, -3, -1, 193, 12,
    -1, 75, 180, -3, -1, 106, 166, 179, -5, -3, -1, 90, 165, 43, -1,
    178, 27, -13, -5, -1, 177, -1, 11, 176, -3, -1, 105, 150, -1, 74,
    164, -5, -3, -1, 120, 135, 163, -3, -1, 58, 89, 42, -97, -57, -33,
    -19, -11, -5, -3, -1, 149, 104, 161, -3, -1, 134, 119, 148, -5, -3,
    -1, 73, 87, 103, 162, -5, -1, 26, -1, 10, 160, -3, -1, 57, 147,
    -1, 88, 133, -9, -3, -1, 41, 146, -3, -1, 118, 9, 25, -5, -1,
    145, -1, 144, 72, -3, -1, 132, 117, -1, 56, 131, -21, -11, -5, -3,
    -1, 102, 40, 130, -3, -1, 71, 116, 24, -3, -1, 129, 128, -3, -1,
    8, 86, 55, -9, -5, -1, 115, -1, 101, 70, -1, 39, 114, -5, -3,
    -1, 100, 85, 7, 23, -23, -13, -5, -1, 113, -1, 112, 54, -3, -1,
    99, 69, -1, 84, 38, -3, -1, 98, 22, -1, 97, -1, 6, 96, -9,
    -5, -1, 83, -1, 53, 68, -1, 37, 82, -1, 81, -1, 21, 5, -33,
    -23, -13, -7, -3, -1, 52, 67, -1, 80, 36, -3, -1, 66, 51, 20,
    -5, -1, 65, -1, 4, 64, -1, 35, 50, -3, -1, 19, 49, -3, -1,
    3, 48, 34, -3, -1, 18, 33, -1, 2, 32, -3, -1, 17, 1, 16,
    0
  };

  private static final short tab24[] = {
    -451, -117, -43, -25, -15, -7, -3, -1, 239, 254, -1, 223, 253, -3, -1,
    207, 252, -1, 191, 251, -5, -1, 250, -1, 175, 159, -1, 249, 248, -9,
    -5, -3, -1, 143, 127, 247, -1, 111, 246, -3, -1, 95, 245, -1, 79,
    244, -71, -7, -3, -1, 63, 243, -1, 47, 242, -5, -1, 241, -1, 31,
    240, -25, -9, -1, 15, -3, -1, 238, 222, -1, 237, 206, -7, -3, -1,
    236, 221, -1, 190, 235, -3, -1, 205, 220, -1, 174, 234, -15, -7, -3,
    -1, 189, 219, -1, 204, 158, -3, -1, 233, 173, -1, 218, 188, -7, -3,
    -1, 203, 142, -1, 232, 157, -3, -1, 217, 126, -1, 231, 172, 255, -235,
    -143, -77, -45, -25, -15, -7, -3, -1, 202, 187, -1, 141, 216, -5, -3,
    -1, 14, 224, 13, 230, -5, -3, -1, 110, 156, 201, -1, 94, 186, -9,
    -5, -1, 229, -1, 171, 125, -1, 215, 228, -3, -1, 140, 200, -3, -1,
    78, 46, 62, -15, -7, -3, -1, 109, 214, -1, 227, 155, -3, -1, 185,
    170, -1, 226, 30, -7, -3, -1, 225, 93, -1, 213, 124, -3, -1, 199,
    77, -1, 139, 184, -31, -15, -7, -3, -1, 212, 154, -1, 169, 108, -3,
    -1, 198, 61, -1, 211, 45, -7, -3, -1, 210, 29, -1, 123, 183, -3,
    -1, 209, 92, -1, 197, 138, -17, -7, -3, -1, 168, 153, -1, 76, 196,
    -3, -1, 107, 182, -3, -1, 208, 12, 60, -7, -3, -1, 195, 122, -1,
    167, 44, -3, -1, 194, 91, -1, 181, 28, -57, -35, -19, -7, -3, -1,
    137, 152, -1, 193, 75, -5, -3, -1, 192, 11, 59, -3, -1, 176, 10,
    26, -5, -1, 180, -1, 106, 166, -3, -1, 121, 151, -3, -1, 160, 9,
    144, -9, -3, -1, 179, 136, -3, -1, 43, 90, 178, -7, -3, -1, 165,
    27, -1, 177, 105, -1, 150, 164, -17, -9, -5, -3, -1, 74, 120, 135,
    -1, 58, 163, -3, -1, 89, 149, -1, 42, 162, -7, -3, -1, 161, 104,
    -1, 134, 119, -3, -1, 73, 148, -1, 57, 147, -63, -31, -15, -7, -3,
    -1, 88, 133, -1, 41, 103, -3, -1, 118, 146, -1, 25, 145, -7, -3,
    -1, 72, 132, -1, 87, 117, -3, -1, 56, 131, -1, 102, 40, -17, -7,
    -3, -1, 130, 24, -1, 71, 116, -5, -1, 129, -1, 8, 128, -1, 86,
    101, -7, -5, -1, 23, -1, 7, 112, 115, -3, -1, 55, 39, 114, -15,
    -7, -3, -1, 70, 100, -1, 85, 113, -3, -1, 54, 99, -1, 69, 84,
    -7, -3, -1, 38, 98, -1, 22, 97, -5, -3, -1, 6, 96, 53, -1,
    83, 68, -51, -37, -23, -15, -9, -3, -1, 37, 82, -1, 21, -1, 5,
    80, -1, 81, -1, 52, 67, -3, -1, 36, 66, -1, 51, 20, -9, -5,
    -1, 65, -1, 4, 64, -1, 35, 50, -1, 19, 49, -7, -5, -3, -1,
    3, 48, 34, 18, -1, 33, -1, 2, 32, -3, -1, 17, 1, -1, 16,
    0
  };

  private static final short tab_c0[] = {
    -29, -21, -13, -7, -3, -1, 11, 15, -1, 13, 14, -3, -1, 7, 5,
    9, -3, -1, 6, 3, -1, 10, 12, -3, -1, 2, 1, -1, 4, 8,
    0
  };

  private static final short tab_c1[] = {
    -15, -7, -3, -1, 15, 14, -1, 13, 12, -3, -1, 11, 10, -1, 9,
    8, -7, -3, -1, 7, 6, -1, 5, 4, -3, -1, 3, 2, -1, 1,
    0
  };

  private static final class Jnewhuff {
    final int linbits;
    final short[] table;
    //
    public Jnewhuff(final int bits, final short[] t) {
      this.linbits = bits;
      this.table = t;
    }
  }

  private static final Jnewhuff sHt[] = {
    new Jnewhuff(/* 0 */ 0, tab0),
    new Jnewhuff(/* 2 */ 0, tab1),
    new Jnewhuff(/* 3 */ 0, tab2),
    new Jnewhuff(/* 3 */ 0, tab3),
    new Jnewhuff(/* 0 */ 0, tab0),
    new Jnewhuff(/* 4 */ 0, tab5),
    new Jnewhuff(/* 4 */ 0, tab6),
    new Jnewhuff(/* 6 */ 0, tab7),
    new Jnewhuff(/* 6 */ 0, tab8),
    new Jnewhuff(/* 6 */ 0, tab9),
    new Jnewhuff(/* 8 */ 0, tab10),
    new Jnewhuff(/* 8 */ 0, tab11),
    new Jnewhuff(/* 8 */ 0, tab12),
    new Jnewhuff(/* 16 */ 0, tab13),
    new Jnewhuff(/* 0  */ 0, tab0),
    new Jnewhuff(/* 16 */ 0, tab15),
    new Jnewhuff(/* 16 */ 1, tab16),
    new Jnewhuff(/* 16 */ 2, tab16),
    new Jnewhuff(/* 16 */ 3, tab16),
    new Jnewhuff(/* 16 */ 4, tab16),
    new Jnewhuff(/* 16 */ 6, tab16),
    new Jnewhuff(/* 16 */ 8, tab16),
    new Jnewhuff(/* 16 */ 10, tab16),
    new Jnewhuff(/* 16 */ 13, tab16),
    new Jnewhuff(/* 16 */ 4, tab24),
    new Jnewhuff(/* 16 */ 5, tab24),
    new Jnewhuff(/* 16 */ 6, tab24),
    new Jnewhuff(/* 16 */ 7, tab24),
    new Jnewhuff(/* 16 */ 8, tab24),
    new Jnewhuff(/* 16 */ 9, tab24),
    new Jnewhuff(/* 16 */ 11, tab24),
    new Jnewhuff(/* 16 */ 13, tab24)
  };

  private static final Jnewhuff sHtc[] = {
    new Jnewhuff(/* 1 , 1 , */ 0, tab_c0), new Jnewhuff(/* 1 , 1 , */ 0, tab_c1)
  };

  private static final int pretab1[ /*22*/] = {
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 3, 3, 3, 2, 0
  }; /* char enough ? */
  private static final int pretab2[ /*22*/] = {
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
  };

  /* don't forget to apply the same changes to III_dequantize_sample_ms() !!! */
  @SuppressWarnings("boxing")
  private static final boolean III_dequantize_sample(
      final Jmpstr_tag mp,
      final float xr[] /*[SBLIMIT][SSLIMIT]*/,
      final int[] scf,
      final Jgr_info gr_infos,
      final int sfreq,
      final int part2bits) {
    int scfoffset = 0;
    final int shift = 1 + gr_infos.scalefac_scale;
    int xrpnt = 0; // xr[ xrpnt ]
    float xr_value = 0;
    final int l[] = new int[3];
    int part2remain = gr_infos.part2_3_length - part2bits;
    // real const * const xr_endptr = &xr[SBLIMIT-1][SSLIMIT-1];
    final int xr_endptr = (Jmpg123.SBLIMIT * Jmpg123.SSLIMIT) - 1;

    boolean isbug = false;
    boolean bobug = false;
    int bobug_sb = 0, bobug_l3 = 0;
    // #define BUFFER_OVERFLOW_BUG() if( ! bobug ) { bobug = true; bobug_sb = cb; bobug_l3 = l3; }
    // else

    {
      // for( int i = (&xr[Jmpg123.SBLIMIT][0] - xrpnt) >> 1; i > 0; i-- ) {// FIXME WTF?
      do {
        xr[xrpnt++] = 0.0f;
        xr[xrpnt++] = 0.0f;
      } while (xrpnt < (Jmpg123.SBLIMIT * Jmpg123.SSLIMIT));

      xrpnt = 0; // xr[ xrpnt ]
    }

    int l3;
    {
      final int bv = gr_infos.big_values;
      final int region1 = gr_infos.region1start;
      final int region2 = gr_infos.region2start;

      l3 = ((576 >> 1) - bv) >> 1;
      /* we may lose the 'odd' bit here !! check this later again */
      if (bv <= region1) {
        l[0] = bv;
        l[1] = 0;
        l[2] = 0;
      } else {
        l[0] = region1;
        if (bv <= region2) {
          l[1] = bv - l[0];
          l[2] = 0;
        } else {
          l[1] = region2 - l[0];
          l[2] = bv - region2;
        }
      }
    }
    /* MDH crash fix */
    {
      for (int i = 0; i < 3; i++) {
        if (l[i] < 0) {
          System.err.printf("hip: Bogus region length (%d)\n", l[i]);
          l[i] = 0;
        }
      }
    }
    /* end MDH crash fix */

    if (gr_infos.block_type == 2) {
      /* decoding with short or mixed mode BandIndex table */
      final int max[] = new int[4];
      int step = 0, lwin = 0, cb = 0;
      float v = 0.0f;
      int[] m;
      int me;

      if (gr_infos.mixed_block_flag != 0) {
        max[3] = -1;
        max[0] = max[1] = max[2] = 2;
        m = map[sfreq][0];
        me = mapend[sfreq][0];
      } else {
        max[0] = max[1] = max[2] = max[3] = -1;
        /* max[3] not really needed in this case */
        m = map[sfreq][1];
        me = mapend[sfreq][1];
      }

      int mc = 0;
      int moffset = 0;
      int i = 0;
      do {
        int lp = l[i];
        final Jnewhuff h[] = sHt;
        final int hoffset = gr_infos.table_select[i];
        for (; lp != 0; lp--, mc--) {
          int x, y;
          if (0 == mc) {
            mc = m[moffset++];
            xrpnt = m[moffset++];
            lwin = m[moffset++];
            cb = m[moffset++];
            if (lwin == 3) {
              try {
                v = gr_infos.pow2gain_base[gr_infos.pow2gain + (scf[scfoffset++] << shift)];
              } catch (final ArrayIndexOutOfBoundsException ae) {
                v = gr_infos.pow2gain_base[gr_infos.pow2gain_base.length - 1];
                isbug = true;
              }
              step = 1;
            } else {
              try {
                v =
                    gr_infos
                        .full_gain[lwin][
                        gr_infos.full_gain_pos[lwin] + (scf[scfoffset++] << shift)];
              } catch (final ArrayIndexOutOfBoundsException ae) {
                v = gr_infos.full_gain[lwin][gr_infos.full_gain[lwin].length - 1];
                isbug = true;
              }
              step = 3;
            }
          }
          {
            final short[] table = h[hoffset].table;
            int val = 0; // table[ val ]
            while ((y = table[val++]) < 0) {
              if (get1bit(mp) != 0) {
                val -= y;
              }
              part2remain--;
            }
            x = y >> 4;
            y &= 0xf;
          }
          if (x == 15) {
            max[lwin] = cb;
            part2remain -= h[hoffset].linbits + 1;
            x += mp.getbits(h[hoffset].linbits);
            if (get1bit(mp) != 0) {
              xr_value = -ispow[x] * v;
            } else {
              xr_value = ispow[x] * v;
            }
          } else if (x != 0) {
            max[lwin] = cb;
            if (get1bit(mp) != 0) {
              xr_value = -ispow[x] * v;
            } else {
              xr_value = ispow[x] * v;
            }
            part2remain--;
          } else {
            xr_value = 0.0f;
          }

          if (xrpnt <= xr_endptr) {
            xr[xrpnt] = xr_value;
          } else {
            // BUFFER_OVERFLOW_BUG();
            if (!bobug) {
              bobug = true;
              bobug_sb = cb;
              bobug_l3 = l3;
            }
          }
          xrpnt += step;
          if (y == 15) {
            max[lwin] = cb;
            part2remain -= h[hoffset].linbits + 1;
            y += mp.getbits(h[hoffset].linbits);
            if (get1bit(mp) != 0) {
              xr_value = -ispow[y] * v;
            } else {
              xr_value = ispow[y] * v;
            }
          } else if (y != 0) {
            max[lwin] = cb;
            if (get1bit(mp) != 0) {
              xr_value = -ispow[y] * v;
            } else {
              xr_value = ispow[y] * v;
            }
            part2remain--;
          } else {
            xr_value = 0.0f;
          }

          if (xrpnt <= xr_endptr) {
            xr[xrpnt] = xr_value;
          } else {
            // BUFFER_OVERFLOW_BUG();
            if (!bobug) {
              bobug = true;
              bobug_sb = cb;
              bobug_l3 = l3;
            }
          }
          xrpnt += step;
        }
      } while (++i < 2);
      for (; l3 != 0 && (part2remain > 0); l3--) {
        final Jnewhuff h[] = sHtc;
        final int hoffset = gr_infos.count1table_select; // h[ hoffset ]
        final short[] table = h[hoffset].table;
        int val = 0;
        short a;

        while ((a = table[val++]) < 0) {
          part2remain--;
          if (part2remain < 0) {
            part2remain++;
            a = 0;
            break;
          }
          if (get1bit(mp) != 0) {
            val -= a;
          }
        }
        i = 0;
        do {
          if (0 == (i & 1)) {
            if (0 == mc) {
              mc = m[moffset++];
              xrpnt = m[moffset++];
              lwin = m[moffset++];
              cb = m[moffset++];
              if (lwin == 3) {
                try {
                  v = gr_infos.pow2gain_base[gr_infos.pow2gain + (scf[scfoffset++] << shift)];
                } catch (final ArrayIndexOutOfBoundsException ae) {
                  v = gr_infos.pow2gain_base[gr_infos.pow2gain_base.length - 1];
                  isbug = true;
                }
                step = 1;
              } else {
                try {
                  v =
                      gr_infos
                          .full_gain[lwin][
                          gr_infos.full_gain_pos[lwin] + (scf[scfoffset++] << shift)];
                } catch (final ArrayIndexOutOfBoundsException ae) {
                  v = gr_infos.full_gain[lwin][gr_infos.full_gain[lwin].length - 1];
                  isbug = true;
                }
                step = 3;
              }
            }
            mc--;
          }
          if ((a & (0x8 >> i)) != 0) {
            max[lwin] = cb;
            part2remain--;
            if (part2remain < 0) {
              part2remain++;
              break;
            }
            if (get1bit(mp) != 0) {
              xr_value = -v;
            } else {
              xr_value = v;
            }
          } else {
            xr_value = 0.0f;
          }

          if (xrpnt <= xr_endptr) {
            xr[xrpnt] = xr_value;
          } else {
            // BUFFER_OVERFLOW_BUG();
            if (!bobug) {
              bobug = true;
              bobug_sb = cb;
              bobug_l3 = l3;
            }
          }
          xrpnt += step;
        } while (++i < 4);
      }

      while (moffset < me) {
        if (0 == mc) {
          mc = m[moffset++];
          xrpnt = m[moffset++];
          if (m[moffset++] == 3) {
            step = 1;
          } else {
            step = 3;
          }
          moffset++; /* cb */
        }
        mc--;
        if (xrpnt <= xr_endptr) {
          xr[xrpnt] = 0.0f;
        } else {
          // BUFFER_OVERFLOW_BUG();
          if (!bobug) {
            bobug = true;
            bobug_sb = cb;
            bobug_l3 = l3;
          }
        }
        xrpnt += step;
        if (xrpnt <= xr_endptr) {
          xr[xrpnt] = 0.0f;
        } else {
          // BUFFER_OVERFLOW_BUG();
          if (!bobug) {
            bobug = true;
            bobug_sb = cb;
            bobug_l3 = l3;
          }
        }
        xrpnt += step;
        /* we could add a little opt. here:
         * if we finished a band for window 3 or a long band
         * further bands could copied in a simple loop without a
         * special 'map' decoding
         */
      }

      gr_infos.maxband[0] = max[0] + 1;
      gr_infos.maxband[1] = max[1] + 1;
      gr_infos.maxband[2] = max[2] + 1;
      gr_infos.maxbandl = max[3] + 1;

      {
        int rmax = max[0] > max[1] ? max[0] : max[1];
        rmax = (rmax > max[2] ? rmax : max[2]) + 1;
        gr_infos.maxb = rmax != 0 ? shortLimit[sfreq][rmax] : longLimit[sfreq][max[3] + 1];
      }

    } else {
      /* decoding with 'long' BandIndex table (block_type != 2) */
      final int[] pretab = (gr_infos.preflag ? pretab1 : pretab2);
      int ipretab = 0; // pretab[ ipretab ]
      int max = -1;
      int cb = 0;
      final int[] m = map[sfreq][2];
      int moffset = 0; // m[ moffset ]
      float v = 0.0f;
      int mc = 0;

      /* long hash table values */
      int i = 0;
      do {
        int lp = l[i];
        final Jnewhuff ht[] = sHt;
        final int h = gr_infos.table_select[i];

        for (; lp != 0; lp--, mc--) {
          if (0 == mc) {
            mc = m[moffset++];
            try {
              v =
                  gr_infos
                      .pow2gain_base[
                      gr_infos.pow2gain + ((scf[scfoffset++] + pretab[ipretab++]) << shift)];
            } catch (final ArrayIndexOutOfBoundsException ae) {
              v = gr_infos.pow2gain_base[gr_infos.pow2gain_base.length - 1];
              isbug = true;
            }
            cb = m[moffset++];
          }
          final short[] table = ht[h].table;
          int val = 0;
          int y;
          while ((y = table[val++]) < 0) {
            if (get1bit(mp) != 0) {
              val -= y;
            }
            part2remain--;
          }
          int x = y >> 4;
          y &= 0xf;
          if (x == 15) {
            max = cb;
            part2remain -= ht[h].linbits + 1;
            x += mp.getbits(ht[h].linbits);
            if (get1bit(mp) != 0) {
              xr_value = -ispow[x] * v;
            } else {
              xr_value = ispow[x] * v;
            }
          } else if (x != 0) {
            max = cb;
            if (get1bit(mp) != 0) {
              xr_value = -ispow[x] * v;
            } else {
              xr_value = ispow[x] * v;
            }
            part2remain--;
          } else {
            xr_value = 0.0f;
          }

          if (xrpnt <= xr_endptr) {
            xr[xrpnt++] = xr_value;
          } else {
            // BUFFER_OVERFLOW_BUG();
            if (!bobug) {
              bobug = true;
              bobug_sb = cb;
              bobug_l3 = l3;
            }
          }
          if (y == 15) {
            max = cb;
            part2remain -= ht[h].linbits + 1;
            y += mp.getbits(ht[h].linbits);
            if (get1bit(mp) != 0) {
              xr_value = -ispow[y] * v;
            } else {
              xr_value = ispow[y] * v;
            }
          } else if (y != 0) {
            max = cb;
            if (get1bit(mp) != 0) {
              xr_value = -ispow[y] * v;
            } else {
              xr_value = ispow[y] * v;
            }
            part2remain--;
          } else {
            xr_value = 0.0f;
          }

          if (xrpnt <= xr_endptr) {
            xr[xrpnt++] = xr_value;
          } else {
            // BUFFER_OVERFLOW_BUG();
            if (!bobug) {
              bobug = true;
              bobug_sb = cb;
              bobug_l3 = l3;
            }
          }
        }
      } while (++i < 3);
      /* short (count1table) values */
      for (; l3 != 0 && (part2remain > 0); l3--) {
        final Jnewhuff htc[] = sHtc;
        final int h = gr_infos.count1table_select;
        final short[] table = htc[h].table;
        int val = 0; // table[ val ]
        short a;

        while ((a = table[val++]) < 0) {
          part2remain--;
          if (part2remain < 0) {
            part2remain++;
            a = 0;
            break;
          }
          if (get1bit(mp) != 0) {
            val -= a;
          }
        }
        i = 0;
        do {
          if (0 == (i & 1)) {
            if (0 == mc) {
              mc = m[moffset++];
              cb = m[moffset++];
              try {
                v =
                    gr_infos
                        .pow2gain_base[
                        gr_infos.pow2gain + ((scf[scfoffset++] + pretab[ipretab++]) << shift)];
              } catch (final ArrayIndexOutOfBoundsException ae) {
                v = gr_infos.pow2gain_base[gr_infos.pow2gain_base.length - 1];
                isbug = true;
              }
            }
            mc--;
          }
          if ((a & (0x8 >> i)) != 0) {
            max = cb;
            part2remain--;
            if (part2remain < 0) {
              part2remain++;
              break;
            }
            if (get1bit(mp) != 0) {
              xr_value = -v;
            } else {
              xr_value = v;
            }
          } else {
            xr_value = 0.0f;
          }

          if (xrpnt <= xr_endptr) {
            xr[xrpnt++] = xr_value;
          } else {
            // BUFFER_OVERFLOW_BUG();
            if (!bobug) {
              bobug = true;
              bobug_sb = cb;
              bobug_l3 = l3;
            }
          }
        } while (++i < 4);
      }

      /* zero part */
      // java: already zeroed at start of the function
      /* while( xrpnt <= xr_endptr ) {
      	xr[xrpnt++] = 0.0f;
      } */

      gr_infos.maxbandl = max + 1;
      gr_infos.maxb = longLimit[sfreq][gr_infos.maxbandl];
    }

    // #undef BUFFER_OVERFLOW_BUG
    if (bobug) {
      /* well, there was a bug report, where this happened!
        The problem was, that mixed blocks summed up to over 576,
         because of a wrong long/short switching index.
        It's likely, that the buffer overflow is fixed now, after correcting mixed block map.
      */
      System.err.printf(
          "hip: OOPS, part2remain=%d l3=%d cb=%d bv=%d region1=%d region2=%d b-type=%d mixed=%d\n",
          part2remain,
          bobug_l3,
          bobug_sb,
          gr_infos.big_values,
          gr_infos.region1start,
          gr_infos.region2start,
          gr_infos.block_type,
          gr_infos.mixed_block_flag);
    }
    if (isbug) {
      /* there is a bug report, where there is trouble with IS coded short block gain.
              Is intensity stereo coding implementation correct? Likely not.
      */
      int i_stereo = 0;
      if (mp.fr.mode == Jmpg123.MPG_MD_JOINT_STEREO) {
        i_stereo = mp.fr.mode_ext & 0x1;
      }
      System.err.printf(
          "hip: OOPS, 'gainpow2' buffer overflow  lsf=%d i-stereo=%d b-type=%d mixed=%d\n",
          mp.fr.lsf, i_stereo, gr_infos.block_type, gr_infos.mixed_block_flag);
    }

    while (part2remain > 16) {
      mp.getbits(16); /* Dismiss stuffing Bits */
      part2remain -= 16;
    }
    if (part2remain > 0) {
      mp.getbits(part2remain);
    } else if (part2remain < 0) {
      System.err.printf("hip: Can't rewind stream by %d bits!\n", -part2remain);
      return true; /* . error */
    }
    return false;
  }

  /* intensity position, transmitted via a scalefactor value, allowed range is 0 - 15 */
  private static final int scalefac_to_is_pos(final int sf) {
    if (0 <= sf && sf <= 15) {
      return sf;
    }
    return (sf < 0 ? 0 : 15);
  }

  /** III_stereo: calculate real channel values for Joint-I-Stereo-mode */
  private static final void III_i_stereo(
      final float xr_buf[][] /*[2][SBLIMIT][SSLIMIT]*/,
      final int[] scalefac,
      final Jgr_info gr_infos,
      final int sfreq,
      final boolean ms_stereo,
      final int lsf) {
    final float[] xr0 = xr_buf[0];
    final float[] xr1 = xr_buf[1];
    final JbandInfoStruct bi = bandInfo[sfreq];
    float[] tabl1, tabl2;

    if (lsf != 0) {
      final int p = gr_infos.scalefac_compress & 0x1;
      if (ms_stereo) {
        tabl1 = pow1_2[p];
        tabl2 = pow2_2[p];
      } else {
        tabl1 = pow1_1[p];
        tabl2 = pow2_1[p];
      }
    } else {
      if (ms_stereo) {
        tabl1 = tan1_2;
        tabl2 = tan2_2;
      } else {
        tabl1 = tan1_1;
        tabl2 = tan2_1;
      }
    }

    if (gr_infos.block_type == 2) {
      boolean do_l = (gr_infos.mixed_block_flag != 0);
      final short[] shortDiff = bi.shortDiff; // java
      final short[] shortIdx = bi.shortIdx; // java
      int lwin = 0;
      do {
        /* process each window */
        /* get first band with zero values */
        int sfb = gr_infos.maxband[lwin]; /* sfb is minimal 3 for mixed mode */
        if (sfb > 3) {
          do_l = false;
        }

        for (; sfb < 12; sfb++) {
          int is_p = scalefac[sfb * 3 + lwin - gr_infos.mixed_block_flag]; /* scale: 0-15 */
          is_p = scalefac_to_is_pos(is_p);
          if (is_p != 7) {
            int sb = shortDiff[sfb];
            int idx = shortIdx[sfb] + lwin;
            final float t1 = tabl1[is_p];
            final float t2 = tabl2[is_p];
            for (; sb > 0; sb--, idx += 3) {
              final float v = xr0[idx];
              xr0[idx] = v * t1;
              xr1[idx] = v * t2;
            }
          }
        }

        // #if 1
        // in the original: copy 10 to 11 , here: copy 11 to 12 maybe still wrong??? (copy 12 to
        // 13?)
        int is_p = scalefac[11 * 3 + lwin - gr_infos.mixed_block_flag]; // scale: 0-15
        int sb = shortDiff[12];
        int idx = shortIdx[12] + lwin;
        /* #else
        				is_p = scalefac[10 * 3 + lwin - gr_infos.mixed_block_flag]; // scale: 0-15
        				sb = bi.shortDiff[11];
        				idx = bi.shortIdx[11] + lwin;
        #endif */
        is_p = scalefac_to_is_pos(is_p);
        if (is_p != 7) {
          final float t1 = tabl1[is_p];
          final float t2 = tabl2[is_p];
          for (; sb > 0; sb--, idx += 3) {
            final float v = xr0[idx];
            xr0[idx] = v * t1;
            xr1[idx] = v * t2;
          }
        }
      } while (++lwin < 3); /* end for(lwin; .. ; . ) */

      if (do_l) {
        /* also check l-part, if ALL bands in the three windows are 'empty'
         * and mode = mixed_mode */
        int sfb = gr_infos.maxbandl;
        int idx = bi.longIdx[sfb];

        for (; sfb < 8; sfb++) {
          int sb = bi.longDiff[sfb];
          int is_p = scalefac[sfb]; /* scale: 0-15 */
          is_p = scalefac_to_is_pos(is_p);
          if (is_p != 7) {
            final float t1 = tabl1[is_p];
            final float t2 = tabl2[is_p];
            for (; sb > 0; sb--, idx++) {
              final float v = xr0[idx];
              xr0[idx] = v * t1;
              xr1[idx] = v * t2;
            }
          } else {
            idx += sb;
          }
        }
      }
      return;
    } // else {              /* ((gr_infos.block_type != 2)) */
    final short[] longDiff = bi.longDiff; // java
    int sfb = gr_infos.maxbandl;
    int idx = bi.longIdx[sfb];
    for (; sfb < 21; sfb++) {
      int sb = longDiff[sfb];
      int is_p = scalefac[sfb]; /* scale: 0-15 */
      is_p = scalefac_to_is_pos(is_p);
      if (is_p != 7) {
        final float t1 = tabl1[is_p];
        final float t2 = tabl2[is_p];
        for (; sb > 0; sb--, idx++) {
          final float v = xr0[idx];
          xr0[idx] = v * t1;
          xr1[idx] = v * t2;
        }
      } else {
        idx += sb;
      }
    }

    int is_p = scalefac[20]; /* copy l-band 20 to l-band 21 */
    is_p = scalefac_to_is_pos(is_p);
    idx = bi.longIdx[21];
    if (is_p != 7) {
      final float t1 = tabl1[is_p], t2 = tabl2[is_p];

      for (int sb = longDiff[21]; sb > 0; sb--, idx++) {
        final float v = xr0[idx];
        xr0[idx] = v * t1;
        xr1[idx] = v * t2;
      }
    }
    // }                   /* ... */
  }

  private static final void III_antialias(
      final float xr[] /*[SBLIMIT][SSLIMIT]*/, final Jgr_info gr_infos) {
    int sblim;
    if (gr_infos.block_type == 2) {
      if (0 == gr_infos.mixed_block_flag) {
        return;
      }
      sblim = 1;
    } else {
      sblim = gr_infos.maxb - 1;
    }

    /* 31 alias-reduction operations between each pair of sub-bands */
    /* with 8 butterflies between each pair                         */

    {
      int xr1 = Jmpg123.SSLIMIT; // xr[1];// FIXME why to declare as 2 dim array?
      final float[] cs = aa_cs, ca = aa_ca;
      for (int sb = sblim; sb != 0; sb--, xr1 += 10) {
        int csoffset = 0;
        int caoffset = 0;
        int xr2 = xr1; // xr1[ xr2 ]

        for (int ss = 7; ss >= 0; ss--) {
          /* upper and lower butterfly inputs */
          final float bu = xr[--xr2], bd = xr[xr1];
          xr[xr2] = (bu * cs[csoffset]) - (bd * ca[caoffset]);
          xr[xr1++] = (bd * cs[csoffset++]) + (bu * ca[caoffset++]);
        }
      }
    }
  }

  /*
   DCT insipired by Jeff Tsay's DCT from the maplay package
   this is an optimized version with manual unroll.

   References:
   [1] S. Winograd: "On Computing the Discrete Fourier Transform",
       Mathematics of Computation, Volume 32, Number 141, January 1978,
       Pages 175-199
  */
  private static void dct36(
      final float[] in,
      final int inoffset,
      final float[] out1,
      final int o1,
      final float[] out2,
      final int o2,
      final float[] wintab,
      final float[] ts,
      final int tsoffset) {
    {
      {
        int i = inoffset + 17;
        int j = i - 1;
        in[i] += in[j];
        in[--i] += in[--j];
        in[--i] += in[--j];
        in[--i] += in[--j];
        in[--i] += in[--j];
        in[--i] += in[--j];
        in[--i] += in[--j];
        in[--i] += in[--j];
        in[--i] += in[--j];
        in[--i] += in[--j];
        in[--i] += in[--j];
        in[--i] += in[--j];
        in[--i] += in[--j];
        in[--i] += in[--j];
        in[--i] += in[--j];
        in[--i] += in[--j];
        in[--i] += in[--j];
        i = inoffset + 17;
        j = i - 2;
        in[i] += in[j];
        i -= 4;
        in[j] += in[i];
        j -= 4;
        in[i] += in[j];
        i -= 4;
        in[j] += in[i];
        j -= 4;
        in[i] += in[j];
        i -= 4;
        in[j] += in[i];
        j -= 4;
        in[i] += in[j];
        i -= 4;
        in[j] += in[i];
      }

      {
        final float[] c = COS9;
        final float[] w = wintab;

        final float ta33 = in[inoffset + 2 * 3 + 0] * c[3];
        final float ta66 = in[inoffset + 2 * 6 + 0] * c[6];
        final float tb33 = in[inoffset + 2 * 3 + 1] * c[3];
        final float tb66 = in[inoffset + 2 * 6 + 1] * c[6];

        {
          final float tmp1a =
              in[inoffset + 2 * 1 + 0] * c[1]
                  + ta33
                  + in[inoffset + 2 * 5 + 0] * c[5]
                  + in[inoffset + 2 * 7 + 0] * c[7];
          final float tmp1b =
              in[inoffset + 2 * 1 + 1] * c[1]
                  + tb33
                  + in[inoffset + 2 * 5 + 1] * c[5]
                  + in[inoffset + 2 * 7 + 1] * c[7];
          final float tmp2a =
              in[inoffset + 2 * 0 + 0]
                  + in[inoffset + 2 * 2 + 0] * c[2]
                  + in[inoffset + 2 * 4 + 0] * c[4]
                  + ta66
                  + in[inoffset + 2 * 8 + 0] * c[8];
          final float tmp2b =
              in[inoffset + 2 * 0 + 1]
                  + in[inoffset + 2 * 2 + 1] * c[2]
                  + in[inoffset + 2 * 4 + 1] * c[4]
                  + tb66
                  + in[inoffset + 2 * 8 + 1] * c[8];

          // MACRO1(0);
          {
            float sum0 = tmp1a + tmp2a;
            final float sum1 = (tmp1b + tmp2b) * tfcos36[0];
            // MACRO0(v);
            {
              float tmp;
              out2[o2 + 9 + 0] = (tmp = sum0 + sum1) * w[27 + 0];
              out2[o2 + 8 - 0] = tmp * w[26 - 0];
            }
            sum0 -= sum1;
            ts[tsoffset + Jmpg123.SBLIMIT * (8 - 0)] = out1[o1 + 8 - 0] + sum0 * w[8 - 0];
            ts[tsoffset + Jmpg123.SBLIMIT * (9 + 0)] = out1[o1 + 9 + 0] + sum0 * w[9 + 0];
          }

          // MACRO2(8);
          {
            float sum0 = tmp2a - tmp1a;
            final float sum1 = (tmp2b - tmp1b) * tfcos36[8];
            // MACRO0(v);
            {
              float tmp;
              out2[o2 + 9 + 8] = (tmp = sum0 + sum1) * w[27 + 8];
              out2[o2 + 8 - 8] = tmp * w[26 - 8];
            }
            sum0 -= sum1;
            ts[tsoffset + Jmpg123.SBLIMIT * (8 - 8)] = out1[o1 + 8 - 8] + sum0 * w[8 - 8];
            ts[tsoffset + Jmpg123.SBLIMIT * (9 + 8)] = out1[o1 + 9 + 8] + sum0 * w[9 + 8];
          }
        }

        {
          final float tmp1a =
              (in[inoffset + 2 * 1 + 0] - in[inoffset + 2 * 5 + 0] - in[inoffset + 2 * 7 + 0])
                  * c[3];
          final float tmp1b =
              (in[inoffset + 2 * 1 + 1] - in[inoffset + 2 * 5 + 1] - in[inoffset + 2 * 7 + 1])
                  * c[3];
          final float tmp2a =
              (in[inoffset + 2 * 2 + 0] - in[inoffset + 2 * 4 + 0] - in[inoffset + 2 * 8 + 0])
                      * c[6]
                  - in[inoffset + 2 * 6 + 0]
                  + in[inoffset + 2 * 0 + 0];
          final float tmp2b =
              (in[inoffset + 2 * 2 + 1] - in[inoffset + 2 * 4 + 1] - in[inoffset + 2 * 8 + 1])
                      * c[6]
                  - in[inoffset + 2 * 6 + 1]
                  + in[inoffset + 2 * 0 + 1];

          // MACRO1(1);
          {
            float sum0 = tmp1a + tmp2a;
            final float sum1 = (tmp1b + tmp2b) * tfcos36[1];
            // MACRO0(v);
            {
              float tmp;
              out2[o2 + 9 + 1] = (tmp = sum0 + sum1) * w[27 + 1];
              out2[o2 + 8 - 1] = tmp * w[26 - 1];
            }
            sum0 -= sum1;
            ts[tsoffset + Jmpg123.SBLIMIT * (8 - 1)] = out1[o1 + 8 - 1] + sum0 * w[8 - 1];
            ts[tsoffset + Jmpg123.SBLIMIT * (9 + 1)] = out1[o1 + 9 + 1] + sum0 * w[9 + 1];
          }

          // MACRO2(7);
          {
            float sum0 = tmp2a - tmp1a;
            final float sum1 = (tmp2b - tmp1b) * tfcos36[7];
            // MACRO0(v);
            {
              float tmp;
              out2[o2 + 9 + 7] = (tmp = sum0 + sum1) * w[27 + 7];
              out2[o2 + 8 - 7] = tmp * w[26 - 7];
            }
            sum0 -= sum1;
            ts[tsoffset + Jmpg123.SBLIMIT * (8 - 7)] = out1[o1 + 8 - 7] + sum0 * w[8 - 7];
            ts[tsoffset + Jmpg123.SBLIMIT * (9 + 7)] = out1[o1 + 9 + 7] + sum0 * w[9 + 7];
          }
        }

        {
          final float tmp1a =
              in[inoffset + 2 * 1 + 0] * c[5]
                  - ta33
                  - in[inoffset + 2 * 5 + 0] * c[7]
                  + in[inoffset + 2 * 7 + 0] * c[1];
          final float tmp1b =
              in[inoffset + 2 * 1 + 1] * c[5]
                  - tb33
                  - in[inoffset + 2 * 5 + 1] * c[7]
                  + in[inoffset + 2 * 7 + 1] * c[1];
          final float tmp2a =
              in[inoffset + 2 * 0 + 0]
                  - in[inoffset + 2 * 2 + 0] * c[8]
                  - in[inoffset + 2 * 4 + 0] * c[2]
                  + ta66
                  + in[inoffset + 2 * 8 + 0] * c[4];
          final float tmp2b =
              in[inoffset + 2 * 0 + 1]
                  - in[inoffset + 2 * 2 + 1] * c[8]
                  - in[inoffset + 2 * 4 + 1] * c[2]
                  + tb66
                  + in[inoffset + 2 * 8 + 1] * c[4];

          // MACRO1(2);
          {
            float sum0 = tmp1a + tmp2a;
            final float sum1 = (tmp1b + tmp2b) * tfcos36[2];
            // MACRO0(v);
            {
              float tmp;
              out2[o2 + 9 + 2] = (tmp = sum0 + sum1) * w[27 + 2];
              out2[o2 + 8 - 2] = tmp * w[26 - 2];
            }
            sum0 -= sum1;
            ts[tsoffset + Jmpg123.SBLIMIT * (8 - 2)] = out1[o1 + 8 - 2] + sum0 * w[8 - 2];
            ts[tsoffset + Jmpg123.SBLIMIT * (9 + 2)] = out1[o1 + 9 + 2] + sum0 * w[9 + 2];
          }

          // MACRO2(6);
          {
            float sum0 = tmp2a - tmp1a;
            final float sum1 = (tmp2b - tmp1b) * tfcos36[6];
            // MACRO0(v);
            {
              float tmp;
              out2[o2 + 9 + 6] = (tmp = sum0 + sum1) * w[27 + 6];
              out2[o2 + 8 - 6] = tmp * w[26 - 6];
            }
            sum0 -= sum1;
            ts[tsoffset + Jmpg123.SBLIMIT * (8 - 6)] = out1[o1 + 8 - 6] + sum0 * w[8 - 6];
            ts[tsoffset + Jmpg123.SBLIMIT * (9 + 6)] = out1[o1 + 9 + 6] + sum0 * w[9 + 6];
          }
        }

        {
          final float tmp1a =
              in[inoffset + 2 * 1 + 0] * c[7]
                  - ta33
                  + in[inoffset + 2 * 5 + 0] * c[1]
                  - in[inoffset + 2 * 7 + 0] * c[5];
          final float tmp1b =
              in[inoffset + 2 * 1 + 1] * c[7]
                  - tb33
                  + in[inoffset + 2 * 5 + 1] * c[1]
                  - in[inoffset + 2 * 7 + 1] * c[5];
          final float tmp2a =
              in[inoffset + 2 * 0 + 0]
                  - in[inoffset + 2 * 2 + 0] * c[4]
                  + in[inoffset + 2 * 4 + 0] * c[8]
                  + ta66
                  - in[inoffset + 2 * 8 + 0] * c[2];
          final float tmp2b =
              in[inoffset + 2 * 0 + 1]
                  - in[inoffset + 2 * 2 + 1] * c[4]
                  + in[inoffset + 2 * 4 + 1] * c[8]
                  + tb66
                  - in[inoffset + 2 * 8 + 1] * c[2];

          // MACRO1(3);
          {
            float sum0 = tmp1a + tmp2a;
            final float sum1 = (tmp1b + tmp2b) * tfcos36[3];
            // MACRO0(v);
            {
              float tmp;
              out2[o2 + 9 + 3] = (tmp = sum0 + sum1) * w[27 + 3];
              out2[o2 + 8 - 3] = tmp * w[26 - 3];
            }
            sum0 -= sum1;
            ts[tsoffset + Jmpg123.SBLIMIT * (8 - 3)] = out1[o1 + 8 - 3] + sum0 * w[8 - 3];
            ts[tsoffset + Jmpg123.SBLIMIT * (9 + 3)] = out1[o1 + 9 + 3] + sum0 * w[9 + 3];
          }

          // MACRO2(5);
          {
            float sum0 = tmp2a - tmp1a;
            final float sum1 = (tmp2b - tmp1b) * tfcos36[5];
            // MACRO0(v);
            {
              float tmp;
              out2[o2 + 9 + 5] = (tmp = sum0 + sum1) * w[27 + 5];
              out2[o2 + 8 - 5] = tmp * w[26 - 5];
            }
            sum0 -= sum1;
            ts[tsoffset + Jmpg123.SBLIMIT * (8 - 5)] = out1[o1 + 8 - 5] + sum0 * w[8 - 5];
            ts[tsoffset + Jmpg123.SBLIMIT * (9 + 5)] = out1[o1 + 9 + 5] + sum0 * w[9 + 5];
          }
        }

        {
          float sum0 =
              in[inoffset + 2 * 0 + 0]
                  - in[inoffset + 2 * 2 + 0]
                  + in[inoffset + 2 * 4 + 0]
                  - in[inoffset + 2 * 6 + 0]
                  + in[inoffset + 2 * 8 + 0];
          final float sum1 =
              (in[inoffset + 2 * 0 + 1]
                      - in[inoffset + 2 * 2 + 1]
                      + in[inoffset + 2 * 4 + 1]
                      - in[inoffset + 2 * 6 + 1]
                      + in[inoffset + 2 * 8 + 1])
                  * tfcos36[4];
          // MACRO0(4);
          {
            float tmp;
            out2[o2 + 9 + 4] = (tmp = sum0 + sum1) * w[27 + 4];
            out2[o2 + 8 - 4] = tmp * w[26 - 4];
          }
          sum0 -= sum1;
          ts[tsoffset + Jmpg123.SBLIMIT * (8 - 4)] = out1[o1 + 8 - 4] + sum0 * w[8 - 4];
          ts[tsoffset + Jmpg123.SBLIMIT * (9 + 4)] = out1[o1 + 9 + 4] + sum0 * w[9 + 4];
        }
      }
    }
  }

  /** new DCT12 */
  private static final void dct12(
      final float[] in,
      int inoffset,
      final float[] rawout1,
      final int out1,
      final float[] rawout2,
      final int out2,
      final float[] wi,
      final float[] ts,
      final int tsoffset) {

    {
      float in0, in1, in2, in3, in4, in5;
      ts[tsoffset + Jmpg123.SBLIMIT * 0] = rawout1[out1 + 0];
      ts[tsoffset + Jmpg123.SBLIMIT * 1] = rawout1[out1 + 1];
      ts[tsoffset + Jmpg123.SBLIMIT * 2] = rawout1[out1 + 2];
      ts[tsoffset + Jmpg123.SBLIMIT * 3] = rawout1[out1 + 3];
      ts[tsoffset + Jmpg123.SBLIMIT * 4] = rawout1[out1 + 4];
      ts[tsoffset + Jmpg123.SBLIMIT * 5] = rawout1[out1 + 5];

      // DCT12_PART1
      in5 = in[inoffset + 5 * 3];
      in5 += (in4 = in[inoffset + 4 * 3]);
      in4 += (in3 = in[inoffset + 3 * 3]);
      in3 += (in2 = in[inoffset + 2 * 3]);
      in2 += (in1 = in[inoffset + 1 * 3]);
      in1 += (in0 = in[inoffset + 0 * 3]);

      in5 += in3;
      in3 += in1;

      in2 *= COS6_1;
      in3 *= COS6_1;

      {
        float tmp0, tmp1 = (in0 - in4);
        {
          final float tmp2 = (in1 - in5) * tfcos12[1];
          tmp0 = tmp1 + tmp2;
          tmp1 -= tmp2;
        }
        ts[tsoffset + (17 - 1) * Jmpg123.SBLIMIT] = rawout1[out1 + 17 - 1] + tmp0 * wi[11 - 1];
        ts[tsoffset + (12 + 1) * Jmpg123.SBLIMIT] = rawout1[out1 + 12 + 1] + tmp0 * wi[6 + 1];
        ts[tsoffset + (6 + 1) * Jmpg123.SBLIMIT] = rawout1[out1 + 6 + 1] + tmp1 * wi[1];
        ts[tsoffset + (11 - 1) * Jmpg123.SBLIMIT] = rawout1[out1 + 11 - 1] + tmp1 * wi[5 - 1];
      }

      // DCT12_PART2
      in0 += in4 * COS6_2;

      in4 = in0 + in2;
      in0 -= in2;

      in1 += in5 * COS6_2;

      in5 = (in1 + in3) * tfcos12[0];
      in1 = (in1 - in3) * tfcos12[2];

      in3 = in4 + in5;
      in4 -= in5;

      in2 = in0 + in1;
      in0 -= in1;

      ts[tsoffset + (17 - 0) * Jmpg123.SBLIMIT] = rawout1[out1 + 17 - 0] + in2 * wi[11 - 0];
      ts[tsoffset + (12 + 0) * Jmpg123.SBLIMIT] = rawout1[out1 + 12 + 0] + in2 * wi[6 + 0];
      ts[tsoffset + (12 + 2) * Jmpg123.SBLIMIT] = rawout1[out1 + 12 + 2] + in3 * wi[6 + 2];
      ts[tsoffset + (17 - 2) * Jmpg123.SBLIMIT] = rawout1[out1 + 17 - 2] + in3 * wi[11 - 2];

      ts[tsoffset + (6 + 0) * Jmpg123.SBLIMIT] = rawout1[out1 + 6 + 0] + in0 * wi[0];
      ts[tsoffset + (11 - 0) * Jmpg123.SBLIMIT] = rawout1[out1 + 11 - 0] + in0 * wi[5 - 0];
      ts[tsoffset + (6 + 2) * Jmpg123.SBLIMIT] = rawout1[out1 + 6 + 2] + in4 * wi[2];
      ts[tsoffset + (11 - 2) * Jmpg123.SBLIMIT] = rawout1[out1 + 11 - 2] + in4 * wi[5 - 2];
    }

    inoffset++;

    {
      float in0, in1, in2, in3, in4, in5;

      // DCT12_PART1
      in5 = in[inoffset + 5 * 3];
      in5 += (in4 = in[inoffset + 4 * 3]);
      in4 += (in3 = in[inoffset + 3 * 3]);
      in3 += (in2 = in[inoffset + 2 * 3]);
      in2 += (in1 = in[inoffset + 1 * 3]);
      in1 += (in0 = in[inoffset + 0 * 3]);

      in5 += in3;
      in3 += in1;

      in2 *= COS6_1;
      in3 *= COS6_1;

      {
        float tmp0, tmp1 = (in0 - in4);
        {
          final float tmp2 = (in1 - in5) * tfcos12[1];
          tmp0 = tmp1 + tmp2;
          tmp1 -= tmp2;
        }
        rawout2[out2 + 5 - 1] = tmp0 * wi[11 - 1];
        rawout2[out2 + 0 + 1] = tmp0 * wi[6 + 1];
        ts[tsoffset + (12 + 1) * Jmpg123.SBLIMIT] += tmp1 * wi[1];
        ts[tsoffset + (17 - 1) * Jmpg123.SBLIMIT] += tmp1 * wi[5 - 1];
      }

      // DCT12_PART2
      in0 += in4 * COS6_2;

      in4 = in0 + in2;
      in0 -= in2;

      in1 += in5 * COS6_2;

      in5 = (in1 + in3) * tfcos12[0];
      in1 = (in1 - in3) * tfcos12[2];

      in3 = in4 + in5;
      in4 -= in5;

      in2 = in0 + in1;
      in0 -= in1;

      rawout2[out2 + 5 - 0] = in2 * wi[11 - 0];
      rawout2[out2 + 0 + 0] = in2 * wi[6 + 0];
      rawout2[out2 + 0 + 2] = in3 * wi[6 + 2];
      rawout2[out2 + 5 - 2] = in3 * wi[11 - 2];

      ts[tsoffset + (12 + 0) * Jmpg123.SBLIMIT] += in0 * wi[0];
      ts[tsoffset + (17 - 0) * Jmpg123.SBLIMIT] += in0 * wi[5 - 0];
      ts[tsoffset + (12 + 2) * Jmpg123.SBLIMIT] += in4 * wi[2];
      ts[tsoffset + (17 - 2) * Jmpg123.SBLIMIT] += in4 * wi[5 - 2];
    }

    inoffset++;

    {
      float in0, in1, in2, in3, in4, in5;
      rawout2[out2 + 12] =
          rawout2[out2 + 13] =
              rawout2[out2 + 14] =
                  rawout2[out2 + 15] = rawout2[out2 + 16] = rawout2[out2 + 17] = 0.0f;

      // DCT12_PART1
      in5 = in[inoffset + 5 * 3];
      in5 += (in4 = in[inoffset + 4 * 3]);
      in4 += (in3 = in[inoffset + 3 * 3]);
      in3 += (in2 = in[inoffset + 2 * 3]);
      in2 += (in1 = in[inoffset + 1 * 3]);
      in1 += (in0 = in[inoffset + 0 * 3]);

      in5 += in3;
      in3 += in1;

      in2 *= COS6_1;
      in3 *= COS6_1;

      {
        float tmp0, tmp1 = (in0 - in4);
        {
          final float tmp2 = (in1 - in5) * tfcos12[1];
          tmp0 = tmp1 + tmp2;
          tmp1 -= tmp2;
        }
        rawout2[out2 + 11 - 1] = tmp0 * wi[11 - 1];
        rawout2[out2 + 6 + 1] = tmp0 * wi[6 + 1];
        rawout2[out2 + 0 + 1] += tmp1 * wi[1];
        rawout2[out2 + 5 - 1] += tmp1 * wi[5 - 1];
      }

      // DCT12_PART2
      in0 += in4 * COS6_2;

      in4 = in0 + in2;
      in0 -= in2;

      in1 += in5 * COS6_2;

      in5 = (in1 + in3) * tfcos12[0];
      in1 = (in1 - in3) * tfcos12[2];

      in3 = in4 + in5;
      in4 -= in5;

      in2 = in0 + in1;
      in0 -= in1;

      rawout2[out2 + 11 - 0] = in2 * wi[11 - 0];
      rawout2[out2 + 6 + 0] = in2 * wi[6 + 0];
      rawout2[out2 + 6 + 2] = in3 * wi[6 + 2];
      rawout2[out2 + 11 - 2] = in3 * wi[11 - 2];

      rawout2[out2 + 0 + 0] += in0 * wi[0];
      rawout2[out2 + 5 - 0] += in0 * wi[5 - 0];
      rawout2[out2 + 0 + 2] += in4 * wi[2];
      rawout2[out2 + 5 - 2] += in4 * wi[5 - 2];
    }
  }

  /** III_hybrid */
  private static final void III_hybrid(
      final Jmpstr_tag mp,
      final float fsIn[] /*[SBLIMIT][SSLIMIT]*/,
      final float tsOut[] /*[SSLIMIT][SBLIMIT]*/,
      final int ch,
      final Jgr_info gr_infos) {
    int tspnt = 0; // tsOut[ tspnt ]
    final int[] blc = mp.hybrid_blc;
    int sb = 0;

    int b = blc[ch];
    final float[] block1 = mp.hybrid_block[b][ch];
    int rawout1 = 0; // block[ rawout1 ]
    b = -b + 1;
    final float[] block2 = mp.hybrid_block[b][ch];
    int rawout2 = 0; // block[ rawout2 ]
    blc[ch] = b;

    if (gr_infos.mixed_block_flag != 0) {
      sb = 2 * Jmpg123.SSLIMIT;
      dct36(fsIn, 0, block1, rawout1, block2, rawout2, win[0], tsOut, tspnt++);
      rawout1 += 18;
      rawout2 += 18;
      dct36(fsIn, Jmpg123.SSLIMIT, block1, rawout1, block2, rawout2, win1[0], tsOut, tspnt++);
      rawout1 += 18;
      rawout2 += 18;
    }

    final int bt = gr_infos.block_type;
    if (bt == 2) {
      for (final int maxb = gr_infos.maxb * Jmpg123.SSLIMIT; sb < maxb; ) {
        dct12(fsIn, sb, block1, rawout1, block2, rawout2, win[2], tsOut, tspnt++);
        sb += Jmpg123.SSLIMIT;
        rawout1 += 18;
        rawout2 += 18;
        dct12(fsIn, sb, block1, rawout1, block2, rawout2, win1[2], tsOut, tspnt++);
        sb += Jmpg123.SSLIMIT;
        rawout1 += 18;
        rawout2 += 18;
      }
    } else {
      for (final int maxb = gr_infos.maxb * Jmpg123.SSLIMIT; sb < maxb; ) {
        dct36(fsIn, sb, block1, rawout1, block2, rawout2, win[bt], tsOut, tspnt++);
        sb += Jmpg123.SSLIMIT;
        rawout1 += 18;
        rawout2 += 18;
        dct36(fsIn, sb, block1, rawout1, block2, rawout2, win1[bt], tsOut, tspnt++);
        sb += Jmpg123.SSLIMIT;
        rawout1 += 18;
        rawout2 += 18;
      }
    }
    for (; tspnt < Jmpg123.SBLIMIT; tspnt++) {
      for (int i = tspnt, ie = tspnt + Jmpg123.SSLIMIT * Jmpg123.SBLIMIT;
          i < ie;
          i += Jmpg123.SBLIMIT) {
        tsOut[i] = block1[rawout1++];
        block2[rawout2++] = 0.0f;
      }
    }
  }

  /** main layer3 handler */
  static final int layer3_audiodata_precedesframes(final Jmpstr_tag mp) {
    /* specific to Layer 3, since Layer 1 & 2 the audio data starts at the frame that describes it. */
    /* determine how many bytes and therefore bitstream frames the audio data precedes it's matching frame */
    /* lame_report_fnc(mp.report_err, "hip: main_data_begin = %d, mp.bsize %d, mp.fsizeold %d, mp.ssize %d\n",
    sideinfo.main_data_begin, mp.bsize, mp.fsizeold, mp.ssize); */
    /* compute the number of frames to backtrack, 4 for the header, ssize already holds the CRC */
    /* TODO Erroneously assumes current frame is same as previous frame. */
    final int audioDataInFrame = mp.bsize - 4 - mp.ssize;
    final int framesToBacktrack =
        (mp.sideinfo.main_data_begin + audioDataInFrame - 1) / audioDataInFrame;
    /* lame_report_fnc(mp.report_err, "hip: audioDataInFrame %d framesToBacktrack %d\n", audioDataInFrame, framesToBacktrack); */
    return framesToBacktrack;
  }

  static final int decode_layer3_sideinfo(final Jmpstr_tag mp) {
    final Jframe frame = mp.fr;
    final int stereo = frame.stereo;
    int single = frame.single;

    if (stereo == 1) {
      /* stream is mono */
      single = 0;
    }

    boolean ms_stereo;
    if (frame.mode == Jmpg123.MPG_MD_JOINT_STEREO) {
      ms_stereo = (frame.mode_ext & 0x2) != 0;
    } else {
      ms_stereo = false;
    }

    int granules;
    if (frame.lsf != 0) {
      granules = 1;
      III_get_side_info_2(mp, stereo, ms_stereo, frame.sampling_frequency, single);
    } else {
      granules = 2;
      III_get_side_info_1(mp, stereo, ms_stereo, frame.sampling_frequency, single);
    }

    int databits = 0;
    final Jch[] chs = mp.sideinfo.ch; // java
    for (int gr = 0; gr < granules; ++gr) {
      for (int ch = 0; ch < stereo; ++ch) {
        final Jgr_info gr_infos = chs[ch].gr[gr];
        databits += gr_infos.part2_3_length;
      }
    }
    return databits - (mp.sideinfo.main_data_begin << 3);
  }

  static final int decode_layer3_frame(
      final Jmpstr_tag mp, final Object pcm_sample, final int[] pcm_point, final Isynth synth) {
    if (mp.set_pointer(mp.sideinfo.main_data_begin) == Jmpg123.MP3_ERR) {
      return 0;
    }

    int clip = 0;
    final int scalefacs[][] =
        new int[2][39]; /* max 39 for short[13][3] mode, mixed: 38, long: 22 */
    /*  struct III_sideinfo sideinfo; */
    final Jframe frame = mp.fr;
    final int stereo = frame.stereo;
    int single = frame.single;
    final int sfreq = frame.sampling_frequency;
    final float hybridIn[][] =
        new float[2]
            [Jmpg123.SBLIMIT * Jmpg123.SSLIMIT]; // FIXME why 3-dim hybridIn[2][SBLIMIT][SSLIMIT];?
    final float[] hybridIn0 = hybridIn[0], hybridIn1 = hybridIn[1]; // java
    final float hybridOut[][] =
        new float[2]
            [Jmpg123.SSLIMIT * Jmpg123.SBLIMIT]; // FIXME why 3-dim hybridOut[2][SSLIMIT][SBLIMIT];?
    final float[] hybridOut0 = hybridOut[0], hybridOut1 = hybridOut[1]; // java
    int stereo1;
    if (stereo == 1) {
      /* stream is mono */
      stereo1 = 1;
      single = 0;
    } else if (single >= 0) {
      stereo1 = 1;
    } else {
      stereo1 = 2;
    }

    boolean ms_stereo, i_stereo;
    if (frame.mode == Jmpg123.MPG_MD_JOINT_STEREO) {
      ms_stereo = (frame.mode_ext & 0x2) != 0;
      i_stereo = (frame.mode_ext & 0x1) != 0;
    } else {
      ms_stereo = i_stereo = false;
    }

    final int granules = (frame.lsf != 0) ? 1 : 2;

    final Jch[] chs = mp.sideinfo.ch; // java
    final int p1[] = new int[1]; // TODO java: find a better way
    int gr = 0;
    do {
      {
        final Jgr_info gr_infos = chs[0].gr[gr];
        int part2bits;

        if (frame.lsf != 0) {
          part2bits = III_get_scale_factors_2(mp, scalefacs[0], gr_infos, false);
        } else {
          part2bits = III_get_scale_factors_1(mp, scalefacs[0], gr_infos);
        }

        /* lame_report_fnc(mp.report_err, "calling III dequantize sample 1 gr_infos.part2_3_length %d\n", gr_infos.part2_3_length); */
        if (III_dequantize_sample(mp, hybridIn0, scalefacs[0], gr_infos, sfreq, part2bits)) {
          return clip;
        }
      }
      if (stereo == 2) {
        final Jgr_info gr_infos = chs[1].gr[gr];
        int part2bits;
        if (frame.lsf != 0) {
          part2bits = III_get_scale_factors_2(mp, scalefacs[1], gr_infos, i_stereo);
        } else {
          part2bits = III_get_scale_factors_1(mp, scalefacs[1], gr_infos);
        }

        /* lame_report_fnc(mp.report_err, "calling III dequantize sample 2  gr_infos.part2_3_length %d\n", gr_infos.part2_3_length); */
        if (III_dequantize_sample(mp, hybridIn1, scalefacs[1], gr_infos, sfreq, part2bits)) {
          return clip;
        }

        if (ms_stereo) {
          for (int i = 0; i < Jmpg123.SBLIMIT * Jmpg123.SSLIMIT; i++) {
            final float tmp0 = hybridIn0[i];
            final float tmp1 = hybridIn1[i];
            hybridIn1[i] = tmp0 - tmp1;
            hybridIn0[i] = tmp0 + tmp1;
          }
        }

        if (i_stereo) {
          III_i_stereo(hybridIn, scalefacs[1], gr_infos, sfreq, ms_stereo, frame.lsf);
        }

        if (ms_stereo || i_stereo || (single == 3)) {
          if (gr_infos.maxb > chs[0].gr[gr].maxb) {
            chs[0].gr[gr].maxb = gr_infos.maxb;
          } else {
            gr_infos.maxb = chs[0].gr[gr].maxb;
          }
        }

        switch (single) {
          case 3:
            {
              for (int inoffset0 = 0, inoffset1 = 0, ie = Jmpg123.SSLIMIT * gr_infos.maxb;
                  inoffset0 < ie;
                  inoffset0++) {
                hybridIn0[inoffset0] =
                    (hybridIn0[inoffset0] + hybridIn1[inoffset1++]); /* *0.5 done by pow-scale */
              }
              break;
            }
          case 1:
            {
              for (int inoffset0 = 0, inoffset1 = 0, ie = Jmpg123.SSLIMIT * gr_infos.maxb;
                  inoffset0 < ie; ) {
                hybridIn0[inoffset0++] = hybridIn1[inoffset1++];
              }
              break;
            }
        }
      }

      for (int ch = 0; ch < stereo1; ch++) {
        final Jgr_info gr_infos = chs[ch].gr[gr];
        III_antialias(hybridIn[ch], gr_infos);
        III_hybrid(mp, hybridIn[ch], hybridOut[ch], ch, gr_infos);
      }
      int ss = 0;
      do {
        if (single >= 0) {
          clip += synth.synth_1to1_mono(mp, hybridOut0, ss, pcm_sample, pcm_point);
        } else {
          p1[0] = pcm_point[0];
          clip += synth.synth_1to1(mp, hybridOut0, ss, 0, pcm_sample, p1);
          clip += synth.synth_1to1(mp, hybridOut1, ss, 1, pcm_sample, pcm_point);
        }
        ss += Jmpg123.SBLIMIT;
      } while (ss < Jmpg123.SSLIMIT * Jmpg123.SBLIMIT);
    } while (++gr < granules);

    return clip;
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy