private int DecodeToWaveR32(byte[] blockData)
        {
            var hcaInfo = HcaInfo;

            if (blockData == null)
            {
                throw new ArgumentNullException(nameof(blockData));
            }
            if (blockData.Length < hcaInfo.BlockSize)
            {
                throw new HcaException(ErrorMessages.GetInvalidParameter("blockData.Length"), ActionResult.InvalidParameter);
            }
            var checksum = HcaHelper.Checksum(blockData, 0);

            if (checksum != 0)
            {
                throw new HcaException(ErrorMessages.GetChecksumNotMatch(0, checksum), ActionResult.ChecksumNotMatch);
            }
            _cipher.Decrypt(blockData);
            var d     = new DataBits(blockData, hcaInfo.BlockSize);
            var magic = d.GetBit(16);

            if (magic != 0xffff)
            {
                throw new HcaException(ErrorMessages.GetMagicNotMatch(0xffff, magic), ActionResult.MagicNotMatch);
            }
            var a        = (d.GetBit(9) << 8) - d.GetBit(7);
            var channels = _channels;
            var ath      = _ath;

            try {
                for (var i = 0; i < hcaInfo.ChannelCount; ++i)
                {
                    channels[i].Decode1(d, hcaInfo.CompR09, a, ath.Table);
                }
                for (var i = 0; i < 8; ++i)
                {
                    for (var j = 0; j < hcaInfo.ChannelCount; ++j)
                    {
                        channels[j].Decode2(d);
                    }
                    for (var j = 0; j < hcaInfo.ChannelCount; ++j)
                    {
                        channels[j].Decode3(hcaInfo.CompR09, hcaInfo.CompR08, (uint)(hcaInfo.CompR07 + hcaInfo.CompR06), hcaInfo.CompR05);
                    }
                    for (var j = 0; j < hcaInfo.ChannelCount - 1; ++j)
                    {
                        Channel.Decode4(ref channels[j], ref channels[j + 1], i, (uint)(hcaInfo.CompR05 - hcaInfo.CompR06), hcaInfo.CompR06, hcaInfo.CompR07);
                    }
                    for (var j = 0; j < hcaInfo.ChannelCount; ++j)
                    {
                        channels[j].Decode5(i);
                    }
                }
                return(blockData.Length);
            } catch (IndexOutOfRangeException ex) {
                const string message = "Index access exception detected. It is probably because you are using an incorrect HCA key pair while decoding a type 56 HCA file.";
                throw new HcaException(message, ActionResult.DecodeFailed, ex);
            }
        }
Beispiel #2
0
        private void TransformWaveDataBlocks(Stream source, byte[] destination, uint startBlockIndex, uint blockCount, IWaveWriter waveWriter)
        {
            if (source == null)
            {
                throw new ArgumentNullException(nameof(source));
            }
            if (destination == null)
            {
                throw new ArgumentNullException(nameof(destination));
            }
            if (waveWriter == null)
            {
                throw new ArgumentNullException(nameof(waveWriter));
            }
            var hcaInfo     = HcaInfo;
            var startOffset = hcaInfo.DataOffset + startBlockIndex * hcaInfo.BlockSize;

            source.Seek(startOffset, SeekOrigin.Begin);
            var channels       = _channels;
            var decodeParams   = _decodeParams;
            var hcaBlockBuffer = GetHcaBlockBuffer();

            var channelCount   = hcaInfo.ChannelCount;
            var rvaVolume      = hcaInfo.RvaVolume;
            var bytesPerSample = waveWriter.BytesPerSample;
            var volume         = decodeParams.Volume;

            for (var l = 0; l < (int)blockCount; ++l)
            {
                source.Read(hcaBlockBuffer, 0, hcaBlockBuffer.Length);

                DecodeToWaveR32(hcaBlockBuffer, l + (int)startBlockIndex);

                for (var i = 0; i < 8; ++i)
                {
                    for (var j = 0; j < 0x80; ++j)
                    {
                        for (var k = 0; k < channelCount; ++k)
                        {
                            float f;

                            unsafe {
                                var pWave = channels.GetPtrOfWave(k);

                                f = pWave[i * 0x80 + j];
                                f = f * volume * rvaVolume;
                            }

                            HcaHelper.Clamp(ref f, -1f, 1f);

                            var offset = (((l * 8 + i) * 0x80 + j) * channelCount + k) * bytesPerSample;

                            waveWriter.DecodeToBuffer(f, destination, (uint)offset);
                        }
                    }
                }
            }
        }
