Example #1
0
        /// <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));
        }
Example #2
0
        /// <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());
        }
Example #3
0
        /// <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());
        }
Example #4
0
        /// <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));
        }