//! \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, }; } }