/// <summary> /// Parses the <paramref name="binaryFile" /> and returns a <see cref="RIFFFileChunk" />. Note that the position of the /// stream has to point to a riff file chunk. /// </summary> /// <param name="binaryFile"><see cref="BinaryFile" /> which contains the riff file chunk.</param> /// <returns> /// Instance of the <see cref="RIFFFileChunk" /> class or any derived classes. It the stream does not point to a /// wave file chunk the instance of the <see cref="RIFFFileChunk" /> which gets return will be invalid. /// </returns> public static RIFFFileChunk FromBinaryFile(BinaryFile binaryFile) { if (binaryFile == null) { throw new ArgumentNullException("binaryFile"); } if (binaryFile.CanRead == false) { throw new ArgumentException("binaryFile is not readable"); } int id = binaryFile.ReadInt32(BinaryFile.ByteOrder.LittleEndian); // Steinberg CPR files have LittleEndian FourCCs binaryFile.Position -= 4; if (StringUtils.IsAsciiPrintable(FourCC.FromFourCC(id))) { Log.Verbose("Processing chunk: '{0}'", FourCC.FromFourCC(id)); } else { if (id == 0) { // likely corrupt wav file with alot of crap after the chunk // skip bytes until only 8 bytes are left // stream.Position = stream.Length - 8; } else { // try to fix chunks that are not word-aligned but should have been?! Log.Verbose("Processing chunk: {0}", string.Format("{0} is not FourCC", id)); long origPos = binaryFile.Position; // rewind one byte and try again binaryFile.Position -= 1; int id2ndTry = binaryFile.ReadInt32(); binaryFile.Position -= 4; if (StringUtils.IsAsciiPrintable(FourCC.FromFourCC(id2ndTry))) { // we believe it worked Log.Verbose("Seem to have fixed non word-aligned chunk: {0}", FourCC.FromFourCC(id2ndTry)); } else { // still didn't work // put position back to where it was. binaryFile.Position = origPos; } } } return(new RIFFFileChunk(binaryFile)); }
/// <summary> /// Return a string describing the chunks found in the file /// </summary> /// <param name="chunks"></param> /// <returns></returns> public static string GetRIFFFileChunkInformation(ReadOnlyCollection <RIFFFileChunk> chunks) { var writer = new StringWriter(); foreach (var chunk in chunks) { int id = chunk.ChunkID; writer.Write("Unknown chunk \"{0}\"", StringUtils.IsAsciiPrintable(FourCC.FromFourCC(id)) ? FourCC.FromFourCC(id) : string.Format("int {0} is not FourCC", id)); writer.Write(", Data size: {0}", chunk.ChunkDataSize); writer.Write(", Start pos: {0}", chunk.StartPosition); writer.Write(", End pos: {0}\n", chunk.EndPosition); } return(writer.ToString()); }
/// <summary> /// Return a string describing the chunks found in the file /// </summary> /// <param name="chunks"></param> /// <returns></returns> public static string GetWaveFileChunkInformation(ReadOnlyCollection <WaveFileChunk> chunks) { var writer = new StringWriter(); foreach (var chunk in chunks) { if (chunk is FmtChunk) { writer.Write("Format chunk: \"{0}\": ", FourCC.FromFourCC(chunk.ChunkID)); writer.Write(" Format: {0}", ((FmtChunk)chunk).WaveFormat); writer.Write(", Data size: {0}", ((FmtChunk)chunk).ChunkDataSize); writer.Write(", Start pos: {0}", ((FmtChunk)chunk).StartPosition); writer.Write(", End pos: {0}\n", ((FmtChunk)chunk).EndPosition); } else if (chunk is DataChunk) { writer.Write("Data chunk \"{0}\"", FourCC.FromFourCC(chunk.ChunkID)); writer.Write(", Data size: {0}", ((DataChunk)chunk).ChunkDataSize); writer.Write(", Data start pos: {0}", ((DataChunk)chunk).DataStartPosition); writer.Write(", Data end pos: {0}\n", ((DataChunk)chunk).DataEndPosition); } else if (chunk is ListChunk) { writer.Write("List chunk \"{0}\"", FourCC.FromFourCC(chunk.ChunkID)); writer.Write(", Data size: {0}", ((ListChunk)chunk).ChunkDataSize); writer.Write(", Start pos: {0}", ((ListChunk)chunk).StartPosition); writer.Write(", End pos: {0}", ((ListChunk)chunk).EndPosition); if (((ListChunk)chunk).InfoTags != null) { foreach (var infoTag in ((ListChunk)chunk).InfoTags) { writer.Write(", {0} = {1}", infoTag.Key, infoTag.Value); } } writer.Write("\n"); } else { int id = chunk.ChunkID; writer.Write("Unknown chunk \"{0}\"", StringUtils.IsAsciiPrintable(FourCC.FromFourCC(id)) ? FourCC.FromFourCC(id) : string.Format("int {0} is not FourCC", id)); writer.Write(", Data size: {0}", chunk.ChunkDataSize); writer.Write(", Start pos: {0}", chunk.StartPosition); writer.Write(", End pos: {0}\n", chunk.EndPosition); } } return(writer.ToString()); }
/// <summary> /// Parses the <paramref name="stream" /> and returns a <see cref="WaveFileChunk" />. Note that the position of the /// stream has to point to a wave file chunk. /// </summary> /// <param name="stream"><see cref="Stream" /> which points to a wave file chunk.</param> /// <returns> /// Instance of the <see cref="WaveFileChunk" /> class or any derived classes. It the stream does not point to a /// wave file chunk the instance of the <see cref="WaveFileChunk" /> which gets return will be invalid. /// </returns> public static WaveFileChunk FromStream(Stream stream) { if (stream == null) { throw new ArgumentNullException("stream"); } if (stream.CanRead == false) { throw new ArgumentException("stream is not readable"); } var reader = new BinaryReader(stream); int id = reader.ReadInt32(); stream.Position -= 4; if (StringUtils.IsAsciiPrintable(FourCC.FromFourCC(id))) { Log.Verbose("Processing chunk: {0}", FourCC.FromFourCC(id)); } else { if (id == 0) { // likely corrupt wav file with alot of crap after the chunk // skip bytes until only 8 bytes are left // stream.Position = stream.Length - 8; } else { // try to fix chunks that are not word-aligned but should have been?! Log.Verbose("Processing chunk: {0}", string.Format("{0} is not FourCC", id)); long origPos = stream.Position; // rewind one byte and try again stream.Position -= 1; int id2ndTry = reader.ReadInt32(); stream.Position -= 4; if (StringUtils.IsAsciiPrintable(FourCC.FromFourCC(id2ndTry))) { // we believe it worked Log.Verbose("Seem to have fixed non word-aligned chunk: {0}", FourCC.FromFourCC(id2ndTry)); } else { // still didn't work // put position back to where it was. stream.Position = origPos; } } } // check https://github.com/michaelwu/libsndfile/blob/master/src/wav.c // for all possible chunks ids if (id == FmtChunk.FmtChunkID) { return(new FmtChunk(reader)); } if (id == DataChunk.DataChunkID) { return(new DataChunk(reader)); } if (id == ListChunk.ListChunkID) { return(new ListChunk(reader)); } // TODO: add bext metadata tag support? // The European Broadcast Union (EBU) has standardized on an extension to the WAVE format that they call Broadcast WAVE format (BWF). // It is aimed at carrying PCM or MPEG audio data. In its simplest form, it adds a <bext> chunk with additional metadata. // https://tech.ebu.ch/docs/tech/tech3285.pdf return(new WaveFileChunk(reader)); }