mirror of
https://mirror.ghproxy.com/https://github.com/dexyfex/CodeWalker
synced 2024-11-30 02:42:54 +08:00
Tidy up AwcAudio.GetWavStream
This commit is contained in:
parent
668e8a2841
commit
84419cc2b7
@ -701,149 +701,93 @@ namespace CodeWalker.GameFiles
|
|||||||
return hash + "Unknown";
|
return hash + "Unknown";
|
||||||
}
|
}
|
||||||
|
|
||||||
public byte[] DecodeADPCM(byte[] data, int sampleCount)
|
|
||||||
|
public byte[] GetWavData()
|
||||||
{
|
{
|
||||||
byte[] dataPCM = new byte[data.Length * 4];
|
if (MultiChannelFormat != null)
|
||||||
int predictor = 0, step_index = 0, step = 0;
|
|
||||||
int readingOffset = 0, writingOffset = 0, bytesInBlock = 0;
|
|
||||||
|
|
||||||
int[] ima_index_table = {
|
|
||||||
-1, -1, -1, -1, 2, 4, 6, 8,
|
|
||||||
-1, -1, -1, -1, 2, 4, 6, 8
|
|
||||||
};
|
|
||||||
|
|
||||||
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
|
|
||||||
};
|
|
||||||
|
|
||||||
int clip(int value, int min, int max)
|
|
||||||
{
|
{
|
||||||
if (value < min)
|
if (Data == null)
|
||||||
return min;
|
|
||||||
if (value > max)
|
|
||||||
return max;
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
void parseNibble(byte nibble)
|
|
||||||
{
|
|
||||||
step_index = clip(step_index + ima_index_table[nibble], 0, 88);
|
|
||||||
|
|
||||||
int diff = step >> 3;
|
|
||||||
if ((nibble & 4) > 0) diff += step;
|
|
||||||
if ((nibble & 2) > 0) diff += step >> 1;
|
|
||||||
if ((nibble & 1) > 0) diff += step >> 2;
|
|
||||||
if ((nibble & 8) > 0) predictor -= diff;
|
|
||||||
else predictor += diff;
|
|
||||||
|
|
||||||
step = ima_step_table[step_index];
|
|
||||||
|
|
||||||
int samplePCM = clip(predictor, -32768, 32767);
|
|
||||||
dataPCM[writingOffset] = (byte)(samplePCM & 0xFF);
|
|
||||||
dataPCM[writingOffset + 1] = (byte)((samplePCM >> 8) & 0xFF);
|
|
||||||
writingOffset += 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
while ((readingOffset < data.Length) && (sampleCount > 0))
|
|
||||||
{
|
|
||||||
if (bytesInBlock == 0)
|
|
||||||
{
|
{
|
||||||
step_index = clip(data[readingOffset], 0, 88);
|
var ms = new MemoryStream();
|
||||||
predictor = BitConverter.ToInt16(data, readingOffset + 2);
|
var bw = new BinaryWriter(ms);
|
||||||
step = ima_step_table[step_index];
|
if (MultiChannelSource?.MultiChannelBlocks != null)
|
||||||
bytesInBlock = 2044;
|
{
|
||||||
readingOffset += 4;
|
foreach (var blk in MultiChannelSource.MultiChannelBlocks)
|
||||||
}
|
{
|
||||||
else
|
if (MultiChannelIndex < (blk?.Channels?.Length ?? 0))
|
||||||
{
|
{
|
||||||
parseNibble((byte)(data[readingOffset] & 0x0F));
|
var chan = blk.Channels[MultiChannelIndex];
|
||||||
parseNibble((byte)((data[readingOffset] >> 4) & 0x0F));
|
var cdata = chan.ChannelData;
|
||||||
bytesInBlock--;
|
bw.Write(cdata);
|
||||||
sampleCount -= 2;
|
}
|
||||||
readingOffset++;
|
}
|
||||||
|
}
|
||||||
|
bw.Flush();
|
||||||
|
ms.Position = 0;
|
||||||
|
Data = new byte[ms.Length];
|
||||||
|
ms.Read(Data, 0, (int)ms.Length);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return Data;
|
||||||
return dataPCM;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Stream GetWavStream()
|
public Stream GetWavStream()
|
||||||
{
|
{
|
||||||
byte[] dataPCM = null;
|
byte[] dataPCM = GetWavData();
|
||||||
int bitsPerSample = BitsPerSample;
|
var bitsPerSample = BitsPerSample;
|
||||||
var channels = Channels;
|
var channels = Channels;
|
||||||
|
var codec = MultiChannelFormat?.Codec ?? Format?.Codec ?? AwcCodecFormat.PCM;
|
||||||
|
|
||||||
if (MultiChannelFormat != null)
|
if (codec == AwcCodecFormat.ADPCM)//just convert ADPCM to PCM for compatibility reasons
|
||||||
{
|
{
|
||||||
var ms = new MemoryStream();
|
dataPCM = ADPCMCodec.DecodeADPCM(dataPCM, SampleCount);
|
||||||
var bw = new BinaryWriter(ms);
|
bitsPerSample = 16;
|
||||||
if (MultiChannelSource?.MultiChannelBlocks != null)
|
|
||||||
{
|
|
||||||
foreach (var blk in MultiChannelSource.MultiChannelBlocks)
|
|
||||||
{
|
|
||||||
if (MultiChannelIndex < (blk?.Channels?.Length ?? 0))
|
|
||||||
{
|
|
||||||
var chan = blk.Channels[MultiChannelIndex];
|
|
||||||
var cdata = chan.ChannelData;
|
|
||||||
bw.Write(cdata);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
bw.Flush();
|
|
||||||
ms.Position = 0;
|
|
||||||
dataPCM = new byte[ms.Length];
|
|
||||||
ms.Read(dataPCM, 0, (int)ms.Length);
|
|
||||||
if (MultiChannelFormat.Codec == AwcCodecFormat.ADPCM)
|
|
||||||
{
|
|
||||||
dataPCM = DecodeADPCM(dataPCM, SampleCount);
|
|
||||||
}
|
|
||||||
channels = 1;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
switch (Format.Codec)
|
|
||||||
{
|
|
||||||
case AwcCodecFormat.PCM:
|
|
||||||
dataPCM = Data;
|
|
||||||
break;
|
|
||||||
case AwcCodecFormat.ADPCM:
|
|
||||||
dataPCM = new byte[Data.Length];
|
|
||||||
Buffer.BlockCopy(Data, 0, dataPCM, 0, Data.Length);
|
|
||||||
dataPCM = DecodeADPCM(dataPCM, SampleCount);
|
|
||||||
bitsPerSample = 16;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
short formatcodec = 1; // 1 = WAVE_FORMAT_PCM
|
||||||
int byteRate = SamplesPerSecond * channels * bitsPerSample / 8;
|
int byteRate = SamplesPerSecond * channels * bitsPerSample / 8;
|
||||||
short blockAlign = (short)(channels * bitsPerSample / 8);
|
short blockAlign = (short)(channels * bitsPerSample / 8);
|
||||||
|
short samplesPerBlock = 0;
|
||||||
|
bool addextrafmt = false;
|
||||||
|
|
||||||
|
//if (codec == AwcCodecFormat.ADPCM)//can't seem to get ADPCM wav files to work :(
|
||||||
|
//{
|
||||||
|
// bitsPerSample = 4;
|
||||||
|
// formatcodec = 17;
|
||||||
|
// byteRate = (int)(SamplesPerSecond * 0.50685 * channels);
|
||||||
|
// blockAlign = 2048;// (short)(256 * (4 * channels));// (short)(36 * channels);//256;// 2048;//
|
||||||
|
// samplesPerBlock = 4088;// (short)(((blockAlign - (4 * channels)) * 8) / (bitsPerSample * channels) + 1); // 2044;//
|
||||||
|
// addextrafmt = true;
|
||||||
|
//}
|
||||||
|
|
||||||
|
|
||||||
MemoryStream stream = new MemoryStream();
|
MemoryStream stream = new MemoryStream();
|
||||||
BinaryWriter w = new BinaryWriter(stream);
|
BinaryWriter w = new BinaryWriter(stream);
|
||||||
int wavLength = 12 + 24 + 8 + dataPCM.Length;
|
int wavLength = 36 + dataPCM.Length;
|
||||||
|
if (addextrafmt)
|
||||||
|
{
|
||||||
|
wavLength += 4;
|
||||||
|
}
|
||||||
|
|
||||||
// RIFF chunk
|
// RIFF chunk
|
||||||
w.Write("RIFF".ToCharArray());
|
w.Write("RIFF".ToCharArray());
|
||||||
w.Write((int)(wavLength - 8));
|
w.Write((int)wavLength);
|
||||||
w.Write("WAVE".ToCharArray());
|
w.Write("WAVE".ToCharArray());
|
||||||
|
|
||||||
// fmt sub-chunk
|
// fmt sub-chunk
|
||||||
w.Write("fmt ".ToCharArray());
|
w.Write("fmt ".ToCharArray());
|
||||||
w.Write((int)16); // fmt size
|
w.Write((int)(addextrafmt ? 20 : 16)); // fmt size
|
||||||
w.Write((short)1); // 1 = WAVE_FORMAT_PCM
|
w.Write((short)formatcodec);
|
||||||
w.Write((short)channels);
|
w.Write((short)channels);
|
||||||
w.Write((int)SamplesPerSecond);
|
w.Write((int)SamplesPerSecond);
|
||||||
w.Write((int)byteRate);
|
w.Write((int)byteRate);
|
||||||
w.Write((short)blockAlign);
|
w.Write((short)blockAlign);
|
||||||
w.Write((short)bitsPerSample);
|
w.Write((short)bitsPerSample);
|
||||||
|
if (addextrafmt)
|
||||||
|
{
|
||||||
|
w.Write((ushort)0x0002);
|
||||||
|
w.Write((ushort)samplesPerBlock);
|
||||||
|
}
|
||||||
|
|
||||||
// data sub-chunk
|
// data sub-chunk
|
||||||
w.Write("data".ToCharArray());
|
w.Write("data".ToCharArray());
|
||||||
@ -1068,4 +1012,88 @@ namespace CodeWalker.GameFiles
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public class ADPCMCodec
|
||||||
|
{
|
||||||
|
|
||||||
|
private static int[] ima_index_table =
|
||||||
|
{
|
||||||
|
-1, -1, -1, -1, 2, 4, 6, 8,
|
||||||
|
-1, -1, -1, -1, 2, 4, 6, 8
|
||||||
|
};
|
||||||
|
|
||||||
|
private static 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
|
||||||
|
};
|
||||||
|
|
||||||
|
private static int clip(int value, int min, int max)
|
||||||
|
{
|
||||||
|
if (value < min) return min;
|
||||||
|
if (value > max) return max;
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static byte[] DecodeADPCM(byte[] data, int sampleCount)
|
||||||
|
{
|
||||||
|
byte[] dataPCM = new byte[data.Length * 4];
|
||||||
|
int predictor = 0, step_index = 0, step = 0;
|
||||||
|
int readingOffset = 0, writingOffset = 0, bytesInBlock = 0;
|
||||||
|
|
||||||
|
void parseNibble(byte nibble)
|
||||||
|
{
|
||||||
|
step_index = clip(step_index + ima_index_table[nibble], 0, 88);
|
||||||
|
|
||||||
|
int diff = step >> 3;
|
||||||
|
if ((nibble & 4) > 0) diff += step;
|
||||||
|
if ((nibble & 2) > 0) diff += step >> 1;
|
||||||
|
if ((nibble & 1) > 0) diff += step >> 2;
|
||||||
|
if ((nibble & 8) > 0) predictor -= diff;
|
||||||
|
else predictor += diff;
|
||||||
|
|
||||||
|
step = ima_step_table[step_index];
|
||||||
|
|
||||||
|
int samplePCM = clip(predictor, -32768, 32767);
|
||||||
|
dataPCM[writingOffset] = (byte)(samplePCM & 0xFF);
|
||||||
|
dataPCM[writingOffset + 1] = (byte)((samplePCM >> 8) & 0xFF);
|
||||||
|
writingOffset += 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
while ((readingOffset < data.Length) && (sampleCount > 0))
|
||||||
|
{
|
||||||
|
if (bytesInBlock == 0)
|
||||||
|
{
|
||||||
|
step_index = clip(data[readingOffset], 0, 88);
|
||||||
|
predictor = BitConverter.ToInt16(data, readingOffset + 2);
|
||||||
|
step = ima_step_table[step_index];
|
||||||
|
bytesInBlock = 2044;
|
||||||
|
readingOffset += 4;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
parseNibble((byte)(data[readingOffset] & 0x0F));
|
||||||
|
parseNibble((byte)((data[readingOffset] >> 4) & 0x0F));
|
||||||
|
bytesInBlock--;
|
||||||
|
sampleCount -= 2;
|
||||||
|
readingOffset++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return dataPCM;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user