Beispiel #3
0
 public HcaDecoder(Stream sourceStream, DecodeParams decodeParams)
     : base(sourceStream)
 {
     _decodeParams = decodeParams;
     HcaHelper.TranslateTables();
     _ath    = new Ath();
     _cipher = new Cipher();
     Initialize();
 }
        private static void FixDataBlock(byte[] blockData)
        {
            var length = blockData.Length;
            var sum    = HcaHelper.Checksum(blockData, 0, length - 2);

            if (BitConverter.IsLittleEndian)
            {
                sum = DereToreHelper.SwapEndian(sum);
            }
            var sumBytes = BitConverter.GetBytes(sum);

            blockData[length - 2] = sumBytes[0];
            blockData[length - 1] = sumBytes[1];
        }
        private void TransformWaveDataBlocks(Stream source, byte[] destination, uint startBlockIndex, uint blockCount, IWaveWriter waveWriter)
        {
            if (source == null)
            {
                throw new ArgumentNullException(nameof(source));
            }
            if (destination == null)
            {
                throw new ArgumentNullException(nameof(destination));
            }
            if (waveWriter == null)
            {
                throw new ArgumentNullException(nameof(waveWriter));
            }
            var hcaInfo     = HcaInfo;
            var startOffset = hcaInfo.DataOffset + startBlockIndex * hcaInfo.BlockSize;

            source.Seek(startOffset, SeekOrigin.Begin);
            var channels       = _channels;
            var decodeParams   = _decodeParams;
            var hcaBlockBuffer = GetHcaBlockBuffer();

            var channelCount   = (int)hcaInfo.ChannelCount;
            var rvaVolume      = hcaInfo.RvaVolume;
            var bytesPerSample = waveWriter.BytesPerSample;

            foreach (var l in Enumerable.Range(0, (int)blockCount))
            {
                source.Read(hcaBlockBuffer, 0, hcaBlockBuffer.Length);
                DecodeToWaveR32(hcaBlockBuffer);
                Parallel.For(0, 8, i => {
                    for (var j = 0; j < 0x80; ++j)
                    {
                        for (var k = 0; k < channelCount; ++k)
                        {
                            var f = channels[k].Wave[i * 0x80 + j] * decodeParams.Volume * rvaVolume;
                            HcaHelper.Clamp(ref f, -1f, 1f);
                            var offset = (((l * 8 + i) * 0x80 + j) * channelCount + k) * bytesPerSample;
                            waveWriter.DecodeToBuffer(f, destination, (uint)offset);
                        }
                    }
                });
            }
        }
        private bool ConvertBlock(byte[] blockData, Stream outputStream)
        {
            var checksum = HcaHelper.Checksum(blockData, 0);

            if (checksum != 0)
            {
                return(false);
            }
            _cipherFrom.Decrypt(blockData);
            var dataClass = new DataBits(blockData, (uint)blockData.Length);
            var magic     = dataClass.GetBit(16);

            if (magic != 0xffff)
            {
                return(false);
            }
            _cipherTo.Encrypt(blockData);
            FixDataBlock(blockData);
            outputStream.Write(blockData, 0, blockData.Length);
            return(true);
        }
