Files
ichni_Creator_Studio/Assets/NLayer/Decoder/LayerIIIDecoder.cs
2025-07-12 18:27:10 +08:00

1951 lines
86 KiB
C#

/*
* NLayer - A C# MPEG1/2/2.5 audio decoder
*
* Portions of this file are courtesy Fluendo, S.A. They are dual licensed as Ms-PL
* and under the following license:
*
* Copyright <2005-2012> Fluendo S.A.
*
* Unless otherwise indicated, Source Code is licensed under MIT license.
* See further explanation attached in License Statement (distributed in the file
* LICENSE).
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is furnished to do
* so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
*/
using System;
using System.Collections.Generic;
namespace NLayer.Decoder
{
/// <summary>
/// Class Implementing Layer 3 Decoder.
/// </summary>
sealed class LayerIIIDecoder : LayerDecoderBase
{
const int SSLIMIT = 18;
#region Child Classes
// This class is based on the Fluendo hybrid logic.
class HybridMDCT
{
const float PI = (float)Math.PI;
static float[][] _swin;
static HybridMDCT()
{
_swin = new float[][] { new float[36], new float[36], new float[36], new float[36] };
int i;
/* type 0 */
for (i = 0; i < 36; i++)
_swin[0][i] = (float)Math.Sin(PI / 36 * (i + 0.5));
/* type 1 */
for (i = 0; i < 18; i++)
_swin[1][i] = (float)Math.Sin(PI / 36 * (i + 0.5));
for (i = 18; i < 24; i++)
_swin[1][i] = 1.0f;
for (i = 24; i < 30; i++)
_swin[1][i] = (float)Math.Sin(PI / 12 * (i + 0.5 - 18));
for (i = 30; i < 36; i++)
_swin[1][i] = 0.0f;
/* type 3 */
for (i = 0; i < 6; i++)
_swin[3][i] = 0.0f;
for (i = 6; i < 12; i++)
_swin[3][i] = (float)Math.Sin(PI / 12 * (i + 0.5 - 6));
for (i = 12; i < 18; i++)
_swin[3][i] = 1.0f;
for (i = 18; i < 36; i++)
_swin[3][i] = (float)Math.Sin(PI / 36 * (i + 0.5));
/* type 2 */
for (i = 0; i < 12; i++)
_swin[2][i] = (float)Math.Sin(PI / 12 * (i + 0.5));
for (i = 12; i < 36; i++)
_swin[2][i] = 0.0f;
}
#region Tables
static float[] icos72_table = {
5.004763425816599609063928255636710673570632934570312500000000e-01f,
5.019099187716736798492433990759309381246566772460937500000000e-01f,
5.043144802900764167574720886477734893560409545898437500000000e-01f,
5.077133059428725614381505693017970770597457885742187500000000e-01f,
5.121397571572545714957414020318537950515747070312500000000000e-01f,
5.176380902050414789528076653368771076202392578125000000000000e-01f,
5.242645625704053236049162478593643754720687866210937500000000e-01f,
5.320888862379560269033618169487453997135162353515625000000000e-01f,
5.411961001461970122150546558259520679712295532226562500000000e-01f,
5.516889594812458552652856269560288637876510620117187500000000e-01f,
5.636909734331712051869089918909594416618347167968750000000000e-01f,
5.773502691896257310588680411456152796745300292968750000000000e-01f,
5.928445237170802961657045671017840504646301269531250000000000e-01f,
6.103872943807280293526673631276935338973999023437500000000000e-01f,
6.302362070051321651931175438221544027328491210937500000000000e-01f,
6.527036446661392821155800447741057723760604858398437500000000e-01f,
6.781708524546284921896699415810871869325637817382812500000000e-01f,
7.071067811865474617150084668537601828575134277343750000000000e-01f,
7.400936164611303658134033867099788039922714233398437500000000e-01f,
7.778619134302061643992942663317080587148666381835937500000000e-01f,
8.213398158522907666068135768000502139329910278320312500000000e-01f,
8.717233978105488612087015098950359970331192016601562500000000e-01f,
9.305794983517888807611484480730723589658737182617187500000000e-01f,
9.999999999999997779553950749686919152736663818359375000000000e-01f,
1.082840285100100219395358180918265134096145629882812500000000e+00f,
1.183100791576249255498964885191526263952255249023437500000000e+00f,
1.306562964876376353728915091778617352247238159179687500000000e+00f,
1.461902200081543146126250576344318687915802001953125000000000e+00f,
1.662754761711521034328598034335300326347351074218750000000000e+00f,
1.931851652578135070115195048856548964977264404296875000000000e+00f,
2.310113157672649020213384574162773787975311279296875000000000e+00f,
2.879385241571815523542454684502445161342620849609375000000000e+00f,
3.830648787770197127855453800293616950511932373046875000000000e+00f,
5.736856622834929808618653623852878808975219726562500000000000e+00f,
1.146279281302667207853573927422985434532165527343750000000000e+01f
};
#endregion
List<float[]> _prevBlock;
List<float[]> _nextBlock;
internal HybridMDCT()
{
_prevBlock = new List<float[]>();
_nextBlock = new List<float[]>();
}
internal void Reset()
{
_prevBlock.Clear();
_nextBlock.Clear();
}
void GetPrevBlock(int channel, out float[] prevBlock, out float[] nextBlock)
{
while (_prevBlock.Count <= channel)
{
_prevBlock.Add(new float[SSLIMIT * SBLIMIT]);
}
while (_nextBlock.Count <= channel)
{
_nextBlock.Add(new float[SSLIMIT * SBLIMIT]);
}
prevBlock = _prevBlock[channel];
nextBlock = _nextBlock[channel];
// now swap them (see Apply(...) below)
_nextBlock[channel] = prevBlock;
_prevBlock[channel] = nextBlock;
}
internal void Apply(float[] fsIn, int channel, int blockType, bool doMixed)
{
// get the previous & next blocks so we can overlap correctly
// NB: we swap each pass so we can add the previous block in a single pass
float[] prevblck, nextblck;
GetPrevBlock(channel, out prevblck, out nextblck);
// now we have a few options for processing blocks...
int start = 0;
if (doMixed)
{
// a mixed block always has the first two subbands as blocktype 0
LongImpl(fsIn, 0, 2, nextblck, 0);
start = 2;
}
if (blockType == 2)
{
// this is the only place we care about short blocks
ShortImpl(fsIn, start, nextblck);
}
else
{
LongImpl(fsIn, start, SBLIMIT, nextblck, blockType);
}
// overlap
for (int i = 0; i < SSLIMIT * SBLIMIT; i++)
{
fsIn[i] += prevblck[i];
}
}
float[] _imdctTemp = new float[SSLIMIT];
float[] _imdctResult = new float[SSLIMIT * 2];
void LongImpl(float[] fsIn, int sbStart, int sbLimit, float[] nextblck, int blockType)
{
for (int sb = sbStart, ofs = sbStart * SSLIMIT; sb < sbLimit; sb++)
{
// IMDCT
Array.Copy(fsIn, ofs, _imdctTemp, 0, SSLIMIT);
LongIMDCT(_imdctTemp, _imdctResult);
// window
var win = _swin[blockType];
int i = 0;
for (; i < SSLIMIT; i++)
{
fsIn[ofs++] = _imdctResult[i] * win[i];
}
ofs -= 18;
for (; i < SSLIMIT * 2; i++)
{
nextblck[ofs++] = _imdctResult[i] * win[i];
}
}
}
static void LongIMDCT(float[] invec, float[] outvec)
{
int i;
float[] H = new float[17], h = new float[18], even = new float[9], odd = new float[9], even_idct = new float[9], odd_idct = new float[9];
for (i = 0; i < 17; i++)
H[i] = invec[i] + invec[i + 1];
even[0] = invec[0];
odd[0] = H[0];
var idx = 0;
for (i = 1; i < 9; i++, idx += 2)
{
even[i] = H[idx + 1];
odd[i] = H[idx] + H[idx + 2];
}
imdct_9pt(even, even_idct);
imdct_9pt(odd, odd_idct);
for (i = 0; i < 9; i++)
{
odd_idct[i] *= ICOS36_A(i);
h[i] = (even_idct[i] + odd_idct[i]) * ICOS72_A(i);
}
for ( /* i = 9 */ ; i < 18; i++)
{
h[i] = (even_idct[17 - i] - odd_idct[17 - i]) * ICOS72_A(i);
}
/* Rearrange the 18 values from the IDCT to the output vector */
outvec[0] = h[9];
outvec[1] = h[10];
outvec[2] = h[11];
outvec[3] = h[12];
outvec[4] = h[13];
outvec[5] = h[14];
outvec[6] = h[15];
outvec[7] = h[16];
outvec[8] = h[17];
outvec[9] = -h[17];
outvec[10] = -h[16];
outvec[11] = -h[15];
outvec[12] = -h[14];
outvec[13] = -h[13];
outvec[14] = -h[12];
outvec[15] = -h[11];
outvec[16] = -h[10];
outvec[17] = -h[9];
outvec[35] = outvec[18] = -h[8];
outvec[34] = outvec[19] = -h[7];
outvec[33] = outvec[20] = -h[6];
outvec[32] = outvec[21] = -h[5];
outvec[31] = outvec[22] = -h[4];
outvec[30] = outvec[23] = -h[3];
outvec[29] = outvec[24] = -h[2];
outvec[28] = outvec[25] = -h[1];
outvec[27] = outvec[26] = -h[0];
}
static float ICOS72_A(int i)
{
return icos72_table[2 * i];
}
static float ICOS36_A(int i)
{
return icos72_table[4 * i + 1];
}
static void imdct_9pt(float[] invec, float[] outvec)
{
int i;
float[] even_idct = new float[5], odd_idct = new float[4];
float t0, t1, t2;
/* BEGIN 5 Point IMDCT */
t0 = invec[6] / 2.0f + invec[0];
t1 = invec[0] - invec[6];
t2 = invec[2] - invec[4] - invec[8];
even_idct[0] = t0 + invec[2] * 0.939692621f
+ invec[4] * 0.766044443f + invec[8] * 0.173648178f;
even_idct[1] = t2 / 2.0f + t1;
even_idct[2] = t0 - invec[2] * 0.173648178f
- invec[4] * 0.939692621f + invec[8] * 0.766044443f;
even_idct[3] = t0 - invec[2] * 0.766044443f
+ invec[4] * 0.173648178f - invec[8] * 0.939692621f;
even_idct[4] = t1 - t2;
/* END 5 Point IMDCT */
/* BEGIN 4 Point IMDCT */
{
float odd1, odd2;
odd1 = invec[1] + invec[3];
odd2 = invec[3] + invec[5];
t0 = (invec[5] + invec[7]) * 0.5f + invec[1];
odd_idct[0] = t0 + odd1 * 0.939692621f + odd2 * 0.766044443f;
odd_idct[1] = (invec[1] - invec[5]) * 1.5f - invec[7];
odd_idct[2] = t0 - odd1 * 0.173648178f - odd2 * 0.939692621f;
odd_idct[3] = t0 - odd1 * 0.766044443f + odd2 * 0.173648178f;
}
/* END 4 Point IMDCT */
/* Adjust for non power of 2 IDCT */
odd_idct[0] += invec[7] * 0.173648178f;
odd_idct[1] -= invec[7] * 0.5f;
odd_idct[2] += invec[7] * 0.766044443f;
odd_idct[3] -= invec[7] * 0.939692621f;
/* Post-Twiddle */
odd_idct[0] *= 0.5f / 0.984807753f;
odd_idct[1] *= 0.5f / 0.866025404f;
odd_idct[2] *= 0.5f / 0.64278761f;
odd_idct[3] *= 0.5f / 0.342020143f;
for (i = 0; i < 4; i++)
{
outvec[i] = even_idct[i] + odd_idct[i];
}
outvec[4] = even_idct[4];
/* Mirror into the other half of the vector */
for (i = 5; i < 9; i++)
{
outvec[i] = even_idct[8 - i] - odd_idct[8 - i];
}
}
void ShortImpl(float[] fsIn, int sbStart, float[] nextblck)
{
var win = _swin[2];
for (int sb = sbStart, ofs = sbStart * SSLIMIT; sb < SBLIMIT; sb++, ofs += SSLIMIT)
{
// rearrange vectors
for (int i = 0, tmpptr = 0; i < 3; i++)
{
var v = ofs + i;
for (int j = 0; j < 6; j++)
{
_imdctTemp[tmpptr + j] = fsIn[v];
v += 3;
}
tmpptr += 6;
}
// short blocks are fun... 3 separate IMDCT's with overlap in two different buffers
Array.Clear(fsIn, ofs, 6);
// do the first 6 samples
ShortIMDCT(_imdctTemp, 0, _imdctResult);
Array.Copy(_imdctResult, 0, fsIn, ofs + 6, 12);
// now the next 6
ShortIMDCT(_imdctTemp, 6, _imdctResult);
for (int i = 0; i < 6; i++)
{
// add the first half to tsOut
fsIn[ofs + i + 12] += _imdctResult[i];
}
Array.Copy(_imdctResult, 6, nextblck, ofs, 6);
// now the final 6
ShortIMDCT(_imdctTemp, 12, _imdctResult);
for (int i = 0; i < 6; i++)
{
// add the first half to nextblck
nextblck[ofs + i] += _imdctResult[i];
}
Array.Copy(_imdctResult, 6, nextblck, ofs + 6, 6);
Array.Clear(nextblck, ofs + 12, 6);
}
}
const float sqrt32 = 0.8660254037844385965883020617184229195117950439453125f;
static void ShortIMDCT(float[] invec, int inIdx, float[] outvec)
{
int i;
float[] H = new float[6], h = new float[6], even_idct = new float[3], odd_idct = new float[3];
float t0, t1, t2;
/* Preprocess the input to the two 3-point IDCT's */
var idx = inIdx;
for (i = 1; i < 6; i++)
{
H[i] = invec[idx];
H[i] += invec[++idx];
}
/* 3-point IMDCT */
t0 = H[4] / 2.0f + invec[inIdx];
t1 = H[2] * sqrt32;
even_idct[0] = t0 + t1;
even_idct[1] = invec[inIdx] - H[4];
even_idct[2] = t0 - t1;
/* END 3-point IMDCT */
/* 3-point IMDCT */
t2 = H[3] + H[5];
t0 = (t2) / 2.0f + H[1];
t1 = (H[1] + H[3]) * sqrt32;
odd_idct[0] = t0 + t1;
odd_idct[1] = H[1] - t2;
odd_idct[2] = t0 - t1;
/* END 3-point IMDCT */
/* Post-Twiddle */
odd_idct[0] *= 0.51763809f;
odd_idct[1] *= 0.707106781f;
odd_idct[2] *= 1.931851653f;
h[0] = (even_idct[0] + odd_idct[0]) * 0.50431448f;
h[1] = (even_idct[1] + odd_idct[1]) * 0.5411961f;
h[2] = (even_idct[2] + odd_idct[2]) * 0.630236207f;
h[3] = (even_idct[2] - odd_idct[2]) * 0.821339816f;
h[4] = (even_idct[1] - odd_idct[1]) * 1.306562965f;
h[5] = (even_idct[0] - odd_idct[0]) * 3.830648788f;
/* Rearrange the 6 values from the IDCT to the output vector */
outvec[0] = h[3] * _swin[2][0];
outvec[1] = h[4] * _swin[2][1];
outvec[2] = h[5] * _swin[2][2];
outvec[3] = -h[5] * _swin[2][3];
outvec[4] = -h[4] * _swin[2][4];
outvec[5] = -h[3] * _swin[2][5];
outvec[6] = -h[2] * _swin[2][6];
outvec[7] = -h[1] * _swin[2][7];
outvec[8] = -h[0] * _swin[2][8];
outvec[9] = -h[0] * _swin[2][9];
outvec[10] = -h[1] * _swin[2][10];
outvec[11] = -h[2] * _swin[2][11];
}
}
#endregion
static internal bool GetCRC(MpegFrame frame, ref uint crc)
{
var cnt = frame.GetSideDataSize();
while (--cnt >= 0)
{
MpegFrame.UpdateCRC(frame.ReadBits(8), 8, ref crc);
}
return true;
}
HybridMDCT _hybrid = new HybridMDCT();
BitReservoir _bitRes = new BitReservoir();
internal LayerIIIDecoder()
{
_tableSelect = new int[][][]
{
new int[][] { new int[3], new int[3] },
new int[][] { new int[3], new int[3] },
};
_subblockGain = new float[][][]
{
new float[][] { new float[3], new float[3] },
new float[][] { new float[3], new float[3] },
};
}
internal override int DecodeFrame(IMpegFrame frame, float[] ch0, float[] ch1)
{
// load the frame information
ReadSideInfo(frame);
// load the frame's main data
if (!_bitRes.AddBits(frame, _mainDataBegin))
{
return 0;
}
// prep the reusable tables
PrepTables(frame);
// do our stereo mode setup
var chanBufs = new float[2][];
var startChannel = 0;
var endChannel = _channels - 1;
if (_channels == 1 || StereoMode == StereoMode.LeftOnly || StereoMode == StereoMode.DownmixToMono)
{
chanBufs[0] = ch0;
endChannel = 0;
}
else if (StereoMode == StereoMode.RightOnly)
{
chanBufs[1] = ch0; // this is correct... if there's only a single channel output, it goes in channel 0's buffer
startChannel = 1;
}
else // MpegStereoMode.Both
{
chanBufs[0] = ch0;
chanBufs[1] = ch1;
}
// get the granule count
int granules;
if (frame.Version == MpegVersion.Version1)
{
granules = 2;
}
else
{
granules = 1;
}
// decode the audio data
int offset = 0;
for (var gr = 0; gr < granules; gr++)
{
for (var ch = 0; ch < _channels; ch++)
{
// read scale factors
int sfbits;
if (frame.Version == MpegVersion.Version1)
{
sfbits = ReadScalefactors(gr, ch);
}
else
{
sfbits = ReadLsfScalefactors(gr, ch, frame.ChannelModeExtension);
}
// huffman & dequant
ReadSamples(sfbits, gr, ch);
}
// stereo processing
Stereo(frame.ChannelMode, frame.ChannelModeExtension, gr, frame.Version != MpegVersion.Version1);
for (int ch = startChannel; ch <= endChannel; ch++)
{
// pull some values so we don't have to index them again later
var buf = _samples[ch];
var blockType = _blockType[gr][ch];
var blockSplit = _blockSplitFlag[gr][ch];
var mixedBlock = _mixedBlockFlag[gr][ch];
// do the short/long/mixed logic here so it's only done once per channel per granule
if (blockSplit && blockType == 2)
{
if (mixedBlock)
{
// reorder & antialias mixed blocks
Reorder(buf, true);
AntiAlias(buf, true);
}
else
{
// reorder short blocks
Reorder(buf, false);
}
}
else
{
// antialias long blocks
AntiAlias(buf, false);
}
// hybrid processing
_hybrid.Apply(buf, ch, blockType, blockSplit && mixedBlock);
// frequency inversion
FrequencyInversion(buf);
// inverse polyphase
InversePolyphase(buf, ch, offset, chanBufs[ch]);
}
offset += SBLIMIT * SSLIMIT;
}
return offset;
}
internal override void ResetForSeek()
{
base.ResetForSeek();
_hybrid.Reset();
_bitRes.Reset();
}
#region Side Info
#region Variables
int _channels, _privBits, _mainDataBegin;
int[][] _scfsi = { new int[4], new int[4] }; // ch, scfsi_band
int[][] _part23Length = { new int[2], new int[2] }; // gr, ch
int[][] _bigValues = { new int[2], new int[2] }; // gr, ch
float[][] _globalGain = { new float[2], new float[2] }; // gr, ch
int[][] _scalefacCompress = { new int[2], new int[2] }; // gr, ch
bool[][] _blockSplitFlag = { new bool[2], new bool[2] }; // gr, ch
bool[][] _mixedBlockFlag = { new bool[2], new bool[2] }; // gr, ch
int[][] _blockType = { new int[2], new int[2] }; // gr, ch
int[][][] _tableSelect; // gr, ch, region
float[][][] _subblockGain; // gr, ch, window
int[][] _regionAddress1 = { new int[2], new int[2] }; // gr, ch
int[][] _regionAddress2 = { new int[2], new int[2] }; // gr, ch
int[][] _preflag = { new int[2], new int[2] }; // gr, ch
float[][] _scalefacScale = { new float[2], new float[2] }; // gr, ch
int[][] _count1TableSelect = { new int[2], new int[2] }; // gr, ch
static float[] GAIN_TAB =
{
1.57009245868378E-16f, 1.86716512307887E-16f, 2.22044604925031E-16f, 2.64057024024816E-16f, 3.14018491736756E-16f, 3.73433024615774E-16f, 4.44089209850063E-16f, 5.28114048049630E-16f,
6.28036983473509E-16f, 7.46866049231544E-16f, 8.88178419700125E-16f, 1.05622809609926E-15f, 1.25607396694702E-15f, 1.49373209846309E-15f, 1.77635683940025E-15f, 2.11245619219853E-15f,
2.51214793389404E-15f, 2.98746419692619E-15f, 3.55271367880050E-15f, 4.22491238439706E-15f, 5.02429586778810E-15f, 5.97492839385238E-15f, 7.10542735760100E-15f, 8.44982476879408E-15f,
1.00485917355761E-14f, 1.19498567877047E-14f, 1.42108547152020E-14f, 1.68996495375882E-14f, 2.00971834711523E-14f, 2.38997135754094E-14f, 2.84217094304040E-14f, 3.37992990751764E-14f,
4.01943669423047E-14f, 4.77994271508190E-14f, 5.68434188608080E-14f, 6.75985981503528E-14f, 8.03887338846093E-14f, 9.55988543016378E-14f, 1.13686837721616E-13f, 1.35197196300706E-13f,
1.60777467769219E-13f, 1.91197708603275E-13f, 2.27373675443232E-13f, 2.70394392601411E-13f, 3.21554935538437E-13f, 3.82395417206551E-13f, 4.54747350886464E-13f, 5.40788785202823E-13f,
6.43109871076876E-13f, 7.64790834413101E-13f, 9.09494701772928E-13f, 1.08157757040564E-12f, 1.28621974215375E-12f, 1.52958166882621E-12f, 1.81898940354586E-12f, 2.16315514081129E-12f,
2.57243948430750E-12f, 3.05916333765241E-12f, 3.63797880709171E-12f, 4.32631028162258E-12f, 5.14487896861500E-12f, 6.11832667530482E-12f, 7.27595761418343E-12f, 8.65262056324518E-12f,
1.02897579372300E-11f, 1.22366533506096E-11f, 1.45519152283669E-11f, 1.73052411264903E-11f, 2.05795158744600E-11f, 2.44733067012193E-11f, 2.91038304567337E-11f, 3.46104822529806E-11f,
4.11590317489199E-11f, 4.89466134024385E-11f, 5.82076609134674E-11f, 6.92209645059613E-11f, 8.23180634978400E-11f, 9.78932268048772E-11f, 1.16415321826935E-10f, 1.38441929011922E-10f,
1.64636126995680E-10f, 1.95786453609754E-10f, 2.32830643653870E-10f, 2.76883858023845E-10f, 3.29272253991360E-10f, 3.91572907219509E-10f, 4.65661287307739E-10f, 5.53767716047690E-10f,
6.58544507982719E-10f, 7.83145814439016E-10f, 9.31322574615479E-10f, 1.10753543209538E-09f, 1.31708901596544E-09f, 1.56629162887804E-09f, 1.86264514923096E-09f, 2.21507086419076E-09f,
2.63417803193088E-09f, 3.13258325775607E-09f, 3.72529029846191E-09f, 4.43014172838152E-09f, 5.26835606386176E-09f, 6.26516651551212E-09f, 7.45058059692383E-09f, 8.86028345676304E-09f,
1.05367121277235E-08f, 1.25303330310243E-08f, 1.49011611938477E-08f, 1.77205669135261E-08f, 2.10734242554471E-08f, 2.50606660620485E-08f, 2.98023223876953E-08f, 3.54411338270521E-08f,
4.21468485108941E-08f, 5.01213321240971E-08f, 5.96046447753906E-08f, 7.08822676541044E-08f, 8.42936970217880E-08f, 1.00242664248194E-07f, 1.19209289550781E-07f, 1.41764535308209E-07f,
1.68587394043576E-07f, 2.00485328496388E-07f, 2.38418579101562E-07f, 2.83529070616417E-07f, 3.37174788087152E-07f, 4.00970656992777E-07f, 4.76837158203125E-07f, 5.67058141232835E-07f,
6.74349576174305E-07f, 8.01941313985553E-07f, 9.53674316406250E-07f, 1.13411628246567E-06f, 1.34869915234861E-06f, 1.60388262797110E-06f, 1.90734863281250E-06f, 2.26823256493134E-06f,
2.69739830469722E-06f, 3.20776525594221E-06f, 3.81469726562500E-06f, 4.53646512986268E-06f, 5.39479660939444E-06f, 6.41553051188442E-06f, 7.62939453125000E-06f, 9.07293025972536E-06f,
1.07895932187889E-05f, 1.28310610237688E-05f, 1.52587890625000E-05f, 1.81458605194507E-05f, 2.15791864375777E-05f, 2.56621220475377E-05f, 3.05175781250000E-05f, 3.62917210389014E-05f,
4.31583728751555E-05f, 5.13242440950754E-05f, 6.10351562500000E-05f, 7.25834420778029E-05f, 8.63167457503110E-05f, 1.02648488190151E-04f, 1.22070312500000E-04f, 1.45166884155606E-04f,
1.72633491500622E-04f, 2.05296976380301E-04f, 2.44140625000000E-04f, 2.90333768311211E-04f, 3.45266983001244E-04f, 4.10593952760603E-04f, 4.88281250000000E-04f, 5.80667536622423E-04f,
6.90533966002488E-04f, 8.21187905521206E-04f, 9.76562500000000E-04f, 1.16133507324485E-03f, 1.38106793200498E-03f, 1.64237581104241E-03f, 1.95312500000000E-03f, 2.32267014648969E-03f,
2.76213586400995E-03f, 3.28475162208482E-03f, 3.90625000000000E-03f, 4.64534029297938E-03f, 5.52427172801990E-03f, 6.56950324416964E-03f, 7.81250000000000E-03f, 9.29068058595876E-03f,
1.10485434560398E-02f, 1.31390064883393E-02f, 1.56250000000000E-02f, 1.85813611719175E-02f, 2.20970869120796E-02f, 2.62780129766786E-02f, 3.12500000000000E-02f, 3.71627223438350E-02f,
4.41941738241592E-02f, 5.25560259533572E-02f, 6.25000000000000E-02f, 7.43254446876701E-02f, 8.83883476483184E-02f, 1.05112051906714E-01f, 1.25000000000000E-01f, 1.48650889375340E-01f,
1.76776695296637E-01f, 2.10224103813429E-01f, 2.50000000000000E-01f, 2.97301778750680E-01f, 3.53553390593274E-01f, 4.20448207626857E-01f, 5.00000000000000E-01f, 5.94603557501361E-01f,
7.07106781186547E-01f, 8.40896415253715E-01f, 1.00000000000000E+00f, 1.18920711500272E+00f, 1.41421356237310E+00f, 1.68179283050743E+00f, 2.00000000000000E+00f, 2.37841423000544E+00f,
2.82842712474619E+00f, 3.36358566101486E+00f, 4.00000000000000E+00f, 4.75682846001088E+00f, 5.65685424949238E+00f, 6.72717132202972E+00f, 8.00000000000000E+00f, 9.51365692002177E+00f,
1.13137084989848E+01f, 1.34543426440594E+01f, 1.60000000000000E+01f, 1.90273138400435E+01f, 2.26274169979695E+01f, 2.69086852881189E+01f, 3.20000000000000E+01f, 3.80546276800871E+01f,
4.52548339959390E+01f, 5.38173705762377E+01f, 6.40000000000000E+01f, 7.61092553601742E+01f, 9.05096679918781E+01f, 1.07634741152475E+02f, 1.28000000000000E+02f, 1.52218510720348E+02f,
1.81019335983756E+02f, 2.15269482304951E+02f, 2.56000000000000E+02f, 3.04437021440696E+02f, 3.62038671967512E+02f, 4.30538964609902E+02f, 5.12000000000000E+02f, 6.08874042881393E+02f,
7.24077343935025E+02f, 8.61077929219803E+02f, 1.02400000000000E+03f, 1.21774808576279E+03f, 1.44815468787005E+03f, 1.72215585843961E+03f, 2.04800000000000E+03f, 2.43549617152557E+03f,
};
#endregion
void ReadSideInfo(IMpegFrame frame)
{
if (frame.Version == MpegVersion.Version1)
{
// main_data_begin 9
_mainDataBegin = frame.ReadBits(9);
// private_bits 3 or 5
if (frame.ChannelMode == MpegChannelMode.Mono)
{
_privBits = frame.ReadBits(5);
_channels = 1;
}
else
{
_privBits = frame.ReadBits(3);
_channels = 2;
}
for (var ch = 0; ch < _channels; ch++)
{
// scfsi[ch][0...3] 1 x4
_scfsi[ch][0] = frame.ReadBits(1);
_scfsi[ch][1] = frame.ReadBits(1);
_scfsi[ch][2] = frame.ReadBits(1);
_scfsi[ch][3] = frame.ReadBits(1);
}
for (var gr = 0; gr < 2; gr++)
{
for (var ch = 0; ch < _channels; ch++)
{
// part2_3_length[gr][ch] 12
_part23Length[gr][ch] = frame.ReadBits(12);
// big_values[gr][ch] 9
_bigValues[gr][ch] = frame.ReadBits(9);
// global_gain[gr][ch] 8
_globalGain[gr][ch] = GAIN_TAB[frame.ReadBits(8)];
// scalefac_compress[gr][ch] 4
_scalefacCompress[gr][ch] = frame.ReadBits(4);
// blocksplit_flag[gr][ch] 1
_blockSplitFlag[gr][ch] = frame.ReadBits(1) == 1;
if (_blockSplitFlag[gr][ch])
{
// block_type[gr][ch] 2
_blockType[gr][ch] = frame.ReadBits(2);
// switch_point[gr][ch] 1
_mixedBlockFlag[gr][ch] = frame.ReadBits(1) == 1;
// table_select[gr][ch][0..1] 5 x2
_tableSelect[gr][ch][0] = frame.ReadBits(5);
_tableSelect[gr][ch][1] = frame.ReadBits(5);
_tableSelect[gr][ch][2] = 0;
// set the region information
if (_blockType[gr][ch] == 2 && !_mixedBlockFlag[gr][ch])
{
_regionAddress1[gr][ch] = 8;
}
else
{
_regionAddress1[gr][ch] = 7;
}
_regionAddress2[gr][ch] = 20 - _regionAddress1[gr][ch];
// subblock_gain[gr][ch][0..2] 3 x3
_subblockGain[gr][ch][0] = frame.ReadBits(3) * -2f;
_subblockGain[gr][ch][1] = frame.ReadBits(3) * -2f;
_subblockGain[gr][ch][2] = frame.ReadBits(3) * -2f;
}
else
{
// table_select[0..2][gr][ch] 5 x3
_tableSelect[gr][ch][0] = frame.ReadBits(5);
_tableSelect[gr][ch][1] = frame.ReadBits(5);
_tableSelect[gr][ch][2] = frame.ReadBits(5);
// region_address1[gr][ch] 4
_regionAddress1[gr][ch] = frame.ReadBits(4);
// region_address2[gr][ch] 3
_regionAddress2[gr][ch] = frame.ReadBits(3);
// set the block type so it doesn't accidentally carry
_blockType[gr][ch] = 0;
// make subblock gain equal unity
_subblockGain[gr][ch][0] = 0;
_subblockGain[gr][ch][1] = 0;
_subblockGain[gr][ch][2] = 0;
}
// preflag[gr][ch] 1
_preflag[gr][ch] = frame.ReadBits(1);
// scalefac_scale[gr][ch] 1
_scalefacScale[gr][ch] = .5f * (1f + frame.ReadBits(1));
// count1table_select[gr][ch] 1
_count1TableSelect[gr][ch] = frame.ReadBits(1);
}
}
}
else // MPEG 2+
{
// main_data_begin 8
_mainDataBegin = frame.ReadBits(8);
// private_bits 1 or 2
if (frame.ChannelMode == MpegChannelMode.Mono)
{
_privBits = frame.ReadBits(1);
_channels = 1;
}
else
{
_privBits = frame.ReadBits(2);
_channels = 2;
}
var gr = 0;
for (var ch = 0; ch < _channels; ch++)
{
// part2_3_length[gr][ch] 12
_part23Length[gr][ch] = frame.ReadBits(12);
// big_values[gr][ch] 9
_bigValues[gr][ch] = frame.ReadBits(9);
// global_gain[gr][ch] 8
_globalGain[gr][ch] = GAIN_TAB[frame.ReadBits(8)];
// scalefac_compress[gr][ch] 9
_scalefacCompress[gr][ch] = frame.ReadBits(9);
// blocksplit_flag[gr][ch] 1
_blockSplitFlag[gr][ch] = frame.ReadBits(1) == 1;
if (_blockSplitFlag[gr][ch])
{
// block_type[gr][ch] 2
_blockType[gr][ch] = frame.ReadBits(2);
// switch_point[gr][ch] 1
_mixedBlockFlag[gr][ch] = frame.ReadBits(1) == 1;
// table_select[gr][ch][0..1] 5 x2
_tableSelect[gr][ch][0] = frame.ReadBits(5);
_tableSelect[gr][ch][1] = frame.ReadBits(5);
_tableSelect[gr][ch][2] = 0;
// set the region information
if (_blockType[gr][ch] == 2 && !_mixedBlockFlag[gr][ch])
{
_regionAddress1[gr][ch] = 8;
}
else
{
_regionAddress1[gr][ch] = 7;
}
_regionAddress2[gr][ch] = 20 - _regionAddress1[gr][ch];
// subblock_gain[gr][ch][0..2] 3 x3
_subblockGain[gr][ch][0] = frame.ReadBits(3) * -2f;
_subblockGain[gr][ch][1] = frame.ReadBits(3) * -2f;
_subblockGain[gr][ch][2] = frame.ReadBits(3) * -2f;
}
else
{
// table_select[0..2][gr][ch] 5 x3
_tableSelect[gr][ch][0] = frame.ReadBits(5);
_tableSelect[gr][ch][1] = frame.ReadBits(5);
_tableSelect[gr][ch][2] = frame.ReadBits(5);
// region_address1[gr][ch] 4
_regionAddress1[gr][ch] = frame.ReadBits(4);
// region_address2[gr][ch] 3
_regionAddress2[gr][ch] = frame.ReadBits(3);
// set the block type so it doesn't accidentally carry
_blockType[gr][ch] = 0;
// make subblock gain equal unity
_subblockGain[gr][ch][0] = 0;
_subblockGain[gr][ch][1] = 0;
_subblockGain[gr][ch][2] = 0;
}
// scalefac_scale[gr][ch] 1
_scalefacScale[gr][ch] = .5f * (1f + frame.ReadBits(1));
// count1table_select[gr][ch] 1
_count1TableSelect[gr][ch] = frame.ReadBits(1);
}
}
}
#endregion
#region Precalc Table Prep
#region Variables
int[] _sfBandIndexL, _sfBandIndexS;
// these are byte[] to save memory
byte[] _cbLookupL = new byte[SSLIMIT * SBLIMIT], _cbLookupS = new byte[SSLIMIT * SBLIMIT], _cbwLookupS = new byte[SSLIMIT * SBLIMIT];
int _cbLookupSR;
static readonly int[][] _sfBandIndexLTable = {
// MPEG 1
// 44.1 kHz
new int[] { 0, 4, 8, 12, 16, 20, 24, 30, 36, 44, 52, 62, 74, 90, 110, 134, 162, 196, 238, 288, 342, 418, 576 },
// 48 kHz
new int[] { 0, 4, 8, 12, 16, 20, 24, 30, 36, 42, 50, 60, 72, 88, 106, 128, 156, 190, 230, 276, 330, 384, 576 },
// 32 kHz
new int[] { 0, 4, 8, 12, 16, 20, 24, 30, 36, 44, 54, 66, 82, 102, 126, 156, 194, 240, 296, 364, 448, 550, 576 },
// MPEG 2
// 22.05 kHz
new int[] { 0, 6, 12, 18, 24, 30, 36, 44, 54, 66, 80, 96, 116, 140, 168, 200, 238, 284, 336, 396, 464, 522, 576 },
// 24 kHz
new int[] { 0, 6, 12, 18, 24, 30, 36, 44, 54, 66, 80, 96, 114, 136, 162, 194, 232, 278, 330, 394, 464, 540, 576 },
// 16 kHz
new int[] { 0, 6, 12, 18, 24, 30, 36, 44, 54, 66, 80, 96, 116, 140, 168, 200, 238, 284, 336, 396, 464, 522, 576 },
// MPEG 2.5
// 11.025 kHz
new int[] { 0, 6, 12, 18, 24, 30, 36, 44, 54, 66, 80, 96, 116, 140, 168, 200, 238, 284, 336, 396, 464, 522, 576 },
// 12 kHz
new int[] { 0, 6, 12, 18, 24, 30, 36, 44, 54, 66, 80, 96, 116, 140, 168, 200, 238, 284, 336, 396, 464, 522, 576 },
// 8 kHz
new int[] { 0, 12, 24, 36, 48, 60, 72, 88, 108, 132, 160, 192, 232, 280, 336, 400, 476, 566, 568, 570, 572, 574, 576 },
};
static readonly int[][] _sfBandIndexSTable = {
// MPEG 1
// 44.1 kHz
new int[] { 0, 4, 8, 12, 16, 22, 30, 40, 52, 66, 84, 106, 136, 192 },
// 48 kHz
new int[] { 0, 4, 8, 12, 16, 22, 28, 38, 50, 64, 80, 100, 126, 192 },
// 32 kHz
new int[] { 0, 4, 8, 12, 16, 22, 30, 42, 58, 78, 104, 138, 180, 192 },
// MPEG 2
// 22.05 kHz
new int[] { 0, 4, 8, 12, 18, 24, 32, 42, 56, 74, 100, 132, 174, 192 },
// 24 kHz
new int[] { 0, 4, 8, 12, 18, 26, 36, 48, 62, 80, 104, 136, 180, 192 },
// 16 kHz
new int[] { 0, 4, 8, 12, 18, 26, 36, 48, 62, 80, 104, 134, 174, 192 },
// MPEG 2.5
// 11.025 kHz
new int[] { 0, 4, 8, 12, 18, 26, 36, 48, 62, 80, 104, 134, 174, 192 },
// 12 kHz
new int[] { 0, 4, 8, 12, 18, 26, 36, 48, 62, 80, 104, 134, 174, 192 },
// 8 kHz
new int[] { 0, 8, 16, 24, 36, 52, 72, 96, 124, 160, 162, 164, 166, 192 },
};
#endregion
void PrepTables(IMpegFrame frame)
{
if (_cbLookupSR != frame.SampleRate)
{
switch (frame.SampleRate)
{
case 44100:
_sfBandIndexL = _sfBandIndexLTable[0];
_sfBandIndexS = _sfBandIndexSTable[0];
break;
case 48000:
_sfBandIndexL = _sfBandIndexLTable[1];
_sfBandIndexS = _sfBandIndexSTable[1];
break;
case 32000:
_sfBandIndexL = _sfBandIndexLTable[2];
_sfBandIndexS = _sfBandIndexSTable[2];
break;
case 22050:
_sfBandIndexL = _sfBandIndexLTable[3];
_sfBandIndexS = _sfBandIndexSTable[3];
break;
case 24000:
_sfBandIndexL = _sfBandIndexLTable[4];
_sfBandIndexS = _sfBandIndexSTable[4];
break;
case 16000:
_sfBandIndexL = _sfBandIndexLTable[5];
_sfBandIndexS = _sfBandIndexSTable[5];
break;
case 11025:
_sfBandIndexL = _sfBandIndexLTable[6];
_sfBandIndexS = _sfBandIndexSTable[6];
break;
case 12000:
_sfBandIndexL = _sfBandIndexLTable[7];
_sfBandIndexS = _sfBandIndexSTable[7];
break;
case 8000:
_sfBandIndexL = _sfBandIndexLTable[8];
_sfBandIndexS = _sfBandIndexSTable[8];
break;
}
// precalculate the critical bands per bucket
int cbL = 0, cbS = 0;
int next_cbL = _sfBandIndexL[1], next_cbS = _sfBandIndexS[1] * 3;
for (int i = 0; i < 576; i++)
{
if (i == next_cbL)
{
++cbL;
next_cbL = _sfBandIndexL[cbL + 1];
}
if (i == next_cbS)
{
++cbS;
next_cbS = _sfBandIndexS[cbS + 1] * 3;
}
_cbLookupL[i] = (byte)cbL;
_cbLookupS[i] = (byte)cbS;
}
// set up the short block windows
int idx = 0;
for (cbS = 0; cbS < 12; cbS++)
{
var width = _sfBandIndexS[cbS + 1] - _sfBandIndexS[cbS];
for (int i = 0; i < 3; i++)
{
for (int j = 0; j < width; j++, idx++)
{
_cbwLookupS[idx] = (byte)i;
}
}
}
_cbLookupSR = frame.SampleRate;
}
}
#endregion
#region Scale Factors
#region Variables
int[][][] _scalefac = { // ch, window, cb
new int[][] { new int[13], new int[13], new int[13], new int[23] },
new int[][] { new int[13], new int[13], new int[13], new int[23] }
};
static readonly int[][] _slen = {
new int[] { 0, 0, 0, 0, 3, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4 },
new int[] { 0, 1, 2, 3, 0, 1, 2, 3, 1, 2, 3, 1, 2, 3, 2, 3 }
};
static readonly int[][][] _sfbBlockCntTab = {
new int[][] { new int[] { 6, 5, 5, 5 }, new int[] { 9, 9, 9, 9 }, new int[] { 6, 9, 9, 9 } },
new int[][] { new int[] { 6, 5, 7, 3 }, new int[] { 9, 9, 12, 6 }, new int[] { 6, 9, 12, 6 } },
new int[][] { new int[] { 11, 10, 0, 0 }, new int[] { 18, 18, 0, 0 }, new int[] { 15, 18, 0, 0 } },
new int[][] { new int[] { 7, 7, 7, 0 }, new int[] { 12, 12, 12, 0 }, new int[] { 6, 15, 12, 0 } },
new int[][] { new int[] { 6, 6, 6, 3 }, new int[] { 12, 9, 9, 6 }, new int[] { 6, 12, 9, 6 } },
new int[][] { new int[] { 8, 8, 5, 0 }, new int[] { 15, 12, 9, 0 }, new int[] { 6, 18, 9, 0 } },
};
#endregion
int ReadScalefactors(int gr, int ch)
{
var slen0 = _slen[0][_scalefacCompress[gr][ch]];
var slen1 = _slen[1][_scalefacCompress[gr][ch]];
int bits;
int cb = 0;
if (_blockSplitFlag[gr][ch] && _blockType[gr][ch] == 2)
{
if (slen0 > 0)
{
bits = slen0 * 18;
if (_mixedBlockFlag[gr][ch])
{
// mixed has bands 0..7 of long, then 3..11 of short
for (; cb < 8; cb++)
{
_scalefac[ch][3][cb] = _bitRes.GetBits(slen0);
}
cb = 3;
bits -= slen0; // mixed blocks need slen0 fewer bits
}
// short / mixed: just read from wherever cb happens to be through 11
for (; cb < 6; cb++)
{
_scalefac[ch][0][cb] = _bitRes.GetBits(slen0);
_scalefac[ch][1][cb] = _bitRes.GetBits(slen0);
_scalefac[ch][2][cb] = _bitRes.GetBits(slen0);
}
}
else
{
Array.Clear(_scalefac[ch][3], 0, 8);
Array.Clear(_scalefac[ch][0], 0, 6);
Array.Clear(_scalefac[ch][1], 0, 6);
Array.Clear(_scalefac[ch][2], 0, 6);
bits = 0;
}
if (slen1 > 0)
{
bits += slen1 * 18;
for (cb = 6; cb < 12; cb++)
{
_scalefac[ch][0][cb] = _bitRes.GetBits(slen1);
_scalefac[ch][1][cb] = _bitRes.GetBits(slen1);
_scalefac[ch][2][cb] = _bitRes.GetBits(slen1);
}
}
else
{
Array.Clear(_scalefac[ch][0], 6, 6);
Array.Clear(_scalefac[ch][1], 6, 6);
Array.Clear(_scalefac[ch][2], 6, 6);
}
}
else
{
// long: read if gr == 0, otherwise honor scfsi for the channel
bits = 0;
if (gr == 0 || _scfsi[ch][0] == 0)
{
if (slen0 > 0)
{
bits += slen0 * 6;
_scalefac[ch][3][0] = _bitRes.GetBits(slen0);
_scalefac[ch][3][1] = _bitRes.GetBits(slen0);
_scalefac[ch][3][2] = _bitRes.GetBits(slen0);
_scalefac[ch][3][3] = _bitRes.GetBits(slen0);
_scalefac[ch][3][4] = _bitRes.GetBits(slen0);
_scalefac[ch][3][5] = _bitRes.GetBits(slen0);
}
else
{
Array.Clear(_scalefac[ch][3], 0, 6);
}
}
if (gr == 0 || _scfsi[ch][1] == 0)
{
if (slen0 > 0)
{
bits += slen0 * 5;
_scalefac[ch][3][6] = _bitRes.GetBits(slen0);
_scalefac[ch][3][7] = _bitRes.GetBits(slen0);
_scalefac[ch][3][8] = _bitRes.GetBits(slen0);
_scalefac[ch][3][9] = _bitRes.GetBits(slen0);
_scalefac[ch][3][10] = _bitRes.GetBits(slen0);
}
else
{
Array.Clear(_scalefac[ch][3], 6, 5);
}
}
if (gr == 0 || _scfsi[ch][2] == 0)
{
if (slen1 > 0)
{
bits += slen1 * 5;
_scalefac[ch][3][11] = _bitRes.GetBits(slen1);
_scalefac[ch][3][12] = _bitRes.GetBits(slen1);
_scalefac[ch][3][13] = _bitRes.GetBits(slen1);
_scalefac[ch][3][14] = _bitRes.GetBits(slen1);
_scalefac[ch][3][15] = _bitRes.GetBits(slen1);
}
else
{
Array.Clear(_scalefac[ch][3], 11, 5);
}
}
if (gr == 0 || _scfsi[ch][3] == 0)
{
if (slen1 > 0)
{
bits += slen1 * 5;
_scalefac[ch][3][16] = _bitRes.GetBits(slen1);
_scalefac[ch][3][17] = _bitRes.GetBits(slen1);
_scalefac[ch][3][18] = _bitRes.GetBits(slen1);
_scalefac[ch][3][19] = _bitRes.GetBits(slen1);
_scalefac[ch][3][20] = _bitRes.GetBits(slen1);
}
else
{
Array.Clear(_scalefac[ch][3], 16, 5);
}
}
}
return bits;
}
int ReadLsfScalefactors(int gr, int ch, int chanModeExt)
{
var sfc = _scalefacCompress[gr][ch];
int blockTypeNumber;
// block type number = 2 if mixed short, 1 if pure short, otherwise 0
if (_blockType[gr][ch] == 2)
{
if (_mixedBlockFlag[gr][ch])
{
blockTypeNumber = 2;
}
else
{
blockTypeNumber = 1;
}
}
else
{
blockTypeNumber = 0;
}
int[] slen = new int[4];
int blockNumber;
if ((chanModeExt & 1) == 1 && ch == 1)
{
var tsfc = sfc >> 1;
if (tsfc < 180)
{
slen[0] = tsfc / 36; // <= 4, 15
slen[1] = (tsfc % 36) / 6; // <= 5, 31
slen[2] = tsfc % 6; // <= 5, 31
slen[3] = 0;
_preflag[gr][ch] = 0;
blockNumber = 3;
}
else if (tsfc < 244)
{
slen[0] = ((tsfc - 180) % 64) >> 4; // <= 3, 7
slen[1] = ((tsfc - 180) % 16) >> 2; // <= 3, 7
slen[2] = ((tsfc - 180) % 4); // <= 3, 7
slen[3] = 0;
_preflag[gr][ch] = 0;
blockNumber = 4;
}
else if (tsfc < 255)
{
slen[0] = (tsfc - 244) / 3; // <= 3, 7
slen[1] = (tsfc - 244) % 3; // <= 1, 1
slen[2] = 0;
slen[3] = 0;
_preflag[gr][ch] = 0;
blockNumber = 5;
}
else
{
blockNumber = 0;
}
}
else
{
// if scalefac_comp < 400
if (sfc < 400)
{
slen[0] = (sfc >> 4) / 5; // <= 4, 15
slen[1] = (sfc >> 4) % 5; // <= 4, 15
slen[2] = (sfc & 15) >> 2; // <= 3, 7
slen[3] = sfc & 3; // <= 3, 7
_preflag[gr][ch] = 0;
blockNumber = 0;
}
else if (sfc < 500)
{
slen[0] = ((sfc - 400) >> 2) / 5; // <= 4, 15
slen[1] = ((sfc - 400) >> 2) % 5; // <= 4, 15
slen[2] = (sfc - 400) & 3; // <= 3, 7
slen[3] = 0;
_preflag[gr][ch] = 0;
blockNumber = 1;
}
else if (sfc < 512)
{
slen[0] = (sfc - 500) / 3; // <= 3, 7
slen[1] = (sfc - 500) % 3; // <= 2, 3
slen[2] = 0;
slen[3] = 0;
_preflag[gr][ch] = 1;
blockNumber = 2;
}
else
{
blockNumber = 0;
}
}
// now we populate our buffer...
var buffer = new int[54];
var k = 0;
var blkCnt = _sfbBlockCntTab[blockNumber][blockTypeNumber];
for (int i = 0; i < 4; i++)
{
if (slen[i] != 0)
{
for (int j = 0; j < blkCnt[i]; j++, k++)
{
buffer[k] = _bitRes.GetBits(slen[i]);
}
}
else
{
k += blkCnt[i];
}
}
// now that we have that done, let's assign our scalefactors
k = 0;
int sfb = 0;
if (_blockSplitFlag[gr][ch] && _blockType[gr][ch] == 2)
{
if (_mixedBlockFlag[gr][ch])
{
for (; sfb < 8; sfb++)
{
_scalefac[ch][3][sfb] = buffer[k++];
}
sfb = 3;
}
for (; sfb < 12; sfb++)
{
for (int window = 0; window < 3; window++)
{
_scalefac[ch][window][sfb] = buffer[k++];
}
}
_scalefac[ch][0][12] = 0;
_scalefac[ch][1][12] = 0;
_scalefac[ch][2][12] = 0;
}
else
{
for (; sfb < 21; sfb++)
{
_scalefac[ch][3][sfb] = buffer[k++];
}
_scalefac[ch][3][22] = 0;
}
return slen[0] * blkCnt[0] + slen[1] * blkCnt[1] + slen[2] * blkCnt[2] + slen[3] * blkCnt[3];
}
#endregion
#region Huffman & Dequantize
#region Variables
float[][] _samples = { new float[SSLIMIT * SBLIMIT + 3], new float[SSLIMIT * SBLIMIT + 3] };
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 };
static readonly float[] POW2_TAB =
{
1.000000000000000E-00f, 7.071067811865470E-01f, 5.000000000000000E-01f, 3.535533905932740E-01f, 2.500000000000000E-01f, 1.767766952966370E-01f, 1.250000000000000E-01f, 8.838834764831840E-02f,
6.250000000000000E-02f, 4.419417382415920E-02f, 3.125000000000000E-02f, 2.209708691207960E-02f, 1.562500000000000E-02f, 1.104854345603980E-02f, 7.812500000000000E-03f, 5.524271728019900E-03f,
3.906250000000000E-03f, 2.762135864009950E-03f, 1.953125000000000E-03f, 1.381067932004980E-03f, 9.765625000000000E-04f, 6.905339660024880E-04f, 4.882812500000000E-04f, 3.452669830012440E-04f,
2.441406250000000E-04f, 1.726334915006220E-04f, 1.220703125000000E-04f, 8.631674575031100E-05f, 6.103515625000000E-05f, 4.315837287515550E-05f, 3.051757812500000E-05f, 2.157918643757770E-05f,
1.525878906250000E-05f, 1.078959321878890E-05f, 7.629394531250000E-06f, 5.394796609394440E-06f, 3.814697265625000E-06f, 2.697398304697220E-06f, 1.907348632812500E-06f, 1.348699152348610E-06f,
9.536743164062500E-07f, 6.743495761743050E-07f, 4.768371582031250E-07f, 3.371747880871520E-07f, 2.384185791015620E-07f, 1.685873940435760E-07f, 1.192092895507810E-07f, 8.429369702178800E-08f,
5.960464477539060E-08f, 4.214684851089410E-08f, 2.980232238769530E-08f, 2.107342425544710E-08f, 1.490116119384770E-08f, 1.053671212772350E-08f, 7.450580596923830E-09f, 5.268356063861760E-09f,
3.725290298461910E-09f, 2.634178031930880E-09f, 1.862645149230960E-09f, 1.317089015965440E-09f, 9.313225746154790E-10f, 6.585445079827190E-10f, 4.656612873077390E-10f, 3.292722539913600E-10f,
};
#endregion
void ReadSamples(int sfBits, int gr, int ch)
{
int region1Start, region2Start;
if (_blockSplitFlag[gr][ch] && _blockType[gr][ch] == 2)
{
region1Start = 36;
region2Start = 576;
}
else
{
region1Start = _sfBandIndexL[_regionAddress1[gr][ch] + 1];
region2Start = _sfBandIndexL[Math.Min(_regionAddress1[gr][ch] + _regionAddress2[gr][ch] + 2, 22)];
}
var part3end = _bitRes.BitsRead - sfBits + _part23Length[gr][ch];
int idx = 0, h = _tableSelect[gr][ch][0];
// bigvalues section
int bigValueCount = _bigValues[gr][ch] * 2;
float x, y;
while (idx < bigValueCount && idx < region1Start)
{
Huffman.Decode(_bitRes, h, out x, out y);
_samples[ch][idx] = Dequantize(idx, x, gr, ch); ++idx;
_samples[ch][idx] = Dequantize(idx, y, gr, ch); ++idx;
}
h = _tableSelect[gr][ch][1];
while (idx < bigValueCount && idx < region2Start)
{
Huffman.Decode(_bitRes, h, out x, out y);
_samples[ch][idx] = Dequantize(idx, x, gr, ch); ++idx;
_samples[ch][idx] = Dequantize(idx, y, gr, ch); ++idx;
}
h = _tableSelect[gr][ch][2];
while (idx < bigValueCount)
{
Huffman.Decode(_bitRes, h, out x, out y);
_samples[ch][idx] = Dequantize(idx, x, gr, ch); ++idx;
_samples[ch][idx] = Dequantize(idx, y, gr, ch); ++idx;
}
// count1 section
h = _count1TableSelect[gr][ch] + 32;
float v, w;
// - 3 to ensure that we never get an out of range exception
while (part3end > _bitRes.BitsRead && idx < SBLIMIT * SSLIMIT - 3)
{
Huffman.Decode(_bitRes, h, out x, out y, out v, out w);
_samples[ch][idx] = Dequantize(idx, v, gr, ch); ++idx;
_samples[ch][idx] = Dequantize(idx, w, gr, ch); ++idx;
_samples[ch][idx] = Dequantize(idx, x, gr, ch); ++idx;
_samples[ch][idx] = Dequantize(idx, y, gr, ch); ++idx;
}
// adjust the bit stream if we're off somehow
if (_bitRes.BitsRead > part3end)
{
_bitRes.RewindBits((int)(_bitRes.BitsRead - part3end));
idx -= 4;
if (idx < 0) idx = 0;
}
if (_bitRes.BitsRead < part3end)
{
_bitRes.SkipBits((int)(part3end - _bitRes.BitsRead));
}
// zero out the highest samples (defined as 0 in the standard)
if (idx < SBLIMIT * SSLIMIT)
{
Array.Clear(_samples[ch], idx, SBLIMIT * SSLIMIT + 3 - idx);
}
}
float Dequantize(int idx, float val, int gr, int ch)
{
if (val != 0f)
{
int cb, window;
if (_blockSplitFlag[gr][ch] && _blockType[gr][ch] == 2 && !(_mixedBlockFlag[gr][ch] && idx < _sfBandIndexL[8]))
{
// short / mixed short section
cb = _cbLookupS[idx];
window = _cbwLookupS[idx];
return val * _globalGain[gr][ch] * POW2_TAB[(int)(-2 * (_subblockGain[gr][ch][window] - (_scalefacScale[gr][ch] * _scalefac[ch][window][cb])))];
}
else
{
// long / mixed long section
cb = _cbLookupL[idx];
return val * _globalGain[gr][ch] * POW2_TAB[(int)(2 * _scalefacScale[gr][ch] * (_scalefac[ch][3][cb] + _preflag[gr][ch] * PRETAB[cb]))];
}
}
return 0f;
}
#endregion
#region Stereo
#region Variables
static readonly float[][] _isRatio = {
new float[] { 0f, 0.211324865405187f, 0.366025403784439f, 0.5f, 0.633974596215561f, 0.788675134594813f, 1f },
new float[] { 1f, 0.788675134594813f, 0.633974596215561f, 0.5f, 0.366025403784439f, 0.211324865405187f, 0f }
};
static readonly float[][][] _lsfRatio = { // sfc%2, ch, isPos
new float[][]
{
new float[] { 1f, 0.840896415256f, 1f, 0.707106781190391f, 1f, 0.594603557506209f, 1f, 0.500000000005436f, 1f, 0.420448207632571f, 1f, 0.353553390599039f, 1f, 0.297301778756337f, 1f, 0.250000000005436f, 1f, 0.210224103818571f, 1f, 0.176776695301441f, 1f, 0.148650889379784f, 1f, 0.125000000004077f, 1f, 0.105112051910428f, 1f, 0.0883883476516816f, 1f, 0.0743254446907002f, 1f, 0.0625000000027179f },
new float[] { 1f, 1f, 0.840896415256f, 1f, 0.707106781190391f, 1f, 0.594603557506209f, 1f, 0.500000000005436f, 1f, 0.420448207632571f, 1f, 0.353553390599039f, 1f, 0.297301778756337f, 1f, 0.250000000005436f, 1f, 0.210224103818571f, 1f, 0.176776695301441f, 1f, 0.148650889379784f, 1f, 0.125000000004077f, 1f, 0.105112051910428f, 1f, 0.0883883476516816f, 1f, 0.0743254446907002f, 1f },
},
new float[][]
{
new float[] { 1f, 0.707106781188f, 1f, 0.500000000002054f, 1f, 0.353553390595452f, 1f, 0.250000000002054f, 1f, 0.176776695298452f, 1f, 0.125000000001541f, 1f, 0.0883883476495893f, 1f, 0.062500000001027f, 1f, 0.0441941738249762f, 1f, 0.0312500000006419f, 1f, 0.0220970869125789f, 1f, 0.0156250000003851f, 1f, 0.0110485434563348f, 1f, 0.00781250000022466f, 1f, 0.00552427172819011f, 1f, 0.00390625000012838f },
new float[] { 1f, 1f, 0.707106781188f, 1f, 0.500000000002054f, 1f, 0.353553390595452f, 1f, 0.250000000002054f, 1f, 0.176776695298452f, 1f, 0.125000000001541f, 1f, 0.0883883476495893f, 1f, 0.062500000001027f, 1f, 0.0441941738249762f, 1f, 0.0312500000006419f, 1f, 0.0220970869125789f, 1f, 0.0156250000003851f, 1f, 0.0110485434563348f, 1f, 0.00781250000022466f, 1f, 0.00552427172819011f, 1f },
},
};
#endregion
void Stereo(MpegChannelMode channelMode, int chanModeExt, int gr, bool lsf)
{
// do the stereo decoding as needed... This really only applies in two cases:
// 1) Joint Stereo and one (or both) of the extensions are enabled, or
// 2) We're doing a downmix to mono
if (channelMode == MpegChannelMode.JointStereo && chanModeExt != 0)
{
var midSide = (chanModeExt & 0x2) == 2;
if ((chanModeExt & 0x1) == 1)
{
// do the intensity stereo processing
#region Common Processing
// find the highest sample index with a value in channel 1
// - now each step only has to start from there
int lastValueIdx = -1;
for (int i = SBLIMIT * SSLIMIT - (SBLIMIT + 1); i >= 0; i--)
{
if (_samples[1][i] != 0f)
{
lastValueIdx = i;
break;
}
}
// figure up which passes we'll need and for which ranges
int lEnd = -1, sStart = -1;
if (_blockSplitFlag[gr][0] && _blockType[gr][0] == 2)
{
if (_mixedBlockFlag[gr][0])
{
// 0 through 8 of long, then 3 through 12 of short
if (lastValueIdx < _sfBandIndexL[8])
{
lEnd = 8;
}
sStart = 3;
}
else
{
// 0 through 12 of short
sStart = 0;
}
}
else
{
// 0 through 21 of long
lEnd = 21;
}
#endregion
#region Long Processing
// long processing is far simpler than short... just process from the start of the scalefactor band after the last non-zero sample
// we also don't have to mess with "finding" again; it was done above
var sfb = 0;
if (lastValueIdx > -1)
{
sfb = _cbLookupL[lastValueIdx] + 1;
}
// make sure we do the mid/side processing on the lower bands (if needed)
if (sfb > 0 && sStart == -1)
{
if (midSide)
{
ApplyMidSide(0, _sfBandIndexL[sfb]);
}
else
{
ApplyFullStereo(0, _sfBandIndexL[sfb]);
}
}
// now process the intensity bands
for (; sfb < lEnd; sfb++)
{
var i = _sfBandIndexL[sfb];
var width = _sfBandIndexL[sfb + 1] - _sfBandIndexL[sfb];
var isPos = _scalefac[1][3][sfb];
if (isPos == 7)
{
if (midSide)
{
ApplyMidSide(i, width);
}
else
{
ApplyFullStereo(i, width);
}
}
else if (lsf)
{
ApplyLsfIStereo(i, width, isPos, _scalefacCompress[gr][0]);
}
else
{
ApplyIStereo(i, width, isPos);
}
}
if (sStart <= -1)
{
// do final long processing
var isPos = _scalefac[1][3][20];
if (isPos == 7)
{
if (midSide)
{
ApplyMidSide(_sfBandIndexL[21], 576 - _sfBandIndexL[21]);
}
else
{
ApplyFullStereo(_sfBandIndexL[21], 576 - _sfBandIndexL[21]);
}
}
else if (lsf)
{
ApplyLsfIStereo(_sfBandIndexL[21], 576 - _sfBandIndexL[21], isPos, _scalefacCompress[gr][0]);
}
else
{
ApplyIStereo(_sfBandIndexL[21], 576 - _sfBandIndexL[21], isPos);
}
}
#endregion
#region Short Processing
// short processing requires that each window be looked at separately... they are interleaved, so it gets really interesting...
// on the plus side, whichever window the {lastValueIdx} is in is already found... :)
else
{
// find where each window starts intensity processing
var sSfb = new int[] { -1, -1, -1 };
int window;
if (lastValueIdx > -1)
{
sfb = _cbLookupS[lastValueIdx];
window = _cbwLookupS[lastValueIdx];
sSfb[window] = sfb;
}
else
{
sfb = 12;
window = 3; // NB: 3 is correct!
}
window = (window - 1) % 3;
for (; sfb >= sStart && window >= 0; window = (window - 1) % 3)
{
if (sSfb[window] != -1)
{
if (sSfb[0] != -1 && sSfb[1] != -1 && sSfb[2] != -1)
{
break;
}
continue;
}
var width = _sfBandIndexS[sfb + 1] - _sfBandIndexS[sfb];
var i = _sfBandIndexS[sfb] * 3 + width * (window + 1);
while (--width >= -1)
{
if (_samples[1][--i] != 0f)
{
sSfb[window] = sfb;
break;
}
}
if (window == 0)
{
--sfb;
}
}
// now apply the intensity processing for each window & scalefactor band
sfb = sStart;
for (; sfb < 12; sfb++)
{
var width = _sfBandIndexS[sfb + 1] - _sfBandIndexS[sfb];
var i = _sfBandIndexS[sfb] * 3;
for (window = 0; window < 3; window++)
{
if (sfb > sSfb[window])
{
var isPos = _scalefac[1][window][sfb];
if (isPos == 7)
{
if (midSide)
{
ApplyMidSide(i, width);
}
else
{
ApplyFullStereo(i, width);
}
}
else if (lsf)
{
ApplyLsfIStereo(i, width, isPos, _scalefacCompress[gr][0]);
}
else
{
ApplyIStereo(i, width, isPos);
}
}
else if (midSide)
{
ApplyMidSide(i, width);
}
else
{
ApplyFullStereo(i, width);
}
i += width;
}
}
// do final short processing
var finalWidth = _sfBandIndexS[13] - _sfBandIndexS[12];
for (window = 0; window < 3; window++)
{
var isPos = _scalefac[1][window][11];
if (isPos == 7)
{
if (midSide)
{
ApplyMidSide(_sfBandIndexS[11] * 3 + finalWidth * window, finalWidth);
}
else
{
ApplyFullStereo(_sfBandIndexS[11] * 3 + finalWidth * window, finalWidth);
}
}
else if (lsf)
{
ApplyLsfIStereo(_sfBandIndexS[11] * 3 + finalWidth * window, finalWidth, isPos, _scalefacCompress[gr][0]);
}
else
{
ApplyIStereo(_sfBandIndexS[11] * 3 + finalWidth * window, finalWidth, isPos);
}
}
}
#endregion
}
else if (midSide)
{
// just do mid/side processing for everything
ApplyMidSide(0, SBLIMIT * SSLIMIT);
}
else
{
// this is a no-op most of the time
ApplyFullStereo(0, SSLIMIT * SBLIMIT);
}
}
else if (_channels != 1)
{
// this is a no-op most of the time
ApplyFullStereo(0, SSLIMIT * SBLIMIT);
}
}
void ApplyIStereo(int i, int sb, int isPos)
{
if (StereoMode == StereoMode.DownmixToMono)
{
for (; sb > 0; sb--, i++)
{
_samples[0][i] /= 2f; // scale appropriately
}
}
else
{
var ratio0 = _isRatio[0][isPos];
var ratio1 = _isRatio[1][isPos];
for (; sb > 0; sb--, i++)
{
_samples[1][i] = _samples[0][i] * ratio1;
_samples[0][i] *= ratio0;
}
}
}
void ApplyLsfIStereo(int i, int sb, int isPos, int scalefacCompress)
{
var k0 = _lsfRatio[scalefacCompress % 1][isPos][0];
var k1 = _lsfRatio[scalefacCompress % 1][isPos][1];
if (StereoMode == NLayer.StereoMode.DownmixToMono)
{
var ratio = 1 / (k0 + k1);
for (; sb > 0; sb--, i++)
{
_samples[0][i] *= ratio;
}
}
else
{
for (; sb > 0; sb--, i++)
{
_samples[1][i] = _samples[0][i] * k1;
_samples[0][i] *= k0;
}
}
}
void ApplyMidSide(int i, int sb)
{
if (StereoMode == StereoMode.DownmixToMono)
{
for (; sb > 0; sb--, i++)
{
_samples[0][i] *= 0.707106781f; // scale appropriately
}
}
else
{
for (; sb > 0; sb--, i++)
{
// apply the mid/side
var a = _samples[0][i];
var b = _samples[1][i];
_samples[0][i] = (a + b) * 0.707106781f;
_samples[1][i] = (a - b) * 0.707106781f;
}
}
}
void ApplyFullStereo(int i, int sb)
{
if (StereoMode == NLayer.StereoMode.DownmixToMono)
{
for (; sb > 0; sb--, i++)
{
_samples[0][i] = (_samples[0][i] + _samples[1][i]) / 2f;
}
}
}
#endregion
#region Reorder
#region Variables
float[] _reorderBuf = new float[SBLIMIT * SSLIMIT];
#endregion
void Reorder(float[] buf, bool mixedBlock)
{
// reorder into _reorderBuf, then copy back
int sfb = 0;
if (mixedBlock)
{
// mixed... copy the first two bands and reorder the rest
Array.Copy(buf, 0, _reorderBuf, 0, SSLIMIT * 2);
sfb = 3;
}
while (sfb < 13)
{
int sfb_start = _sfBandIndexS[sfb];
int sfb_lines = _sfBandIndexS[sfb + 1] - sfb_start;
for (int window = 0; window < 3; window++)
{
for (int freq = 0; freq < sfb_lines; freq++)
{
var src_line = sfb_start * 3 + window * sfb_lines + freq;
var des_line = (sfb_start * 3) + window + (freq * 3);
_reorderBuf[des_line] = buf[src_line];
}
}
++sfb;
}
Array.Copy(_reorderBuf, buf, SSLIMIT * SBLIMIT);
}
#endregion
#region Anti-Alias
#region Variables
static readonly float[] _scs = {
0.85749292571254400f, 0.88174199731770500f, 0.94962864910273300f, 0.98331459249179000f,
0.99551781606758600f, 0.99916055817814800f, 0.99989919524444700f, 0.99999315507028000f,
};
static readonly float[] _sca = {
-0.51449575542752700f, -0.47173196856497200f, -0.31337745420390200f, -0.18191319961098100f,
-0.09457419252642070f, -0.04096558288530410f, -0.01419856857247120f, -0.00369997467376004f,
};
#endregion
void AntiAlias(float[] buf, bool mixedBlock)
{
int sblim;
if (mixedBlock)
{
sblim = 1;
}
else
{
sblim = SBLIMIT - 1;
}
for (int sb = 0, offset = 0; sb < sblim; sb++, offset += SSLIMIT)
{
for (int ss = 0, buOfs = offset + SSLIMIT - 1, bdOfs = offset + SSLIMIT; ss < 8; ss++, buOfs--, bdOfs++)
{
var bu = buf[buOfs];
var bd = buf[bdOfs];
buf[buOfs] = (bu * _scs[ss]) - (bd * _sca[ss]);
buf[bdOfs] = (bd * _scs[ss]) + (bu * _sca[ss]);
}
}
}
#endregion
#region Frequency Inversion
void FrequencyInversion(float[] buf)
{
for (int ss = 1; ss < SSLIMIT; ss += 2)
{
for (int sb = 1; sb < SBLIMIT; sb += 2)
{
buf[sb * SSLIMIT + ss] = -buf[sb * SSLIMIT + ss];
}
}
}
#endregion
#region Inverse Polyphase
#region Variables
float[] _polyPhase = new float[SBLIMIT];
#endregion
// Layer III interleaves the samples, so we have to make them linear again
void InversePolyphase(float[] buf, int ch, int ofs, float[] outBuf)
{
for (int ss = 0; ss < SSLIMIT; ss++, ofs += SBLIMIT)
{
for (int sb = 0; sb < SBLIMIT; sb++)
{
_polyPhase[sb] = buf[sb * SSLIMIT + ss];
}
base.InversePolyPhase(ch, _polyPhase);
Array.Copy(_polyPhase, 0, outBuf, ofs, SBLIMIT);
}
}
#endregion
}
}