208 lines
7.3 KiB
C#
208 lines
7.3 KiB
C#
using KKdBaseLib;
|
|
using KKdMainLib.IO;
|
|
|
|
namespace KKdSoundLib
|
|
{
|
|
public unsafe class DIVA
|
|
{
|
|
public DIVAFile Data = new DIVAFile();
|
|
private int c, i;
|
|
|
|
public DIVA() { Data = new DIVAFile(); }
|
|
|
|
public void DIVAReader(string file, bool ToArray = false)
|
|
{
|
|
if (!File.Exists(file + ".diva")) return;
|
|
|
|
Data = new DIVAFile();
|
|
Stream reader = File.OpenReader(file + ".diva");
|
|
|
|
if (reader.RS(0x04) != "DIVA") { reader.C(); return; }
|
|
|
|
reader.RI32();
|
|
Data.Size = reader.RI32();
|
|
Data.SampleRate = reader.RI32();
|
|
Data.SamplesCount = reader.RI32();
|
|
reader.RI64();
|
|
Data.Channels = reader.RU8();
|
|
reader.RU8();
|
|
reader.RU16();
|
|
reader.RBy(0x20);
|
|
|
|
byte value = 0;
|
|
byte[] data = new byte[Data.SamplesCount * Data.Channels * 4];
|
|
int[] current = new int[Data.Channels];
|
|
int[] currentclamp = new int[Data.Channels];
|
|
sbyte[] stepindex = new sbyte[Data.Channels];
|
|
|
|
fixed (int* currentPtr = current)
|
|
fixed (int* currentclampPtr = currentclamp)
|
|
fixed (sbyte* stepindexPtr = stepindex)
|
|
fixed (byte* ptr = data)
|
|
{
|
|
reader.S(0, SeekOrigin.Begin);
|
|
float* dataPtr = (float*)ptr;
|
|
for (i = 0; i < Data.SamplesCount; i++)
|
|
for (c = 0; c < Data.Channels; c++, dataPtr++)
|
|
{
|
|
value = reader.RHB();
|
|
IMADecoder(value, ref currentPtr[c], ref currentclampPtr[c], ref stepindexPtr[c]);
|
|
*dataPtr = (float)(currentPtr[c] / 32768.0);
|
|
}
|
|
}
|
|
reader.CR();
|
|
|
|
|
|
if (ToArray) Data.Data = data;
|
|
else
|
|
{
|
|
Stream writer = File.OpenWriter(file + ".wav", true);
|
|
WAV.Header Header = new WAV.Header { Bytes = 4, Channels = Data.Channels, Format = 3,
|
|
SampleRate = Data.SampleRate, Size = Data.SamplesCount * Data.Channels * 4 };
|
|
writer.W(Header, 0);
|
|
writer.W(data);
|
|
writer.C();
|
|
}
|
|
|
|
reader.C();
|
|
}
|
|
|
|
public void DIVAWriter(string file)
|
|
{
|
|
if (!File.Exists(file + ".wav")) return;
|
|
|
|
Stream reader = File.OpenReader(file + ".wav");
|
|
|
|
Data = new DIVAFile();
|
|
WAV.Header Header = reader.ReadWAVHeader();
|
|
if (!Header.IsSupported) { reader.C(); return; }
|
|
|
|
Stream writer = File.OpenWriter(file + ".diva", true);
|
|
Data.Channels = (byte)Header.Channels;
|
|
Data.SampleRate = Header.SampleRate;
|
|
Data.SamplesCount = Header.Size / Header.Channels / Header.Bytes;
|
|
writer.PI64 = 0x40;
|
|
writer.LI64 = 0x40 + (Data.SamplesCount * Data.Channels).A(2, 2);
|
|
|
|
byte value = 0;
|
|
int[] sample = new int[Data.Channels];
|
|
int[] current = new int[Data.Channels];
|
|
int[] currentclamp = new int[Data.Channels];
|
|
sbyte[] stepindex = new sbyte[Data.Channels];
|
|
|
|
fixed (int* samplePtr = sample)
|
|
fixed (int* currentPtr = current)
|
|
fixed (int* currentclampPtr = currentclamp)
|
|
fixed (sbyte* stepindexPtr = stepindex)
|
|
{
|
|
for (i = 0; i < Data.SamplesCount; i++)
|
|
for (c = 0; c < Header.Channels; c++)
|
|
{
|
|
samplePtr[c] = (reader.RS(Header.Bytes, Header.Format) * 0x8000).CFTI();
|
|
value = IMAEncoder(samplePtr[c], ref currentPtr[c],
|
|
ref currentclampPtr[c], ref stepindexPtr[c]);
|
|
writer.W(value, 4);
|
|
}
|
|
}
|
|
|
|
writer.CW();
|
|
|
|
writer.PI64 = 0x00;
|
|
writer.W("DIVA");
|
|
writer.W(0x00);
|
|
writer.W((Data.SamplesCount * Data.Channels).A(2, 2));
|
|
writer.W(Data.SampleRate);
|
|
writer.W(Data.SamplesCount);
|
|
writer.W(0x00);
|
|
writer.W(0x00);
|
|
writer.W(Data.Channels);
|
|
writer.C();
|
|
reader.C();
|
|
}
|
|
|
|
private void IMADecoder(byte value, ref int current, ref int currentclamp, ref sbyte stepindex)
|
|
{
|
|
step = ima_step_table[stepindex];
|
|
|
|
diff = step >> 3;
|
|
if ((value & 1) == 1) diff += step >> 2;
|
|
if ((value & 2) == 2) diff += step >> 1;
|
|
if ((value & 4) == 4) diff += step;
|
|
|
|
if ((value & 8) == 8)
|
|
{ currentclamp -= diff; current = currentclamp;
|
|
if (currentclamp < -0x8000) currentclamp = -0x8000; }
|
|
else
|
|
{ currentclamp += diff; current = currentclamp;
|
|
if (currentclamp > 0x7FFF) currentclamp = 0x7FFF; }
|
|
|
|
stepindex += ima_index_table[value & 7];
|
|
if (stepindex < 0) stepindex = 0;
|
|
if (stepindex > 88) stepindex = 88;
|
|
}
|
|
|
|
private int delta, diff;
|
|
private byte value;
|
|
private short step;
|
|
|
|
private byte IMAEncoder(int sample, ref int current, ref int currentclamp, ref sbyte stepindex)
|
|
{
|
|
value = 0;
|
|
step = ima_step_table[stepindex];
|
|
|
|
delta = sample - current;
|
|
|
|
if (delta < 0)
|
|
{ value |= 8; delta = -delta; }
|
|
diff = step >> 3;
|
|
if (delta > step)
|
|
{ value |= 4; diff += step; delta -= step; }
|
|
step >>= 1;
|
|
if (delta > step)
|
|
{ value |= 2; diff += step; delta -= step; }
|
|
step >>= 1;
|
|
if (delta > step)
|
|
{ value |= 1; diff += step; }
|
|
|
|
if ((value & 8) == 8)
|
|
{ currentclamp -= diff; current = currentclamp;
|
|
if (currentclamp < -0x8000) currentclamp = -0x8000; }
|
|
else
|
|
{ currentclamp += diff; current = currentclamp;
|
|
if (currentclamp > 0x7FFF) currentclamp = 0x7FFF; }
|
|
|
|
stepindex += ima_index_table[value & 0x07];
|
|
if (stepindex < 0) stepindex = 0;
|
|
if (stepindex > 88) stepindex = 88;
|
|
return value;
|
|
}
|
|
|
|
private readonly sbyte[] ima_index_table =
|
|
{ -1, -1, -1, -1, 2, 4, 6, 8 };
|
|
|
|
private readonly short[] ima_step_table = {
|
|
7, 8, 9, 10, 11, 12, 13, 14,
|
|
16, 17, 19, 21, 23, 25, 28, 31,
|
|
34, 37, 41, 45, 50, 55, 60, 66,
|
|
73, 80, 88, 97, 107, 118, 130, 143,
|
|
157, 173, 190, 209, 230, 253, 279, 307,
|
|
337, 371, 408, 449, 494, 544, 598, 658,
|
|
724, 796, 876, 963, 1060, 1166, 1282, 1411,
|
|
1552, 1707, 1878, 2066, 2272, 2499, 2749, 3024,
|
|
3327, 3660, 4026, 4428, 4871, 5358, 5894, 6484,
|
|
7132, 7845, 8630, 9493, 10442, 11487, 12635, 13899,
|
|
15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794,
|
|
32767
|
|
};
|
|
|
|
public struct DIVAFile
|
|
{
|
|
public int Size;
|
|
public int SampleRate;
|
|
public int SamplesCount;
|
|
public byte Channels;
|
|
public byte[] Data;
|
|
}
|
|
}
|
|
}
|