Beispiel #7
0
        public void Decode5(int index)
        {
            float[] s;
            float[] d;
            s = Block;
            d = Wav1;
            int sIndex = 0, dIndex = 0;
            int s1Index, s2Index;

            for (int i = 0, count1 = 1, count2 = 0x40; i < 7; ++i, count1 <<= 1, count2 >>= 1)
            {
                int dIndex1 = dIndex, dIndex2 = dIndex + count2;
                for (int j = 0; j < count1; ++j)
                {
                    for (int k = 0; k < count2; ++k)
                    {
                        float a = s[sIndex++];
                        float b = s[sIndex++];
                        d[dIndex1++] = b + a;
                        d[dIndex2++] = a - b;
                    }
                    dIndex1 += count2;
                    dIndex2 += count2;
                }
                sIndex -= 0x80;
                HcaHelper.Exchange(ref sIndex, ref dIndex);
                HcaHelper.Exchange(ref s, ref d);
            }
            s      = Wav1;
            d      = Block;
            sIndex = dIndex = 0;
            for (int i = 0, count1 = 0x40, count2 = 1; i < 7; ++i, count1 >>= 1, count2 <<= 1)
            {
                // The original array is a 2-rank array, [7][0x40].
                int list1FloatIndex = i * 0x40;
                // The original array is a 2-rank array, [7][0x40].
                int list2FloatIndex = i * 0x40;
                s1Index = sIndex;
                s2Index = sIndex + count2;
                int dIndex1 = dIndex;
                int dIndex2 = dIndex + count2 * 2 - 1;
                for (int j = 0; j < count1; ++j)
                {
                    for (int k = 0; k < count2; ++k)
                    {
                        float fa = s[s1Index++];
                        float fb = s[s2Index++];
                        float fc = ChannelTables.Decode5List1Single[list1FloatIndex++];
                        float fd = ChannelTables.Decode5List2Single[list2FloatIndex++];
                        d[dIndex1++] = fa * fc - fb * fd;
                        d[dIndex2--] = fa * fd + fb * fc;
                    }
                    s1Index += count2;
                    s2Index += count2;
                    dIndex1 += count2;
                    dIndex2 += count2 * 3;
                }
                HcaHelper.Exchange(ref sIndex, ref dIndex);
                HcaHelper.Exchange(ref s, ref d);
            }
            d = Wav2;
            for (int i = 0; i < 0x80; ++i)
            {
                d[i] = s[i];
            }
            s      = ChannelTables.Decode5List3Single;
            sIndex = 0;
            d      = Wave;
            // The original array is [8][0x80].
            dIndex = index * 0x80;
            float[] s1 = Wav2;
            s1Index = 0x40;
            float[] s2 = Wav3;
            s2Index = 0;
            for (int i = 0; i < 0x40; ++i)
            {
                d[dIndex++] = s1[s1Index++] * s[sIndex++] + s2[s2Index++];
            }
            for (int i = 0; i < 0x40; ++i)
            {
                d[dIndex++] = s[sIndex++] * s1[--s1Index] - s2[s2Index++];
            }
            s1      = Wav2;
            s2      = Wav3;
            s1Index = 0x40 - 1;
            s2Index = 0;
            for (int i = 0; i < 0x40; ++i)
            {
                s2[s2Index++] = s1[s1Index--] * s[--sIndex];
            }
            for (int i = 0; i < 0x40; ++i)
            {
                s2[s2Index++] = s[--sIndex] * s1[++s1Index];
            }
        }
