context: // /***************************************************************************
  //  * LayerIIIDecoder.cs
  //  * Copyright (c) 2015, 2021 The Authors.
  //  * 
  //  * All rights reserved. This program and the accompanying materials
  //  * are made available under the terms of the GNU Lesser General Public License
  //  * (LGPL) version 3 which accompanies this distribution, and is available at
  //  * https://www.gnu.org/licenses/lgpl-3.0.en.html
  //  *
  //  * 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
  //  * Lesser General Public License for more details.
  //  *
  //  ***************************************************************************/
  
  using System;
  using MP3Sharp.Decoding.Decoders.LayerIII;
  using MP3Sharp.Support;
  
  namespace MP3Sharp.Decoding.Decoders {
      /// <summary>
      /// Implements decoding of MPEG Audio Layer 3 frames.
      /// </summary>
      internal sealed class LayerIIIDecoder : IFrameDecoder {
          private const int SSLIMIT = 18;
          private const int SBLIMIT = 32;
  
          private static readonly int[][] Slen = {
              new[] {0, 0, 0, 0, 3, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4},
              new[] {0, 1, 2, 3, 0, 1, 2, 3, 1, 2, 3, 1, 2, 3, 2, 3}
          };
  
          internal static readonly int[] Pretab = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 3, 3, 3, 2, 0};
  
          internal static readonly float[] TwoToNegativeHalfPow = {
              1.0000000000e+00f, 7.0710678119e-01f, 5.0000000000e-01f, 3.5355339059e-01f, 2.5000000000e-01f,
              1.7677669530e-01f, 1.2500000000e-01f, 8.8388347648e-02f, 6.2500000000e-02f, 4.4194173824e-02f,
              3.1250000000e-02f, 2.2097086912e-02f, 1.5625000000e-02f, 1.1048543456e-02f, 7.8125000000e-03f,
              5.5242717280e-03f, 3.9062500000e-03f, 2.7621358640e-03f, 1.9531250000e-03f, 1.3810679320e-03f,
              9.7656250000e-04f, 6.9053396600e-04f, 4.8828125000e-04f, 3.4526698300e-04f, 2.4414062500e-04f,
              1.7263349150e-04f, 1.2207031250e-04f, 8.6316745750e-05f, 6.1035156250e-05f, 4.3158372875e-05f,
              3.0517578125e-05f, 2.1579186438e-05f, 1.5258789062e-05f, 1.0789593219e-05f, 7.6293945312e-06f,
              5.3947966094e-06f, 3.8146972656e-06f, 2.6973983047e-06f, 1.9073486328e-06f, 1.3486991523e-06f,
              9.5367431641e-07f, 6.7434957617e-07f, 4.7683715820e-07f, 3.3717478809e-07f, 2.3841857910e-07f,
              1.6858739404e-07f, 1.1920928955e-07f, 8.4293697022e-08f, 5.9604644775e-08f, 4.2146848511e-08f,
              2.9802322388e-08f, 2.1073424255e-08f, 1.4901161194e-08f, 1.0536712128e-08f, 7.4505805969e-09f,
              5.2683560639e-09f, 3.7252902985e-09f, 2.6341780319e-09f, 1.8626451492e-09f, 1.3170890160e-09f,
              9.3132257462e-10f, 6.5854450798e-10f, 4.6566128731e-10f, 3.2927225399e-10f
          };
  
          internal static readonly float[] PowerTable;
  
          internal static readonly float[][] Io = {
              new[] {
                  1.0000000000e+00f, 8.4089641526e-01f, 7.0710678119e-01f, 5.9460355751e-01f, 5.0000000001e-01f,
                  4.2044820763e-01f, 3.5355339060e-01f, 2.9730177876e-01f, 2.5000000001e-01f, 2.1022410382e-01f,
                  1.7677669530e-01f, 1.4865088938e-01f, 1.2500000000e-01f, 1.0511205191e-01f, 8.8388347652e-02f,
                  7.4325444691e-02f, 6.2500000003e-02f, 5.2556025956e-02f, 4.4194173826e-02f, 3.7162722346e-02f,
                  3.1250000002e-02f, 2.6278012978e-02f, 2.2097086913e-02f, 1.8581361173e-02f, 1.5625000001e-02f,
                  1.3139006489e-02f, 1.1048543457e-02f, 9.2906805866e-03f, 7.8125000006e-03f, 6.5695032447e-03f,
                  5.5242717285e-03f, 4.6453402934e-03f
              },
              new[] {
                  1.0000000000e+00f, 7.0710678119e-01f, 5.0000000000e-01f, 3.5355339060e-01f, 2.5000000000e-01f,
                  1.7677669530e-01f, 1.2500000000e-01f, 8.8388347650e-02f, 6.2500000001e-02f, 4.4194173825e-02f,
                  3.1250000001e-02f, 2.2097086913e-02f, 1.5625000000e-02f, 1.1048543456e-02f, 7.8125000002e-03f,
                  5.5242717282e-03f, 3.9062500001e-03f, 2.7621358641e-03f, 1.9531250001e-03f, 1.3810679321e-03f,
                  9.7656250004e-04f, 6.9053396603e-04f, 4.8828125002e-04f, 3.4526698302e-04f, 2.4414062501e-04f,
                  1.7263349151e-04f, 1.2207031251e-04f, 8.6316745755e-05f, 6.1035156254e-05f, 4.3158372878e-05f,
                  3.0517578127e-05f, 2.1579186439e-05f
              }
          };
  
          internal static readonly float[] Tan12 = {
              0.0f, 0.26794919f, 0.57735027f, 1.0f, 1.73205081f, 3.73205081f, 9.9999999e10f, -3.73205081f, -1.73205081f,
              -1.0f, -0.57735027f, -0.26794919f, 0.0f, 0.26794919f, 0.57735027f, 1.0f
          };
  
          private static int[][] _reorderTable; // Generated on demand
  
          private static readonly float[] Cs = {
              0.857492925712f, 0.881741997318f, 0.949628649103f, 0.983314592492f, 0.995517816065f, 0.999160558175f,
              0.999899195243f, 0.999993155067f
          };
  
          private static readonly float[] Ca = {
              -0.5144957554270f, -0.4717319685650f, -0.3133774542040f, -0.1819131996110f, -0.0945741925262f,
              -0.0409655828852f, -0.0141985685725f, -0.00369997467375f
          };
  
          internal static readonly float[][] Win = {
              new[] {
                  -1.6141214951e-02f, -5.3603178919e-02f, -1.0070713296e-01f, -1.6280817573e-01f, -4.9999999679e-01f,
                  -3.8388735032e-01f, -6.2061144372e-01f, -1.1659756083e+00f, -3.8720752656e+00f, -4.2256286556e+00f,
                  -1.5195289984e+00f, -9.7416483388e-01f, -7.3744074053e-01f, -1.2071067773e+00f, -5.1636156596e-01f,
                  -4.5426052317e-01f, -4.0715656898e-01f, -3.6969460527e-01f, -3.3876269197e-01f, -3.1242222492e-01f,
                  -2.8939587111e-01f, -2.6880081906e-01f, -5.0000000266e-01f, -2.3251417468e-01f, -2.1596714708e-01f,
                  -2.0004979098e-01f, -1.8449493497e-01f, -1.6905846094e-01f, -1.5350360518e-01f, -1.3758624925e-01f,
                  -1.2103922149e-01f, -2.0710679058e-01f, -8.4752577594e-02f, -6.4157525656e-02f, -4.1131172614e-02f,
                  -1.4790705759e-02f
              },
              new[] {
                  -1.6141214951e-02f, -5.3603178919e-02f, -1.0070713296e-01f, -1.6280817573e-01f, -4.9999999679e-01f,
                  -3.8388735032e-01f, -6.2061144372e-01f, -1.1659756083e+00f, -3.8720752656e+00f, -4.2256286556e+00f,
                  -1.5195289984e+00f, -9.7416483388e-01f, -7.3744074053e-01f, -1.2071067773e+00f, -5.1636156596e-01f,
                  -4.5426052317e-01f, -4.0715656898e-01f, -3.6969460527e-01f, -3.3908542600e-01f, -3.1511810350e-01f,
                  -2.9642226150e-01f, -2.8184548650e-01f, -5.4119610000e-01f, -2.6213228100e-01f, -2.5387916537e-01f,
                  -2.3296291359e-01f, -1.9852728987e-01f, -1.5233534808e-01f, -9.6496400054e-02f, -3.3423828516e-02f,
                  0.0000000000e+00f, 0.0000000000e+00f, 0.0000000000e+00f, 0.0000000000e+00f, 0.0000000000e+00f,
                  0.0000000000e+00f
              },
              new[] {
                  -4.8300800645e-02f, -1.5715656932e-01f, -2.8325045177e-01f, -4.2953747763e-01f, -1.2071067795e+00f,
                  -8.2426483178e-01f, -1.1451749106e+00f, -1.7695290101e+00f, -4.5470225061e+00f, -3.4890531002e+00f,
                  -7.3296292804e-01f, -1.5076514758e-01f, 0.0000000000e+00f, 0.0000000000e+00f, 0.0000000000e+00f,
                  0.0000000000e+00f, 0.0000000000e+00f, 0.0000000000e+00f, 0.0000000000e+00f, 0.0000000000e+00f,
                  0.0000000000e+00f, 0.0000000000e+00f, 0.0000000000e+00f, 0.0000000000e+00f, 0.0000000000e+00f,
                  0.0000000000e+00f, 0.0000000000e+00f, 0.0000000000e+00f, 0.0000000000e+00f, 0.0000000000e+00f,
                  0.0000000000e+00f, 0.0000000000e+00f, 0.0000000000e+00f, 0.0000000000e+00f, 0.0000000000e+00f,
                  0.0000000000e+00f
              },
              new[] {
                  0.0000000000e+00f, 0.0000000000e+00f, 0.0000000000e+00f, 0.0000000000e+00f, 0.0000000000e+00f,
                  0.0000000000e+00f, -1.5076513660e-01f, -7.3296291107e-01f, -3.4890530566e+00f, -4.5470224727e+00f,
                  -1.7695290031e+00f, -1.1451749092e+00f, -8.3137738100e-01f, -1.3065629650e+00f, -5.4142014250e-01f,
                  -4.6528974900e-01f, -4.1066990750e-01f, -3.7004680800e-01f, -3.3876269197e-01f, -3.1242222492e-01f,
                  -2.8939587111e-01f, -2.6880081906e-01f, -5.0000000266e-01f, -2.3251417468e-01f, -2.1596714708e-01f,
                  -2.0004979098e-01f,
                  -1.8449493497e-01f, -1.6905846094e-01f, -1.5350360518e-01f, -1.3758624925e-01f, -1.2103922149e-01f,
                  -2.0710679058e-01f, -8.4752577594e-02f, -6.4157525656e-02f, -4.1131172614e-02f, -1.4790705759e-02f
              }
          };
  
          internal static readonly int[][][] NrOfSfbBlock = {
              new[] {new[] {6, 5, 5, 5}, new[] {9, 9, 9, 9}, new[] {6, 9, 9, 9}},
              new[] {new[] {6, 5, 7, 3}, new[] {9, 9, 12, 6}, new[] {6, 9, 12, 6}},
              new[] {new[] {11, 10, 0, 0}, new[] {18, 18, 0, 0}, new[] {15, 18, 0, 0}},
              new[] {new[] {7, 7, 7, 0}, new[] {12, 12, 12, 0}, new[] {6, 15, 12, 0}},
              new[] {new[] {6, 6, 6, 3}, new[] {12, 9, 9, 6}, new[] {6, 12, 9, 6}},
              new[] {new[] {8, 8, 5, 0}, new[] {15, 12, 9, 0}, new[] {6, 18, 9, 0}}
          };
  
          private readonly ABuffer _Buffer;
          private readonly int _Channels;
          private readonly SynthesisFilter _Filter1;
          private readonly SynthesisFilter _Filter2;
          private readonly int _FirstChannel;
          private readonly Header _Header;
          private readonly int[] _Is1D;
          private readonly float[][] _K;
          private readonly int _LastChannel;
          private readonly float[][][] _Lr;
  
          private readonly int _MaxGr;
          private readonly int[] _Nonzero;
          private readonly float[] _Out1D;
          private readonly float[][] _Prevblck;
          private readonly float[][][] _Ro;
          private readonly ScaleFactorData[] _Scalefac;
          private readonly SBI[] _SfBandIndex; // Init in the ctor.
          private readonly int _Sfreq;
          private readonly Layer3SideInfo _SideInfo;
          private readonly Bitstream _Stream;
          private readonly int _WhichChannels;
          private BitReserve _BitReserve;
  
          private int _CheckSumHuff;
          private int _FrameStart;
  
          internal int[] IsPos;
  
          internal float[] IsRatio;
  
          // MDM: new_slen is fully initialized before use, no need
          // to reallocate array.
          private int[] _NewSlen;
  
          private int _Part2Start;
          internal float[] Rawout;
  
          // subband samples are buffered and passed to the
          // SynthesisFilter in one go.
          private float[] _Samples1;
  
          private float[] _Samples2;
          internal int[] ScalefacBuffer;
          internal ScaleFactorTable Sftable;
  
          // MDM: tsOutCopy and rawout do not need initializing, so the arrays
          // can be reused.
          internal float[] TsOutCopy;
  
          internal int[] V = {0};
          internal int[] W = {0};
          internal int[] X = {0};
          internal int[] Y = {0};
  
          static LayerIIIDecoder() {
              PowerTable = CreatePowerTable();
          }
  
          /// <summary>
          /// REVIEW: these ctor arguments should be moved to the decodeFrame() method.
          /// </summary>
          internal LayerIIIDecoder(Bitstream stream, Header header, SynthesisFilter filtera, SynthesisFilter filterb, ABuffer buffer, int whichCh) {
              Huffman.Initialize();
  
              InitBlock();
              _Is1D = new int[SBLIMIT * SSLIMIT + 4];
              _Ro = new float[2][][];
              for (int i = 0; i < 2; i++) {
                  _Ro[i] = new float[SBLIMIT][];
                  for (int i2 = 0; i2 < SBLIMIT; i2++) {
                      _Ro[i][i2] = new float[SSLIMIT];
                  }
              }
              _Lr = new float[2][][];
              for (int i3 = 0; i3 < 2; i3++) {
                  _Lr[i3] = new float[SBLIMIT][];
                  for (int i4 = 0; i4 < SBLIMIT; i4++) {
                      _Lr[i3][i4] = new float[SSLIMIT];
                  }
              }
              _Out1D = new float[SBLIMIT * SSLIMIT];
              _Prevblck = new float[2][];
              for (int i5 = 0; i5 < 2; i5++) {
                  _Prevblck[i5] = new float[SBLIMIT * SSLIMIT];
              }
  
gt:             _K = new float[2][];