public static WavFormat ReadWavFormat(BinaryReader inReader, out ushort inCbSize) { var inFormat = new WavFormat(); ExpectAscii(inReader, "fmt "); var fmtLength = inReader.ReadUInt32(); inFormat.Format = (WavFormatCode)inReader.ReadUInt16(); inFormat.Channels = inReader.ReadUInt16(); inFormat.SampleRate = inReader.ReadUInt32(); var inByteRate = inReader.ReadUInt32(); var inBlockAlign = inReader.ReadUInt16(); inFormat.BitDepth = inReader.ReadUInt16(); inCbSize = (ushort)(fmtLength > 16 ? inReader.ReadUInt16() : 0); inReader.BaseStream.Seek(inCbSize, SeekOrigin.Current); // Skip CB if (inFormat.BlockAlign != inBlockAlign) { throw new FormatException( string.Format("Inconsistent block alignment: {0} channels of {1} bits is not {2} bytes", inFormat.Channels, inFormat.BitDepth, inBlockAlign)); } if (inFormat.ByteRate != inByteRate) { throw new FormatException( string.Format("Inconsistent sample rate: {0} channels of {1} bits at {2} KHz is not {3} KBps", inFormat.Channels, inFormat.BitDepth, inFormat.SampleRate/1000, inByteRate/1000)); } return inFormat; }
public static void Convert( Stream inStream, Stream outStream, WavFormat outFormat) { using (var inReader = new BinaryReader(inStream)) { var inFormat = new WavFormat(); // Read header ExpectAscii(inReader, "RIFF"); var fileLength = inReader.ReadUInt32() + 8; ExpectAscii(inReader, "WAVE"); ushort inCbSize; inFormat = ReadWavFormat(inReader, out inCbSize); ExpectAscii(inReader, "data"); inFormat.SetDataLength(inReader.ReadUInt32()); Console.WriteLine(); Console.WriteLine("Input file:"); Console.WriteLine(" Format: {0}", inFormat.Format); Console.WriteLine(" Channels: {0}", inFormat.ChannelString); Console.WriteLine(" Bit depth: {0} bit", inFormat.BitDepth); Console.WriteLine(" Sample rate: {0} KHz", inFormat.SampleRate / 1000.0); Console.WriteLine(" Bit rate: {0} Kbs", inFormat.ByteRate * 8 / 1000); Console.WriteLine(); Console.WriteLine(" File length: {0} bytes", fileLength); Console.WriteLine(" CB Size: {0} bytes", inCbSize); Console.WriteLine(" Block align: {0} bytes", inFormat.BlockAlign); Console.WriteLine(" Data: {0} samples", inFormat.Samples); Console.WriteLine(); switch (inFormat.Format) { case WavFormatCode.Pcm: case WavFormatCode.Ieee754: case WavFormatCode.Extensible: break; default: throw new FormatException(string.Format( "File format {0} is not supported. Only PCM, Extensible, and IEEE 574", inFormat.Format)); } outFormat.Samples = inFormat.Samples; if (outStream != null) { using (var outWriter = new BinaryWriter(outStream)) { Console.WriteLine("Writing output file"); var outFileLength = 44 + outFormat.DataLength; // Write header WriteAscii(outWriter, "RIFF"); outWriter.Write(outFileLength - 8); WriteAscii(outWriter, "WAVE"); WriteAscii(outWriter, "fmt "); outWriter.Write(16); // no CB outWriter.Write((ushort)outFormat.Format); outWriter.Write(outFormat.Channels); outWriter.Write(outFormat.SampleRate); outWriter.Write(outFormat.ByteRate); outWriter.Write(outFormat.BlockAlign); outWriter.Write(outFormat.BitDepth); WriteAscii(outWriter, "data"); outWriter.Write(outFormat.DataLength); MoveSamples(inReader, inFormat, outWriter, outFormat); } } } }
private static void WriteFrame(BinaryWriter outWriter, WavFormat outFormat, double[] frame) { switch (outFormat.Format) { case WavFormatCode.Pcm: switch (outFormat.BitDepth) { case 8: WriteFrameI8(outWriter, frame); break; case 16: WriteFrameI16(outWriter, frame); break; case 32: WriteFrameI32(outWriter, frame); break; default: throw new FormatException(string.Format( "Output bit depth {0} is not supported", outFormat.BitDepth)); } break; case WavFormatCode.Ieee754: switch (outFormat.BitDepth) { case 32: WriteFrameF32(outWriter, frame); break; case 64: WriteFrameF64(outWriter, frame); break; default: throw new FormatException(string.Format( "Output IEEE bit depth {0} is not supported", outFormat.BitDepth)); } break; default: throw new FormatException(string.Format( "Output file format {0} is not supported", outFormat.Format)); } }
private static double[] ReadFrame(BinaryReader inReader, WavFormat inFormat) { double[] frame; switch (inFormat.Format) { case WavFormatCode.Pcm: case WavFormatCode.Extensible: switch (inFormat.BitDepth) { case 8: frame = ReadFrameI8(inReader, inFormat.Channels); break; case 16: frame = ReadFrameI16(inReader, inFormat.Channels); break; case 24: frame = ReadFrameI24(inReader, inFormat.Channels); break; case 32: frame = ReadFrameI32(inReader, inFormat.Channels); break; default: throw new FormatException( "Input PCM bit depth " + inFormat.BitDepth + " is not supported"); } break; case WavFormatCode.Ieee754: switch (inFormat.BitDepth) { case 32: frame = ReadFrameF32(inReader, inFormat.Channels); break; case 64: frame = ReadFrameF64(inReader, inFormat.Channels); break; default: throw new FormatException( "Input IEEE bit depth " + inFormat.BitDepth + " is not supported"); } break; default: throw new FormatException("Input file format " + inFormat.Format + " is not supported"); } return frame; }
private static void MoveSamples( BinaryReader inReader, WavFormat inFormat, BinaryWriter outWriter, WavFormat outFormat) { // For each frame that we read, we write as many frames as required for this slice of time // (possibly zero if the output sample rate is lower than the input) var lastInFrameTime = 0.0; var lastOutFrameTime = 0.0; var lastInFrame = new double[] {}; if (inReader.BaseStream.Position != inReader.BaseStream.Length) { lastInFrame = ReadFrame(inReader, inFormat); lastInFrame = ApplyMatrix(lastInFrame, outFormat.Channels); WriteFrame(outWriter, outFormat, lastInFrame); } var inDeltaTime = 1.0 / inFormat.SampleRate; var outDeltaTime = 1.0 / outFormat.SampleRate; while (inReader.BaseStream.Position != inReader.BaseStream.Length) { var thisInFrame = ReadFrame(inReader, inFormat); var thisInFrameTime = lastInFrameTime + inDeltaTime; thisInFrame = ApplyMatrix(thisInFrame, outFormat.Channels); // Resample: output is interpolated from the last two frames from the source for (var thisOutFrameTime = lastOutFrameTime + outDeltaTime; thisOutFrameTime < thisInFrameTime; thisOutFrameTime += outDeltaTime) { var ratio = (thisOutFrameTime - lastInFrameTime)/outDeltaTime; var frame = lastInFrame.Zip(thisInFrame, (s1, s2) => ratio*s1 + (1.0 - ratio)*s2) .ToArray(); WriteFrame(outWriter, outFormat, frame); lastOutFrameTime = thisOutFrameTime; } lastInFrameTime = thisInFrameTime; lastInFrame = thisInFrame; } }