Beispiel #1
0
 internal static IEnumerable <MidiEvent> GetEvents(this MidiFile midiFile)
 {
     return(midiFile.GetTrackChunks().SelectMany(c => c.Events));
 }
Beispiel #2
0
        /// <summary>
        /// Reads a MIDI file from the stream.
        /// </summary>
        /// <param name="stream">Stream to read file from.</param>
        /// <param name="settings">Settings according to which the file must be read.</param>
        /// <returns>An instance of the <see cref="MidiFile"/> representing a MIDI file was read from the stream.</returns>
        /// <remarks>
        /// Stream must be readable, seekable and be able to provide its position and length via <see cref="Stream.Position"/>
        /// and <see cref="Stream.Length"/> properties.
        /// </remarks>
        /// <exception cref="ArgumentNullException"><paramref name="stream"/> is null.</exception>
        /// <exception cref="ArgumentException"><paramref name="stream"/> doesn't support reading. -or
        /// <paramref name="stream"/> doesn't support seeking. -or- <paramref name="stream"/> is already read.</exception>
        /// <exception cref="IOException">An I/O error occurred while reading from the stream.</exception>
        /// <exception cref="ObjectDisposedException"><paramref name="stream"/> is disposed. -or-
        /// Underlying stream reader is disposed.</exception>
        /// <exception cref="NotSupportedException">Unable to get position of the <paramref name="stream"/>. -or
        /// Unable to get length of the <paramref name="stream"/>.</exception>
        /// <exception cref="NoHeaderChunkException">There is no header chunk in a file.</exception>
        /// <exception cref="InvalidChunkSizeException">Actual header or track chunk's size differs from the one declared
        /// in its header and that should be treated as error according to the <paramref name="settings"/>.</exception>
        /// <exception cref="UnknownChunkException">Chunk to be read has unknown ID and that
        /// should be treated as error accordng to the <paramref name="settings"/>.</exception>
        /// <exception cref="UnexpectedTrackChunksCountException">Actual track chunks
        /// count differs from the expected one and that should be treated as error according to
        /// the specified <paramref name="settings"/>.</exception>
        /// <exception cref="UnknownFileFormatException">The header chunk contains unknown file format and
        /// <see cref="ReadingSettings.UnknownFileFormatPolicy"/> property of the <paramref name="settings"/> set to
        /// <see cref="UnknownFileFormatPolicy.Abort"/>.</exception>
        /// <exception cref="NotEnoughBytesException">MIDI file cannot be read since the reader's underlying stream doesn't
        /// have enough bytes.</exception>
        /// <exception cref="UnexpectedRunningStatusException">Unexpected running status is encountered.</exception>
        /// <exception cref="MissedEndOfTrackEventException">Track chunk doesn't end with End Of Track event and that
        /// should be treated as error accordng to the specified <paramref name="settings"/>.</exception>
        /// <exception cref="InvalidChannelEventParameterValueException">Value of a channel event's parameter
        /// just read is invalid.</exception>
        /// <exception cref="InvalidMetaEventParameterValueException">Value of a meta event's parameter
        /// just read is invalid.</exception>
        public static MidiFile Read(Stream stream, ReadingSettings settings = null)
        {
            ThrowIfArgument.IsNull(nameof(stream), stream);

            if (!stream.CanRead)
            {
                throw new ArgumentException("Stream doesn't support reading.", nameof(stream));
            }

            if (!stream.CanSeek)
            {
                throw new ArgumentException("Stream doesn't support seeking.", nameof(stream));
            }

            if (stream.Position >= stream.Length)
            {
                throw new ArgumentException("Stream is already read.", nameof(stream));
            }

            //

            if (settings == null)
            {
                settings = new ReadingSettings();
            }

            var file = new MidiFile();

            int? expectedTrackChunksCount = null;
            int  actualTrackChunksCount   = 0;
            bool headerChunkIsRead        = false;

            //

            try
            {
                using (var reader = new MidiReader(stream))
                {
                    // Read RIFF header

                    long?smfEndPosition = null;

                    var chunkId = reader.ReadString(RiffChunkId.Length);
                    if (chunkId == RiffChunkId)
                    {
                        reader.Position += RmidPreambleSize;
                        var smfSize = reader.ReadDword();
                        smfEndPosition = reader.Position + smfSize;
                    }
                    else
                    {
                        reader.Position -= chunkId.Length;
                    }

                    // Read SMF

                    while (!reader.EndReached && (smfEndPosition == null || reader.Position < smfEndPosition))
                    {
                        // Read chunk

                        var chunk = ReadChunk(reader, settings, actualTrackChunksCount, expectedTrackChunksCount);
                        if (chunk == null)
                        {
                            continue;
                        }

                        // Process header chunk

                        var headerChunk = chunk as HeaderChunk;
                        if (headerChunk != null)
                        {
                            if (!headerChunkIsRead)
                            {
                                expectedTrackChunksCount = headerChunk.TracksNumber;
                                file.TimeDivision        = headerChunk.TimeDivision;
                                file._originalFormat     = headerChunk.FileFormat;
                            }

                            headerChunkIsRead = true;
                            continue;
                        }

                        // Process track chunk

                        if (chunk is TrackChunk)
                        {
                            actualTrackChunksCount++;
                        }

                        // Add chunk to chunks collection of the file

                        file.Chunks.Add(chunk);
                    }

                    if (expectedTrackChunksCount != null && actualTrackChunksCount != expectedTrackChunksCount)
                    {
                        ReactOnUnexpectedTrackChunksCount(settings.UnexpectedTrackChunksCountPolicy, actualTrackChunksCount, expectedTrackChunksCount.Value);
                    }
                }

                // Process header chunks count

                if (!headerChunkIsRead)
                {
                    file.TimeDivision = null;

                    if (settings.NoHeaderChunkPolicy == NoHeaderChunkPolicy.Abort)
                    {
                        throw new NoHeaderChunkException();
                    }
                }
            }
            catch (NotEnoughBytesException ex)
            {
                ReactOnNotEnoughBytes(settings.NotEnoughBytesPolicy, ex);
            }
            catch (EndOfStreamException ex)
            {
                ReactOnNotEnoughBytes(settings.NotEnoughBytesPolicy, ex);
            }

            //

            return(file);
        }
