From eb72b78b45e376ce1bfecc15f23f4acce5b17dac Mon Sep 17 00:00:00 2001 From: morkt Date: Wed, 19 Dec 2018 03:34:57 +0400 Subject: [PATCH] (Legacy): FL2 archives and WV1 audio. --- Legacy/Aaru/ArcFL2.cs | 78 ++++++++++++++++++++ Legacy/Aaru/AudioWV1.cs | 160 ++++++++++++++++++++++++++++++++++++++++ Legacy/Legacy.csproj | 2 + 3 files changed, 240 insertions(+) create mode 100644 Legacy/Aaru/ArcFL2.cs create mode 100644 Legacy/Aaru/AudioWV1.cs diff --git a/Legacy/Aaru/ArcFL2.cs b/Legacy/Aaru/ArcFL2.cs new file mode 100644 index 00000000..39bbd236 --- /dev/null +++ b/Legacy/Aaru/ArcFL2.cs @@ -0,0 +1,78 @@ +//! \file ArcFL2.cs +//! \date 2018 Dec 13 +//! \brief Aaru resource archive +// +// Copyright (C) 2018 by morkt +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +// + +using System; +using System.Collections.Generic; +using System.ComponentModel.Composition; +using System.IO; + +// [000428][Aaru] Koutei Heika ni Narou! + +namespace GameRes.Formats.Aaru +{ + [Export(typeof(ArchiveFormat))] + public class Fl2Opener : Fl4Opener + { + public override string Tag { get { return "FL2/AARU"; } } + public override string Description { get { return "Aaru resource archive"; } } + public override uint Signature { get { return 0x2E324C46; } } // 'FL2.0' + public override bool IsHierarchic { get { return false; } } + public override bool CanWrite { get { return false; } } + + public override ArcFile TryOpen (ArcView file) + { + if (file.View.ReadByte (4) != '0') + return null; + uint data_offset = file.View.ReadUInt16 (6); + int count = file.View.ReadInt16 (8); + uint index_size = file.View.ReadUInt32 (0xC); + long index_offset = file.View.ReadUInt32 (0x10); + if (index_offset + index_size > file.MaxOffset || !IsSaneCount (count)) + return null; + using (var index = file.CreateStream (index_offset, index_size)) + { + var dir = new List (count); + for (int i = 0; i < count; ++i) + { + uint size = index.ReadUInt32(); + if (uint.MaxValue == size) + break; + int name_length = index.ReadUInt8(); + var name = index.ReadCString (name_length); + var entry = Create (name); + entry.Offset = data_offset; + entry.Size = size; + if (!entry.CheckPlacement (file.MaxOffset)) + return null; + data_offset += size; + dir.Add (entry); + } + if (0 == dir.Count) + return null; + return new ArcFile (file, this, dir); + } + } + } +} diff --git a/Legacy/Aaru/AudioWV1.cs b/Legacy/Aaru/AudioWV1.cs new file mode 100644 index 00000000..e5f026fb --- /dev/null +++ b/Legacy/Aaru/AudioWV1.cs @@ -0,0 +1,160 @@ +//! \file AudioWV1.cs +//! \date 2018 Dec 13 +//! \brief Aaru compressed audio format. +// +// Copyright (C) 2018 by morkt +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +// + +using System; +using System.ComponentModel.Composition; +using System.IO; +using System.Text; + +namespace GameRes.Formats.Aaru +{ + [Export(typeof(AudioFormat))] + public class Wv1Audio : AudioFormat + { + public override string Tag { get { return "WV1"; } } + public override string Description { get { return "Aaru compressed audio"; } } + public override uint Signature { get { return 0x2E315657; } } // 'WV1.0' + public override bool CanWrite { get { return false; } } + + public Wv1Audio () + { + Extensions = new string[] { "wv1", "wav" }; + } + + public override SoundInput TryOpen (IBinaryStream file) + { + var header = file.ReadHeader (0x30); + if (!header.AsciiEqual (0, "WV1.0\0")) + return null; + var format = new WaveFormat { + FormatTag = 1, + Channels = header.ToUInt16 (0xA), + SamplesPerSecond = header.ToUInt32 (0xE), + BitsPerSample = 16, + }; + format.BlockAlign = (ushort)(format.Channels * format.BitsPerSample / 8); + format.SetBPS(); + int sample_count = header.ToInt32 (0x26); + var pcm = new MemoryStream (2 * sample_count); + using (var output = new BinaryWriter (pcm, Encoding.ASCII, true)) + { + var l_decoder = new Wv1Decoder(); + var r_decoder = l_decoder; + if (format.Channels > 1) + r_decoder = new Wv1Decoder(); + int input_sample = 0; + for (int i = 0; i < sample_count; ++i) + { + bool odd_sample = (i & 1) != 0; + short sample; + if (odd_sample) + { + sample = r_decoder.DecodeSample (input_sample >> 4); + } + else + { + input_sample = file.ReadByte(); + if (-1 == input_sample) + break; + sample = l_decoder.DecodeSample (input_sample & 0xF); + } + output.Write (sample); + } + } + file.Dispose(); + pcm.Position = 0; + return new RawPcmInput (pcm, format); + } + } + + internal class Wv1Decoder + { + short last_sample = 0; + int last_index = 0; + int[] shift_table = new int[8]; + + public short DecodeSample (int input) + { + int s0 = SampleTable[last_index]; + shift_table[0] = s0 >> 3; + shift_table[1] = shift_table[0] + (s0 >> 2); + shift_table[2] = shift_table[0] + (s0 >> 1); + shift_table[3] = shift_table[1] + (s0 >> 1); + shift_table[4] = shift_table[0] + s0; + shift_table[5] = shift_table[1] + s0; + shift_table[6] = shift_table[2] + s0; + shift_table[7] = shift_table[3] + s0; + int shift_index = input & 7; + if ((input & 8) != 0) + last_sample -= (short)shift_table[shift_index]; + else + last_sample += (short)shift_table[shift_index]; + switch (shift_index) + { + case 0: + case 1: + case 2: + case 3: + if (last_index > 0) + --last_index; + break; + case 4: + last_index = Math.Min (last_index + 2, 0x7F); + break; + case 5: + last_index = Math.Min (last_index + 4, 0x7F); + break; + case 6: + last_index = Math.Min (last_index + 6, 0x7F); + break; + case 7: + last_index = Math.Min (last_index + 8, 0x7F); + break; + default: + break; + } + return (short)(2 * last_sample); + } + + static readonly short[] SampleTable = { + 0x0007, 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000E, 0x000F, + 0x0010, 0x0012, 0x0014, 0x0015, 0x0017, 0x0019, 0x001B, 0x001D, + 0x0020, 0x0022, 0x0025, 0x0028, 0x002B, 0x002E, 0x0031, 0x0035, + 0x0038, 0x003C, 0x0041, 0x0045, 0x004A, 0x004F, 0x0055, 0x005A, + 0x0061, 0x0067, 0x006E, 0x0075, 0x007D, 0x0085, 0x008E, 0x0098, + 0x00A2, 0x00AC, 0x00B7, 0x00C3, 0x00D0, 0x00DE, 0x00EC, 0x00FB, + 0x010B, 0x011C, 0x012F, 0x0142, 0x0157, 0x016D, 0x0184, 0x019C, + 0x01B7, 0x01D3, 0x01F0, 0x0210, 0x0231, 0x0254, 0x027A, 0x02A2, + 0x02CD, 0x02FA, 0x032A, 0x035D, 0x0393, 0x03CD, 0x040A, 0x044B, + 0x0490, 0x04D9, 0x0527, 0x057A, 0x05D2, 0x062F, 0x0693, 0x06FC, + 0x076C, 0x07E3, 0x0862, 0x08E8, 0x0977, 0x0A0E, 0x0AAF, 0x0B5A, + 0x0C10, 0x0CD1, 0x0D9E, 0x0E78, 0x0F60, 0x1056, 0x115B, 0x1270, + 0x1397, 0x14D1, 0x161D, 0x177F, 0x18F7, 0x1A86, 0x1C2E, 0x1DF0, + 0x1FCF, 0x21CB, 0x23E7, 0x2625, 0x2886, 0x2B0E, 0x2DBE, 0x3098, + 0x33A1, 0x36D9, 0x3A46, 0x3DE9, 0x41C5, 0x45E0, 0x4A3C, 0x4EDE, + 0x53CA, 0x5904, 0x5E92, 0x6478, 0x6ABC, 0x7165, 0x7878, 0x7FFF, + }; + } +} diff --git a/Legacy/Legacy.csproj b/Legacy/Legacy.csproj index 876ecd97..d8be698d 100644 --- a/Legacy/Legacy.csproj +++ b/Legacy/Legacy.csproj @@ -62,8 +62,10 @@ + +