/* Based on daemon1's HEVAG decoder (i decompiled his xD) */ using System; using System.IO; using General; namespace VAG { class VAGAudio { private 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 * 16 * channels)/8); bw.Write((short)(16 * channels)); 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 FileStream VagStream; public static void Init(string VagFile) { VagStream = new FileStream(VagFile, FileMode.Open, FileAccess.Read); if (Tools.ReadStringAt(VagStream, 0x00) != "VAGp") throw new Exception("Not a VAG file."); } public static byte[] Vag2Wav(string VagFile) { Init(VagFile); byte[] PCMData = DecodePCM(); byte[] WAVData = WriteWaveHeader(PCMData, 1, GetSampleRate()); return WAVData; } public static int GetChannels() { VagStream.Seek(0x1E, SeekOrigin.Begin); int ChannelCount = VagStream.ReadByte(); if (ChannelCount >= 2) ChannelCount = 2; else ChannelCount = 1; return ChannelCount; } public static string GetFilename(string VagFile) { return Tools.ReadStringAt(VagStream, 0x20); } public static int GetSampleRate() { return Tools.ReadBigEndainIntAt(VagStream, 0x10); } public static int GetWaveformDataSize() { return Tools.ReadBigEndainIntAt(VagStream, 0x0C); } public static byte[] DecodePCM() { int Hist = 0; int Hist2 = 0; int Hist3 = 0; int Hist4 = 0; int FileSize = GetWaveformDataSize() - 0x40; int Channels = GetChannels(); bool IsStereo = (Channels > 1); BinaryReader VagReader = new BinaryReader(VagStream); MemoryStream PCMStream = new MemoryStream(); BinaryWriter PCMWriter = new BinaryWriter(PCMStream); VagStream.Seek(0x40, SeekOrigin.Begin); while (VagStream.Position < FileSize) { 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++) { byte ADPCMData = VagReader.ReadByte(); int SampleFlags = ADPCMData & 0xF; int Coefficent; short Sample; for(int ii = 0; ii <= 1; ii++) { 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 = (short)(Coefficent / 32 + (SampleFlags << 20 - ShiftBy) + 128 >> 8); PCMWriter.Write(Sample); Hist4 = Hist3; Hist3 = Hist2; Hist2 = Hist; Hist = Sample; SampleFlags = ADPCMData >> 4; } } } /* * Arg im mad because i know how to get left/right channels * But i have no idea how to combine them * So lets just get one and call it a day. */ if (IsStereo) VagStream.Seek(16, SeekOrigin.Current); } PCMStream.Seek(0x00, SeekOrigin.Begin); byte[] PCMData = PCMStream.ToArray(); PCMWriter.Close(); PCMStream.Close(); return PCMData; } } }