--- OniSplit/Sound/WavExporter.cs 2020/05/28 21:28:44 1130 +++ OniSplit/Sound/WavExporter.cs 2021/05/03 15:22:15 1154 @@ -7,6 +7,7 @@ namespace Oni.Sound { #region Private data private bool convert_to_PCM; + private bool do_pc_demo_test; private const int fcc_RIFF = 0x46464952; private const int fcc_WAVE = 0x45564157; @@ -85,10 +86,11 @@ namespace Oni.Sound }; #endregion - public WavExporter(InstanceFileManager fileManager, string outputDirPath, bool convertToPCM = false) + public WavExporter(InstanceFileManager fileManager, string outputDirPath, bool convertToPCM = false, bool noDemo = false) : base(fileManager, outputDirPath) { convert_to_PCM = convertToPCM; + do_pc_demo_test = !noDemo; } private static void ClampToRange(ref int value, int lower, int upper) @@ -146,35 +148,37 @@ namespace Oni.Sound protected override void ExportInstance(InstanceDescriptor descriptor) { - var sound = SoundData.Read(descriptor); + var sound = SoundData.Read(descriptor, do_pc_demo_test); using (var stream = File.Create(Path.Combine(OutputDirPath, descriptor.FullName + ".wav"))) using (var writer = new BinaryWriter(stream)) { - var blockSizeADPCM = 512 * sound.ChannelCount * sound.SampleRate / 22050; + var blockSizeADPCM = sound.BlockAlignment; + int wholeBlocks = sound.Data.Length / blockSizeADPCM; int leftoverBytes = sound.Data.Length - (wholeBlocks * blockSizeADPCM); - int leftoverSamples = 8 * (leftoverBytes - 7 * sound.ChannelCount) - / 4 / sound.ChannelCount + 2; // 4 bits per sample + int leftoverSamples = 0; + if(leftoverBytes > 14) + leftoverSamples = 2 + (leftoverBytes - 7 * sound.ChannelCount) + * 8 / sound.BitsPerSample / sound.ChannelCount; int paddingBytes = 0; if (leftoverBytes > 0) // incomplete trailing block paddingBytes = blockSizeADPCM - leftoverBytes; - var samplesPerBlock = 2 + (blockSizeADPCM - sound.ChannelCount * 7) * 8 / sound.ChannelCount / 4; + var samplesPerBlock = 2 + (blockSizeADPCM - sound.ChannelCount * 7) * 8 / sound.ChannelCount / sound.BitsPerSample; + + Int32 sampleCount = wholeBlocks * samplesPerBlock + leftoverSamples; - Int32 sampleCount = sampleCount = wholeBlocks * samplesPerBlock + leftoverSamples; - if (sound.IsIMA4) // IMA4 ADPCM format { blockSizeADPCM = 34 * sound.ChannelCount; samplesPerBlock = 64; sampleCount = (sound.Data.Length / blockSizeADPCM) * samplesPerBlock; } - if (!convert_to_PCM) { if (sound.IsIMA4) { - throw new NotSupportedException("Transcoding from Mac/demo ADPCM to PC ADPCM not supported! Please use -extract:pcm"); + throw new NotSupportedException("Transcoding from IMA4 ADPCM (Mac) to MS ADPCM (PC) not supported! Please use -extract:pcm"); } var format = (byte[])formatTemplate_ADPCM.Clone(); var fact = (byte[])factTemplate.Clone(); // needed for ADPCM (to specify the actual sample count) @@ -270,6 +274,10 @@ namespace Oni.Sound if (predictorL > 32767) predictorL -= 65536; } stepIndexL = headerLoL & 0x7f; + if (stepIndexL > 88) + Console.WriteLine("Block {0} (L): Initial IMA4 step index is {1}, clamping to 88.", block, stepIndexL); + ClampToRange(ref stepIndexL, 0, 88); + for (int b = 0; b < 32; b++) { Byte nibblesL = sound.Data[pos++]; @@ -290,6 +298,9 @@ namespace Oni.Sound if (predictorR > 32767) predictorR -= 65536; } stepIndexR = headerLoR & 0x7f; + if (stepIndexR > 88) + Console.WriteLine("Block {0} (R): Initial IMA4 step index is {1}, clamping to 88.", block, stepIndexR); + ClampToRange(ref stepIndexR, 0, 88); for (int b = 0; b < 32; b++) { @@ -359,15 +370,17 @@ namespace Oni.Sound samplesR[iSampleR++] = sample1R; } } - // read pair of nibbles - Byte nibbles = sound.Data[pos++]; - Byte nibbleHi = (Byte)(nibbles >> 4); - Byte nibbleLo = (Byte)(nibbles & 0xF); - samplesL[iSampleL++] = NibbletoSampleMSADPCM(ref sample1L, ref sample2L, ref deltaL, pred_indexL, nibbleHi); - if (sound.ChannelCount == 2) - samplesR[iSampleR++] = NibbletoSampleMSADPCM(ref sample1R, ref sample2R, ref deltaR, pred_indexR, nibbleLo); - else - samplesL[iSampleL++] = NibbletoSampleMSADPCM(ref sample1L, ref sample2L, ref deltaL, pred_indexL, nibbleLo); + else // read pair of nibbles + { + Byte nibbles = sound.Data[pos++]; + Byte nibbleHi = (Byte)(nibbles >> 4); + Byte nibbleLo = (Byte)(nibbles & 0xF); + samplesL[iSampleL++] = NibbletoSampleMSADPCM(ref sample1L, ref sample2L, ref deltaL, pred_indexL, nibbleHi); + if (sound.ChannelCount == 2) + samplesR[iSampleR++] = NibbletoSampleMSADPCM(ref sample1R, ref sample2R, ref deltaR, pred_indexR, nibbleLo); + else + samplesL[iSampleL++] = NibbletoSampleMSADPCM(ref sample1L, ref sample2L, ref deltaL, pred_indexL, nibbleLo); + } } } writer.Write(fcc_data);