internal static IEnumerable <MidiEvent> GetEvents(this MidiFile midiFile) { return(midiFile.GetTrackChunks().SelectMany(c => c.Events)); }
/// <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); }
/// <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>()); }
/// <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)); }
public static bool Equals(MidiFile midiFile1, MidiFile midiFile2, MidiFileEqualityCheckSettings settings) { string message; return(Equals(midiFile1, midiFile2, settings, out message)); }
/// <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)); }
/// <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)); }