add VAG decoder.

This commit is contained in:
AtelierWindows 2019-05-07 00:53:11 +12:00
parent 71a888d526
commit 2379bf30e7
6 changed files with 697 additions and 243 deletions

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8" ?>
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6.1" />
</startup>
</configuration>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.7"/></startup>
</configuration>

View File

@ -2,13 +2,15 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using General;
using System.IO;
using System.Text;
using System.Xml;
namespace CXML
{
enum AttributeType
{
TYPE_NONE,
@ -26,216 +28,10 @@ namespace CXML
TYPE_ID_INT
};
class Tools
{
public static String RemoveDecimals(float FloatValue)
{
String FloatStr = FloatValue.ToString();
String[] FloatParts = FloatStr.Split('.');
if (FloatParts.Length > 1)
if(FloatParts[1].Length > 2)
FloatParts[1] = FloatParts[1].Substring(0, 2);
FloatStr = String.Join(".", FloatParts);
return FloatStr;
}
public static MemoryStream ByteToStream(byte[] Array)
{
MemoryStream ms = new MemoryStream();
ms.Write(Array, 0x00, Array.Length);
ms.Seek(0, SeekOrigin.Begin);
return ms;
}
public static byte[] StreamToByte(Stream stream)
{
int StreamLen = (int)stream.Length;
byte[] Bytes = new byte[StreamLen];
stream.Seek(0, SeekOrigin.Begin);
stream.Read(Bytes, 0x00, StreamLen);
return Bytes;
}
public static string GetFileExtension(byte[] Bytes)
{
if(IsImage(Bytes))
{
return ".png";
}
else if(IsZlib(Bytes))
{
return ".zlib";
}
else if(IsGim(Bytes))
{
return ".gim";
}
else if(IsRcf(Bytes))
{
return ".rcs";
}
else if(IsDDS(Bytes))
{
return ".dds";
}
else if (IsVAG(Bytes))
{
return ".vag";
}
else
{
return ".bin";
}
}
public static bool IsVAG(byte[] Bytes)
{
MemoryStream Data = ByteToStream(Bytes);
String header = ReadString(Data, 4);
if (header.StartsWith("VAG"))
{
return true;
}
else
{
return false;
}
}
public static bool IsDDS(byte[] Bytes)
{
MemoryStream Data = ByteToStream(Bytes);
String header = ReadString(Data, 4);
if (header.StartsWith("DDS"))
{
return true;
}
else
{
return false;
}
}
public static bool IsRcf(byte[] Bytes)
{
MemoryStream Data = ByteToStream(Bytes);
String header = ReadString(Data, 5);
if (header.StartsWith("RCSF"))
{
return true;
}
else
{
return false;
}
}
public static bool IsGim(byte[] Bytes)
{
MemoryStream Data = ByteToStream(Bytes);
String header = ReadString(Data,4);
if(header.StartsWith("MIG"))
{
return true;
}
else
{
return false;
}
}
public static bool IsZlib(byte[] Bytes)
{
if(Bytes[0] == 0x78)
{
if (Bytes[1] == 0x01)
return true;
if (Bytes[1] == 0x9C)
return true;
if (Bytes[1] == 0xDA)
return true;
}
return false;
}
public static bool IsImage(byte[] Bytes)
{
try
{
GetBitmap(Bytes);
}
catch(Exception)
{
return false;
}
return true;
}
public static Bitmap GetBitmap(byte[] BitmapBytes)
{
MemoryStream ms = ByteToStream(BitmapBytes);
Bitmap bmp = new Bitmap(ms);
ms.Dispose();
return bmp;
}
public static String ReadStringAt(Stream ms, int location)
{
long ogPos = ms.Position;
ms.Seek(location, SeekOrigin.Begin);
String str = ReadString(ms);
ms.Seek(ogPos, SeekOrigin.Begin);
return str;
}
public static int ReadIntAt(Stream ms, int location)
{
BinaryReader BinReader = new BinaryReader(ms);
long ogPos = ms.Position;
ms.Seek(location, SeekOrigin.Begin);
int i = BinReader.ReadInt32();
ms.Seek(ogPos, SeekOrigin.Begin);
return i;
}
public static int ReadInt(Stream ms)
{
BinaryReader BinReader = new BinaryReader(ms);
int i = BinReader.ReadInt32();
return i;
}
public static String ReadString(Stream ms, int limit = -1)
{
int i = 0xFF;
MemoryStream StringStream = new MemoryStream();
do
{
i = ms.ReadByte();
if (i == 0 && i != limit)
break;
StringStream.WriteByte((byte)i);
}
while (true);
byte[] StringData = StringStream.ToArray();
String str = Encoding.UTF8.GetString(StringData);
return str;
}
}
class Parser
{
private bool DECODE_VAG = true;
private bool DECODE_GIM = true;
private static bool _checkMagicNumber()
{
@ -532,6 +328,48 @@ namespace CXML
Term();
}
public static void ProcessFile(String FileName)
{
String Extension = Path.GetExtension(FileName);
if (Extension == ".vag") //Remove this IF statment if you dont want VAG Conversion.
{
Console.WriteLine("Decoding: " + Path.GetFileName(FileName));
byte[] WaveData = VAG.VAGAudio.Vag2Wav(FileName);
String WaveName = Path.GetFileNameWithoutExtension(FileName) + "-" + VAG.VAGAudio.GetFilename(FileName) + ".wav";
if (!Directory.Exists("files/converted/VAGtoWAV"))
Directory.CreateDirectory("files/converted/VAGtoWAV");
File.WriteAllBytes("files/converted/VAGtoWAV/" + WaveName, WaveData);
Console.WriteLine("Decoded file written to: " + WaveName);
}
if (Extension == ".gim") //Remove this IF statement if you dont want GIM Conversion.
{
if (File.Exists("GimConv/GimConv.exe"))
{
if (!Directory.Exists("files/converted"))
Directory.CreateDirectory("files/converted/GIMtoPNG");
Console.WriteLine("Decoding GIM.");
Process Proc = new Process();
Proc.StartInfo.FileName = "GimConv/GimConv.exe";
Proc.StartInfo.Arguments = Path.GetFileName(FileName) + " -o " + "../converted/GIMtoPNG/" + Path.GetFileName(Path.ChangeExtension(FileName, "png"));
Proc.StartInfo.RedirectStandardOutput = true;
Proc.StartInfo.RedirectStandardError = true;
Proc.StartInfo.UseShellExecute = false;
Proc.StartInfo.WorkingDirectory = Directory.GetCurrentDirectory() + "/files/decompressed";
Proc.Start();
Proc.WaitForExit();
Console.WriteLine(Proc.StandardOutput.ReadToEnd());
Console.WriteLine("Done!");
}
}
}
public static void ReadAttribute(String ElementName = "")
{
int AttributePtr = bTreeTable.ReadInt32();
@ -651,35 +489,13 @@ namespace CXML
Directory.CreateDirectory("files/decompressed");
String DecompressedFilename = "files/decompressed/" + ElementName + "-" + AttributeName + CounterStr + Extension;
Console.WriteLine("Decompressed file written to: " + DecompressedFilename);
File.WriteAllBytes(DecompressedFilename, DecompressedData);
if(Extension == ".gim")
{
if(File.Exists("GimConv/GimConv.exe"))
{
if (!Directory.Exists("files/converted"))
Directory.CreateDirectory("files/converted");
Console.WriteLine("Decoding GIM.");
Process Proc = new Process();
Proc.StartInfo.FileName = "GimConv/GimConv.exe";
Proc.StartInfo.Arguments = Path.GetFileName(DecompressedFilename) + " -o " + "../converted/" + ElementName + "-" + AttributeName + CounterStr + ".png";
Proc.StartInfo.RedirectStandardOutput = true;
Proc.StartInfo.RedirectStandardError = true;
Proc.StartInfo.UseShellExecute = false;
Proc.StartInfo.WorkingDirectory = Directory.GetCurrentDirectory()+ "/files/decompressed";
Proc.Start();
Proc.WaitForExit();
Console.WriteLine(Proc.StandardOutput.ReadToEnd());
Console.WriteLine("Done!");
}
}
ProcessFile(DecompressedFilename);
}
File.WriteAllBytes(FileName, FileData);
ProcessFile(FileName);
AttributeValue = FileName;
break;

View File

@ -8,10 +8,11 @@
<OutputType>Exe</OutputType>
<RootNamespace>CXMLDecompiler</RootNamespace>
<AssemblyName>CXMLDecompiler</AssemblyName>
<TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion>
<TargetFrameworkVersion>v4.7</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
<Deterministic>true</Deterministic>
<TargetFrameworkProfile />
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
@ -22,6 +23,7 @@
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
@ -31,6 +33,47 @@
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\x64\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<DebugType>full</DebugType>
<PlatformTarget>x64</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
<Prefer32Bit>true</Prefer32Bit>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
<OutputPath>bin\x64\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<Optimize>true</Optimize>
<DebugType>pdbonly</DebugType>
<PlatformTarget>x64</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
<Prefer32Bit>true</Prefer32Bit>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x86'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\x86\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<DebugType>full</DebugType>
<PlatformTarget>x86</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
<Prefer32Bit>true</Prefer32Bit>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x86'">
<OutputPath>bin\x86\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<Optimize>true</Optimize>
<DebugType>pdbonly</DebugType>
<PlatformTarget>x86</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
<Prefer32Bit>true</Prefer32Bit>
</PropertyGroup>
<ItemGroup>
<Reference Include="DotNetZip, Version=1.13.3.0, Culture=neutral, PublicKeyToken=6583c7c814667745, processorArchitecture=MSIL">
@ -50,6 +93,8 @@
<Compile Include="CXML.cs" />
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Tools.cs" />
<Compile Include="VAG.cs" />
</ItemGroup>
<ItemGroup>
<None Include="App.config" />

View File

@ -1,4 +1,5 @@
using System;
using General;
using System;
using System.IO;
using System.Reflection;
@ -8,7 +9,6 @@ namespace CXMLCli
{
static void Main(string[] args)
{
bool Check = true;
if (args.Length == 0)
@ -16,8 +16,9 @@ namespace CXMLCli
Console.WriteLine("-- app.info/CXML Decompiler --");
Console.WriteLine("I like to see girls die :3");
Console.WriteLine("Required Arguments:");
Console.WriteLine("\t<file>");
Console.WriteLine("\t<input_filename>");
Console.WriteLine("Optional Arguments:");
Console.WriteLine("\t-iv --is-vag File is HE-VAG audio and NOT CXML");
Console.WriteLine("\t-f --force Dont check magic number.");
Console.WriteLine("\t-dt --dump-tables Dump ALL tables.");
Console.WriteLine("\t-tt --dump-tree Dump tree table.");
@ -37,8 +38,20 @@ namespace CXMLCli
String ArgsFull = String.Join(" ", args);
String path = args[0];
if (ArgsFull.Contains("-iv") || ArgsFull.Contains("--is-vag"))
{
byte[] WaveData = VAG.VAGAudio.Vag2Wav(path);
string FileName = Path.GetFileNameWithoutExtension(path) + "-" + VAG.VAGAudio.GetFilename(path) + ".wav";
Console.WriteLine("Writing "+FileName);
File.WriteAllBytes(FileName, WaveData);
return;
}
CXML.Parser.Init(path, Check);
if (ArgsFull.Contains("-f") || ArgsFull.Contains("--force"))
{
Check = false;

223
AppInfoCli/Tools.cs Normal file
View File

@ -0,0 +1,223 @@
using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace General
{
class Tools
{
public static String RemoveDecimals(float FloatValue)
{
String FloatStr = FloatValue.ToString();
String[] FloatParts = FloatStr.Split('.');
if (FloatParts.Length > 1)
if (FloatParts[1].Length > 2)
FloatParts[1] = FloatParts[1].Substring(0, 2);
FloatStr = String.Join(".", FloatParts);
return FloatStr;
}
public static void WriteStringToStream(Stream s, String str)
{
Byte[] bytes = Encoding.UTF8.GetBytes(str);
s.Write(bytes, 0x00, bytes.Length);
}
public static MemoryStream ByteToStream(byte[] Array)
{
MemoryStream ms = new MemoryStream();
ms.Write(Array, 0x00, Array.Length);
ms.Seek(0, SeekOrigin.Begin);
return ms;
}
public static byte[] StreamToByte(Stream stream)
{
int StreamLen = (int)stream.Length;
byte[] Bytes = new byte[StreamLen];
stream.Seek(0, SeekOrigin.Begin);
stream.Read(Bytes, 0x00, StreamLen);
return Bytes;
}
public static string GetFileExtension(byte[] Bytes)
{
if (IsImage(Bytes))
{
return ".png";
}
else if (IsZlib(Bytes))
{
return ".zlib";
}
else if (IsGim(Bytes))
{
return ".gim";
}
else if (IsRcf(Bytes))
{
return ".rcs";
}
else if (IsDDS(Bytes))
{
return ".dds";
}
else if (IsVAG(Bytes))
{
return ".vag";
}
else
{
return ".bin";
}
}
public static bool IsVAG(byte[] Bytes)
{
MemoryStream Data = ByteToStream(Bytes);
String header = ReadString(Data, 4);
if (header.StartsWith("VAG"))
{
return true;
}
else
{
return false;
}
}
public static bool IsDDS(byte[] Bytes)
{
MemoryStream Data = ByteToStream(Bytes);
String header = ReadString(Data, 4);
if (header.StartsWith("DDS"))
{
return true;
}
else
{
return false;
}
}
public static bool IsRcf(byte[] Bytes)
{
MemoryStream Data = ByteToStream(Bytes);
String header = ReadString(Data, 5);
if (header.StartsWith("RCSF"))
{
return true;
}
else
{
return false;
}
}
public static bool IsGim(byte[] Bytes)
{
MemoryStream Data = ByteToStream(Bytes);
String header = ReadString(Data, 4);
if (header.StartsWith("MIG"))
{
return true;
}
else
{
return false;
}
}
public static bool IsZlib(byte[] Bytes)
{
if (Bytes[0] == 0x78)
{
if (Bytes[1] == 0x01)
return true;
if (Bytes[1] == 0x9C)
return true;
if (Bytes[1] == 0xDA)
return true;
}
return false;
}
public static bool IsImage(byte[] Bytes)
{
try
{
GetBitmap(Bytes);
}
catch (Exception)
{
return false;
}
return true;
}
public static Bitmap GetBitmap(byte[] BitmapBytes)
{
MemoryStream ms = ByteToStream(BitmapBytes);
Bitmap bmp = new Bitmap(ms);
ms.Dispose();
return bmp;
}
public static String ReadStringAt(Stream ms, int location)
{
long ogPos = ms.Position;
ms.Seek(location, SeekOrigin.Begin);
String str = ReadString(ms);
ms.Seek(ogPos, SeekOrigin.Begin);
return str;
}
public static int ReadIntAt(Stream ms, int location)
{
BinaryReader BinReader = new BinaryReader(ms);
long ogPos = ms.Position;
ms.Seek(location, SeekOrigin.Begin);
int i = BinReader.ReadInt32();
ms.Seek(ogPos, SeekOrigin.Begin);
return i;
}
public static int ReadInt(Stream ms)
{
BinaryReader BinReader = new BinaryReader(ms);
int i = BinReader.ReadInt32();
return i;
}
public static String ReadString(Stream ms, int limit = -1)
{
int i = 0xFF;
MemoryStream StringStream = new MemoryStream();
do
{
i = ms.ReadByte();
if (i == 0 && i != limit)
break;
StringStream.WriteByte((byte)i);
}
while (true);
byte[] StringData = StringStream.ToArray();
String str = Encoding.UTF8.GetString(StringData);
return str;
}
}
}

357
AppInfoCli/VAG.cs Normal file
View File

@ -0,0 +1,357 @@
/*
Based on daemon1's HEVAG decoder
(i decompiled his xD)
*/
using System;
using System.IO;
using General;
namespace VAG
{
class VAGAudio
{
static int[,] HEVAGCoeffTable = new int[,]
{
{ 0, 0, 0, 0 },
{ 7680, 0, 0, 0 },
{ 14720, -6656, 0, 0 },
{ 12544, -7040, 0, 0 },
{ 15616, -7680, 0, 0 },
{ 14731, -7059, 0, 0 },
{ 14507, -7366, 0, 0 },
{ 13920, -7522, 0, 0 },
{ 13133, -7680, 0, 0 },
{ 12028, -7680, 0, 0 },
{ 10764, -7680, 0, 0 },
{ 9359, -7680, 0, 0 },
{ 7832, -7680, 0, 0 },
{ 6201, -7680, 0, 0 },
{ 4488, -7680, 0, 0 },
{ 2717, -7680, 0, 0 },
{ 910, -7680, 0, 0 },
{ -910, -7680, 0, 0 },
{ -2717, -7680, 0, 0 },
{ -4488, -7680, 0, 0 },
{ -6201, -7680, 0, 0 },
{ -7832, -7680, 0, 0 },
{ -9359, -7680, 0, 0 },
{ -10764, -7680, 0, 0 },
{ -12028, -7680, 0, 0 },
{ -13133, -7680, 0, 0 },
{ -13920, -7522, 0, 0 },
{ -14507, -7366, 0, 0 },
{ -14731, -7059, 0, 0 },
{ 5376, -9216, 3328, -3072 },
{ -6400, -7168, -3328, -2304 },
{ -10496, -7424, -3584, -1024 },
{ -167, -2722, -494, -541 },
{ -7430, -2221, -2298, 424 },
{ -8001, -3166, -2814, 289 },
{ 6018, -4750, 2649, -1298 },
{ 3798, -6946, 3875, -1216 },
{ -8237, -2596, -2071, 227 },
{ 9199, 1982, -1382, -2316 },
{ 13021, -3044, -3792, 1267 },
{ 13112, -4487, -2250, 1665 },
{ -1668, -3744, -6456, 840 },
{ 7819, -4328, 2111, -506 },
{ 9571, -1336, -757, 487 },
{ 10032, -2562, 300, 199 },
{ -4745, -4122, -5486, -1493 },
{ -5896, 2378, -4787, -6947 },
{ -1193, -9117, -1237, -3114 },
{ 2783, -7108, -1575, -1447 },
{ -7334, -2062, -2212, 446 },
{ 6127, -2577, -315, -18 },
{ 9457, -1858, 102, 258 },
{ 7876, -4483, 2126, -538 },
{ -7172, -1795, -2069, 482 },
{ -7358, -2102, -2233, 440 },
{ -9170, -3509, -2674, -391 },
{ -2638, -2647, -1929, -1637 },
{ 1873, 9183, 1860, -5746 },
{ 9214, 1859, -1124, -2427 },
{ 13204, -3012, -4139, 1370 },
{ 12437, -4792, -256, 622 },
{ -2653, -1144, -3182, -6878 },
{ 9331, -1048, -828, 507 },
{ 1642, -620, -946, -4229 },
{ 4246, -7585, -533, -2259 },
{ -8988, -3891, -2807, 44 },
{ -2562, -2735, -1730, -1899 },
{ 3182, -483, -714, -1421 },
{ 7937, -3844, 2821, -1019 },
{ 10069, -2609, 314, 195 },
{ 8400, -3297, 1551, -155 },
{ -8529, -2775, -2432, -336 },
{ 9477, -1882, 108, 256 },
{ 75, -2241, -298, -6937 },
{ -9143, -4160, -2963, 5 },
{ -7270, -1958, -2156, 460 },
{ -2740, 3745, 5936, -1089 },
{ 8993, 1948, -683, -2704 },
{ 13101, -2835, -3854, 1055 },
{ 9543, -1961, 130, 250 },
{ 5272, -4270, 3124, -3157 },
{ -7696, -3383, -2907, -456 },
{ 7309, 2523, 434, -2461 },
{ 10275, -2867, 391, 172 },
{ 10940, -3721, 665, 97 },
{ 24, -310, -1262, 320 },
{ -8122, -2411, -2311, -271 },
{ -8511, -3067, -2337, 163 },
{ 326, -3846, 419, -933 },
{ 8895, 2194, -541, -2880 },
{ 12073, -1876, -2017, -601 },
{ 8729, -3423, 1674, -169 },
{ 12950, -3847, -3007, 1946 },
{ 10038, -2570, 302, 198 },
{ 9385, -2757, 1008, 41 },
{ -4720, -5006, -2852, -1161 },
{ 7869, -4326, 2135, -501 },
{ 2450, -8597, 1299, -2780 },
{ 10192, -2763, 360, 181 },
{ 11313, -4213, 833, 53 },
{ 10154, -2716, 345, 185 },
{ 9638, -1417, -737, 482 },
{ 3854, -4554, 2843, -3397 },
{ 6699, -5659, 2249, -1074 },
{ 11082, -3908, 728, 80 },
{ -1026, -9810, -805, -3462 },
{ 10396, -3746, 1367, -96 },
{ 10287, 988, -1915, -1437 },
{ 7953, 3878, -764, -3263 },
{ 12689, -3375, -3354, 2079 },
{ 6641, 3166, 231, -2089 },
{ -2348, -7354, -1944, -4122 },
{ 9290, -4039, 1885, -246 },
{ 4633, -6403, 1748, -1619 },
{ 11247, -4125, 802, 61 },
{ 9807, -2284, 219, 222 },
{ 9736, -1536, -706, 473 },
{ 8440, -3436, 1562, -176 },
{ 9307, -1021, -835, 509 },
{ 1698, -9025, 688, -3037 },
{ 10214, -2791, 368, 179 },
{ 8390, 3248, -758, -2989 },
{ 7201, 3316, 46, -2614 },
{ -88, -7809, -538, -4571 },
{ 6193, -5189, 2760, -1245 },
{ 12325, -1290, -3284, 253 },
{ 13064, -4075, -2824, 1877 },
{ 5333, 2999, 775, -1132 },
};
private static byte[] WriteWaveHeader(byte[] PCMData, int channels, int samplerate)
{
MemoryStream ms = new MemoryStream();
int FileSize = PCMData.Length;
BinaryWriter bw = new BinaryWriter(ms);
Tools.WriteStringToStream(ms, "RIFF");
bw.Write(FileSize + 36);
Tools.WriteStringToStream(ms, "WAVE");
Tools.WriteStringToStream(ms, "fmt ");
bw.Write(16);
bw.Write((short)1);
bw.Write((short)channels);
bw.Write(samplerate);
bw.Write(samplerate * channels * 2);
bw.Write((short)(channels * 2));
bw.Write((short)16);
Tools.WriteStringToStream(ms, "data");
bw.Write(FileSize);
ms.Write(PCMData, 0x00, FileSize);
ms.Seek(0x00, SeekOrigin.Begin);
return ms.ToArray();
}
public static byte[] Vag2Wav(string VagFile)
{
byte[] FileData = File.ReadAllBytes(VagFile);
if(Tools.IsVAG(FileData))
{
byte[] PCMData = DecodePCM(FileData);
byte[] WAVData = WriteWaveHeader(PCMData, GetChannels(VagFile), GetSampleRate(VagFile));
return WAVData;
}
throw new Exception("Not a VAG file.");
}
public static int GetChannels(string VagFile)
{
FileStream VagStream = new FileStream(VagFile, FileMode.Open, FileAccess.Read);
VagStream.Seek(0x1E, SeekOrigin.Begin);
int ChannelCount = VagStream.ReadByte();
if (ChannelCount == 0)
ChannelCount = 1; //Its most likely mono...
VagStream.Close();
return ChannelCount;
}
public static string GetFilename(string VagFile)
{
FileStream VagStream = new FileStream(VagFile, FileMode.Open, FileAccess.Read);
String FileName = Tools.ReadStringAt(VagStream, 0x20);
VagStream.Close();
return FileName;
}
public static int GetSampleRate(String VagFile)
{
FileStream VagStream = new FileStream(VagFile, FileMode.Open, FileAccess.Read);
VagStream.Seek(0x12, SeekOrigin.Begin);
//IDK Either, ask sony why they didnt just use an int16
int SampleRate = VagStream.ReadByte() * 256 + VagStream.ReadByte();
VagStream.Close();
return SampleRate;
}
public static byte[] DecodePCM(byte[] VagFile)
{
int Hist = 0;
int Hist2 = 0;
int Hist3 = 0;
int Hist4 = 0;
MemoryStream VagStream = Tools.ByteToStream(VagFile);
BinaryReader VagReader = new BinaryReader(VagStream);
MemoryStream PCMStream = new MemoryStream();
BinaryWriter PCMWriter = new BinaryWriter(PCMStream);
VagStream.Seek(0x40, SeekOrigin.Begin);
while (VagStream.Position < VagStream.Length)
{
byte DecodingCoefficent = VagReader.ReadByte();
int ShiftBy = DecodingCoefficent & 0xf;
int PredictNr = DecodingCoefficent >> 0x4;
byte LoopData = VagReader.ReadByte();
PredictNr |= LoopData & 0xF0;
int LoopFlag = LoopData & 0xf;
if (LoopFlag == 0x7)
{
VagStream.Seek(14, SeekOrigin.Current);
Hist = 0;
Hist2 = 0;
Hist3 = 0;
Hist4 = 0;
}
else
{
for (int i = 0; i < 14; i++)
{
//First Byte:
byte ADPCMData = VagReader.ReadByte();
int SampleFlags = ADPCMData & 0xF;
int Coefficent;
int Sample;
if (SampleFlags > 7)
{
SampleFlags -= 16;
}
if (PredictNr < 128)
{
Coefficent = Hist * HEVAGCoeffTable[PredictNr, 0] + Hist2 * HEVAGCoeffTable[PredictNr, 1] + Hist3 * HEVAGCoeffTable[PredictNr, 2] + Hist4 * HEVAGCoeffTable[PredictNr, 3];
}
else
{
Coefficent = 0;
}
Sample = Coefficent / 32 + (SampleFlags << 20 - ShiftBy) + 128 >> 8;
//Apparently unchecked(short) isnt good enough?
//I guess it cant be modulo?
//IDK im just doing what i saw in the decompiled code.
if (Sample > 32767)
{
Sample = 32767;
}
else if (Sample < -32768)
{
Sample = -32768;
}
PCMWriter.Write((short)Sample);
//Second Byte:
Hist4 = Hist3;
Hist3 = Hist2;
Hist2 = Hist;
Hist = Sample;
SampleFlags = ADPCMData >> 4;
if (SampleFlags > 7)
{
SampleFlags -= 16;
}
if (PredictNr < 128)
{
Coefficent = Hist * HEVAGCoeffTable[PredictNr, 0] + Hist2 * HEVAGCoeffTable[PredictNr, 1] + Hist3 * HEVAGCoeffTable[PredictNr, 2] + Hist4 * HEVAGCoeffTable[PredictNr, 3];
}
else
{
Coefficent = 0;
}
Sample = Coefficent / 32 + (SampleFlags << 20 - ShiftBy) + 128 >> 8;
if (Sample > 32767)
{
Sample = 32767;
}
else if (Sample < -32768)
{
Sample = -32768;
}
PCMWriter.Write((short)Sample);
Hist4 = Hist3;
Hist3 = Hist2;
Hist2 = Hist;
Hist = Sample;
}
}
}
PCMStream.Seek(0x00, SeekOrigin.Begin);
byte[] PCMData = PCMStream.ToArray();
VagReader.Close();
VagStream.Close();
PCMWriter.Close();
PCMStream.Close();
return PCMData;
}
}
}