GARbro-mirror/Legacy/Aaru/AudioWV1.cs

161 lines
6.4 KiB
C#
Raw Normal View History

2018-12-19 07:34:57 +08:00
//! \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,
};
}
}