Beispiel #8
0
        private int DecodeToWaveR32(byte[] blockData, int blockIndex)
        {
            var hcaInfo = HcaInfo;

            if (blockData == null)
            {
                throw new ArgumentNullException(nameof(blockData));
            }
            if (blockData.Length < hcaInfo.BlockSize)
            {
                throw new HcaException(ErrorMessages.GetInvalidParameter(nameof(blockData) + "." + nameof(blockData.Length)), ActionResult.InvalidParameter);
            }
            var checksum = HcaHelper.Checksum(blockData, 0);

            if (checksum != 0)
            {
                throw new HcaException(ErrorMessages.GetChecksumNotMatch(0, checksum), ActionResult.ChecksumNotMatch);
            }
            _cipher.Decrypt(blockData);
            var d     = new DataBits(blockData, hcaInfo.BlockSize);
            var magic = d.GetBit(16);

            if (magic != 0xffff)
            {
                throw new HcaException(ErrorMessages.GetMagicNotMatch(0xffff, magic), ActionResult.MagicNotMatch);
            }
            var    a        = (d.GetBit(9) << 8) - d.GetBit(7);
            var    channels = _channels;
            var    ath      = _ath;
            string site     = null;

            try {
                int i;

                for (i = 0; i < hcaInfo.ChannelCount; ++i)
                {
                    site = $"Decode1({i.ToString()})";
                    channels.Decode1(i, d, hcaInfo.CompR09, a, ath.Table);
                }

                for (i = 0; i < 8; ++i)
                {
                    for (var j = 0; j < hcaInfo.ChannelCount; ++j)
                    {
                        site = $"Decode2({i.ToString()}/{j.ToString()})";
                        channels.Decode2(j, d);
                    }

                    for (var j = 0; j < hcaInfo.ChannelCount; ++j)
                    {
                        site = $"Decode3({i.ToString()}/{j.ToString()})";
                        channels.Decode3(j, hcaInfo.CompR09, hcaInfo.CompR08, (uint)(hcaInfo.CompR07 + hcaInfo.CompR06), hcaInfo.CompR05);
                    }

                    for (var j = 0; j < hcaInfo.ChannelCount - 1; ++j)
                    {
                        site = $"Decode4({i.ToString()}/{j.ToString()})";
                        channels.Decode4(j, j + 1, i, (uint)(hcaInfo.CompR05 - hcaInfo.CompR06), hcaInfo.CompR06, hcaInfo.CompR07);
                    }

                    for (var j = 0; j < hcaInfo.ChannelCount; ++j)
                    {
                        site = $"Decode5({i.ToString()}/{j.ToString()})";
                        channels.Decode5(j, i);
                    }
                }

                return(blockData.Length);
            } catch (IndexOutOfRangeException ex) {
                const string message  = "Index access exception detected. It is probably because you are using an incorrect HCA key pair while decoding a type 56 HCA file.";
                var          siteInfo = $"Site: {site} @ block {blockIndex.ToString()}";
                var          err      = message + Environment.NewLine + siteInfo;
                throw new HcaException(err, ActionResult.DecodeFailed, ex);
            }
        }
