diff --git a/Apps/Acb2Wavs/DereTore.Apps.BatchDecodeFromAcb.csproj b/Apps/Acb2Wavs/DereTore.Apps.Acb2Wavs.csproj similarity index 98% rename from Apps/Acb2Wavs/DereTore.Apps.BatchDecodeFromAcb.csproj rename to Apps/Acb2Wavs/DereTore.Apps.Acb2Wavs.csproj index fea188c..9ae29de 100644 --- a/Apps/Acb2Wavs/DereTore.Apps.BatchDecodeFromAcb.csproj +++ b/Apps/Acb2Wavs/DereTore.Apps.Acb2Wavs.csproj @@ -6,7 +6,7 @@ AnyCPU {2E1C8FF3-0E5E-4963-8DC4-F711F09B9419} Exe - DereTore.Apps.BatchDecodeFromAcb + DereTore.Apps.Acb2Wavs acb2wavs v4.5 512 diff --git a/Apps/Acb2Wavs/Options.cs b/Apps/Acb2Wavs/Options.cs index b81e907..825284b 100644 --- a/Apps/Acb2Wavs/Options.cs +++ b/Apps/Acb2Wavs/Options.cs @@ -1,15 +1,12 @@ using CommandLine; using DereTore.Common.StarlightStage; -namespace DereTore.Apps.BatchDecodeFromAcb { +namespace DereTore.Apps.Acb2Wavs { public sealed class Options { [Value(0, HelpText = "Input file name", Required = true)] public string InputFileName { get; set; } = string.Empty; - [Option('o', "out", HelpText = "Output file name", Required = false)] - public string OutputFileName { get; set; } = string.Empty; - [Option('a', "key1", HelpText = "Key 1 (8 hex digits)", Required = false, Default = "f27e3b22")] public string Key1 { get; set; } = CgssCipher.Key1.ToString("x8"); diff --git a/Apps/Acb2Wavs/Program.cs b/Apps/Acb2Wavs/Program.cs index 02ded84..4da39e2 100644 --- a/Apps/Acb2Wavs/Program.cs +++ b/Apps/Acb2Wavs/Program.cs @@ -6,7 +6,7 @@ using DereTore.Exchange.Archive.ACB; using DereTore.Exchange.Audio.HCA; -namespace DereTore.Apps.BatchDecodeFromAcb { +namespace DereTore.Apps.Acb2Wavs { internal static class Program { private static int Main(string[] args) { @@ -162,7 +162,12 @@ private static void ProcessAllBinaries(uint acbFormatVersion, DecodeParams baseD File.Delete(extractFilePath); } - Console.WriteLine(ex.Message); + Console.WriteLine(ex.ToString()); + + if (ex.InnerException != null) { + Console.WriteLine("Details:"); + Console.WriteLine(ex.InnerException.ToString()); + } } } else { Console.WriteLine("skipped (not HCA)"); diff --git a/DereTore.sln b/DereTore.sln index 354ec9a..8e5dc34 100644 --- a/DereTore.sln +++ b/DereTore.sln @@ -66,7 +66,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "external", "external", "{F8 EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SharpAL", "external\SharpAL\SharpAL\SharpAL.csproj", "{7E5E07E6-4300-438E-BD37-C9F6E5E14A41}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DereTore.Apps.BatchDecodeFromAcb", "Apps\Acb2Wavs\DereTore.Apps.BatchDecodeFromAcb.csproj", "{2E1C8FF3-0E5E-4963-8DC4-F711F09B9419}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DereTore.Apps.Acb2Wavs", "Apps\Acb2Wavs\DereTore.Apps.Acb2Wavs.csproj", "{2E1C8FF3-0E5E-4963-8DC4-F711F09B9419}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DereTore.Interop.D3DX9", "Interop\DereTore.Interop.D3DX9\DereTore.Interop.D3DX9.csproj", "{F81398AD-9CF5-43A4-9CD3-DABB50F6BA3B}" EndProject diff --git a/Exchange/DereTore.Exchange.Audio.HCA/Ath.cs b/Exchange/DereTore.Exchange.Audio.HCA/Ath.cs index b8c6646..0eb39ac 100644 --- a/Exchange/DereTore.Exchange.Audio.HCA/Ath.cs +++ b/Exchange/DereTore.Exchange.Audio.HCA/Ath.cs @@ -1,8 +1,11 @@ -using DereTore.Common; +using DereTore.Common; namespace DereTore.Exchange.Audio.HCA { internal sealed class Ath { + static Ath() { + } + public bool Initialize(uint type, uint key) { switch (type) { case 0: @@ -38,7 +41,7 @@ private void Init1(uint key) { private readonly byte[] _table = new byte[0x80]; - private static readonly byte[] AthInitList = new byte[] { + private static readonly byte[] AthInitList = { 0x78, 0x5f, 0x56, 0x51, 0x4e, 0x4c, 0x4b, 0x49, 0x48, 0x48, 0x47, 0x46, 0x46, 0x45, 0x45, 0x45, 0x44, 0x44, 0x44, 0x44, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x40, 0x40, 0x40, 0x40, diff --git a/Exchange/DereTore.Exchange.Audio.HCA/Channel.cs b/Exchange/DereTore.Exchange.Audio.HCA/Channel.cs index 813da16..0a69991 100644 --- a/Exchange/DereTore.Exchange.Audio.HCA/Channel.cs +++ b/Exchange/DereTore.Exchange.Audio.HCA/Channel.cs @@ -1,294 +1,34 @@ -using System; +using System; using System.Runtime.InteropServices; -using DereTore.Common; namespace DereTore.Exchange.Audio.HCA { [StructLayout(LayoutKind.Sequential, Pack = 1)] internal struct Channel { - [MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.R8, SizeConst = 0x80)] + [MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.R4, SizeConst = 0x80)] public float[] Block; - [MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.R8, SizeConst = 0x80)] + [MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.R4, SizeConst = 0x80)] public float[] Base; - [MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.U1, SizeConst = 0x80)] - public byte[] Value; - [MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.U1, SizeConst = 0x80)] - public byte[] Scale; - [MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.U1, SizeConst = 8)] - public byte[] Value2; + [MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.I1, SizeConst = 0x80)] + public sbyte[] Value; + [MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.I1, SizeConst = 0x80)] + public sbyte[] Scale; + [MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.I1, SizeConst = 8)] + public sbyte[] Value2; [MarshalAs(UnmanagedType.I4)] public int Type; // Original type: public char * + public IntPtr Value3; [MarshalAs(UnmanagedType.U4)] - public uint Value3; public uint Count; - [MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.R8, SizeConst = 0x80)] + [MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.R4, SizeConst = 0x80)] public float[] Wav1; - [MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.R8, SizeConst = 0x80)] + [MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.R4, SizeConst = 0x80)] public float[] Wav2; - [MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.R8, SizeConst = 0x80)] + [MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.R4, SizeConst = 0x80)] public float[] Wav3; - [MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.R8, SizeConst = 8 * 0x80)] + [MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.R4, SizeConst = 8 * 0x80)] public float[] Wave; - public static Channel CreateDefault() { - var v = default(Channel); - v.Block = new float[0x80]; - v.Base = new float[0x80]; - v.Value = new byte[0x80]; - v.Scale = new byte[0x80]; - v.Value2 = new byte[8]; - v.Type = 0; - v.Value3 = 0; - v.Count = 0; - v.Wav1 = new float[0x80]; - v.Wav2 = new float[0x80]; - v.Wav3 = new float[0x80]; - v.Wave = new float[8 * 0x80]; - return v; - } - - public void Decode1(DataBits data, uint a, int b, byte[] ath) { - int v = data.GetBit(3); - if (v >= 6) { - for (uint i = 0; i < Count; ++i) { - Value[i] = (byte)data.GetBit(6); - } - } else if (v != 0) { - int v1 = data.GetBit(6); - int v2 = (1 << v) - 1; - int v3 = v2 >> 1; - Value[0] = (byte)v1; - for (uint i = 1; i < Count; ++i) { - int v4 = data.GetBit(v); - if (v4 != v2) { - v1 += v4 - v3; - } else { - v1 = data.GetBit(6); - } - Value[i] = (byte)v1; - } - } else { - Value.ZeroMem(); - } - if (Type == 2) { - v = data.CheckBit(4); - Value2[0] = (byte)v; - if (v < 15) { - for (var i = 0; i < 8; ++i) { - Value2[i] = (byte)data.GetBit(4); - } - } - } else { - for (uint i = 0; i < a; ++i) { - //Value3[i] = (byte)data.GetBit(6); - SetValue3(i, (byte)data.GetBit(6)); - } - } - for (uint i = 0; i < Count; ++i) { - v = Value[i]; - if (v != 0) { - v = (int)(ath[i] + ((b + i) >> 8) - ((v * 5) >> 1) + 1); - if (v < 0) { - v = 15; - } else if (v >= 0x39) { - v = 1; - } else { - v = ChannelTables.Decode1ScaleList[v]; - } - } - Scale[i] = (byte)v; - } - for (var i = Count; i < Scale.Length; ++i) { - Scale[i] = 0; - } - for (uint i = 0; i < Count; ++i) { - Base[i] = ChannelTables.Decode1ValueSingle[Value[i]] * ChannelTables.Decode1ScaleSingle[Scale[i]]; - } - } - - public void Decode2(DataBits data) { - for (uint i = 0; i < Count; ++i) { - float f; - int s = Scale[i]; - int bitSize = ChannelTables.Decode2List1[s]; - int v = data.GetBit(bitSize); - if (s < 8) { - v += s << 4; - data.AddBit(ChannelTables.Decode2List2[v] - bitSize); - f = ChannelTables.Decode2List3[v]; - } else { - v = (1 - ((v & 1) << 1)) * (v >> 1); - if (v == 0) { - data.AddBit(-1); - } - f = v; - } - Block[i] = Base[i] * f; - } - for (var i = Count; i < Block.Length; ++i) { - Block[i] = 0; - } - } - - public void Decode3(uint a, uint b, uint c, uint d) { - if (Type != 2 && b != 0) { - float[] listFloat = ChannelTables.Decode3ListSingle; - int offset = ChannelTables.Decode3ListOffset; - for (uint i = 0, k = c, l = c - 1; i < a; ++i) { - for (uint j = 0; j < b && k < d; ++j, --l) { - Block[k++] = listFloat[GetValue3(i) - Value[l] + offset] * Block[l]; - } - } - Block[0x80 - 1] = 0; - } - } - - public static void Decode4(ref Channel @this, ref Channel next, int index, uint a, uint b, uint c) { - if (@this.Type == 1 && c != 0) { - var f1 = ChannelTables.Decode4ListSingle[next.Value2[index]]; - var f2 = f1 - 2f; - float[] s = @this.Block; - float[] d = next.Block; - int sIndex, dIndex; - sIndex = (int)b; - dIndex = (int)b; - for (uint i = 0; i < a; ++i) { - // Don't know why, but it just happened. - // See se_live_flic_perfect.hca - // original: - /* - * (no 'break') - * d[dIndex++] = s[sIndex] * f2; - * s[sIndex++] = s[sIndex] * f1; - */ - if (sIndex >= s.Length || dIndex >= d.Length) { - break; - } - d[dIndex] = s[sIndex] * f2; - dIndex++; - s[sIndex] = s[sIndex] * f1; - sIndex++; - } - } - } - - 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]; - } - } - - private byte GetValue3(int refIndex) { - int index = (int)(refIndex + Value3); - if (0 <= index && index < 0x80) { - return Value[index]; - } else if (0x80 <= index && index < 0x80 + 0x80) { - return Scale[index - 0x80]; - } else { - throw new ArgumentOutOfRangeException(nameof(refIndex)); - } - } - - private byte GetValue3(uint refIndex) { - var index = refIndex + Value3; - if (index < 0x80) { - return Value[index]; - } else if (index < 0x80 + 0x80) { - return Scale[index - 0x80]; - } else { - throw new ArgumentOutOfRangeException(nameof(refIndex)); - } - } - - private void SetValue3(int refIndex, byte value) { - Value[refIndex + Value3] = value; - } - - private void SetValue3(uint refIndex, byte value) { - Value[refIndex + Value3] = value; - } - - private void SetValue3(byte value) { - Value[Value3] = value; - } - } } diff --git a/Exchange/DereTore.Exchange.Audio.HCA/ChannelArray.cs b/Exchange/DereTore.Exchange.Audio.HCA/ChannelArray.cs new file mode 100644 index 0000000..028c0d0 --- /dev/null +++ b/Exchange/DereTore.Exchange.Audio.HCA/ChannelArray.cs @@ -0,0 +1,382 @@ +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using DereTore.Common; +using DereTore.Interop.OS; + +namespace DereTore.Exchange.Audio.HCA { + internal sealed unsafe class ChannelArray : DisposableBase { + + static ChannelArray() { + } + + public ChannelArray(int channelCount) { + ChannelCount = channelCount; + + var totalSize = channelCount * ChannelSize; + + _basePtr = Marshal.AllocHGlobal(totalSize); + + NativeMethods.RtlZeroMemory(_basePtr, totalSize); + } + + public int ChannelCount { get; } + + public void Decode1(int channelIndex, DataBits data, uint a, int b, byte[] ath) { + var v = data.GetBit(3); + var pCount = GetPtrOfCount(channelIndex); + var pValue = GetPtrOfValue(channelIndex); + + if (v >= 6) { + for (var i = 0; i < *pCount; ++i) { + pValue[i] = (sbyte)data.GetBit(6); + } + } else if (v != 0) { + var v1 = data.GetBit(6); + var v2 = (1 << v) - 1; + var v3 = v2 >> 1; + + pValue[0] = (sbyte)v1; + + for (var i = 1; i < *pCount; ++i) { + var v4 = data.GetBit(v); + + if (v4 != v2) { + v1 += v4 - v3; + } else { + v1 = data.GetBit(6); + } + + pValue[i] = (sbyte)v1; + } + } else { + NativeMethods.RtlZeroMemory(pValue, 0x80); + } + + var pType = GetPtrOfType(channelIndex); + var pValue2 = GetPtrOfValue2(channelIndex); + var ppValue3 = GetPtrOfValue3(channelIndex); + + if (*pType == 2) { + v = data.CheckBit(4); + pValue2[0] = (sbyte)v; + + if (v < 15) { + for (var i = 0; i < 8; ++i) { + pValue2[i] = (sbyte)data.GetBit(4); + } + } + } else { + for (var i = 0; i < a; ++i) { + (*ppValue3)[i] = (sbyte)data.GetBit(6); + } + } + + var pScale = GetPtrOfScale(channelIndex); + + for (var i = 0; i < *pCount; ++i) { + v = pValue[i]; + + if (v != 0) { + v = ath[i] + ((b + i) >> 8) - ((v * 5) >> 1) + 1; + + if (v < 0) { + v = 15; + } else if (v >= 0x39) { + v = 1; + } else { + v = ChannelTables.Decode1ScaleList[v]; + } + } + + pScale[i] = (sbyte)v; + } + + NativeMethods.RtlZeroMemory(&pScale[*pCount], (int)(0x80 - *pCount)); + + var pBase = GetPtrOfBase(channelIndex); + + for (var i = 0; i < *pCount; ++i) { + pBase[i] = ChannelTables.Decode1ValueSingle[pValue[i]] * ChannelTables.Decode1ScaleSingle[pScale[i]]; + } + } + + public void Decode2(int channelIndex, DataBits data) { + var pCount = GetPtrOfCount(channelIndex); + var pScale = GetPtrOfScale(channelIndex); + var pBlock = GetPtrOfBlock(channelIndex); + var pBase = GetPtrOfBase(channelIndex); + + for (var i = 0; i < *pCount; ++i) { + int s = pScale[i]; + int bitSize = ChannelTables.Decode2List1[s]; + var v = data.GetBit(bitSize); + float f; + + if (s < 8) { + v += s << 4; + data.AddBit(ChannelTables.Decode2List2[v] - bitSize); + f = ChannelTables.Decode2List3[v]; + } else { + v = (1 - ((v & 1) << 1)) * (v >> 1); + + if (v == 0) { + data.AddBit(-1); + } + + f = v; + } + + pBlock[i] = pBase[i] * f; + } + + NativeMethods.RtlZeroMemory(&pBlock[*pCount], sizeof(float) * (int)(0x80 - *pCount)); + } + + public void Decode3(int channelIndex, uint a, uint b, uint c, uint d) { + var pType = GetPtrOfType(channelIndex); + + if (*pType != 2 && b != 0) { + fixed (float* listFloatBase = ChannelTables.Decode3ListSingle) { + var pBlock = GetPtrOfBlock(channelIndex); + var ppValue3 = GetPtrOfValue3(channelIndex); + var pValue = GetPtrOfValue(channelIndex); + var listFloat = listFloatBase + 0x40; + + var k = c; + var l = c - 1; + + for (var i = 0; i < a; ++i) { + for (var j = 0; j < b && k < d; ++j, --l) { + pBlock[k++] = listFloat[(*ppValue3)[i] - pValue[l]] * pBlock[l]; + } + } + + pBlock[0x80 - 1] = 0; + } + } + } + + public void Decode4(int channelIndex1, int channelIndex2, int index, uint a, uint b, uint c) { + var pTypeA = GetPtrOfType(channelIndex1); + + if (*pTypeA == 1 && c != 0) { + var pValue2B = GetPtrOfValue2(channelIndex2); + var pBlockA = GetPtrOfBlock(channelIndex1); + var pBlockB = GetPtrOfBlock(channelIndex2); + + var f1 = ChannelTables.Decode4ListSingle[pValue2B[index]]; + var f2 = f1 - 2.0f; + + var s = &pBlockA[b]; + var d = &pBlockB[b]; + + for (var i = 0; i < a; ++i) { + *(d++) = *s * f2; + *(s++) = *s * f1; + } + } + } + + public void Decode5(int channelIndex, int index) { + float* s, d; + + s = GetPtrOfBlock(channelIndex); + d = GetPtrOfWav1(channelIndex); + + var count1 = 1; + var count2 = 0x40; + + for (var i = 0; i < 7; ++i, count1 <<= 1, count2 >>= 1) { + var d1 = d; + var d2 = &d[count2]; + + for (var j = 0; j < count1; ++j) { + for (var k = 0; k < count2; ++k) { + var a = *(s++); + var b = *(s++); + + *(d1++) = b + a; + *(d2++) = a - b; + } + + d1 += count2; + d2 += count2; + } + + var w = &s[-0x80]; + s = d; + d = w; + } + + s = GetPtrOfWav1(channelIndex); + d = GetPtrOfBlock(channelIndex); + + fixed (float* list1FloatBase = ChannelTables.Decode5List1Single) { + fixed (float* list2FloatBase = ChannelTables.Decode5List2Single) { + count1 = 0x40; + count2 = 1; + + for (var i = 0; i < 7; ++i, count1 >>= 1, count2 <<= 1) { + var list1Float = &list1FloatBase[i * 0x40]; + var list2Float = &list2FloatBase[i * 0x40]; + + var s1 = s; + var s2 = &s1[count2]; + var d1 = d; + var d2 = &d1[count2 * 2 - 1]; + + for (var j = 0; j < count1; ++j) { + for (var k = 0; k < count2; ++k) { + var fa = *(s1++); + var fb = *(s2++); + var fc = *(list1Float++); + var fd = *(list2Float++); + + *(d1++) = fa * fc - fb * fd; + *(d2--) = fa * fd + fb * fc; + } + + s1 += count2; + s2 += count2; + d1 += count2; + d2 += count2 * 3; + } + + var w = s; + s = d; + d = w; + } + } + } + + d = GetPtrOfWav2(channelIndex); + + for (var i = 0; i < 0x80; ++i) { + *(d++) = *(s++); + } + + fixed (float* list3FloatBase = ChannelTables.Decode5List3Single) { + s = list3FloatBase; + d = GetPtrOfWave(channelIndex) + index * 0x80; + + var s1 = &GetPtrOfWav2(channelIndex)[0x40]; + var s2 = GetPtrOfWav3(channelIndex); + + for (var i = 0; i < 0x40; ++i) { + *(d++) = *(s1++) * *(s++) + *(s2++); + } + + for (var i = 0; i < 0x40; ++i) { + *(d++) = *(s++) * *(--s1) - *(s2++); + } + + s1 = &GetPtrOfWav2(channelIndex)[0x40 - 1]; + s2 = GetPtrOfWav3(channelIndex); + + for (var i = 0; i < 0x40; ++i) { + *(s2++) = *(s1--) * *(--s); + } + + for (var i = 0; i < 0x40; ++i) { + *(s2++) = *(--s) * *(++s1); + } + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void* GetBasePtr(int channelIndex) { + return (void*)(_basePtr + ChannelSize * channelIndex); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public float* GetPtrOfBlock(int channelIndex) { + return (float*)GetPtrOf(channelIndex, OffsetOfBlock); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public float* GetPtrOfBase(int channelIndex) { + return (float*)GetPtrOf(channelIndex, OffsetOfBase); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public sbyte* GetPtrOfValue(int channelIndex) { + return (sbyte*)GetPtrOf(channelIndex, OffsetOfValue); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public sbyte* GetPtrOfScale(int channelIndex) { + return (sbyte*)GetPtrOf(channelIndex, OffsetOfScale); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public sbyte* GetPtrOfValue2(int channelIndex) { + return (sbyte*)GetPtrOf(channelIndex, OffsetOfValue2); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public int* GetPtrOfType(int channelIndex) { + return (int*)GetPtrOf(channelIndex, OffsetOfType); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public sbyte** GetPtrOfValue3(int channelIndex) { + return (sbyte**)GetPtrOf(channelIndex, OffsetOfValue3); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public uint* GetPtrOfCount(int channelIndex) { + return (uint*)GetPtrOf(channelIndex, OffsetOfCount); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public float* GetPtrOfWav1(int channelIndex) { + return (float*)GetPtrOf(channelIndex, OffsetOfWav1); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public float* GetPtrOfWav2(int channelIndex) { + return (float*)GetPtrOf(channelIndex, OffsetOfWav2); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public float* GetPtrOfWav3(int channelIndex) { + return (float*)GetPtrOf(channelIndex, OffsetOfWav3); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public float* GetPtrOfWave(int channelIndex) { + return (float*)GetPtrOf(channelIndex, OffsetOfWave); + } + + protected override void Dispose(bool disposing) { + if (_basePtr != IntPtr.Zero) { + Marshal.FreeHGlobal(_basePtr); + } + + _basePtr = IntPtr.Zero; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private IntPtr GetPtrOf(int channelIndex, IntPtr fieldOffset) { + return _basePtr + ChannelSize * channelIndex + fieldOffset.ToInt32(); + } + + private static readonly int ChannelSize = Marshal.SizeOf(typeof(Channel)); + private static readonly IntPtr OffsetOfBlock = Marshal.OffsetOf(typeof(Channel), nameof(Channel.Block)); + private static readonly IntPtr OffsetOfBase = Marshal.OffsetOf(typeof(Channel), nameof(Channel.Base)); + private static readonly IntPtr OffsetOfValue = Marshal.OffsetOf(typeof(Channel), nameof(Channel.Value)); + private static readonly IntPtr OffsetOfScale = Marshal.OffsetOf(typeof(Channel), nameof(Channel.Scale)); + private static readonly IntPtr OffsetOfValue2 = Marshal.OffsetOf(typeof(Channel), nameof(Channel.Value2)); + private static readonly IntPtr OffsetOfType = Marshal.OffsetOf(typeof(Channel), nameof(Channel.Type)); + private static readonly IntPtr OffsetOfValue3 = Marshal.OffsetOf(typeof(Channel), nameof(Channel.Value3)); + private static readonly IntPtr OffsetOfCount = Marshal.OffsetOf(typeof(Channel), nameof(Channel.Count)); + private static readonly IntPtr OffsetOfWav1 = Marshal.OffsetOf(typeof(Channel), nameof(Channel.Wav1)); + private static readonly IntPtr OffsetOfWav2 = Marshal.OffsetOf(typeof(Channel), nameof(Channel.Wav2)); + private static readonly IntPtr OffsetOfWav3 = Marshal.OffsetOf(typeof(Channel), nameof(Channel.Wav3)); + private static readonly IntPtr OffsetOfWave = Marshal.OffsetOf(typeof(Channel), nameof(Channel.Wave)); + + private IntPtr _basePtr; + + } +} diff --git a/Exchange/DereTore.Exchange.Audio.HCA/ChannelTables.cs b/Exchange/DereTore.Exchange.Audio.HCA/ChannelTables.cs index a4b17ab..58f8906 100644 --- a/Exchange/DereTore.Exchange.Audio.HCA/ChannelTables.cs +++ b/Exchange/DereTore.Exchange.Audio.HCA/ChannelTables.cs @@ -1,6 +1,9 @@ -namespace DereTore.Exchange.Audio.HCA { +namespace DereTore.Exchange.Audio.HCA { internal static class ChannelTables { + static ChannelTables() { + } + public static void TranslateTables() { _decode1ValueSingle = new float[_decode1ValueUInt.Length]; for (var i = 0; i < _decode1ValueSingle.Length; ++i) { diff --git a/Exchange/DereTore.Exchange.Audio.HCA/DataBits.cs b/Exchange/DereTore.Exchange.Audio.HCA/DataBits.cs index e1b1cce..0f82287 100644 --- a/Exchange/DereTore.Exchange.Audio.HCA/DataBits.cs +++ b/Exchange/DereTore.Exchange.Audio.HCA/DataBits.cs @@ -1,6 +1,11 @@ -namespace DereTore.Exchange.Audio.HCA { +using System.Runtime.CompilerServices; + +namespace DereTore.Exchange.Audio.HCA { internal sealed class DataBits { + static DataBits() { + } + public DataBits(byte[] data, uint size) { _data = data; _size = size * 8 - 16; @@ -9,27 +14,40 @@ public DataBits(byte[] data, uint size) { public int CheckBit(int bitSize) { var v = 0; + if (_bit + bitSize <= _size) { var i = _bit >> 3; - v = _data[i]; - v = (v << 8) | _data[i + 1]; - v = (v << 8) | _data[i + 2]; + v = SafeAccessData(i); + v = (v << 8) | SafeAccessData(i + 1); + v = (v << 8) | SafeAccessData(i + 2); v &= Mask[_bit & 7]; v >>= 24 - (_bit & 7) - bitSize; } + return v; } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public int GetBit(int bitSize) { var v = CheckBit(bitSize); _bit += bitSize; return v; } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public void AddBit(int bitSize) { _bit += bitSize; } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private byte SafeAccessData(int index) { + if (0 <= index && index < _data.Length) { + return _data[index]; + } else { + return 0; + } + } + private static readonly int[] Mask = { 0xffffff, 0x7fffff, 0x3fffff, 0x1fffff, 0x0fffff, 0x07ffff, 0x03ffff, 0x01ffff }; private readonly byte[] _data; diff --git a/Exchange/DereTore.Exchange.Audio.HCA/DereTore.Exchange.Audio.HCA.csproj b/Exchange/DereTore.Exchange.Audio.HCA/DereTore.Exchange.Audio.HCA.csproj index 0f4eb55..77b7d0b 100644 --- a/Exchange/DereTore.Exchange.Audio.HCA/DereTore.Exchange.Audio.HCA.csproj +++ b/Exchange/DereTore.Exchange.Audio.HCA/DereTore.Exchange.Audio.HCA.csproj @@ -22,6 +22,7 @@ 6 prompt MinimumRecommendedRules.ruleset + true bin\Release\ @@ -32,6 +33,7 @@ 6 prompt MinimumRecommendedRules.ruleset + true @@ -41,6 +43,7 @@ + @@ -95,6 +98,10 @@ {dbd0da4a-0057-4d04-ad69-0e7267d72793} DereTore.Common + + {3a0d1281-a503-4e5d-9765-d7bf56f89266} + DereTore.Interop.OS +