using System; using System.Collections.Generic; using System.Text; namespace Oni.Sound { internal class SoundData { public bool IsIMA4; public int SampleRate; public int ChannelCount; public byte[] Data; public static SoundData Read(InstanceDescriptor sndd, bool do_pc_demo_test) { if (sndd.Template.Tag != TemplateTag.SNDD) throw new ArgumentException("descriptor"); var sound = new SoundData(); int dataSize; int dataOffset; using (var reader = sndd.OpenRead()) { if (sndd.IsMacFile) { sound.ChannelCount = (reader.ReadInt32() >> 1) + 1; sound.SampleRate = 22050; reader.Skip(4); sound.IsIMA4 = true; } else { reader.Skip(6); // ADPCM format identifiers (change to support PCM?) sound.ChannelCount = reader.ReadInt16(); sound.SampleRate = reader.ReadInt32(); reader.Skip(44); sound.IsIMA4 = false; } dataSize = reader.ReadInt32(); dataOffset = reader.ReadInt32(); } using (var rawReader = sndd.GetRawReader(dataOffset)) sound.Data = rawReader.ReadBytes(dataSize); if (sound.IsIMA4 && do_pc_demo_test) // check if the raw data actually looks like IMA4 { int nIMABlocks = sound.Data.Length / 34; int remainder = sound.Data.Length - nIMABlocks * 34; if (remainder == 0 && (nIMABlocks % sound.ChannelCount) == 0) { bool stepIndexAbove88 = false; for (int ii = 0; ii < nIMABlocks; ii++) { Byte cc = sound.Data[ii * 34 + 1]; if ((cc & 0x7F) > 88) stepIndexAbove88 = true; } if (stepIndexAbove88) sound.IsIMA4 = false; } else sound.IsIMA4 = false; if (!(sound.IsIMA4)) Console.WriteLine("PC-demo MS ADPCM detected; use -nodemo flag to treat as IMA4."); } return sound; } } }