/* * 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; } } }