using System; using System.IO; namespace Oni.Sound { internal class WavExporter : SoundExporter { #region Private data private const int fcc_RIFF = 0x46464952; private const int fcc_WAVE = 0x45564157; private const int fcc_fmt = 0x20746d66; private const int fcc_data = 0x61746164; private static readonly byte[] formatTemplate = new byte[50] { 0x02, 0, // format ID (always 2) 0, 0, // ChannelCount (overwritten) 0x22, 0x56, 0, 0, // SampleRate (usually 22050, can be 44100) 0, 0, 0, 0, // average data rate (computed and overwritten) 0, 0x02, // block alignment (default 512, can be 1024) 0x04, 0, // bits per sample (always 4) 0x20, 0, // size of extended header block 0xf4, 0x03, // samples per block (usually 1012, can be 2036) 0x07, 0, // standard ADPCM coefficient table (always the same) 0, 0x01, 0, 0, 0, 0x02, 0, 0xff, 0, 0, 0, 0, 0xc0, 0, 0x40, 0, 0xf0, 0, 0, 0, 0xcc, 0x01, 0x30, 0xff, 0x88, 0x01, 0x18, 0xff }; #endregion public WavExporter(InstanceFileManager fileManager, string outputDirPath) : base(fileManager, outputDirPath) { } protected override void ExportInstance(InstanceDescriptor descriptor) { var sound = SoundData.Read(descriptor); using (var stream = File.Create(Path.Combine(OutputDirPath, descriptor.FullName + ".wav"))) using (var writer = new BinaryWriter(stream)) { var format = (byte[])formatTemplate.Clone(); var blockAlignment = 512 * sound.ChannelCount * sound.SampleRate / 22050; var samplesPerBlock = 2 + (blockAlignment - sound.ChannelCount * 7) * 8 / sound.ChannelCount / 4; var averageRate = sound.SampleRate * blockAlignment / samplesPerBlock; Array.Copy(BitConverter.GetBytes(sound.ChannelCount), 0, format, 2, 2); Array.Copy(BitConverter.GetBytes(sound.SampleRate), 0, format, 4, 4); Array.Copy(BitConverter.GetBytes(averageRate), 0, format, 8, 4); Array.Copy(BitConverter.GetBytes(blockAlignment), 0, format, 12, 2); Array.Copy(BitConverter.GetBytes(samplesPerBlock), 0, format, 18, 2); writer.Write(fcc_RIFF); writer.Write(8 + format.Length + 8 + sound.Data.Length); writer.Write(fcc_WAVE); // // write format chunk // writer.Write(fcc_fmt); writer.Write(format.Length); writer.Write(format); // // write data chunk // writer.Write(fcc_data); writer.Write(sound.Data.Length); writer.Write(sound.Data); } } } }