Beispiel #9
0
        internal void ParseHeaders()
        {
            var  stream = SourceStream;
            uint v;
            var  hcaInfo = new HcaInfo();

            // HCA
            v = stream.PeekUInt32LE();
            if (MagicValues.IsMagicMatch(v, MagicValues.HCA))
            {
                HcaHeader header;
                stream.Read(out header);
                hcaInfo.Version    = DereToreHelper.SwapEndian(header.Version);
                hcaInfo.DataOffset = DereToreHelper.SwapEndian(header.DataOffset);
            }
            else
            {
                throw new HcaException("Missing HCA signature.", ActionResult.MagicNotMatch);
            }
            // FMT
            v = stream.PeekUInt32LE();
            if (MagicValues.IsMagicMatch(v, MagicValues.FMT))
            {
                FormatHeader header;
                stream.Read(out header);
                hcaInfo.ChannelCount = header.Channels;
                hcaInfo.SamplingRate = DereToreHelper.SwapEndian(header.SamplingRate << 8);
                hcaInfo.BlockCount   = DereToreHelper.SwapEndian(header.Blocks);
                hcaInfo.FmtR01       = DereToreHelper.SwapEndian(header.R01);
                hcaInfo.FmtR02       = DereToreHelper.SwapEndian(header.R02);
                if (hcaInfo.ChannelCount < 1 || hcaInfo.ChannelCount > 16)
                {
                    throw new HcaException($"Channel count should be between 1 and 16, read {hcaInfo.ChannelCount}.", ActionResult.InvalidFieldValue);
                }
                if (hcaInfo.SamplingRate < 1 || hcaInfo.SamplingRate > 0x7fffff)
                {
                    throw new HcaException($"Sampling rate should be between 1 and {0x7fffffff}, read {hcaInfo.SamplingRate}.", ActionResult.InvalidFieldValue);
                }
            }
            else
            {
                throw new HcaException("Missing FMT signature.", ActionResult.MagicNotMatch);
            }
            // COMP / DEC
            v = stream.PeekUInt32LE();
            if (MagicValues.IsMagicMatch(v, MagicValues.COMP))
            {
                CompressHeader header;
                stream.Read(out header);
                hcaInfo.BlockSize = DereToreHelper.SwapEndian(header.BlockSize);
                hcaInfo.CompR01   = header.R01;
                hcaInfo.CompR02   = header.R02;
                hcaInfo.CompR03   = header.R03;
                hcaInfo.CompR04   = header.R04;
                hcaInfo.CompR05   = header.R05;
                hcaInfo.CompR06   = header.R06;
                hcaInfo.CompR07   = header.R07;
                hcaInfo.CompR08   = header.R08;
                if ((hcaInfo.BlockSize < 8 || hcaInfo.BlockSize > 0xffff) && hcaInfo.BlockSize != 0)
                {
                    throw new HcaException($"Block size should be between 8 and {0xffff}, read {hcaInfo.BlockSize}.", ActionResult.InvalidFieldValue);
                }
                if (!(hcaInfo.CompR01 <= hcaInfo.CompR02 && hcaInfo.CompR02 <= 0x1f))
                {
                    throw new HcaException($"CompR01 should be less than or equal to CompR02, and CompR02 should be less than or equal to {0x1f}, read {hcaInfo.CompR01} and {hcaInfo.CompR02}.", ActionResult.InvalidFieldValue);
                }
            }
            else if (MagicValues.IsMagicMatch(v, MagicValues.DEC))
            {
                DecodeHeader header;
                stream.Read(out header);
                hcaInfo.CompR01 = header.R01;
                hcaInfo.CompR02 = header.R02;
                hcaInfo.CompR03 = header.R04;
                hcaInfo.CompR04 = header.R03;
                hcaInfo.CompR05 = (ushort)(header.Count1 + 1);
                hcaInfo.CompR06 = (ushort)((header.EnableCount2 ? header.Count2 : header.Count1) + 1);
                hcaInfo.CompR07 = (ushort)(hcaInfo.CompR05 - hcaInfo.CompR06);
                hcaInfo.CompR08 = 0;
                if ((hcaInfo.BlockSize < 8 || hcaInfo.BlockSize > 0xffff) && hcaInfo.BlockSize != 0)
                {
                    throw new HcaException($"Block size should be between 8 and {0xffff}, read {hcaInfo.BlockSize}.", ActionResult.InvalidFieldValue);
                }
                if (!(hcaInfo.CompR01 <= hcaInfo.CompR02 && hcaInfo.CompR02 <= 0x1f))
                {
                    throw new HcaException($"CompR01 should be less than or equal to CompR02, and CompR02 should be less than or equal to {0x1f}, read {hcaInfo.CompR01} and {hcaInfo.CompR02}.", ActionResult.InvalidFieldValue);
                }
                if (hcaInfo.CompR03 == 0)
                {
                    hcaInfo.CompR03 = 1;
                }
            }
            else
            {
                throw new HcaException("Missing COMP/DEC signature.", ActionResult.MagicNotMatch);
            }
            // VBR
            v = stream.PeekUInt32LE();
            if (MagicValues.IsMagicMatch(v, MagicValues.VBR))
            {
                VbrHeader header;
                stream.Read(out header);
                hcaInfo.VbrR01 = DereToreHelper.SwapEndian(header.R01);
                hcaInfo.VbrR02 = DereToreHelper.SwapEndian(header.R02);
                if (!(hcaInfo.BlockSize == 0 && hcaInfo.VbrR01 < 0x01ff))
                {
                    throw new HcaException($"VbrR01 should be less than {0x01ff} in VBR HCA.", ActionResult.InvalidFieldValue);
                }
            }
            else
            {
                hcaInfo.VbrR01 = hcaInfo.VbrR02 = 0;
            }
            // ATH
            v = stream.PeekUInt32LE();
            if (MagicValues.IsMagicMatch(v, MagicValues.ATH))
            {
                AthHeader header;
                stream.Read(out header);
                hcaInfo.AthType = header.Type;
            }
            else
            {
                hcaInfo.AthType = (ushort)(hcaInfo.Version < 0x0200 ? 1 : 0);
            }
            // LOOP
            v = stream.PeekUInt32LE();
            if (MagicValues.IsMagicMatch(v, MagicValues.LOOP))
            {
                LoopHeader header;
                stream.Read(out header);
                hcaInfo.LoopStart = DereToreHelper.SwapEndian(header.LoopStart);
                hcaInfo.LoopEnd   = DereToreHelper.SwapEndian(header.LoopEnd);
                hcaInfo.LoopR01   = DereToreHelper.SwapEndian(header.R01);
                hcaInfo.LoopR02   = DereToreHelper.SwapEndian(header.R02);
                hcaInfo.LoopFlag  = true;
            }
            else
            {
                hcaInfo.LoopStart = 0;
                hcaInfo.LoopEnd   = 0;
                hcaInfo.LoopR01   = 0;
                hcaInfo.LoopR02   = 0x400;
                hcaInfo.LoopFlag  = false;
            }
            // CIPH
            v = stream.PeekUInt32LE();
            if (MagicValues.IsMagicMatch(v, MagicValues.CIPH))
            {
                CipherHeader header;
                stream.Read(out header);
                hcaInfo.CipherType = (CipherType)DereToreHelper.SwapEndian(header.Type);
            }
            else
            {
                hcaInfo.CipherType = CipherType.NoChipher;
            }
            // RVA
            v = stream.PeekUInt32LE();
            if (MagicValues.IsMagicMatch(v, MagicValues.RVA))
            {
                RvaHeader header;
                stream.Read(out header);
                hcaInfo.RvaVolume = DereToreHelper.SwapEndian(header.Volume);
            }
            else
            {
                hcaInfo.RvaVolume = 1;
            }
            // COMM
            v = stream.PeekUInt32LE();
            if (MagicValues.IsMagicMatch(v, MagicValues.COMM))
            {
                CommentHeader header;
                stream.Read(out header);
                hcaInfo.CommentLength = header.Length;
                var  tmpCommentCharList = new List <byte>();
                byte tmpByte;
                do
                {
                    tmpByte = (byte)stream.ReadByte();
                    tmpCommentCharList.Add(tmpByte);
                } while (tmpByte != 0);
                hcaInfo.Comment = tmpCommentCharList.ToArray();
            }
            else
            {
                hcaInfo.CommentLength = 0;
                hcaInfo.Comment       = null;
            }
            // PAD (undocumented)
            v = stream.PeekUInt32LE();
            if (MagicValues.IsMagicMatch(v, MagicValues.PAD))
            {
                stream.Skip(4); // Length of 'pad '
            }

            if (hcaInfo.CompR03 == 0)
            {
                hcaInfo.CompR03 = 1;
            }

            if (hcaInfo.CompR01 != 1 || hcaInfo.CompR02 != 0xf)
            {
                throw new HcaException($"Expected CompR01=1, CompR02=15, read {hcaInfo.CompR01}, {hcaInfo.CompR02}.", ActionResult.InvalidFieldValue);
            }
            hcaInfo.CompR09 = HcaHelper.Ceil2((uint)(hcaInfo.CompR05 - (hcaInfo.CompR06 + hcaInfo.CompR07)), hcaInfo.CompR08);
            HcaInfo         = hcaInfo;
        }