| 7 |  | { | 
 
 
 
 
 
 
 
 
 
 
 
 
 | 8 |  | #region Private data | 
 
 
 
 
 
 
 
 
 
 
 
 
 | 9 |  | private bool convert_to_PCM; | 
 
 
 
 
 
 
 
 | 10 | + | private bool do_pc_demo_test; | 
 
 
 
 
 
 
 
 
 
 
 
 
 | 11 |  |  | 
 
 
 
 
 
 
 
 
 
 
 
 
 | 12 |  | private const int fcc_RIFF = 0x46464952; | 
 
 
 
 
 
 
 
 
 
 
 
 
 | 13 |  | private const int fcc_WAVE = 0x45564157; | 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 | 86 |  | }; | 
 
 
 
 
 
 
 
 
 
 
 
 
 | 87 |  | #endregion | 
 
 
 
 
 
 
 
 
 
 
 
 
 | 88 |  |  | 
 
 
 
 
 
 
 
 
 
 
 | 89 | < | public WavExporter(InstanceFileManager fileManager, string outputDirPath, bool convertToPCM = false) | 
 
 
 
 
 
 
 
 
 | 89 | > | public WavExporter(InstanceFileManager fileManager, string outputDirPath, bool convertToPCM = false, bool noDemo = false) | 
 
 
 
 
 
 
 
 
 
 
 | 90 |  | : base(fileManager, outputDirPath) | 
 
 
 
 
 
 
 
 
 
 
 
 
 | 91 |  | { | 
 
 
 
 
 
 
 
 
 
 
 
 
 | 92 |  | convert_to_PCM = convertToPCM; | 
 
 
 
 
 
 
 
 | 93 | + | do_pc_demo_test = !noDemo; | 
 
 
 
 
 
 
 
 
 
 
 
 
 | 94 |  | } | 
 
 
 
 
 
 
 
 
 
 
 
 
 | 95 |  |  | 
 
 
 
 
 
 
 
 
 
 
 
 
 | 96 |  | private static void ClampToRange(ref int value, int lower, int upper) | 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 | 148 |  |  | 
 
 
 
 
 
 
 
 
 
 
 
 
 | 149 |  | protected override void ExportInstance(InstanceDescriptor descriptor) | 
 
 
 
 
 
 
 
 
 
 
 
 
 | 150 |  | { | 
 
 
 
 
 
 
 
 
 
 
 | 151 | < | var sound = SoundData.Read(descriptor); | 
 
 
 
 
 
 
 
 
 | 151 | > | var sound = SoundData.Read(descriptor, do_pc_demo_test); | 
 
 
 
 
 
 
 
 
 
 
 | 152 |  |  | 
 
 
 
 
 
 
 
 
 
 
 
 
 | 153 |  | using (var stream = File.Create(Path.Combine(OutputDirPath, descriptor.FullName + ".wav"))) | 
 
 
 
 
 
 
 
 
 
 
 
 
 | 154 |  | using (var writer = new BinaryWriter(stream)) | 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 | 163 |  | paddingBytes = blockSizeADPCM - leftoverBytes; | 
 
 
 
 
 
 
 
 
 
 
 
 
 | 164 |  | var samplesPerBlock = 2 + (blockSizeADPCM - sound.ChannelCount * 7) * 8 / sound.ChannelCount / 4; | 
 
 
 
 
 
 
 
 
 
 
 
 
 | 165 |  |  | 
 
 
 
 
 
 
 
 
 
 
 | 166 | < | Int32 sampleCount = sampleCount = wholeBlocks * samplesPerBlock + leftoverSamples; | 
 
 
 
 
 
 
 
 
 
 
 
 
 | 167 | < |  | 
 
 
 
 
 
 
 
 
 | 166 | > | Int32 sampleCount = sampleCount = wholeBlocks * samplesPerBlock + leftoverSamples; | 
 
 
 
 
 | 167 | > |  | 
 
 
 
 
 
 
 
 
 
 
 | 168 |  | if (sound.IsIMA4) // IMA4 ADPCM format | 
 
 
 
 
 
 
 
 
 
 
 
 
 | 169 |  | { | 
 
 
 
 
 
 
 
 
 
 
 
 
 | 170 |  | blockSizeADPCM = 34 * sound.ChannelCount; | 
 
 
 
 
 
 
 
 
 
 
 
 
 | 171 |  | samplesPerBlock = 64; | 
 
 
 
 
 
 
 
 
 
 
 
 
 | 172 |  | sampleCount = (sound.Data.Length / blockSizeADPCM) * samplesPerBlock; | 
 
 
 
 
 
 
 
 
 
 
 
 
 | 173 |  | } | 
 
 
 
 
 
 
 
 
 | 172 | – |  | 
 
 
 
 
 
 
 
 
 
 
 
 
 | 174 |  | if (!convert_to_PCM) | 
 
 
 
 
 
 
 
 
 
 
 
 
 | 175 |  | { | 
 
 
 
 
 
 
 
 
 
 
 
 
 | 176 |  | if (sound.IsIMA4) | 
 
 
 
 
 
 
 
 
 
 
 
 
 | 177 |  | { | 
 
 
 
 
 
 
 
 
 
 
 | 178 | < | throw new NotSupportedException("Transcoding from Mac/demo ADPCM to PC ADPCM not supported! Please use -extract:pcm"); | 
 
 
 
 
 
 
 
 
 | 178 | > | throw new NotSupportedException("Transcoding from IMA4 ADPCM (Mac) to MS ADPCM (PC) not supported! Please use -extract:pcm"); | 
 
 
 
 
 
 
 
 
 
 
 | 179 |  | } | 
 
 
 
 
 
 
 
 
 
 
 
 
 | 180 |  | var format = (byte[])formatTemplate_ADPCM.Clone(); | 
 
 
 
 
 
 
 
 
 
 
 
 
 | 181 |  | var fact = (byte[])factTemplate.Clone(); // needed for ADPCM (to specify the actual sample count) | 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 | 271 |  | if (predictorL > 32767) predictorL -= 65536; | 
 
 
 
 
 
 
 
 
 
 
 
 
 | 272 |  | } | 
 
 
 
 
 
 
 
 
 
 
 
 
 | 273 |  | stepIndexL = headerLoL & 0x7f; | 
 
 
 
 
 
 
 
 | 274 | + | if (stepIndexL > 88) | 
 
 
 
 
 
 
 
 | 275 | + | Console.WriteLine("Block {0} (L): Initial IMA4 step index is {1}, clamping to 88.", block, stepIndexL); | 
 
 
 
 
 
 
 
 | 276 | + | ClampToRange(ref stepIndexL, 0, 88); | 
 
 
 
 
 
 
 
 | 277 | + |  | 
 
 
 
 
 
 
 
 
 
 
 
 
 | 278 |  | for (int b = 0; b < 32; b++) | 
 
 
 
 
 
 
 
 
 
 
 
 
 | 279 |  | { | 
 
 
 
 
 
 
 
 
 
 
 
 
 | 280 |  | Byte nibblesL = sound.Data[pos++]; | 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 | 295 |  | if (predictorR > 32767) predictorR -= 65536; | 
 
 
 
 
 
 
 
 
 
 
 
 
 | 296 |  | } | 
 
 
 
 
 
 
 
 
 
 
 
 
 | 297 |  | stepIndexR = headerLoR & 0x7f; | 
 
 
 
 
 
 
 
 | 298 | + | if (stepIndexR > 88) | 
 
 
 
 
 
 
 
 | 299 | + | Console.WriteLine("Block {0} (R): Initial IMA4 step index is {1}, clamping to 88.", block, stepIndexR); | 
 
 
 
 
 
 
 
 | 300 | + | ClampToRange(ref stepIndexR, 0, 88); | 
 
 
 
 
 
 
 
 
 
 
 
 
 | 301 |  |  | 
 
 
 
 
 
 
 
 
 
 
 
 
 | 302 |  | for (int b = 0; b < 32; b++) | 
 
 
 
 
 
 
 
 
 
 
 
 
 | 303 |  | { | 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 | 367 |  | samplesR[iSampleR++] = sample1R; | 
 
 
 
 
 
 
 
 
 
 
 
 
 | 368 |  | } | 
 
 
 
 
 
 
 
 
 
 
 
 
 | 369 |  | } | 
 
 
 
 
 
 
 
 
 
 
 | 370 | < | // read pair of nibbles | 
 
 
 
 
 
 
 
 
 
 
 
 
 | 371 | < | Byte nibbles = sound.Data[pos++]; | 
 
 
 
 
 
 
 
 
 
 
 
 
 | 372 | < | Byte nibbleHi = (Byte)(nibbles >> 4); | 
 
 
 
 
 
 
 
 
 
 
 
 
 | 373 | < | Byte nibbleLo = (Byte)(nibbles & 0xF); | 
 
 
 
 
 
 
 
 
 
 
 
 
 | 374 | < | samplesL[iSampleL++] = NibbletoSampleMSADPCM(ref sample1L, ref sample2L, ref deltaL, pred_indexL, nibbleHi); | 
 
 
 
 
 
 
 
 
 
 
 
 
 | 375 | < | if (sound.ChannelCount == 2) | 
 
 
 
 
 
 
 
 
 
 
 
 
 | 376 | < | samplesR[iSampleR++] = NibbletoSampleMSADPCM(ref sample1R, ref sample2R, ref deltaR, pred_indexR, nibbleLo); | 
 
 
 
 
 
 
 
 
 
 
 
 
 | 377 | < | else | 
 
 
 
 
 
 
 
 
 
 
 
 
 | 378 | < | samplesL[iSampleL++] = NibbletoSampleMSADPCM(ref sample1L, ref sample2L, ref deltaL, pred_indexL, nibbleLo); | 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 | 370 | > | else // read pair of nibbles | 
 
 
 
 
 | 371 | > | { | 
 
 
 
 
 | 372 | > | Byte nibbles = sound.Data[pos++]; | 
 
 
 
 
 | 373 | > | Byte nibbleHi = (Byte)(nibbles >> 4); | 
 
 
 
 
 | 374 | > | Byte nibbleLo = (Byte)(nibbles & 0xF); | 
 
 
 
 
 | 375 | > | samplesL[iSampleL++] = NibbletoSampleMSADPCM(ref sample1L, ref sample2L, ref deltaL, pred_indexL, nibbleHi); | 
 
 
 
 
 | 376 | > | if (sound.ChannelCount == 2) | 
 
 
 
 
 | 377 | > | samplesR[iSampleR++] = NibbletoSampleMSADPCM(ref sample1R, ref sample2R, ref deltaR, pred_indexR, nibbleLo); | 
 
 
 
 
 | 378 | > | else | 
 
 
 
 
 | 379 | > | samplesL[iSampleL++] = NibbletoSampleMSADPCM(ref sample1L, ref sample2L, ref deltaL, pred_indexL, nibbleLo); | 
 
 
 
 
 | 380 | > | } | 
 
 
 
 
 
 
 
 
 
 
 | 381 |  | } | 
 
 
 
 
 
 
 
 
 
 
 
 
 | 382 |  | } | 
 
 
 
 
 
 
 
 
 
 
 
 
 | 383 |  | writer.Write(fcc_data); |