diff --git a/ArcFormats/ArcFormats.csproj b/ArcFormats/ArcFormats.csproj
index 89c7d7a9..8ca4d741 100644
--- a/ArcFormats/ArcFormats.csproj
+++ b/ArcFormats/ArcFormats.csproj
@@ -115,6 +115,7 @@
+
diff --git a/ArcFormats/AudioMIO.cs b/ArcFormats/AudioMIO.cs
new file mode 100644
index 00000000..f7b7cee0
--- /dev/null
+++ b/ArcFormats/AudioMIO.cs
@@ -0,0 +1,1186 @@
+//! \file AudioMIO.cs
+//! \date Thu May 28 13:33:07 2015
+//! \brief Entis audio format implementation.
+//
+// Copyright (C) 2015 by morkt
+//
+// 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;
+using System.ComponentModel.Composition;
+using System.Diagnostics;
+using System.IO;
+using GameRes.Utility;
+
+namespace GameRes.Formats.Entis
+{
+ [Export(typeof(AudioFormat))]
+ public class MioAudio : AudioFormat
+ {
+ public override string Tag { get { return "MIO"; } }
+ public override string Description { get { return "Entis engine compressed audio format"; } }
+ public override uint Signature { get { return 0x69746e45u; } } // 'Enti'
+
+ public override SoundInput TryOpen (Stream file)
+ {
+ byte[] header = new byte[0x40];
+ if (header.Length != file.Read (header, 0, header.Length))
+ return null;
+ if (0x03000100 != LittleEndian.ToUInt32 (header, 8))
+ return null;
+ if (!Binary.AsciiEqual (header, 0x10, "Music Interleaved and Orthogonal transformed"))
+ return null;
+
+ return new MioInput (file);
+ }
+ }
+
+ public class MioInput : SoundInput
+ {
+ EriFile m_erif;
+ MioInfoHeader m_info;
+ long m_stream_pos;
+ int m_bitrate;
+ uint m_total_samples;
+ ERISADecodeContext m_pmioc;
+ MioDecoder m_pmiod;
+ Stream m_decoded_stream;
+
+ public int ChannelCount { get { return m_info.ChannelCount; } }
+ public uint BitsPerSample { get { return m_info.BitsPerSample; } }
+
+ public override int SourceBitrate { get { return m_bitrate; } }
+ public override string SourceFormat { get { return "raw"; } }
+
+ #region Stream Members
+ public override bool CanSeek { get { return Source.CanSeek; } }
+
+ public override long Position
+ {
+ get { return m_decoded_stream.Position; }
+ set { m_decoded_stream.Position = value; }
+ }
+
+ public override int Read (byte[] buffer, int offset, int count)
+ {
+ return m_decoded_stream.Read (buffer, offset, count);
+ }
+ #endregion
+
+ public MioInput (Stream file) : base (file)
+ {
+ file.Position = 0x40;
+ m_erif = new EriFile (file);
+ try
+ {
+ var section = m_erif.ReadSection();
+ if (section.Id != "Header " || section.Length <= 0 || section.Length > int.MaxValue)
+ throw new InvalidFormatException();
+ m_stream_pos = 0x50 + section.Length;
+ int header_size = (int)section.Length;
+ while (header_size > 8)
+ {
+ section = m_erif.ReadSection();
+ header_size -= 8;
+ if (section.Length <= 0 || section.Length > header_size)
+ break;
+ if ("SoundInf" == section.Id)
+ {
+ m_info = new MioInfoHeader();
+ m_info.Version = m_erif.ReadInt32();
+ m_info.Transformation = (CvType)m_erif.ReadInt32();
+ m_info.Architecture = (EriCode)m_erif.ReadInt32();
+ m_info.ChannelCount = m_erif.ReadInt32();
+ m_info.SamplesPerSec = m_erif.ReadUInt32();
+ m_info.BlocksetCount = m_erif.ReadUInt32();
+ m_info.SubbandDegree = m_erif.ReadInt32();
+ m_info.AllSampleCount = m_erif.ReadUInt32();
+ m_info.LappedDegree = m_erif.ReadUInt32();
+ m_info.BitsPerSample = m_erif.ReadUInt32();
+ break;
+ }
+ header_size -= (int)section.Length;
+ m_erif.BaseStream.Seek (section.Length, SeekOrigin.Current);
+ }
+ if (null == m_info)
+ throw new InvalidFormatException ("MIO sound header not found");
+
+ m_erif.BaseStream.Position = m_stream_pos;
+ var stream_size = m_erif.FindSection ("Stream ");
+ m_stream_pos = m_erif.BaseStream.Position;
+
+ m_pmiod = new MioDecoder (m_info);
+ m_pmioc = new HuffmanDecodeContext (0x10000);
+ int pcm_bitrate = (int)m_info.SamplesPerSec * 16 * m_info.ChannelCount;
+
+ var format = new GameRes.WaveFormat();
+ format.FormatTag = 1;
+ format.Channels = (ushort)m_info.ChannelCount;
+ format.SamplesPerSecond = m_info.SamplesPerSec;
+ format.BitsPerSample = 16;
+ format.BlockAlign = (ushort)(2*format.Channels);
+ format.AverageBytesPerSecond = (uint)pcm_bitrate/8;
+ this.Format = format;
+ m_decoded_stream = LoadChunks();
+ if (0 != m_total_samples)
+ m_bitrate = (int)(stream_size * 8 * m_info.SamplesPerSec / m_total_samples);
+ this.PcmSize = m_decoded_stream.Length;
+ m_decoded_stream.Position = 0;
+ }
+ catch
+ {
+ m_erif.Dispose();
+ throw;
+ }
+ }
+
+ class MioChunk : MioDataHeader
+ {
+ public uint FirstSample;
+ public long Position;
+ public uint Size;
+ }
+
+ class ChunkStream : Stream
+ {
+ Stream m_source;
+ MioChunk m_chunk;
+
+ public ChunkStream (Stream source, MioChunk chunk)
+ {
+ m_source = source;
+ m_chunk = chunk;
+ m_source.Position = m_chunk.Position;
+ }
+
+ public override bool CanRead { get { return true; } }
+ public override bool CanWrite { get { return false; } }
+ public override bool CanSeek { get { return m_source.CanSeek; } }
+ public override long Length { get { return m_chunk.Size; } }
+
+ public override long Position
+ {
+ get { return m_source.Position-m_chunk.Position; }
+ set { Seek (value, SeekOrigin.Begin); }
+ }
+
+ public override long Seek (long offset, SeekOrigin origin)
+ {
+ if (origin == SeekOrigin.Begin)
+ offset += m_chunk.Position;
+ else if (origin == SeekOrigin.Current)
+ offset += m_source.Position;
+ else
+ offset += m_chunk.Position + m_chunk.Size;
+ if (offset < m_chunk.Position)
+ offset = m_chunk.Position;
+ m_source.Position = offset;
+ return offset - m_chunk.Position;
+ }
+
+ public override void Flush()
+ {
+ m_source.Flush();
+ }
+
+ public override int Read (byte[] buf, int index, int count)
+ {
+ long remaining = (m_chunk.Position + m_chunk.Size) - m_source.Position;
+ if (count > remaining)
+ count = (int)remaining;
+ if (count <= 0)
+ return 0;
+ return m_source.Read (buf, index, count);
+ }
+
+ public override void SetLength (long length)
+ {
+ throw new System.NotSupportedException ();
+ }
+
+ public override void Write (byte[] buffer, int offset, int count)
+ {
+ throw new System.NotSupportedException ();
+ }
+
+ public override void WriteByte (byte value)
+ {
+ throw new System.NotSupportedException ();
+ }
+ }
+
+ private Stream LoadChunks ()
+ {
+ uint current_sample = 0;
+ List chunks = new List();
+ try
+ {
+ m_erif.BaseStream.Position = m_stream_pos;
+ for (;;)
+ {
+ long chunk_length = m_erif.FindSection ("SoundStm");
+ if (chunk_length > int.MaxValue)
+ throw new FileSizeException();
+ var chunk = new MioChunk();
+ chunk.FirstSample = current_sample;
+ chunk.Version = m_erif.ReadByte();
+ chunk.Flags = m_erif.ReadByte();
+ m_erif.ReadInt16();
+ chunk.SampleCount = m_erif.ReadUInt32();
+ chunk.Position = m_erif.BaseStream.Position;
+ chunk.Size = (uint)(chunk_length - 8);
+ current_sample += chunk.SampleCount;
+ chunks.Add (chunk);
+ m_erif.BaseStream.Seek (chunk.Size, SeekOrigin.Current);
+ }
+ }
+ catch (EndOfStreamException) { /* ignore EOF errors */ }
+ m_total_samples = current_sample;
+ if (0 == m_total_samples)
+ return Stream.Null;
+
+ uint sample_bytes = (uint)ChannelCount * BitsPerSample / 8;
+ var total_bytes = m_total_samples * sample_bytes;
+ var wave_buf = new byte[total_bytes];
+
+ int current_pos = 0;
+ foreach (var chunk in chunks)
+ {
+ using (var input = new ChunkStream (Source, chunk))
+ {
+ m_pmioc.AttachInputFile (input);
+ if (!m_pmiod.DecodeSound (m_pmioc, chunk, wave_buf, current_pos))
+ throw new InvalidFormatException();
+ current_pos += (int)(chunk.SampleCount * sample_bytes);
+ }
+ }
+ return new MemoryStream (wave_buf);
+ }
+
+ #region IDisposable Members
+ protected override void Dispose (bool disposing)
+ {
+ if (null != m_erif)
+ {
+ if (disposing)
+ {
+ m_erif.Dispose();
+ if (m_decoded_stream != null)
+ m_decoded_stream.Dispose();
+ }
+ m_erif = null;
+ base.Dispose (disposing);
+ }
+ }
+ #endregion
+ }
+
+/*****************************************************************************
+ E R I S A - L i b r a r y
+ -----------------------------------------------------------------------------
+ Copyright (C) 2002-2007 Leshade Entis, Entis-soft. All rights reserved.
+ *****************************************************************************/
+
+ internal class MioInfoHeader
+ {
+ public int Version;
+ public CvType Transformation;
+ public EriCode Architecture;
+ public int ChannelCount;
+ public uint SamplesPerSec;
+ public uint BlocksetCount;
+ public int SubbandDegree;
+ public uint AllSampleCount;
+ public uint LappedDegree;
+ public uint BitsPerSample;
+ }
+
+ internal class MioDataHeader
+ {
+ public byte Version;
+ public byte Flags;
+ public uint SampleCount;
+ }
+
+ internal struct EriSinCos
+ {
+ public float rSin;
+ public float rCos;
+ }
+
+ internal class MioDecoder
+ {
+ MioInfoHeader m_mioih;
+
+ uint m_nBufLength = 0;
+ int[] m_ptrBuffer1;
+ int[] m_ptrBuffer2;
+ sbyte[] m_ptrBuffer3;
+ byte[] m_ptrDivisionTable;
+ byte[] m_ptrRevolveCode;
+ int[] m_ptrWeightCode;
+ int[] m_ptrCoefficient;
+
+ float[] m_ptrMatrixBuf;
+ float[] m_ptrInternalBuf;
+ float[] m_ptrWorkBuf;
+ float[] m_ptrWorkBuf2;
+ float[] m_ptrWeightTable;
+ float[] m_ptrLastDCT;
+
+ int m_ptrNextDivision;
+ byte[] m_ptrNextRevCode;
+ int m_ptrNextWeight;
+ int m_ptrNextCoefficient;
+ int m_ptrNextSource;
+ int m_ptrLastDCTBuf;
+ int m_nSubbandDegree;
+ uint m_nDegreeNum;
+ EriSinCos[] m_pRevolveParam;
+ readonly int[] m_nFrequencyPoint = new int[7];
+
+ const int MIN_DCT_DEGREE = 2;
+ const int MAX_DCT_DEGREE = 12;
+
+ static MioDecoder ()
+ {
+ eriInitializeMatrix();
+ }
+
+ public MioDecoder (MioInfoHeader info)
+ {
+ m_nBufLength = 0;
+ m_mioih = info;
+
+ if (!Initialize())
+ throw new InvalidFormatException();
+ }
+
+ bool Initialize ()
+ {
+ if ((m_mioih.ChannelCount != 1) && (m_mioih.ChannelCount != 2))
+ {
+ return false;
+ }
+
+ if (m_mioih.Transformation == CvType.Lossless_ERI)
+ {
+ if (m_mioih.Architecture != EriCode.RunlengthHuffman)
+ {
+ return false;
+ }
+ if ((m_mioih.BitsPerSample != 8) && (m_mioih.BitsPerSample != 16))
+ {
+ return false;
+ }
+ }
+ else if ((m_mioih.Transformation == CvType.LOT_ERI)
+ || (m_mioih.Transformation == CvType.LOT_ERI_MSS))
+ {
+ if ((m_mioih.Architecture != EriCode.RunlengthGamma)
+ && (m_mioih.Architecture != EriCode.RunlengthHuffman)
+ && (m_mioih.Architecture != EriCode.Nemesis))
+ {
+ return false;
+ }
+ if (m_mioih.BitsPerSample != 16)
+ {
+ return false;
+ }
+ if ((m_mioih.SubbandDegree < 8) || (m_mioih.SubbandDegree > MAX_DCT_DEGREE))
+ {
+ return false;
+ }
+ if (m_mioih.LappedDegree != 1)
+ {
+ return false;
+ }
+ int subband = (sizeof(float) << m_mioih.SubbandDegree) / sizeof(float);
+ int block_size = m_mioih.ChannelCount * subband;
+ m_ptrBuffer1 = new int[block_size];
+ m_ptrMatrixBuf = new float[block_size];
+ m_ptrInternalBuf = new float[block_size];
+ m_ptrWorkBuf = new float[subband];
+ m_ptrWorkBuf2 = new float[subband];
+
+ m_ptrWeightTable = new float[subband];
+
+ uint nBlocksetSamples = (uint)(m_mioih.ChannelCount << m_mioih.SubbandDegree);
+ uint nLappedSamples = nBlocksetSamples * m_mioih.LappedDegree;
+ if (nLappedSamples > 0)
+ {
+ m_ptrLastDCT = new float[nLappedSamples];
+ }
+ InitializeWithDegree (m_mioih.SubbandDegree);
+ }
+ else
+ {
+ return false;
+ }
+ return true;
+ }
+
+ public bool DecodeSound (ERISADecodeContext context, MioDataHeader datahdr, byte[] ptrWaveBuf, int wave_pos)
+ {
+ context.FlushBuffer();
+
+ if (m_mioih.Transformation == CvType.Lossless_ERI)
+ {
+ if (m_mioih.BitsPerSample == 8)
+ {
+ return DecodeSoundPCM8 (context, datahdr, ptrWaveBuf, wave_pos);
+ }
+ else if (m_mioih.BitsPerSample == 16)
+ {
+ return DecodeSoundPCM16 (context, datahdr, ptrWaveBuf, wave_pos);
+ }
+ }
+ else if ((m_mioih.Transformation == CvType.LOT_ERI)
+ || (m_mioih.Transformation == CvType.LOT_ERI_MSS))
+ {
+ if ((m_mioih.ChannelCount != 2) || (m_mioih.Transformation == CvType.LOT_ERI))
+ {
+ return DecodeSoundDCT (context, datahdr, ptrWaveBuf, wave_pos);
+ }
+ else
+ {
+ return DecodeSoundDCT_MSS (context, datahdr, ptrWaveBuf, wave_pos);
+ }
+ }
+ return false;
+ }
+
+ bool DecodeSoundPCM8 (ERISADecodeContext context, MioDataHeader datahdr, byte[] ptrWaveBuf, int wave_pos)
+ {
+ throw new NotImplementedException ("MioDecoder.DecodeSoundPCM8 not implemented");
+ }
+
+ bool DecodeSoundPCM16 (ERISADecodeContext context, MioDataHeader datahdr, byte[] ptrWaveBuf, int wave_pos)
+ {
+ throw new NotImplementedException ("MioDecoder.DecodeSoundPCM16 not implemented");
+ }
+
+ static readonly int[] FreqWidth = new int[7] { -6, -6, -5, -4, -3, -2, -1 };
+
+ void InitializeWithDegree (int nSubbandDegree)
+ {
+ m_pRevolveParam = eriCreateRevolveParameter (nSubbandDegree);
+ for (int i = 0, j = 0; i < 7; i ++)
+ {
+ int nFrequencyWidth = 1 << (nSubbandDegree + FreqWidth[i]);
+ m_nFrequencyPoint[i] = j + (nFrequencyWidth / 2);
+ j += nFrequencyWidth;
+ }
+ m_nSubbandDegree = nSubbandDegree;
+ m_nDegreeNum = (1u << nSubbandDegree);
+ }
+
+ const uint MIO_LEAD_BLOCK = 0x01;
+
+ bool DecodeSoundDCT (ERISADecodeContext context, MioDataHeader datahdr, byte[] ptrWaveBuf, int wave_pos)
+ {
+ uint i, j, k;
+ uint nDegreeWidth = 1u << m_mioih.SubbandDegree;
+ uint nSampleCount = (datahdr.SampleCount + nDegreeWidth - 1) & ~(nDegreeWidth - 1);
+ uint nSubbandCount = (nSampleCount >> m_mioih.SubbandDegree);
+ uint nChannelCount = (uint)m_mioih.ChannelCount;
+ uint nAllSampleCount = nSampleCount * nChannelCount;
+ uint nAllSubbandCount = nSubbandCount * nChannelCount;
+
+ if (nSampleCount > m_nBufLength)
+ {
+ m_ptrBuffer2 = new int[nAllSampleCount];
+ m_ptrBuffer3 = new sbyte[nAllSampleCount * sizeof(short)];
+ m_ptrDivisionTable = new byte[nAllSubbandCount];
+ m_ptrWeightCode = new int[nAllSubbandCount * 5];
+ m_ptrCoefficient = new int[nAllSubbandCount * 5];
+ m_nBufLength = nSampleCount;
+ }
+ if (context.GetABit() != 0)
+ {
+ return false;
+ }
+ int[] pLastDivision = new int [nChannelCount];
+ m_ptrNextDivision = 0; // within m_ptrDivisionTable;
+ m_ptrNextWeight = 0; // within m_ptrWeightCode;
+ m_ptrNextCoefficient = 0; // within m_ptrCoefficient;
+
+ for (i = 0; i < nChannelCount; i++)
+ {
+ pLastDivision[i] = -1;
+ }
+ for (i = 0; i < nSubbandCount; i++)
+ {
+ for (j = 0; j < nChannelCount; j++)
+ {
+ int nDivisionCode = (int)context.GetNBits(2);
+ m_ptrDivisionTable[m_ptrNextDivision++] = (byte)nDivisionCode;
+
+ if (nDivisionCode != pLastDivision[j])
+ {
+ if (i != 0)
+ {
+ m_ptrWeightCode[m_ptrNextWeight++] = (int)context.GetNBits (32);
+ m_ptrCoefficient[m_ptrNextCoefficient++] = (int)context.GetNBits (16);
+ }
+ pLastDivision[j] = nDivisionCode;
+ }
+
+ uint nDivisionCount = 1u << nDivisionCode;
+ for (k = 0; k < nDivisionCount; k ++)
+ {
+ m_ptrWeightCode[m_ptrNextWeight++] = (int)context.GetNBits (32);
+ m_ptrCoefficient[m_ptrNextCoefficient++] = (int)context.GetNBits (16);
+ }
+ }
+ }
+ if (nSubbandCount > 0)
+ {
+ for (i = 0; i < nChannelCount; i++)
+ {
+ m_ptrWeightCode[m_ptrNextWeight++] = (int)context.GetNBits (32);
+ m_ptrCoefficient[m_ptrNextCoefficient++] = (int)context.GetNBits (16);
+ }
+ }
+
+ if (context.GetABit() != 0)
+ {
+ return false;
+ }
+ if (0 != (datahdr.Flags & MIO_LEAD_BLOCK))
+ {
+ if (m_mioih.Architecture != EriCode.Nemesis)
+ {
+ (context as HuffmanDecodeContext).PrepareToDecodeERINACode();
+ }
+ else
+ {
+ throw new NotImplementedException ("Nemesis encoding not implemented");
+// context.PrepareToDecodeERISACode();
+ }
+ }
+ else if (m_mioih.Architecture == EriCode.Nemesis)
+ {
+ throw new NotImplementedException ("Nemesis encoding not implemented");
+// context.InitializeERISACode();
+ }
+ if (m_mioih.Architecture != EriCode.Nemesis)
+ {
+ if (context.DecodeBytes (m_ptrBuffer3, nAllSampleCount * 2 ) < nAllSampleCount * 2)
+ {
+ return false;
+ }
+ int ptrHBuf = 0; // within m_ptrBuffer3;
+ int ptrLBuf = (int)nAllSampleCount; // within m_ptrBuffer3
+
+ for (i = 0; i < nDegreeWidth; i++)
+ {
+ int ptrQuantumized = (int)i; // within (PINT) m_ptrBuffer2
+ for (j = 0; j < nAllSubbandCount; j++)
+ {
+ int nLow = m_ptrBuffer3[ptrLBuf++];
+ int nHigh = m_ptrBuffer3[ptrHBuf++] ^ (nLow >> 8);
+ m_ptrBuffer2[ptrQuantumized] = (nLow & 0xFF) | (nHigh << 8);
+ ptrQuantumized += (int)nDegreeWidth;
+ }
+ }
+ }
+ else
+ {
+ throw new NotImplementedException ("Nemesis encoding not implemented");
+ /*
+ if (context.DecodeERISACodeWords (m_ptrBuffer3, nAllSampleCount) < nAllSampleCount)
+ {
+ return false;
+ }
+ for (i = 0; i < nAllSampleCount; i++)
+ {
+ ((PINT)m_ptrBuffer2)[i] = ((SWORD*)m_ptrBuffer3)[i];
+ }
+ */
+ }
+ uint nSamples;
+ uint[] pRestSamples = new uint [nChannelCount];
+ int[] ptrDstBuf = new int [nChannelCount]; // indices within ptrWaveBuf
+
+ m_ptrNextDivision = 0; // within m_ptrDivisionTable;
+ m_ptrNextWeight = 0; // within m_ptrWeightCode;
+ m_ptrNextCoefficient = 0; // within m_ptrCoefficient;
+ m_ptrNextSource = 0; // within (PINT) m_ptrBuffer2;
+
+ for (i = 0; i < nChannelCount; i++)
+ {
+ pLastDivision[i] = -1;
+ pRestSamples[i] = datahdr.SampleCount;
+ ptrDstBuf[i] = wave_pos + (int)i*sizeof(short);
+ }
+ int nCurrentDivision = -1;
+
+ for (i = 0; i < nSubbandCount; i++)
+ {
+ for (j = 0; j < nChannelCount; j++)
+ {
+ int nDivisionCode = m_ptrDivisionTable[m_ptrNextDivision++];
+ int nDivisionCount = 1 << nDivisionCode;
+ int nChannelStep = (int)(nDegreeWidth * m_mioih.LappedDegree * j);
+ m_ptrLastDCTBuf = nChannelStep; // within m_ptrLastDCT
+
+ bool fLeadBlock = false;
+ if (pLastDivision[j] != nDivisionCode)
+ {
+ if (i != 0)
+ {
+ if (nCurrentDivision != pLastDivision[j])
+ {
+ InitializeWithDegree (m_mioih.SubbandDegree - pLastDivision[j]);
+ nCurrentDivision = pLastDivision[j];
+ }
+ nSamples = pRestSamples[j];
+ if (nSamples > m_nDegreeNum)
+ {
+ nSamples = m_nDegreeNum;
+ }
+ DecodePostBlock (ptrWaveBuf, ptrDstBuf[j], nSamples);
+ pRestSamples[j] -= nSamples;
+ ptrDstBuf[j] += (int)(nSamples * nChannelCount * sizeof(short));
+ }
+ pLastDivision[j] = (int)nDivisionCode;
+ fLeadBlock = true;
+ }
+ if (nCurrentDivision != nDivisionCode)
+ {
+ InitializeWithDegree (m_mioih.SubbandDegree - nDivisionCode);
+ nCurrentDivision = nDivisionCode;
+ }
+ for (k = 0; k < nDivisionCount; k++)
+ {
+ if (fLeadBlock)
+ {
+ DecodeLeadBlock();
+ fLeadBlock = false;
+ }
+ else
+ {
+ nSamples = pRestSamples[j];
+ if (nSamples > m_nDegreeNum)
+ {
+ nSamples = m_nDegreeNum;
+ }
+ DecodeInternalBlock (ptrWaveBuf, ptrDstBuf[j], nSamples);
+ pRestSamples[j] -= nSamples;
+ ptrDstBuf[j] += (int)(nSamples * nChannelCount * sizeof(short));
+ }
+ }
+ }
+ }
+ if (nSubbandCount > 0)
+ {
+ for (i = 0; i < nChannelCount; i ++)
+ {
+ int nChannelStep = (int)(nDegreeWidth * m_mioih.LappedDegree * i);
+ m_ptrLastDCTBuf = nChannelStep; // within m_ptrLastDCT
+
+ if (nCurrentDivision != pLastDivision[i])
+ {
+ InitializeWithDegree (m_mioih.SubbandDegree - pLastDivision[i]);
+ nCurrentDivision = pLastDivision[i];
+ }
+ nSamples = pRestSamples[i];
+ if (nSamples > m_nDegreeNum)
+ {
+ nSamples = m_nDegreeNum;
+ }
+ DecodePostBlock (ptrWaveBuf, ptrDstBuf[i], nSamples);
+ pRestSamples[i] -= nSamples;
+ ptrDstBuf[i] += (int)(nSamples * nChannelCount * sizeof(short));
+ }
+ }
+ return true;
+ }
+
+ void DecodeInternalBlock (byte[] ptrDst, int iDst, uint nSamples)
+ {
+ int nWeightCode = m_ptrWeightCode[m_ptrNextWeight++];
+ int nCoefficient = m_ptrCoefficient[m_ptrNextCoefficient++];
+ IQuantumize (m_ptrMatrixBuf, 0, m_ptrBuffer2, m_ptrNextSource, (int)m_nDegreeNum, nWeightCode, nCoefficient);
+ m_ptrNextSource += (int)m_nDegreeNum;
+
+ eriOddGivensInverseMatrix (m_ptrMatrixBuf, 0, m_pRevolveParam, m_nSubbandDegree);
+ eriFastIPLOT (m_ptrMatrixBuf, 0, m_nSubbandDegree);
+ eriFastILOT (m_ptrWorkBuf, m_ptrLastDCT, m_ptrLastDCTBuf, m_ptrMatrixBuf, m_nSubbandDegree);
+
+ for (uint i = 0; i < m_nDegreeNum; i++)
+ {
+ m_ptrLastDCT[m_ptrLastDCTBuf + i] = m_ptrMatrixBuf[i];
+ m_ptrMatrixBuf[i] = m_ptrWorkBuf[i];
+ }
+ eriFastIDCT (m_ptrInternalBuf, m_ptrMatrixBuf, 1, m_ptrWorkBuf, m_nSubbandDegree);
+ if (nSamples != 0)
+ {
+ eriRoundR32ToWordArray (ptrDst, iDst, m_mioih.ChannelCount, m_ptrInternalBuf, (int)nSamples);
+ }
+ }
+
+ void DecodeLeadBlock ()
+ {
+ int nWeightCode = m_ptrWeightCode[m_ptrNextWeight++];
+ int nCoefficient = m_ptrCoefficient[m_ptrNextCoefficient++];
+ uint i;
+ uint nHalfDegree = m_nDegreeNum / 2;
+ for (i = 0; i < nHalfDegree; i++)
+ {
+ m_ptrBuffer1[i * 2] = 0;
+ m_ptrBuffer1[i * 2 + 1] = m_ptrBuffer2[m_ptrNextSource++];
+ }
+ IQuantumize (m_ptrLastDCT, m_ptrLastDCTBuf, m_ptrBuffer1, 0, (int)m_nDegreeNum, nWeightCode, nCoefficient);
+ eriOddGivensInverseMatrix (m_ptrLastDCT, m_ptrLastDCTBuf, m_pRevolveParam, m_nSubbandDegree);
+ for (i = 0; i < m_nDegreeNum; i += 2)
+ {
+ m_ptrLastDCT[m_ptrLastDCTBuf + i] = m_ptrLastDCT[m_ptrLastDCTBuf + i + 1];
+ }
+ eriFastIPLOT (m_ptrLastDCT, m_ptrLastDCTBuf, m_nSubbandDegree);
+ }
+
+ void DecodePostBlock (byte[] ptrDst, int iDst, uint nSamples)
+ {
+ int nWeightCode = m_ptrWeightCode[m_ptrNextWeight++];
+ int nCoefficient = m_ptrCoefficient[m_ptrNextCoefficient++];
+ uint i;
+ uint nHalfDegree = m_nDegreeNum / 2;
+ for (i = 0; i < nHalfDegree; i++)
+ {
+ m_ptrBuffer1[i * 2] = 0;
+ m_ptrBuffer1[i * 2 + 1] = m_ptrBuffer2[m_ptrNextSource++];
+ }
+ IQuantumize (m_ptrMatrixBuf, 0, m_ptrBuffer1, 0, (int)m_nDegreeNum, nWeightCode, nCoefficient);
+ eriOddGivensInverseMatrix (m_ptrMatrixBuf, 0, m_pRevolveParam, m_nSubbandDegree);
+
+ for (i = 0; i < m_nDegreeNum; i += 2)
+ {
+ m_ptrMatrixBuf[i] = - m_ptrMatrixBuf[i + 1];
+ }
+
+ eriFastIPLOT (m_ptrMatrixBuf, 0, m_nSubbandDegree);
+ eriFastILOT (m_ptrWorkBuf, m_ptrLastDCT, m_ptrLastDCTBuf, m_ptrMatrixBuf, m_nSubbandDegree);
+
+ for (i = 0; i < m_nDegreeNum; i++)
+ {
+ m_ptrMatrixBuf[i] = m_ptrWorkBuf[i];
+ }
+ eriFastIDCT (m_ptrInternalBuf, m_ptrMatrixBuf, 1, m_ptrWorkBuf, m_nSubbandDegree);
+ if (nSamples != 0)
+ {
+ eriRoundR32ToWordArray (ptrDst, iDst, m_mioih.ChannelCount, m_ptrInternalBuf, (int)nSamples);
+ }
+ }
+
+ void IQuantumize (float[] ptrDestination, int dst, int[] ptrQuantumized, int qsrc, int nDegreeNum, int nWeightCode, int nCoefficient)
+ {
+ int i, j;
+ double rMatrixScale = Math.Sqrt (2.0 / nDegreeNum);
+ double rCoefficient = rMatrixScale * nCoefficient;
+ double[] rAvgRatio = new double[7];
+ for (i = 0; i < 6; i++)
+ {
+ rAvgRatio[i] = 1.0 / Math.Pow (2.0, (((nWeightCode >> (i * 5)) & 0x1F) - 15) * 0.5);
+ }
+ rAvgRatio[6] = 1.0;
+ for (i = 0; i < m_nFrequencyPoint[0]; i++)
+ {
+ m_ptrWeightTable[i] = (float) rAvgRatio[0];
+ }
+ for (j = 1; j < 7; j++)
+ {
+ double a = rAvgRatio[j - 1];
+ double k = (rAvgRatio[j] - a) / (m_nFrequencyPoint[j] - m_nFrequencyPoint[j - 1]);
+ while (i < m_nFrequencyPoint[j])
+ {
+ m_ptrWeightTable[i] = (float)(k * (i - m_nFrequencyPoint[j - 1]) + a);
+ i++;
+ }
+ }
+ while (i < nDegreeNum)
+ {
+ m_ptrWeightTable[i++] = (float)rAvgRatio[6];
+ }
+ float rOddWeight = (float)((((nWeightCode >> 30) & 0x03) + 0x02) / 2.0);
+ for (i = 15; i < nDegreeNum; i += 16)
+ {
+ m_ptrWeightTable[i] *= rOddWeight;
+ }
+ m_ptrWeightTable[nDegreeNum-1] = (float) nCoefficient;
+ for (i = 0; i < nDegreeNum; i++)
+ {
+ m_ptrWeightTable[i] = 1.0F / m_ptrWeightTable[i];
+ }
+ for (i = 0; i < nDegreeNum; i ++)
+ {
+ ptrDestination[dst + i] = (float) (rCoefficient * m_ptrWeightTable[i] * ptrQuantumized[qsrc+i]);
+ }
+ }
+
+ bool DecodeSoundDCT_MSS (ERISADecodeContext context, MioDataHeader datahdr, byte[] ptrWaveBuf, int wave_pos)
+ {
+ throw new NotImplementedException ("MioDecoder.DecodeSoundDCT_MSS not implemented");
+ }
+
+ bool DecodeInternalBlock_MSS (byte[] ptrDst, int iDst, uint nSamples)
+ {
+ throw new NotImplementedException ("MioDecoder.DecodeInternalBlock_MSS not implemented");
+ }
+
+ bool DecodeLeadBlock_MSS ()
+ {
+ throw new NotImplementedException ("MioDecoder.DecodeLeadBlock_MSS not implemented");
+ }
+
+ bool DecodePostBlock_MSS (byte[] ptrDst, int iDst, uint nSamples)
+ {
+ throw new NotImplementedException ("MioDecoder.DecodePostBlock_MSS not implemented");
+ }
+
+ static readonly float ERI_rCosPI4 = (float)Math.Cos (Math.PI / 4);
+ static readonly float ERI_r2CosPI4 = 2 * ERI_rCosPI4;
+ static readonly float[] ERI_DCTofK2 = new float[2]; // = cos ((2*i+1) / 8)
+ static readonly float[] ERI_DCTofK4 = new float[4]; // = cos( (2*i+1) / 16 )
+ static readonly float[] ERI_DCTofK8 = new float[8]; // = cos( (2*i+1) / 32 )
+ static readonly float[] ERI_DCTofK16 = new float[16]; // = cos( (2*i+1) / 64 )
+ static readonly float[] ERI_DCTofK32 = new float[32]; // = cos( (2*i+1) / 128 )
+ static readonly float[] ERI_DCTofK64 = new float[64]; // = cos( (2*i+1) / 256 )
+ static readonly float[] ERI_DCTofK128 = new float[128]; // = cos( (2*i+1) / 512 )
+ static readonly float[] ERI_DCTofK256 = new float[256]; // = cos( (2*i+1) / 1024 )
+ static readonly float[] ERI_DCTofK512 = new float[512]; // = cos( (2*i+1) / 2048 )
+ static readonly float[] ERI_DCTofK1024 = new float[1024]; // = cos( (2*i+1) / 4096 )
+ static readonly float[] ERI_DCTofK2048 = new float[2048]; // = cos( (2*i+1) / 8192 )
+
+ static readonly float[][] ERI_pMatrixDCTofK = new float[MAX_DCT_DEGREE][]
+ {
+ null,
+ ERI_DCTofK2,
+ ERI_DCTofK4,
+ ERI_DCTofK8,
+ ERI_DCTofK16,
+ ERI_DCTofK32,
+ ERI_DCTofK64,
+ ERI_DCTofK128,
+ ERI_DCTofK256,
+ ERI_DCTofK512,
+ ERI_DCTofK1024,
+ ERI_DCTofK2048
+ };
+
+ static void eriInitializeMatrix ()
+ {
+ for (int i = 1; i < MAX_DCT_DEGREE; i++)
+ {
+ int n = (1 << i);
+ float[] pDCTofK = ERI_pMatrixDCTofK[i];
+ double nr = Math.PI / (4.0 * n);
+ double dr = nr + nr;
+ double ir = nr;
+ for (int j = 0; j < n; j++)
+ {
+ pDCTofK[j] = (float)Math.Cos (ir);
+ ir += dr;
+ }
+ }
+ }
+
+ static void eriRoundR32ToWordArray (byte[] ptrDst, int dst, int nStep, float[] ptrSrc, int nCount)
+ {
+ for (int i = 0; i < nCount; i++)
+ {
+ int nValue = eriRoundR32ToInt (ptrSrc[i]);
+ if (nValue <= -0x8000)
+ {
+ LittleEndian.Pack ((short)-0x8000, ptrDst, dst);
+ }
+ else if (nValue >= 0x7FFF)
+ {
+ LittleEndian.Pack ((short)0x7FFF, ptrDst, dst);
+ }
+ else
+ {
+ LittleEndian.Pack ((short)nValue, ptrDst, dst);
+ }
+ dst += nStep*2;
+ }
+ }
+
+ static int eriRoundR32ToInt (float r)
+ {
+ if (r >= 0.0)
+ return (int)Math.Floor (r + 0.5);
+ else
+ return (int)Math.Ceiling (r - 0.5);
+ }
+
+ static EriSinCos[] eriCreateRevolveParameter (int nDegreeDCT)
+ {
+ int nDegreeNum = 1 << nDegreeDCT;
+ int lc = 1;
+ for (int n = nDegreeNum / 2; n >= 8; n /= 8)
+ {
+ ++lc;
+ }
+ EriSinCos[] ptrRevolve = new EriSinCos[lc*8];
+
+ double k = Math.PI / (nDegreeNum * 2);
+ int ptrNextRev = 0;
+ int nStep = 2;
+ do
+ {
+ for (int i = 0; i < 7; i++)
+ {
+ double ws = 1.0;
+ double a = 0.0;
+ for (int j = 0; j < i; j++)
+ {
+ a += nStep;
+ ws = ws * ptrRevolve[ptrNextRev+j].rSin + ptrRevolve[ptrNextRev+j].rCos * Math.Cos (a * k);
+ }
+ double r = Math.Atan2 (ws, Math.Cos ((a + nStep) * k));
+ ptrRevolve[ptrNextRev+i].rSin = (float)Math.Sin (r);
+ ptrRevolve[ptrNextRev+i].rCos = (float)Math.Cos (r);
+ }
+ ptrNextRev += 7;
+ nStep *= 8;
+ }
+ while (nStep < nDegreeNum);
+ return ptrRevolve;
+ }
+
+ static void eriOddGivensInverseMatrix (float[] ptrSrc, int src, EriSinCos[] ptrRevolve, int nDegreeDCT)
+ {
+ int nDegreeNum = 1 << nDegreeDCT;
+ int index = 1;
+ int nStep = 2;
+ int lc = (nDegreeNum / 2) / 8;
+ int resolve_idx = 0;
+ for (;;)
+ {
+ resolve_idx += 7;
+ index += nStep * 7;
+ nStep *= 8;
+ if (lc <= 8)
+ break;
+ lc /= 8;
+ }
+ int k = index + nStep * (lc - 2);
+ int j;
+ float r1, r2;
+ for (j = lc - 2; j >= 0; j--)
+ {
+ r1 = ptrSrc[src + k];
+ r2 = ptrSrc[src + k + nStep];
+ ptrSrc[src + k] = r1 * ptrRevolve[resolve_idx+j].rCos + r2 * ptrRevolve[resolve_idx+j].rSin;
+ ptrSrc[src + k + nStep] = r2 * ptrRevolve[resolve_idx+j].rCos - r1 * ptrRevolve[resolve_idx+j].rSin;
+ k -= nStep;
+ }
+ for (; lc <= (nDegreeNum / 2) / 8; lc *= 8)
+ {
+ resolve_idx -= 7;
+ nStep /= 8;
+ index -= nStep * 7;
+ for (int i = 0; i < lc; i++)
+ {
+ k = i * (nStep * 8) + index + nStep * 6;
+ for ( j = 6; j >= 0; j -- )
+ {
+ r1 = ptrSrc[src + k];
+ r2 = ptrSrc[src + k + nStep];
+ ptrSrc[src + k] =
+ r1 * ptrRevolve[resolve_idx+j].rCos + r2 * ptrRevolve[resolve_idx+j].rSin;
+ ptrSrc[src + k + nStep] =
+ r2 * ptrRevolve[resolve_idx+j].rCos - r1 * ptrRevolve[resolve_idx+j].rSin;
+ k -= nStep;
+ }
+ }
+ }
+ }
+
+ static void eriFastIPLOT (float[] ptrSrc, int src, int nDegreeDCT)
+ {
+ int nDegreeNum = 1 << nDegreeDCT;
+ for (int i = 0; i < nDegreeNum; i += 2)
+ {
+ float r1 = ptrSrc[src + i];
+ float r2 = ptrSrc[src + i + 1];
+ ptrSrc[src + i] = 0.5f * (r1 + r2);
+ ptrSrc[src + i + 1] = 0.5f * (r1 - r2);
+ }
+ }
+
+ static void eriFastILOT (float[] ptrDst, float[] ptrSrc1, int src1, float[] ptrSrc2, int nDegreeDCT)
+ {
+ int nDegreeNum = 1 << nDegreeDCT;
+ for (int i = 0; i < nDegreeNum; i += 2)
+ {
+ float r1 = ptrSrc1[src1 + i];
+ float r2 = ptrSrc2[i + 1];
+ ptrDst[i] = r1 + r2;
+ ptrDst[i + 1] = r1 - r2;
+ }
+ }
+
+ static void eriFastDCT (float[] ptrDst, int dst, int nDstInterval, float[] ptrSrc, int src, float[] ptrWorkBuf, int work, int nDegreeDCT)
+ {
+ Debug.Assert ((nDegreeDCT >= MIN_DCT_DEGREE) && (nDegreeDCT <= MAX_DCT_DEGREE));
+
+ if (nDegreeDCT == MIN_DCT_DEGREE)
+ {
+ float[] r32Buf = new float[4];
+ r32Buf[0] = ptrSrc[src] + ptrSrc[src+3];
+ r32Buf[2] = ptrSrc[src] - ptrSrc[src+3];
+ r32Buf[1] = ptrSrc[src+1] + ptrSrc[src+2];
+ r32Buf[3] = ptrSrc[src+1] - ptrSrc[src+2];
+
+ ptrDst[dst] = 0.5f * (r32Buf[0] + r32Buf[1]);
+ ptrDst[dst+nDstInterval * 2] = ERI_rCosPI4 * (r32Buf[0] - r32Buf[1]);
+
+ r32Buf[2] = ERI_DCTofK2[0] * r32Buf[2];
+ r32Buf[3] = ERI_DCTofK2[1] * r32Buf[3];
+
+ r32Buf[0] = r32Buf[2] + r32Buf[3];
+ r32Buf[1] = ERI_r2CosPI4 * (r32Buf[2] - r32Buf[3]);
+
+ r32Buf[1] -= r32Buf[0];
+
+ ptrDst[dst+nDstInterval] = r32Buf[0];
+ ptrDst[dst+nDstInterval * 3] = r32Buf[1];
+ }
+ else
+ {
+ uint i;
+ uint nDegreeNum = 1u << nDegreeDCT;
+ uint nHalfDegree = nDegreeNum >> 1;
+ for (i = 0; i < nHalfDegree; i++)
+ {
+ ptrWorkBuf[work+i] = ptrSrc[src+i] + ptrSrc[src + nDegreeNum - i - 1];
+ ptrWorkBuf[work+i + nHalfDegree] = ptrSrc[src+i] - ptrSrc[src + nDegreeNum - i - 1];
+ }
+ int nDstStep = nDstInterval << 1;
+ eriFastDCT (ptrDst, dst, nDstStep, ptrWorkBuf, work, ptrSrc, src, nDegreeDCT - 1);
+
+ float[] pDCTofK = ERI_pMatrixDCTofK[nDegreeDCT - 1];
+ src = (int)(work+nHalfDegree); // ptrSrc = ptrWorkBuf + nHalfDegree;
+ dst += nDstInterval; // ptrDst += nDstInterval;
+
+ for (i = 0; i < nHalfDegree; i++)
+ {
+ ptrWorkBuf[src + i] *= pDCTofK[i];
+ }
+
+ eriFastDCT (ptrDst, dst, nDstStep, ptrWorkBuf, src, ptrWorkBuf, work, nDegreeDCT - 1);
+ // eriFastDCT (ptrDst, nDstStep, ptrSrc, ptrWorkBuf, nDegreeDCT - 1);
+
+ int ptrNext = dst; // within ptrDst;
+ for (i = 0; i < nHalfDegree; i++)
+ {
+ ptrDst[ptrNext] += ptrDst[ptrNext]; // *ptrNext += *ptrNext;
+ ptrNext += nDstStep;
+ }
+ ptrNext = dst;
+ for (i = 1; i < nHalfDegree; i ++)
+ {
+ ptrDst[ptrNext + nDstStep] -= ptrDst[ptrNext];
+ ptrNext += nDstStep;
+ }
+ }
+ }
+
+ static void eriFastIDCT (float[] ptrDst, float[] ptrSrc, int nSrcInterval, float[] ptrWorkBuf, int nDegreeDCT)
+ {
+ Debug.Assert ((nDegreeDCT >= MIN_DCT_DEGREE) && (nDegreeDCT <= MAX_DCT_DEGREE));
+
+ if (nDegreeDCT == MIN_DCT_DEGREE)
+ {
+ float[] r32Buf1 = new float[2];
+ float[] r32Buf2 = new float[4];
+
+ r32Buf1[0] = ptrSrc[0];
+ r32Buf1[1] = ERI_rCosPI4 * ptrSrc[nSrcInterval * 2];
+
+ r32Buf2[0] = r32Buf1[0] + r32Buf1[1];
+ r32Buf2[1] = r32Buf1[0] - r32Buf1[1];
+
+ r32Buf1[0] = ERI_DCTofK2[0] * ptrSrc[nSrcInterval];
+ r32Buf1[1] = ERI_DCTofK2[1] * ptrSrc[nSrcInterval * 3];
+
+ r32Buf2[2] = r32Buf1[0] + r32Buf1[1];
+ r32Buf2[3] = ERI_r2CosPI4 * (r32Buf1[0] - r32Buf1[1]);
+
+ r32Buf2[3] -= r32Buf2[2];
+
+ ptrDst[0] = r32Buf2[0] + r32Buf2[2];
+ ptrDst[3] = r32Buf2[0] - r32Buf2[2];
+ ptrDst[1] = r32Buf2[1] + r32Buf2[3];
+ ptrDst[2] = r32Buf2[1] - r32Buf2[3];
+ }
+ else
+ {
+ uint i;
+ uint nDegreeNum = 1u << nDegreeDCT;
+ uint nHalfDegree = nDegreeNum >> 1;
+ int nSrcStep = nSrcInterval << 1;
+ eriFastIDCT (ptrDst, ptrSrc, nSrcStep, ptrWorkBuf, nDegreeDCT - 1);
+
+ float[] pDCTofK = ERI_pMatrixDCTofK[nDegreeDCT - 1];
+ int pOddSrc = nSrcInterval; // within ptrSrc
+ int pOddDst = (int)nHalfDegree; // within ptrDst
+
+ int ptrNext = pOddSrc;
+ for (i = 0; i < nHalfDegree; i++)
+ {
+ ptrWorkBuf[i] = ptrSrc[ptrNext] * pDCTofK[i];
+ ptrNext += nSrcStep;
+ }
+
+ eriFastDCT (ptrDst, pOddDst, 1, ptrWorkBuf, 0, ptrWorkBuf, (int)nHalfDegree, nDegreeDCT - 1);
+ // eriFastDCT(pOddDst, 1, ptrWorkBuf, (ptrWorkBuf + nHalfDegree), nDegreeDCT - 1);
+
+ for (i = 0; i < nHalfDegree; i ++)
+ {
+ ptrDst[pOddDst + i] += ptrDst[pOddDst + i];
+ }
+
+ for (i = 1; i < nHalfDegree; i++)
+ {
+ ptrDst[pOddDst + i] -= ptrDst[pOddDst + i - 1];
+ }
+ float[] r32Buf = new float[4];
+ uint nQuadDegree = nHalfDegree >> 1;
+ for (i = 0; i < nQuadDegree; i++)
+ {
+ r32Buf[0] = ptrDst[i] + ptrDst[nHalfDegree + i];
+ r32Buf[3] = ptrDst[i] - ptrDst[nHalfDegree + i];
+ r32Buf[1] = ptrDst[nHalfDegree - 1 - i] + ptrDst[nDegreeNum - 1 - i];
+ r32Buf[2] = ptrDst[nHalfDegree - 1 - i] - ptrDst[nDegreeNum - 1 - i];
+
+ ptrDst[i] = r32Buf[0];
+ ptrDst[nHalfDegree - 1 - i] = r32Buf[1];
+ ptrDst[nHalfDegree + i] = r32Buf[2];
+ ptrDst[nDegreeNum - 1 - i] = r32Buf[3];
+ }
+ }
+ }
+ }
+}