Beispiel #3
0
        /// <summary>
        /// Gets all channel numbers presented in the specified <see cref="MidiFile"/>.
        /// </summary>
        /// <param name="midiFile"><see cref="MidiFile"/> to get channels of.</param>
        /// <returns>Collection of channel numbers presented in the <paramref name="midiFile"/>.</returns>
        /// <exception cref="ArgumentNullException"><paramref name="midiFile"/> is <c>null</c>.</exception>
        public static IEnumerable <FourBitNumber> GetChannels(this MidiFile midiFile)
        {
            ThrowIfArgument.IsNull(nameof(midiFile), midiFile);

            return(midiFile.GetTrackChunks().GetChannels());
        }
        /// <summary>
        /// Gets all track chunks of a MIDI file.
        /// </summary>
        /// <param name="midiFile">MIDI file to get track chunks of.</param>
        /// <returns>Collection of track chunks contained in the <paramref name="midiFile"/>.</returns>
        /// <exception cref="ArgumentNullException"><paramref name="midiFile"/> is <c>null</c>.</exception>
        public static IEnumerable <TrackChunk> GetTrackChunks(this MidiFile midiFile)
        {
            ThrowIfArgument.IsNull(nameof(midiFile), midiFile);

            return(midiFile.Chunks.OfType <TrackChunk>());
        }
Beispiel #5
0
 /// <summary>
 /// Determines whether two specified <see cref="MidiFile"/> objects have the same content using
 /// the specified comparison settings.
 /// </summary>
 /// <param name="midiFile1">The first file to compare, or <c>null</c>.</param>
 /// <param name="midiFile2">The second file to compare, or <c>null</c>.</param>
 /// <param name="settings">Settings according to which files should be compared.</param>
 /// <param name="message">Message containing information about what exactly is different in
 /// <paramref name="midiFile1"/> and <paramref name="midiFile2"/>.</param>
 /// <returns><c>true</c> if the <paramref name="midiFile1"/> is equal to the <paramref name="midiFile2"/>;
 /// otherwise, <c>false</c>.</returns>
 public static bool Equals(MidiFile midiFile1, MidiFile midiFile2, MidiFileEqualityCheckSettings settings, out string message)
 {
     return(MidiFileEquality.Equals(midiFile1, midiFile2, settings ?? new MidiFileEqualityCheckSettings(), out message));
 }
Beispiel #6
0
        public static bool Equals(MidiFile midiFile1, MidiFile midiFile2, MidiFileEqualityCheckSettings settings)
        {
            string message;

            return(Equals(midiFile1, midiFile2, settings, out message));
        }
Beispiel #7
0
 /// <summary>
 /// Determines whether two specified <see cref="MidiFile"/> objects have the same content.
 /// </summary>
 /// <param name="midiFile1">The first file to compare, or <c>null</c>.</param>
 /// <param name="midiFile2">The second file to compare, or <c>null</c>.</param>
 /// <param name="message">Message containing information about what exactly is different in
 /// <paramref name="midiFile1"/> and <paramref name="midiFile2"/>.</param>
 /// <returns><c>true</c> if the <paramref name="midiFile1"/> is equal to the <paramref name="midiFile2"/>;
 /// otherwise, <c>false</c>.</returns>
 public static bool Equals(MidiFile midiFile1, MidiFile midiFile2, out string message)
 {
     return(Equals(midiFile1, midiFile2, null, out message));
 }
Beispiel #8
0
        /// <summary>
        /// Determines whether two specified <see cref="MidiFile"/> objects have the same content.
        /// </summary>
        /// <param name="midiFile1">The first file to compare, or <c>null</c>.</param>
        /// <param name="midiFile2">The second file to compare, or <c>null</c>.</param>
        /// <returns><c>true</c> if the <paramref name="midiFile1"/> is equal to the <paramref name="midiFile2"/>;
        /// otherwise, <c>false</c>.</returns>
        public static bool Equals(MidiFile midiFile1, MidiFile midiFile2)
        {
            string message;

            return(Equals(midiFile1, midiFile2, out message));
        }