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
+