732 lines
26 KiB
C#
732 lines
26 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.IO;
|
|
using UnityEngine;
|
|
using static ClHcaSharp.Constants;
|
|
using static ClHcaSharp.Header;
|
|
using static ClHcaSharp.Tables;
|
|
|
|
namespace ClHcaSharp
|
|
{
|
|
public class HcaDecoder
|
|
{
|
|
private readonly HcaContext hca;
|
|
|
|
public HcaDecoder(Stream hcaStream, ulong key)
|
|
{
|
|
hca = new HcaContext();
|
|
|
|
InitializeTables();
|
|
|
|
DecodeHeader(hca, hcaStream);
|
|
SetKey(key);
|
|
}
|
|
|
|
public HcaInfo GetInfo()
|
|
{
|
|
HcaInfo info = new HcaInfo()
|
|
{
|
|
Version = hca.Version,
|
|
HeaderSize = hca.HeaderSize,
|
|
SamplingRate = hca.SampleRate,
|
|
ChannelCount = hca.ChannelCount,
|
|
BlockSize = hca.FrameSize,
|
|
BlockCount = hca.FrameCount,
|
|
EncoderDelay = hca.EncoderDelay,
|
|
EncoderPadding = hca.EncoderPadding,
|
|
LoopEnabled = hca.LoopFlag,
|
|
LoopStartBlock = hca.LoopStartFrame,
|
|
LoopEndBlock = hca.LoopEndFrame,
|
|
LoopStartDelay = hca.LoopStartDelay,
|
|
LoopEndPadding = hca.LoopEndPadding,
|
|
SamplesPerBlock = SamplesPerFrame,
|
|
Comment = hca.Comment,
|
|
EncryptionEnabled = hca.CiphType == 56
|
|
};
|
|
return info;
|
|
}
|
|
|
|
public void SetKey(ulong key)
|
|
{
|
|
hca.KeyCode = key;
|
|
hca.CipherTable = Cipher.Init(hca.CiphType, hca.KeyCode);
|
|
}
|
|
|
|
public int TestBlock(byte[] data)
|
|
{
|
|
const int frameSamples = Subframes * SamplesPerSubframe;
|
|
const float scale = 32768.0f;
|
|
|
|
int status;
|
|
int clips = 0;
|
|
int blanks = 0;
|
|
int[] channelBlanks = new int[MaxChannels];
|
|
|
|
byte[] buffer = data;
|
|
|
|
{
|
|
bool isEmpty = true;
|
|
|
|
for (int i = 0x02; i < data.Length - 0x02; i++)
|
|
{
|
|
if (buffer[i] != 0)
|
|
{
|
|
isEmpty = false;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (isEmpty) return 0;
|
|
}
|
|
|
|
status = DecodeBlockUnpack(data);
|
|
if (status < 0) return -1;
|
|
|
|
{
|
|
int bitsMax = hca.FrameSize * 8;
|
|
int byteStart;
|
|
|
|
if (status + 14 > bitsMax)
|
|
return -1;
|
|
//throw new Exception("BitReader error.");
|
|
|
|
byteStart = (status / 8) + (status % 8 > 0 ? 0x01 : 0);
|
|
|
|
for (int i = byteStart; i < hca.FrameSize - 0x02; i++)
|
|
{
|
|
if (buffer[i] != 0)
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
DecodeBlockTransform();
|
|
for (int ch = 0; ch < hca.ChannelCount; ch++)
|
|
{
|
|
for (int sf = 0; sf < Subframes; sf++)
|
|
{
|
|
for (int s = 0; s < SamplesPerSubframe; s++)
|
|
{
|
|
float fSample = hca.Channels[ch].Wave[sf][s];
|
|
|
|
if (fSample > 1.0f || fSample < -1.0f)
|
|
clips++;
|
|
else
|
|
{
|
|
int pSample = (int)(fSample * scale);
|
|
if (pSample == 0 || pSample == -1)
|
|
{
|
|
blanks++;
|
|
channelBlanks[ch]++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (clips == 1)
|
|
clips++;
|
|
if (clips > 1)
|
|
return clips;
|
|
|
|
if (blanks == hca.ChannelCount * frameSamples)
|
|
return 0;
|
|
|
|
if (hca.ChannelCount >= 2)
|
|
{
|
|
if (channelBlanks[0] == frameSamples && channelBlanks[1] != frameSamples)
|
|
return 3;
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
public void ReadSamples16(short[][] samples)
|
|
{
|
|
for (int subframe = 0; subframe < Subframes; subframe++)
|
|
{
|
|
for (int sample = 0; sample < SamplesPerSubframe; sample++)
|
|
{
|
|
for (int channel = 0; channel < hca.ChannelCount; channel++)
|
|
{
|
|
float f = hca.Channels[channel].Wave[subframe][sample];
|
|
int sInt = (int)(32768 * f);
|
|
if (sInt > 32767)
|
|
sInt = 32767;
|
|
else if (sInt < -32767)
|
|
sInt = -32767;
|
|
samples[channel][(SamplesPerSubframe * subframe) + sample] = (short)sInt;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
public void ReadSamples16(short[] samples)
|
|
{
|
|
int sampleIndex = 0;
|
|
for (int subframe = 0; subframe < Subframes; subframe++)
|
|
{
|
|
for (int sample = 0; sample < SamplesPerSubframe; sample++)
|
|
{
|
|
for (int channel = 0; channel < hca.ChannelCount; channel++)
|
|
{
|
|
float f = hca.Channels[channel].Wave[subframe][sample];
|
|
int sInt = (int)(32768 * f);
|
|
if (sInt > 32767)
|
|
sInt = 32767;
|
|
else if (sInt < -32767)
|
|
sInt = -32767;
|
|
samples[sampleIndex++] = (short)sInt;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
public float[] ReadSamples16()
|
|
{
|
|
List<float> data = new List<float>();
|
|
for (int subframe = 0; subframe < Subframes; subframe++)
|
|
{
|
|
for (int sample = 0; sample < SamplesPerSubframe; sample++)
|
|
{
|
|
for (int channel = 0; channel < hca.ChannelCount; channel++)
|
|
{
|
|
float f = hca.Channels[channel].Wave[subframe][sample];
|
|
data.Add(f);
|
|
}
|
|
}
|
|
}
|
|
return data.ToArray();
|
|
}
|
|
|
|
public void DecodeReset()
|
|
{
|
|
if (hca != null)
|
|
{
|
|
hca.Random = DefaultRandom;
|
|
|
|
for (int i = 0; i < hca.ChannelCount; i++)
|
|
{
|
|
Channel channel = hca.Channels[i];
|
|
|
|
Array.Clear(channel.ImdctPrevious, 0, channel.ImdctPrevious.Length);
|
|
}
|
|
}
|
|
}
|
|
|
|
public int DecodeBlock(byte[] data)
|
|
{
|
|
int result = DecodeBlockUnpack(data);
|
|
|
|
if (result < 0) return result;
|
|
|
|
DecodeBlockTransform();
|
|
|
|
return result;
|
|
}
|
|
|
|
private int DecodeBlockUnpack(byte[] data)
|
|
{
|
|
if (data.Length < hca.FrameSize)
|
|
throw new ArgumentException("Data is less than expected frame size.");
|
|
|
|
BitReader bitReader = new BitReader(data);
|
|
|
|
ushort sync = (ushort)bitReader.Read(16);
|
|
if (sync != 0xFFFF) throw new InvalidDataException("Sync error.");
|
|
|
|
if (Crc.Crc16Checksum(data) > 0) throw new InvalidDataException("Checksum error.");
|
|
|
|
Cipher.Decrypt(hca.CipherTable, data);
|
|
|
|
int frameAcceptableNoiseLevel = bitReader.Read(9);
|
|
int frameEvaluationBoundary = bitReader.Read(7);
|
|
|
|
int packedNoiseLevel = (frameAcceptableNoiseLevel << 8) - frameEvaluationBoundary;
|
|
|
|
for (int channel = 0; channel < hca.ChannelCount; channel++)
|
|
{
|
|
UnpackScaleFactors(hca.Channels[channel], bitReader, hca.HfrGroupCount, hca.Version);
|
|
UnpackIntensity(hca.Channels[channel], bitReader, hca.HfrGroupCount, hca.Version);
|
|
CalculateResolution(hca.Channels[channel], packedNoiseLevel, hca.AthCurve, hca.MinResolution, hca.MaxResolution);
|
|
CalculateGain(hca.Channels[channel]);
|
|
}
|
|
|
|
for (int subframe = 0; subframe < Subframes; subframe++)
|
|
{
|
|
for (int channel = 0; channel < hca.ChannelCount; channel++)
|
|
{
|
|
DequantizeCoefficients(hca.Channels[channel], bitReader, subframe);
|
|
}
|
|
}
|
|
|
|
return bitReader.Bit;
|
|
}
|
|
|
|
private void DecodeBlockTransform()
|
|
{
|
|
for (int subframe = 0; subframe < Subframes; subframe++)
|
|
{
|
|
for (int channel = 0; channel < hca.ChannelCount; channel++)
|
|
{
|
|
int random = hca.Random;
|
|
ReconstructNoise(hca.Channels[channel], hca.MinResolution, hca.MsStereo, ref random, subframe);
|
|
hca.Random = random;
|
|
ReconstructHighFrequency(hca.Channels[channel], hca.HfrGroupCount, hca.BandsPerHfrGroup,
|
|
hca.StereoBandCount, hca.BaseBandCount, hca.TotalBandCount, hca.Version, subframe);
|
|
}
|
|
|
|
if (hca.StereoBandCount > 0)
|
|
{
|
|
for (int ch = 0; ch < hca.ChannelCount - 1; ch++)
|
|
{
|
|
ApplyIntensityStereo(hca.Channels, ch * 2, subframe, hca.BaseBandCount, hca.TotalBandCount);
|
|
ApplyMsStereo(hca.Channels, ch * 2, hca.MsStereo, hca.BaseBandCount, hca.TotalBandCount, subframe);
|
|
}
|
|
}
|
|
|
|
for (int channel = 0; channel < hca.ChannelCount; channel++)
|
|
{
|
|
ImdctTransform(hca.Channels[channel], subframe);
|
|
}
|
|
}
|
|
}
|
|
|
|
private static void UnpackScaleFactors(Channel channel, BitReader bitReader, int hfrGroupCount, int version)
|
|
{
|
|
int csCount = channel.CodedCount;
|
|
int extraCount;
|
|
byte deltaBits = (byte)bitReader.Read(3);
|
|
|
|
if (channel.Type == ChannelType.StereoSecondary || hfrGroupCount <= 0 || version <= Version200)
|
|
extraCount = 0;
|
|
else
|
|
{
|
|
extraCount = hfrGroupCount;
|
|
csCount += extraCount;
|
|
|
|
if (csCount > SamplesPerSubframe)
|
|
return;
|
|
//throw new InvalidDataException("Invalid scale count.");
|
|
}
|
|
|
|
if (deltaBits >= 6)
|
|
{
|
|
for (int i = 0; i < csCount; i++)
|
|
{
|
|
channel.ScaleFactors[i] = (byte)bitReader.Read(6);
|
|
}
|
|
}
|
|
else if (deltaBits > 0)
|
|
{
|
|
byte expectedDelta = (byte)((1 << deltaBits) - 1);
|
|
byte value = (byte)bitReader.Read(6);
|
|
|
|
channel.ScaleFactors[0] = value;
|
|
for (int i = 1; i < csCount; i++)
|
|
{
|
|
byte delta = (byte)bitReader.Read(deltaBits);
|
|
|
|
if (delta == expectedDelta)
|
|
value = (byte)bitReader.Read(6);
|
|
else
|
|
{
|
|
int scaleFactorTest = value + (delta - (expectedDelta >> 1));
|
|
if (scaleFactorTest < 0 || scaleFactorTest >= 64)
|
|
return;
|
|
//throw new InvalidDataException("Invalid scale factor.");
|
|
|
|
value = (byte)(value - (expectedDelta >> 1) + delta);
|
|
value = (byte)(value & 0x3F);
|
|
}
|
|
|
|
channel.ScaleFactors[i] = value;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (int i = 0; i < SamplesPerSubframe; i++)
|
|
{
|
|
channel.ScaleFactors[i] = 0;
|
|
}
|
|
}
|
|
|
|
for (int i = 0; i < extraCount; i++)
|
|
{
|
|
channel.ScaleFactors[SamplesPerSubframe - 1 - i] = channel.ScaleFactors[csCount - i];
|
|
}
|
|
}
|
|
|
|
private static void UnpackIntensity(Channel channel, BitReader bitReader, int hfrGroupCount, int version)
|
|
{
|
|
if (channel.Type == ChannelType.StereoSecondary)
|
|
{
|
|
if (version <= Version200)
|
|
{
|
|
byte value = (byte)bitReader.Peek(4);
|
|
|
|
channel.Intensity[0] = value;
|
|
if (value < 15)
|
|
{
|
|
bitReader.Skip(4);
|
|
for (int i = 1; i < Subframes; i++)
|
|
{
|
|
channel.Intensity[i] = (byte)bitReader.Read(4);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
byte value = (byte)bitReader.Peek(4);
|
|
|
|
if (value < 15)
|
|
{
|
|
bitReader.Skip(4);
|
|
|
|
byte deltaBits = (byte)bitReader.Read(2);
|
|
|
|
channel.Intensity[0] = value;
|
|
if (deltaBits == 3)
|
|
{
|
|
for (int i = 1; i < Subframes; i++)
|
|
{
|
|
channel.Intensity[i] = (byte)bitReader.Read(4);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
byte bMax = (byte)((2 << deltaBits) - 1);
|
|
byte bits = (byte)(deltaBits + 1);
|
|
|
|
for (int i = 1; i < Subframes; i++)
|
|
{
|
|
byte delta = (byte)bitReader.Read(bits);
|
|
if (delta == bMax)
|
|
value = (byte)bitReader.Read(4);
|
|
else
|
|
{
|
|
value = (byte)(value - (bMax >> 1) + delta);
|
|
if (value > 15)
|
|
return;
|
|
//throw new InvalidDataException("Intensity value out of range.");
|
|
}
|
|
|
|
channel.Intensity[i] = value;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
bitReader.Skip(4);
|
|
for (int i = 0; i < Subframes; i++)
|
|
{
|
|
channel.Intensity[i] = 7;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (version <= Version200)
|
|
{
|
|
byte[] hfrScales = channel.ScaleFactors;
|
|
int hfrScalesOffset = 128 - hfrGroupCount;
|
|
|
|
for (int i = 0; i < hfrGroupCount; i++)
|
|
{
|
|
hfrScales[hfrScalesOffset + i] = (byte)bitReader.Read(6);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private static void CalculateResolution(Channel channel, int packedNoiseLevel, byte[] athCurve, int minResolution, int maxResolution)
|
|
{
|
|
int crCount = channel.CodedCount;
|
|
int noiseCount = 0;
|
|
int validCount = 0;
|
|
|
|
for (int i = 0; i < crCount; i++)
|
|
{
|
|
byte newResolution = 0;
|
|
byte scaleFactor = channel.ScaleFactors[i];
|
|
|
|
if (scaleFactor > 0)
|
|
{
|
|
int noiseLevel = athCurve[i] + ((packedNoiseLevel + i) >> 8);
|
|
int curvePosition = noiseLevel + 1 - ((5 * scaleFactor) >> 1);
|
|
|
|
if (curvePosition < 0)
|
|
newResolution = 15;
|
|
else if (curvePosition <= 65)
|
|
newResolution = InvertTable[curvePosition];
|
|
else
|
|
newResolution = 0;
|
|
|
|
if (newResolution > maxResolution)
|
|
newResolution = (byte)maxResolution;
|
|
else if (newResolution < minResolution)
|
|
newResolution = (byte)minResolution;
|
|
|
|
if (newResolution < 1)
|
|
{
|
|
channel.Noises[noiseCount] = (byte)i;
|
|
noiseCount++;
|
|
}
|
|
else
|
|
{
|
|
channel.Noises[SamplesPerSubframe - 1 - validCount] = (byte)i;
|
|
validCount++;
|
|
}
|
|
}
|
|
channel.Resolution[i] = newResolution;
|
|
}
|
|
|
|
channel.NoiseCount = noiseCount;
|
|
channel.ValidCount = validCount;
|
|
|
|
Array.Clear(channel.Resolution, crCount, SamplesPerSubframe - crCount);
|
|
}
|
|
|
|
private static void CalculateGain(Channel channel)
|
|
{
|
|
int cgCount = channel.CodedCount;
|
|
for (int i = 0; i < cgCount; i++)
|
|
{
|
|
float scaleFactorScale = DequantizerScalingTable[channel.ScaleFactors[i]];
|
|
float resolutionScale = DequantizerRangeTable[channel.Resolution[i]];
|
|
channel.Gain[i] = scaleFactorScale * resolutionScale;
|
|
}
|
|
}
|
|
|
|
private static void DequantizeCoefficients(Channel channel, BitReader bitReader, int subframe)
|
|
{
|
|
int ccCount = channel.CodedCount;
|
|
|
|
for (int i = 0; i < ccCount; i++)
|
|
{
|
|
float qc;
|
|
byte resolution = channel.Resolution[i];
|
|
byte bits = MaxBitTable[resolution];
|
|
int code = bitReader.Read(bits);
|
|
|
|
if (resolution > 7)
|
|
{
|
|
int signedCode = (1 - ((code & 1) << 1)) * (code >> 1);
|
|
if (signedCode == 0)
|
|
bitReader.Skip(-1);
|
|
qc = signedCode;
|
|
}
|
|
else
|
|
{
|
|
int index = (resolution << 4) + code;
|
|
int skip = ReadBitTable[index] - bits;
|
|
bitReader.Skip(skip);
|
|
qc = ReadValueTable[index];
|
|
}
|
|
|
|
channel.Spectra[subframe][i] = channel.Gain[i] * qc;
|
|
}
|
|
|
|
Array.Clear(channel.Spectra[subframe], ccCount, SamplesPerSubframe - ccCount);
|
|
}
|
|
|
|
private static void ReconstructNoise(Channel channel, int minResolution, int msStereo, ref int random, int subframe)
|
|
{
|
|
if (minResolution > 0) return;
|
|
if (channel.ValidCount <= 0 || channel.NoiseCount <= 0) return;
|
|
if (msStereo != 0 && channel.Type == ChannelType.StereoPrimary) return;
|
|
|
|
for (int i = 0; i < channel.NoiseCount; i++)
|
|
{
|
|
random = 0x343FD * random + 0x269EC3;
|
|
|
|
int randomIndex = SamplesPerSubframe - channel.ValidCount + (((random & 0x7FFF) * channel.ValidCount) >> 15);
|
|
|
|
int noiseIndex = channel.Noises[i];
|
|
int validIndex = channel.Noises[randomIndex];
|
|
|
|
int sfNoise = channel.ScaleFactors[noiseIndex];
|
|
int sfValid = channel.ScaleFactors[validIndex];
|
|
int scIndex = (sfNoise - sfValid + 62) & ~((sfNoise - sfValid + 62) >> 31);
|
|
|
|
channel.Spectra[subframe][noiseIndex] = ScaleConversionTable[scIndex] * channel.Spectra[subframe][validIndex];
|
|
}
|
|
}
|
|
|
|
private static void ReconstructHighFrequency(Channel channel, int hfrGroupCount, int bandsPerHfrGroup,
|
|
int stereoBandCount, int baseBandCount, int totalBandCount, int version, int subframe)
|
|
{
|
|
if (bandsPerHfrGroup == 0) return;
|
|
if (channel.Type == ChannelType.StereoSecondary) return;
|
|
|
|
int groupLimit;
|
|
int startBand = stereoBandCount + baseBandCount;
|
|
int highBand = startBand;
|
|
int lowBand = startBand - 1;
|
|
|
|
int hfrScalesOffset = 128 - hfrGroupCount;
|
|
byte[] hfrScales = channel.ScaleFactors;
|
|
|
|
if (version <= Version200)
|
|
groupLimit = hfrGroupCount;
|
|
else
|
|
{
|
|
groupLimit = hfrGroupCount >= 0 ? hfrGroupCount : hfrGroupCount + 1;
|
|
groupLimit >>= 1;
|
|
}
|
|
|
|
for (int group = 0; group < hfrGroupCount; group++)
|
|
{
|
|
int lowBandSub = group < groupLimit ? 1 : 0;
|
|
|
|
for (int i = 0; i < bandsPerHfrGroup; i++)
|
|
{
|
|
if (highBand >= totalBandCount || lowBand < 0) break;
|
|
|
|
int scIndex = hfrScales[hfrScalesOffset + group];
|
|
scIndex &= ~(scIndex >> 31);
|
|
|
|
channel.Spectra[subframe][highBand] = ScaleConversionTable[scIndex] * channel.Spectra[subframe][lowBand];
|
|
|
|
highBand++;
|
|
lowBand -= lowBandSub;
|
|
}
|
|
}
|
|
|
|
channel.Spectra[subframe][highBand - 1] = 0.0f;
|
|
}
|
|
|
|
private static void ApplyIntensityStereo(Channel[] channelPair, int channelOffset, int subframe, int baseBandCount, int totalBandCount)
|
|
{
|
|
if (channelPair[channelOffset + 0].Type != ChannelType.StereoPrimary) return;
|
|
|
|
float ratioL = IntensityRatioTable[channelPair[channelOffset + 1].Intensity[subframe]];
|
|
float ratioR = 2.0f - ratioL;
|
|
float[] spectraL = channelPair[channelOffset + 0].Spectra[subframe];
|
|
float[] spectraR = channelPair[channelOffset + 1].Spectra[subframe];
|
|
|
|
for (int band = baseBandCount; band < totalBandCount; band++)
|
|
{
|
|
float coefL = spectraL[band] * ratioL;
|
|
float coefR = spectraR[band] * ratioR;
|
|
spectraL[band] = coefL;
|
|
spectraR[band] = coefR;
|
|
}
|
|
}
|
|
|
|
private static void ApplyMsStereo(Channel[] channelPair, int channelOffset, int msStereo, int baseBandCount, int totalBandCount, int subframe)
|
|
{
|
|
if (msStereo != 0) return;
|
|
if (channelPair[channelOffset + 0].Type != ChannelType.StereoPrimary) return;
|
|
|
|
float ratio = MsStereoRatio;
|
|
float[] spectraL = channelPair[channelOffset + 0].Spectra[subframe];
|
|
float[] spectraR = channelPair[channelOffset + 1].Spectra[subframe];
|
|
|
|
for (int band = baseBandCount; band < totalBandCount; band++)
|
|
{
|
|
float coefL = (spectraL[band] + spectraR[band]) * ratio;
|
|
float coefR = (spectraL[band] - spectraR[band]) * ratio;
|
|
spectraL[band] = coefL;
|
|
spectraR[band] = coefR;
|
|
}
|
|
}
|
|
|
|
private static void ImdctTransform(Channel channel, int subframe)
|
|
{
|
|
const int size = SamplesPerSubframe;
|
|
const int half = SamplesPerSubframe / 2;
|
|
const int mdctBits = MdctBits;
|
|
|
|
int count1 = 1;
|
|
int count2 = half;
|
|
float[] temp1 = channel.Spectra[subframe];
|
|
float[] temp2 = channel.Temp;
|
|
int temp1Index = 0;
|
|
|
|
for (int i = 0; i < mdctBits; i++)
|
|
{
|
|
float[] swap;
|
|
float[] d = temp2;
|
|
int d1Index = 0;
|
|
int d2Index = count2;
|
|
|
|
for (int j = 0; j < count1; j++)
|
|
{
|
|
for (int k = 0; k < count2; k++)
|
|
{
|
|
float a = temp1[temp1Index++];
|
|
float b = temp1[temp1Index++];
|
|
d[d1Index++] = a + b;
|
|
d[d2Index++] = a - b;
|
|
}
|
|
|
|
d1Index += count2;
|
|
d2Index += count2;
|
|
}
|
|
|
|
temp1Index -= SamplesPerSubframe;
|
|
swap = temp1;
|
|
temp1 = temp2;
|
|
temp2 = swap;
|
|
|
|
count1 <<= 1;
|
|
count2 >>= 1;
|
|
}
|
|
|
|
count1 = half;
|
|
count2 = 1;
|
|
temp1 = channel.Temp;
|
|
temp2 = channel.Spectra[subframe];
|
|
|
|
for (int i = 0; i < mdctBits; i++)
|
|
{
|
|
int sinTableIndex = 0;
|
|
int cosTableIndex = 0;
|
|
|
|
float[] swap;
|
|
float[] d = temp2;
|
|
float[] s = temp1;
|
|
int d1Index = 0;
|
|
int d2Index = count2 * 2 - 1;
|
|
int s1Index = 0;
|
|
int s2Index = count2;
|
|
|
|
for (int j = 0; j < count1; j++)
|
|
{
|
|
for (int k = 0; k < count2; k++)
|
|
{
|
|
float a = s[s1Index++];
|
|
float b = s[s2Index++];
|
|
float sin = SinTable[i][sinTableIndex++];
|
|
float cos = CosTable[i][cosTableIndex++];
|
|
d[d1Index++] = a * sin - b * cos;
|
|
d[d2Index--] = a * cos + b * sin;
|
|
}
|
|
|
|
s1Index += count2;
|
|
s2Index += count2;
|
|
d1Index += count2;
|
|
d2Index += count2 * 3;
|
|
}
|
|
|
|
swap = temp1;
|
|
temp1 = temp2;
|
|
temp2 = swap;
|
|
|
|
count1 >>= 1;
|
|
count2 <<= 1;
|
|
}
|
|
|
|
float[] dct = channel.Spectra[subframe];
|
|
float[] prev = channel.ImdctPrevious;
|
|
for (int i = 0; i < half; i++)
|
|
{
|
|
channel.Wave[subframe][i] = ImdctWindow[i] * dct[i + half] + prev[i];
|
|
channel.Wave[subframe][i + half] = ImdctWindow[i + half] * dct[size - 1 - i] - prev[i + half];
|
|
channel.ImdctPrevious[i] = ImdctWindow[size - 1 - i] * dct[half - i - 1];
|
|
channel.ImdctPrevious[i + half] = ImdctWindow[half - i - 1] * dct[i];
|
|
}
|
|
}
|
|
}
|
|
} |