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

398 lines
17 KiB
C#

/*
* NLayer - A C# MPEG1/2/2.5 audio decoder
*
*/
using System;
namespace NLayer.Decoder
{
// Layers I & II are basically identical... Layer II adds sample grouping, per subband allocation schemes, and granules
// Because of this fact, we can use the same decoder for both
abstract class LayerIIDecoderBase : LayerDecoderBase
{
protected const int SSLIMIT = 12;
static protected bool GetCRC(MpegFrame frame, int[] rateTable, int[][] allocLookupTable, bool readScfsiBits, ref uint crc)
{
// ugh... we basically have to re-implement the allocation logic here.
// keep up with how many active subbands we need to read selection info for
var scfsiBits = 0;
// only read as many subbands as we actually need; pay attention to the intensity stereo subbands
var subbandCount = rateTable.Length;
var jsbound = subbandCount;
if (frame.ChannelMode == MpegChannelMode.JointStereo)
{
jsbound = frame.ChannelModeExtension * 4 + 4;
}
// read the full stereo subbands
var channels = frame.ChannelMode == MpegChannelMode.Mono ? 1 : 2;
var sb = 0;
for (; sb < jsbound; sb++)
{
var bits = allocLookupTable[rateTable[sb]][0];
for (int ch = 0; ch < channels; ch++)
{
var alloc = frame.ReadBits(bits);
if (alloc > 0) scfsiBits += 2;
MpegFrame.UpdateCRC(alloc, bits, ref crc);
}
}
// read the intensity stereo subbands
for (; sb < subbandCount; sb++)
{
var bits = allocLookupTable[rateTable[sb]][0];
var alloc = frame.ReadBits(bits);
if (alloc > 0) scfsiBits += channels * 2;
MpegFrame.UpdateCRC(alloc, bits, ref crc);
}
// finally, read the scalefac selection bits
if (readScfsiBits)
{
while (scfsiBits >= 2)
{
MpegFrame.UpdateCRC(frame.ReadBits(2), 2, ref crc);
scfsiBits -= 2;
}
}
return true;
}
#region Lookup Tables
// this is from the formula: C = 1 / (1 / (1 << (Bits / 2 + Bits % 2 - 1)) + .5f)
// index by real bits (Bits / 2 + Bits % 2 - 1)
static readonly float[] _groupedC = { 0, 0, 1.33333333333f, 1.60000000000f, 1.77777777777f };
// these are always -0.5
// index by real bits (Bits / 2 + Bits % 2 - 1)
static readonly float[] _groupedD = { 0, 0, -0.5f, -0.5f, -0.5f };
// this is from the formula: 1 / (1 - (1f / (1 << Bits)))
// index by bits
static readonly float[] _C = {
0.00000000000f,
0.00000000000f, 1.33333333333f, 1.14285714286f, 1.06666666666f, 1.03225806452f, 1.01587301587f, 1.00787401575f, 1.00392156863f,
1.00195694716f, 1.00097751711f, 1.00048851979f, 1.00024420024f, 1.00012208522f, 1.00006103888f, 1.00003051851f, 1.00001525902f
};
// this is from the formula: 1f / (1 << Bits - 1) - 1
// index by bits
static readonly float[] _D = {
0.00000000000f - 0f,
0.00000000000f - 0f, 0.50000000000f - 1f, 0.25000000000f - 1f, 0.12500000000f - 1f, 0.062500000000f - 1f, 0.03125000000f - 1f, 0.01562500000f - 1f, 0.00781250000f - 1f,
0.00390625000f - 1f, 0.00195312500f - 1f, 0.00097656250f - 1f, 0.00048828125f - 1f, 0.000244140630f - 1f, 0.00012207031f - 1f, 0.00006103516f - 1f, 0.00003051758f - 1f
};
// this is from a (really annoying) formula:
// x = Math.Pow(4, 1 / ((2 << (idx % 3) + 1) - (idx % 3))) / (1 << (idx / 3))
// Basically...
// [0] = Math.Pow(4, 1 / 2), [1] = Math.Pow(4, 1 / 3), [2] = Math.Pow(4, 1 / 6)
// For every remaining element, calculate (in order): [idx] = [idx - 3] / 2
static readonly float[] _denormalMultiplier = {
2.00000000000000f, 1.58740105196820f, 1.25992104989487f, 1.00000000000000f, 0.79370052598410f, 0.62996052494744f, 0.50000000000000f, 0.39685026299205f,
0.31498026247372f, 0.25000000000000f, 0.19842513149602f, 0.15749013123686f, 0.12500000000000f, 0.09921256574801f, 0.07874506561843f, 0.06250000000000f,
0.04960628287401f, 0.03937253280921f, 0.03125000000000f, 0.02480314143700f, 0.01968626640461f, 0.01562500000000f, 0.01240157071850f, 0.00984313320230f,
0.00781250000000f, 0.00620078535925f, 0.00492156660115f, 0.00390625000000f, 0.00310039267963f, 0.00246078330058f, 0.00195312500000f, 0.00155019633981f,
0.00123039165029f, 0.00097656250000f, 0.00077509816991f, 0.00061519582514f, 0.00048828125000f, 0.00038754908495f, 0.00030759791257f, 0.00024414062500f,
0.00019377454248f, 0.00015379895629f, 0.00012207031250f, 0.00009688727124f, 0.00007689947814f, 0.00006103515625f, 0.00004844363562f, 0.00003844973907f,
0.00003051757813f, 0.00002422181781f, 0.00001922486954f, 0.00001525878906f, 0.00001211090890f, 0.00000961243477f, 0.00000762939453f, 0.00000605545445f,
0.00000480621738f, 0.00000381469727f, 0.00000302772723f, 0.00000240310869f, 0.00000190734863f, 0.00000151386361f, 0.00000120155435f, 0.00000095367432f
};
#endregion
int _channels, _jsbound, _granuleCount;
int[][] _allocLookupTable, _scfsi, _samples;
int[][][] _scalefac;
float[] _polyPhaseBuf;
int[][] _allocation;
protected LayerIIDecoderBase(int[][] allocLookupTable, int granuleCount)
: base()
{
_allocLookupTable = allocLookupTable;
_granuleCount = granuleCount;
_allocation = new int[][] { new int[SBLIMIT], new int[SBLIMIT] };
_scfsi = new int[][] { new int[SBLIMIT], new int[SBLIMIT] };
_samples = new int[][] { new int[SBLIMIT * SSLIMIT * _granuleCount], new int[SBLIMIT * SSLIMIT * _granuleCount] };
// NB: ReadScaleFactors(...) requires all three granules, even in Layer I
_scalefac = new int[][][] { new int[3][], new int[3][] };
for (int i = 0; i < 3; i++)
{
_scalefac[0][i] = new int[SBLIMIT];
_scalefac[1][i] = new int[SBLIMIT];
}
_polyPhaseBuf = new float[SBLIMIT];
}
internal override int DecodeFrame(IMpegFrame frame, float[] ch0, float[] ch1)
{
InitFrame(frame);
var rateTable = GetRateTable(frame);
ReadAllocation(frame, rateTable);
for (int i = 0; i < _scfsi[0].Length; i++)
{
// Since Layer II has to know which subbands have energy, we use the "Layer I valid" selection to mark that energy is present.
// That way Layer I doesn't have to do anything else.
_scfsi[0][i] = _allocation[0][i] != 0 ? 2 : -1;
_scfsi[1][i] = _allocation[1][i] != 0 ? 2 : -1;
}
ReadScaleFactorSelection(frame, _scfsi, _channels);
ReadScaleFactors(frame);
ReadSamples(frame);
return DecodeSamples(ch0, ch1);
}
// this just reads the channel mode and set a few flags
void InitFrame(IMpegFrame frame)
{
switch (frame.ChannelMode)
{
case MpegChannelMode.Mono:
_channels = 1;
_jsbound = SBLIMIT;
break;
case MpegChannelMode.JointStereo:
_channels = 2;
_jsbound = frame.ChannelModeExtension * 4 + 4;
break;
default:
_channels = 2;
_jsbound = SBLIMIT;
break;
}
}
abstract protected int[] GetRateTable(IMpegFrame frame);
void ReadAllocation(IMpegFrame frame, int[] rateTable)
{
var _subBandCount = rateTable.Length;
if (_jsbound > _subBandCount) _jsbound = _subBandCount;
Array.Clear(_allocation[0], 0, SBLIMIT);
Array.Clear(_allocation[1], 0, SBLIMIT);
int sb = 0;
for (; sb < _jsbound; sb++)
{
var table = _allocLookupTable[rateTable[sb]];
var bits = table[0];
for (int ch = 0; ch < _channels; ch++)
{
_allocation[ch][sb] = table[frame.ReadBits(bits) + 1];
}
}
for (; sb < _subBandCount; sb++)
{
var table = _allocLookupTable[rateTable[sb]];
_allocation[0][sb] = _allocation[1][sb] = table[frame.ReadBits(table[0]) + 1];
}
}
abstract protected void ReadScaleFactorSelection(IMpegFrame frame, int[][] scfsi, int channels);
void ReadScaleFactors(IMpegFrame frame)
{
for (int sb = 0; sb < SBLIMIT; sb++)
{
for (int ch = 0; ch < _channels; ch++)
{
switch (_scfsi[ch][sb])
{
case 0:
// all three
_scalefac[ch][0][sb] = frame.ReadBits(6);
_scalefac[ch][1][sb] = frame.ReadBits(6);
_scalefac[ch][2][sb] = frame.ReadBits(6);
break;
case 1:
// only two (2 = 1)
_scalefac[ch][0][sb] =
_scalefac[ch][1][sb] = frame.ReadBits(6);
_scalefac[ch][2][sb] = frame.ReadBits(6);
break;
case 2:
// only one (3 = 2 = 1)
_scalefac[ch][0][sb] =
_scalefac[ch][1][sb] =
_scalefac[ch][2][sb] = frame.ReadBits(6);
break;
case 3:
// only two (3 = 2)
_scalefac[ch][0][sb] = frame.ReadBits(6);
_scalefac[ch][1][sb] =
_scalefac[ch][2][sb] = frame.ReadBits(6);
break;
default:
// none
_scalefac[ch][0][sb] = 63;
_scalefac[ch][1][sb] = 63;
_scalefac[ch][2][sb] = 63;
break;
}
}
}
}
void ReadSamples(IMpegFrame frame)
{
// load in all the data for this frame (1152 samples in this case)
// NB: we flatten these into output order
for (int ss = 0, idx = 0; ss < SSLIMIT; ss++, idx += SBLIMIT * (_granuleCount - 1))
{
for (int sb = 0; sb < SBLIMIT; sb++, idx++)
{
for (int ch = 0; ch < _channels; ch++)
{
if (ch == 0 || sb < _jsbound)
{
var alloc = _allocation[ch][sb];
if (alloc != 0)
{
if (alloc < 0)
{
// grouping (Layer II only, so we don't have to play with the granule count)
var val = frame.ReadBits(-alloc);
var levels = (1 << (-alloc / 2 + -alloc % 2 - 1)) + 1;
_samples[ch][idx] = val % levels;
val /= levels;
_samples[ch][idx + SBLIMIT] = val % levels;
_samples[ch][idx + SBLIMIT * 2] = val / levels;
}
else
{
// non-grouping
for (int gr = 0; gr < _granuleCount; gr++)
{
_samples[ch][idx + SBLIMIT * gr] = frame.ReadBits(alloc);
}
}
}
else
{
// no energy... zero out the samples
for (int gr = 0; gr < _granuleCount; gr++)
{
_samples[ch][idx + SBLIMIT * gr] = 0;
}
}
}
else
{
// copy chan 0 to chan 1
for (int gr = 0; gr < _granuleCount; gr++)
{
_samples[1][idx + SBLIMIT * gr] = _samples[0][idx + SBLIMIT * gr];
}
}
}
}
}
}
int DecodeSamples(float[] ch0, float[] ch1)
{
// do our stereo mode setup
var chanBufs = new float[2][];
var startChannel = 0;
var endChannel = _channels - 1;
if (_channels == 1 || StereoMode == StereoMode.LeftOnly)
{
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 or StereoMode.DownmixToMono
{
chanBufs[0] = ch0;
chanBufs[1] = ch1;
}
int idx = 0;
for (int ch = startChannel; ch <= endChannel; ch++)
{
idx = 0;
for (int gr = 0; gr < _granuleCount; gr++)
{
for (int ss = 0; ss < SSLIMIT; ss++)
{
for (int sb = 0; sb < SBLIMIT; sb++, idx++)
{
// do the dequant and the denorm; output to _polyPhaseBuf
// NB: Layers I & II use the same algorithm here... Grouping changes the bit counts, but doesn't change the algo
// - Up to 65534 possible values (65535 does not appear to be usable)
// - All values can be handled with 16-bit logic as long as the correct C and D constants are used
// - Make sure to normalize each sample to 16 bits!
var alloc = _allocation[ch][sb];
if (alloc != 0)
{
float[] c, d;
if (alloc < 0)
{
alloc = -alloc / 2 + -alloc % 2 - 1;
c = _groupedC;
d = _groupedD;
}
else
{
c = _C;
d = _D;
}
// read sample; normalize, scale & center to [-0.999984741f..0.999984741f]; apply scalefactor
_polyPhaseBuf[sb] = c[alloc] * ((_samples[ch][idx] << (16 - alloc)) / 32768f + d[alloc]) * _denormalMultiplier[_scalefac[ch][gr][sb]];
}
else
{
// no transmitted energy...
_polyPhaseBuf[sb] = 0f;
}
}
// do the polyphase output for this channel, section, and granule
base.InversePolyPhase(ch, _polyPhaseBuf);
Array.Copy(_polyPhaseBuf, 0, chanBufs[ch], idx - SBLIMIT, SBLIMIT);
}
}
}
if (_channels == 2 && StereoMode == NLayer.StereoMode.DownmixToMono)
{
for (int i = 0; i < idx; i++)
{
ch0[i] = (ch0[i] + ch1[i]) / 2;
}
}
return idx;
}
}
}