2016-12-03 19:16:44 +04:00

270 lines
14 KiB
C#

//! \file AudioMV2.cs
//! \date Sat Dec 03 05:42:52 2016
//! \brief CVNS engine audio format.
//
// Copyright (C) 2016 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 GameRes.Utility;
namespace GameRes.Formats.Purple
{
[Export(typeof(AudioFormat))]
public class Mv2Audio : AudioFormat
{
public override string Tag { get { return "MV2"; } }
public override string Description { get { return "CVNS engine compressed audio format"; } }
public override uint Signature { get { return 0x5832564D; } } // 'MV2X'
public override bool CanWrite { get { return false; } }
public override SoundInput TryOpen (IBinaryStream file)
{
using (var decoder = new Mv2Decoder (file))
{
decoder.Unpack();
var pcm = new MemoryStream (decoder.Data);
var sound = new RawPcmInput (pcm, decoder.Format);
file.Dispose();
return sound;
}
}
}
internal sealed class Mv2Decoder : MvDecoderBase
{
int m_shift;
int m_samples;
public Mv2Decoder (IBinaryStream input) : base (input)
{
var header = input.ReadHeader (0x12);
m_channel_size = header.ToInt32 (4);
m_format.FormatTag = 1;
m_format.BitsPerSample = 16;
m_format.Channels = header[0xC];
m_format.SamplesPerSecond = header.ToUInt16 (0xA);
m_format.BlockAlign = (ushort)(m_format.Channels*m_format.BitsPerSample/8);
m_format.AverageBytesPerSecond = m_format.BlockAlign * m_format.SamplesPerSecond;
m_output = new byte[m_format.BlockAlign * m_channel_size];
m_shift = header[0xD];
m_samples = header.ToInt32 (0xE);
}
int pre2_idx;
int[] pre_sample1;
int[] pre_sample2;
int[] pre_sample3;
public void Unpack ()
{
SetPosition (0x12);
pre_sample1 = new int[0x400];
pre_sample2 = new int[0x400 * m_format.Channels];
pre_sample3 = new int[0x140 * m_format.Channels];
pre2_idx = 0;
int dst_pos = 0;
for (int i = 0; i < m_samples && dst_pos < m_output.Length; ++i)
{
for (int c = 0; c < m_format.Channels; ++c)
{
int n1 = GetBits (10);
if (-1 == n1)
return;
int n2 = GetBits (9);
if (-1 == n2)
return;
FillSample1 (n1, n2);
int t = 0; // within pre_sample1
for (int j = 0; j < 10; ++j)
{
FilterSamples (t, t, c);
t += 0x20;
}
int shift = 6 - m_shift;
int dst = dst_pos + 2 * c;
for (int j = 0; j < 0x140 && dst < m_output.Length; ++j)
{
short sample = Clamp (pre_sample3[j] >> shift);
LittleEndian.Pack (sample, m_output, dst);
dst += m_format.BlockAlign;
}
}
dst_pos += 2 * m_format.Channels * 0x140;
}
}
void FillSample1 (int n1, int n2)
{
for (int i = 0; i < 0x140; ++i)
pre_sample1[i] = 0;
n2 = SampleTable[n2];
for (int i = 0; i < n1; ++i)
{
int count = GetCount();
if (count > 0)
{
int coef = GetBits (count);
if (coef < 1 << (count-1))
coef += 1 - (1 << count);
pre_sample1[i] = n2 * coef;
}
else
{
i += GetBits (3);
}
}
}
void FilterSamples (int dst, int src, int channel)
{
int idx2 = pre2_idx + (channel << 10);
int coef1_idx = 0;
for (int j = 0; j < 64; ++j)
{
int pre1_idx = src;
int sample = 0;
for (int k = 0; k < 8; ++k)
{
for (int m = 0; m < 4; ++m)
{
sample += MvDecoder.Coef1Table[coef1_idx++] * pre_sample1[pre1_idx++] >> 10;
}
}
pre_sample2[idx2 + j] = sample;
}
for (int j = 0; j < 0x20; ++j)
{
int m = idx2 + j;
int coef2_idx = j;
int x = 0;
for (int k = 0; k < 4; ++k)
{
x += pre_sample2[m & 0x3FF] * Coef2Table[coef2_idx] >> 10;
coef2_idx += 32;
m += 96;
x += pre_sample2[m & 0x3FF] * Coef2Table[coef2_idx] >> 10;
coef2_idx += 32;
m += 32;
x -= pre_sample2[m & 0x3FF] * Coef2Table[coef2_idx] >> 10;
coef2_idx += 32;
m += 96;
x -= pre_sample2[m & 0x3FF] * Coef2Table[coef2_idx] >> 10;
coef2_idx += 32;
m += 32;
}
pre_sample3[dst++] = x;
}
pre2_idx = ((ushort)pre2_idx - 0x40) & 0x3FF;
}
static readonly int[] SampleTable = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 4, 4, 5, 6, 6, 7, 8, 10, 11, 12, 14, 16,
18, 20, 23, 26, 29, 33, 38, 42,
48, 54, 61, 69, 78, 88, 100, 113,
128, 144, 163, 184, 207, 234, 265, 299,
337, 381, 430, 486, 548, 619, 699, 789,
891, 1006, 1136, 1282, 1448, 1634, 1845, 2083,
2352, 2655, 2998, 3385, 3821, 4314, 4870, 5499,
6208, 7009, 7912, 8933, 10085, 11386, 12854, 14512,
16384, 18496, 20882, 23575, 26615, 30048, 33923, 38298,
43237, 48813, 55108, 62216, 70239, 79298, 89524, 101070,
114104, 128820, 145433, 164189, 185363, 209269, 236257, 266726,
301124, 339958, 383801, 433297, 489178, 552264, 623487, 703894,
794672, 897156, 1012857, 1143480, 1290948, 1457434, 1645392, 1857589,
-47447340, 47512876, -47447340, 47512876, -47447340, 47512876, -47447340, 47512876,
-47447340, 47512876, -47447340, 47512876, -47447340, 47512876, -47447340, 47512876,
-53869905, 60685810, -65076904, 67043178, -66256946, 63176952, -57475509, 49676897,
-39846646, 28640110, -16188356, 3277812, 9894914, -22543391, 34536547, -45022410,
-59178359, 66846423, -64094308, 51839458, -31523607, 6554579, 19528709, -42531961,
59243895, -66780887, 64159844, -51773922, 31589143, -6489043, -19463173, 42597497,
-63176095, 65142734, -44958222, 9831325, 28703756, -57539850, 67043080, -53805400,
22545206, 16317442, -49675410, 66387531, -60555414, 34472623, 3341343, -39910460,
-65797576, 55771335, -12976979, -37223444, 65863112, -55705799, 13042515, 37288980,
-65797576, 55771335, -12976979, -37223444, 65863112, -55705799, 13042515, 37288980,
-66977266, 39911861, 22608908, -65076561, 49676536, 9894972, -60619978, 57540658,
-3212142, -53869667, 63242090, -16188150, -45022239, 66387624, -28574305, -34470914,
-66780702, 19464841, 51903533, -59178908, -6552697, 64224489, -42467625, -31587333,
66846238, -19399305, -51837997, 59244444, 6618233, -64158953, 42533161, 31652869,
-65076811, -3275978, 66387210, -22479374, -57539644, 45023382, 39975938, -60620552,
-16252003, 67042719, -9765551, -63175826, 34472280, 49740812, -53870542, -28638239,
-61996665, -25623630, 62062201, 25689166, -61996665, -25623630, 62062201, 25689166,
-61996665, -25623630, 62062201, 25689166, -61996665, -25623630, 62062201, 25689166,
-57540264, -45022220, 39911474, 60685343, -16187829, -66976970, -9829642, 63241714,
34536508, -49676138, -53869570, 28639480, 65141859, -3211873, -66321745, -22543506,
-51838679, -59177989, 6554082, 64224631, 42597421, -31522916, -66780281, -19463401,
51904215, 59243525, -6488546, -64159095, -42531885, 31588452, 66845817, 19528937,
-45022984, -66321468, -28638410, 34537422, 67042450, 39976035, -22478998, -65076490,
-49675295, 9830744, 60685727, 57605122, 3341810, -53870155, -63175692, -16252241,
-37224249, -65797293, -55770132, -13041096, 37289785, 65862829, 55835668, 13106632,
-37224249, -65797293, -55770132, -13041096, 37289785, 65862829, 55835668, 13106632,
-28639082, -57539921, -66976799, -53869628, -22543775, 16252978, 49741298, 66387043,
60685324, 34536714, -3211512, -39911080, -63175882, -65076226, -45022354, -9829963,
-19464092, -42532382, -59178217, -66780205, -64158725, -51838073, -31587703, -6553303,
19529628, 42597918, 59243753, 66845741, 64224261, 51903609, 31653239, 6618839,
-9830350, -22544136, -34471499, -45022623, -53869834, -60619922, -65076284, -66976780,
-66321410, -63175711, -57539683, -49675466, -39910737, -28638706, -16252584, -3276650,
};
static readonly short[] Coef2Table = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -2, -2, -2, -2, -2, -2, -2, -2, -2, -3, -3, -3,
-3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -2, -2, -2,
-2, -1, -1, -1, 0, 0, 0, 0, 1, 1, 2, 3, 3, 4, 5, 6,
7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 20, 21, 22, 23,
24, 25, 26, 27, 28, 29, 29, 30, 31, 31, 32, 32, 32, 32, 32, 32,
31, 31, 30, 29, 28, 27, 25, 23, 22, 20, 17, 15, 12, 9, 6, 2,
0, -4, -8, -12, -17, -21, -26, -31, -36, -41, -46, -52, -57, -63, -69, -74,
-80, -86, -91, -97, -102, -108, -113, -118, -123, -128, -132, -136, -140, -144, -147, -149,
-151, -153, -154, -155, -155, -155, -154, -152, -149, -146, -142, -138, -132, -126, -119, -111,
-102, -93, -82, -71, -58, -45, -31, -16, -1, 15, 33, 51, 70, 90, 111, 133,
155, 178, 202, 227, 252, 278, 304, 331, 358, 385, 413, 442, 470, 499, 527, 556,
585, 614, 643, 671, 700, 728, 756, 783, 810, 836, 862, 887, 911, 934, 957, 979,
1000, 1020, 1038, 1056, 1073, 1088, 1102, 1115, 1127, 1138, 1147, 1154, 1161, 1166, 1169, 1171,
1172, 1171, 1169, 1166, 1161, 1154, 1147, 1138, 1127, 1115, 1102, 1088, 1073, 1056, 1038, 1020,
1000, 979, 957, 934, 911, 887, 862, 836, 810, 783, 756, 728, 700, 671, 643, 614,
585, 556, 527, 499, 470, 442, 413, 385, 358, 331, 304, 278, 252, 227, 202, 178,
155, 133, 111, 90, 70, 51, 33, 15, -1, -16, -31, -45, -58, -71, -82, -93,
-102, -111, -119, -126, -132, -138, -142, -146, -149, -152, -154, -155, -155, -155, -154, -153,
-151, -149, -147, -144, -140, -136, -132, -128, -123, -118, -113, -108, -102, -97, -91, -86,
-80, -74, -69, -63, -57, -52, -46, -41, -36, -31, -26, -21, -17, -12, -8, -4,
0, 2, 6, 9, 12, 15, 17, 20, 22, 23, 25, 27, 28, 29, 30, 31,
31, 32, 32, 32, 32, 32, 32, 31, 31, 30, 29, 29, 28, 27, 26, 25,
24, 23, 22, 21, 20, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8,
7, 6, 5, 4, 3, 3, 2, 1, 1, 0, 0, 0, 0, -1, -1, -1,
-2, -2, -2, -2, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3,
-3, -3, -3, -3, -2, -2, -2, -2, -2, -2, -2, -2, -2, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
};
}
}