diff --git a/Legacy/Mermaid/AudioPWV.cs b/Legacy/Mermaid/AudioPWV.cs new file mode 100644 index 00000000..2bded301 --- /dev/null +++ b/Legacy/Mermaid/AudioPWV.cs @@ -0,0 +1,105 @@ +//! \file AudioPWV.cs +//! \date 2019 Jan 10 +//! \brief Mermaid compressed WAVE file. +// +// Copyright (C) 2019 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.ComponentModel.Composition; +using System.IO; + +namespace GameRes.Formats.Mermaid +{ + [Export(typeof(AudioFormat))] + public class PwvAudio : AudioFormat + { + public override string Tag { get { return "PWV"; } } + public override string Description { get { return "Mermaid compressed audio"; } } + public override uint Signature { get { return 0x46495200; } } // '\0RIF' + public override bool CanWrite { get { return false; } } + + public override SoundInput TryOpen (IBinaryStream file) + { + if (!file.Name.HasExtension ("PWV")) + return null; + var header = file.ReadHeader (0x10); + if (!header.AsciiEqual (9, "WAVE")) + return null; + var output = new MemoryStream ((int)file.Length); + try + { + file.Position = 0; + Unpack (file, output); + output.Position = 0; + var wave = new WaveInput (output); + file.Dispose(); + return wave; + } + catch + { + output.Dispose(); + throw; + } + } + + void Unpack (IBinaryStream input, Stream output) + { + var buffer = new byte[16]; + int ctl; + while ((ctl = input.ReadByte()) != -1) + { + if (0 == ctl) + { + input.Read (buffer, 0, 16); + output.Write (buffer, 0, 16); + } + else if (1 == ctl) + { + for (int i = 0; i < 16; i += 2) + { + buffer[i] = input.ReadUInt8(); + buffer[i+1] = 0; + } + output.Write (buffer, 0, 16); + } + else if (8 == ctl) + { + for (int i = 0; i < 16; i += 2) + { + buffer[i] = input.ReadUInt8(); + buffer[i+1] = 0xFF; + } + output.Write (buffer, 0, 16); + } + else if (15 == ctl) + { + int count = input.ReadUInt8(); + if (count > buffer.Length) + buffer = new byte[count]; + input.Read (buffer, 0, count); + output.Write (buffer, 0, count); + } + else if (input.PeekByte() != -1) + throw new InvalidFormatException(); + } + } + } +} diff --git a/Legacy/Mermaid/ImageGP1.cs b/Legacy/Mermaid/ImageGP1.cs new file mode 100644 index 00000000..3b5be2fb --- /dev/null +++ b/Legacy/Mermaid/ImageGP1.cs @@ -0,0 +1,104 @@ +//! \file ImageGP1.cs +//! \date 2019 Jan 10 +//! \brief Mermaid image format. +// +// Copyright (C) 2019 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.ComponentModel.Composition; +using System.IO; +using System.Windows.Media; + +// [030314][Mermaid] Ayakashizoushi ~Oumagatoki no Yume~ + +namespace GameRes.Formats.Mermaid +{ + [Export(typeof(ImageFormat))] + public class Gp1Format : ImageFormat + { + public override string Tag { get { return "GP1"; } } + public override string Description { get { return "Mermaid image format"; } } + public override uint Signature { get { return 0; } } + + public override ImageMetaData ReadMetaData (IBinaryStream file) + { + if (!file.Name.HasExtension ("GP1")) + return null; + var header = file.ReadHeader (8); + uint width = header.ToUInt32 (0); + uint height = header.ToUInt32 (4); + return new ImageMetaData { + Width = width, + Height = height, + BPP = 24, + }; + } + + public override ImageData Read (IBinaryStream file, ImageMetaData info) + { + file.Position = 8; + int plane_size = info.iWidth * info.iHeight; + var b = new byte[plane_size]; + UnpackChannel (file, b); + var g = new byte[plane_size]; + UnpackChannel (file, g); + var r = new byte[plane_size]; + UnpackChannel (file, r); + var pixels = new byte[plane_size * 3]; + int dst = 0; + for (int src = 0; src < plane_size; ++src) + { + pixels[dst++] = b[src]; + pixels[dst++] = g[src]; + pixels[dst++] = r[src]; + } + return ImageData.Create (info, PixelFormats.Bgr24, null, pixels); + } + + public override void Write (Stream file, ImageData image) + { + throw new System.NotImplementedException ("Gp1Format.Write not implemented"); + } + + void UnpackChannel (IBinaryStream input, byte[] output) + { + int dst = 0; + while (dst < output.Length) + { + int count = input.ReadByte(); + if (count < 0) + break; + if (count <= 0x32) + { + input.Read (output, dst, count); + dst += count; + } + else + { + count -= 0x32; + byte v = input.ReadUInt8(); + while (count --> 0) + output[dst++] = v; + } + } + } + } +}