Exemplo n.º 1
0
        public MidiEvent Read(MidiReader reader, ReadingSettings settings, byte currentStatusByte)
        {
            var statusByte = currentStatusByte.GetHead();
            var channel    = currentStatusByte.GetTail();

            Type eventType;

            if (!StandardEventTypes.Channel.TryGetType(statusByte, out eventType))
            {
                throw new UnknownChannelEventException(statusByte, channel);
            }

            var channelEvent = (ChannelEvent)Activator.CreateInstance(eventType);

            channelEvent.Read(reader, settings, MidiEvent.UnknownContentSize);
            channelEvent.Channel = channel;

            var noteOnEvent = channelEvent as NoteOnEvent;

            if (noteOnEvent != null && settings.SilentNoteOnPolicy == SilentNoteOnPolicy.NoteOff && noteOnEvent.Velocity == 0)
            {
                channelEvent = new NoteOffEvent
                {
                    DeltaTime  = noteOnEvent.DeltaTime,
                    Channel    = noteOnEvent.Channel,
                    NoteNumber = noteOnEvent.NoteNumber
                }
            }
            ;

            return(channelEvent);
        }

        #endregion
    }
Exemplo n.º 2
0
 /// <summary>
 /// Reads a MIDI file specified by its full path.
 /// </summary>
 /// <param name="filePath">Path to the file to read.</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.</returns>
 /// <exception cref="ArgumentException"><paramref name="filePath"/> is a zero-length string,
 /// contains only white space, or contains one or more invalid characters as defined by
 /// <see cref="Path.InvalidPathChars"/>.</exception>
 /// <exception cref="ArgumentNullException"><paramref name="filePath"/> is null.</exception>
 /// <exception cref="PathTooLongException">The specified path, file name, or both exceed the system-defined
 /// maximum length. For example, on Windows-based platforms, paths must be less than 248 characters,
 /// and file names must be less than 260 characters.</exception>
 /// <exception cref="DirectoryNotFoundException">The specified path is invalid, (for example,
 /// it is on an unmapped drive).</exception>
 /// <exception cref="IOException">An I/O error occurred while reading the file.</exception>
 /// <exception cref="NotSupportedException"><paramref name="filePath"/> is in an invalid format.</exception>
 /// <exception cref="UnauthorizedAccessException">This operation is not supported on the current platform. -or-
 /// <paramref name="filePath"/> specified a directory. -or- The caller does not have the required permission.</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="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>
 /// <exception cref="UnknownChannelEventException">Reader has encountered an unknown channel event.</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>
 public static MidiFile Read(string filePath, ReadingSettings settings = null)
 {
     using (var fileStream = FileUtilities.OpenFileForRead(filePath))
     {
         return(Read(fileStream, settings));
     }
 }
Exemplo n.º 3
0
        /// <summary>
        /// Reads chunk from the <see cref="MidiReader"/>'s underlying stream according to
        /// specified <see cref="ReadingSettings"/>.
        /// </summary>
        /// <param name="reader">Reader to read the chunk's data with.</param>
        /// <param name="settings">Settings according to which the chunk's data must be read.</param>
        /// <exception cref="ObjectDisposedException">Method was called after <paramref name="reader"/>
        /// was disposed.</exception>
        /// <exception cref="IOException">An I/O error occurred on the <paramref name="reader"/>'s
        /// underlying stream.</exception>
        /// <exception cref="InvalidChunkSizeException">Actual chunk's size differs from the one declared
        /// in its header.</exception>
        /// <exception cref="NotEnoughBytesException">Size of the chunk cannot be read since the reader's
        /// underlying stream doesn't have enough bytes.</exception>
        internal void Read(MidiReader reader, ReadingSettings settings)
        {
            // LOGREAD: c a
            // LOGREAD: c s a

            var size = reader.ReadDword();

            // LOGREAD: c s z <{size}>

            var readerPosition = reader.Position;

            ReadContent(reader, settings, size);

            var bytesReadCount = reader.Position - readerPosition;

            if (settings.InvalidChunkSizePolicy == InvalidChunkSizePolicy.Abort && bytesReadCount != size)
            {
                throw new InvalidChunkSizeException(ChunkId, size, bytesReadCount);
            }

            // Skip unread bytes

            var bytesUnread = size - bytesReadCount;

            if (bytesUnread > 0)
            {
                reader.Position += Math.Min(bytesUnread, reader.Length);
            }

            // LOGREAD: c z <{ToString()}>
        }
Exemplo n.º 4
0
        /// <summary>
        /// Reads content of a <see cref="TrackChunk"/>.
        /// </summary>
        /// <remarks>
        /// Content of a <see cref="TrackChunk"/> is collection of MIDI events.
        /// </remarks>
        /// <param name="reader">Reader to read the chunk's content with.</param>
        /// <param name="settings">Settings according to which the chunk's content must be read.</param>
        /// <param name="size">Expected size of the content taken from the chunk's header.</param>
        /// <exception cref="ObjectDisposedException">Method was called after the writer's underlying stream
        /// was disposed.</exception>
        /// <exception cref="IOException">An I/O error occurred on the writer's underlying stream.</exception>
        /// <exception cref="UnexpectedRunningStatusException">Unexpected running status is encountered.</exception>
        /// <exception cref="UnknownChannelEventException">Reader has encountered an unknown channel event.</exception>
        /// <exception cref="NotEnoughBytesException">Not enough bytes to read an event.</exception>
        /// <exception cref="InvalidChannelEventParameterValueException">Value of a channel event's parameter just
        /// read is invalid.</exception>
        /// <exception cref="MissedEndOfTrackEventException">Track chunk doesn't end with End Of Track event.</exception>
        protected override void ReadContent(MidiReader reader, ReadingSettings settings, uint size)
        {
            var endReaderPosition   = reader.Position + size;
            var endOfTrackPresented = false;

            byte?currentChannelEventStatusByte = null;

            //

            while (reader.Position < endReaderPosition && !reader.EndReached)
            {
                var midiEvent = ReadEvent(reader, settings, ref currentChannelEventStatusByte);
                if (midiEvent is EndOfTrackEvent)
                {
                    endOfTrackPresented = true;
                    break;
                }

                Events.Add(midiEvent);
            }

            //

            if (settings.MissedEndOfTrackPolicy == MissedEndOfTrackPolicy.Abort && !endOfTrackPresented)
            {
                throw new MissedEndOfTrackEventException();
            }
        }
Exemplo n.º 5
0
        /// <summary>
        /// Reads content of a MIDI event.
        /// </summary>
        /// <param name="reader">Reader to read the content with.</param>
        /// <param name="settings">Settings according to which the event's content must be read.</param>
        /// <param name="size">Size of the event's content.</param>
        /// <exception cref="InvalidChannelEventParameterValueException">An invalid value for channel
        /// event's parameter was encountered.</exception>
        internal sealed override void Read(MidiReader reader, ReadingSettings settings, int size)
        {
            for (int i = 0; i < _parameters.Length; i++)
            {
                var parameter = reader.ReadByte();
                if (parameter > SevenBitNumber.MaxValue)
                {
                    switch (settings.InvalidChannelEventParameterValuePolicy)
                    {
                    case InvalidChannelEventParameterValuePolicy.Abort:
                        throw new InvalidChannelEventParameterValueException($"{parameter} is invalid value for channel event's parameter.", parameter);

                    case InvalidChannelEventParameterValuePolicy.ReadValid:
                        parameter &= SevenBitNumber.MaxValue;
                        break;

                    case InvalidChannelEventParameterValuePolicy.SnapToLimits:
                        parameter = SevenBitNumber.MaxValue;
                        break;
                    }
                }

                _parameters[i] = (SevenBitNumber)parameter;
            }
        }
Exemplo n.º 6
0
        public MidiEvent Read(MidiReader reader, ReadingSettings settings, byte currentStatusByte)
        {
            var statusByte = currentStatusByte.GetHead();
            var channel    = currentStatusByte.GetTail();

            ChannelEvent channelEvent = null;

            switch (statusByte)
            {
            case EventStatusBytes.Channel.NoteOff:
                channelEvent = new NoteOffEvent();
                break;

            case EventStatusBytes.Channel.NoteOn:
                channelEvent = new NoteOnEvent();
                break;

            case EventStatusBytes.Channel.ControlChange:
                channelEvent = new ControlChangeEvent();
                break;

            case EventStatusBytes.Channel.PitchBend:
                channelEvent = new PitchBendEvent();
                break;

            case EventStatusBytes.Channel.ChannelAftertouch:
                channelEvent = new ChannelAftertouchEvent();
                break;

            case EventStatusBytes.Channel.ProgramChange:
                channelEvent = new ProgramChangeEvent();
                break;

            case EventStatusBytes.Channel.NoteAftertouch:
                channelEvent = new NoteAftertouchEvent();
                break;

            default:
                ReactOnUnknownChannelEvent(statusByte, channel, reader, settings);
                return(null);
            }

            channelEvent.Read(reader, settings, MidiEvent.UnknownContentSize);
            channelEvent.Channel = channel;

            var noteOnEvent = channelEvent as NoteOnEvent;

            if (noteOnEvent != null && settings.SilentNoteOnPolicy == SilentNoteOnPolicy.NoteOff && noteOnEvent.Velocity == 0)
            {
                channelEvent = new NoteOffEvent
                {
                    DeltaTime  = noteOnEvent.DeltaTime,
                    Channel    = noteOnEvent.Channel,
                    NoteNumber = noteOnEvent.NoteNumber
                }
            }
            ;

            return(channelEvent);
        }
        /// <summary>
        /// Reads content of a MIDI meta event.
        /// </summary>
        /// <param name="reader">Reader to read the content with.</param>
        /// <param name="settings">Settings according to which the event's content must be read.</param>
        /// <param name="size">Size of the event's content.</param>
        /// <exception cref="ArgumentOutOfRangeException">Text event cannot be read since the size is
        /// negative number.</exception>
        protected sealed override void ReadContent(MidiReader reader, ReadingSettings settings, int size)
        {
            ThrowIfArgument.IsNegative(
                nameof(size),
                size,
                "Text event cannot be read since the size is negative number.");

            if (size == 0)
            {
                switch (settings.ZeroLengthDataPolicy)
                {
                case ZeroLengthDataPolicy.ReadAsEmptyObject:
                    Text = string.Empty;
                    break;

                case ZeroLengthDataPolicy.ReadAsNull:
                    Text = null;
                    break;
                }

                return;
            }

            var bytes    = reader.ReadBytes(size);
            var encoding = settings.TextEncoding ?? SmfConstants.DefaultTextEncoding;

            var decodeTextCallback = settings.DecodeTextCallback;

            Text = decodeTextCallback != null
                ? decodeTextCallback(bytes, settings)
                : encoding.GetString(bytes);
        }
        /// <summary>
        /// Reads content of a <see cref="UnknownChunk"/>.
        /// </summary>
        /// <remarks>
        /// Content of an <see cref="UnknownChunk"/> is array of bytes.
        /// </remarks>
        /// <param name="reader">Reader to read the chunk's content with.</param>
        /// <param name="settings">Settings according to which the chunk's content must be read.</param>
        /// <param name="size">Expected size of the content taken from the chunk's header.</param>
        /// <exception cref="ObjectDisposedException">Method was called after the reader's underlying stream was disposed.</exception>
        /// <exception cref="IOException">An I/O error occurred on the reader's underlying stream.</exception>
        protected override void ReadContent(MidiReader reader, ReadingSettings settings, uint size)
        {
            if (size == 0)
            {
                switch (settings.ZeroLengthDataPolicy)
                {
                case ZeroLengthDataPolicy.ReadAsEmptyObject:
                    Data = new byte[0];
                    break;

                case ZeroLengthDataPolicy.ReadAsNull:
                    Data = null;
                    break;
                }

                return;
            }

            var availableSize = reader.Length - reader.Position;
            var bytesCount    = availableSize < size ? availableSize : size;
            var bytes         = reader.ReadBytes((int)Math.Min(bytesCount, int.MaxValue));

            if (bytes.Length < size && settings.NotEnoughBytesPolicy == NotEnoughBytesPolicy.Abort)
            {
                throw new NotEnoughBytesException(
                          "Unknown chunk's data cannot be read since the reader's underlying stream doesn't have enough bytes.",
                          size,
                          bytes.Length);
            }

            Data = bytes;
        }
Exemplo n.º 9
0
        /// <summary>
        /// Reads content of a MIDI meta event.
        /// </summary>
        /// <param name="reader">Reader to read the content with.</param>
        /// <param name="settings">Settings according to which the event's content must be read.</param>
        /// <param name="size">Size of the event's content.</param>
        /// <exception cref="ArgumentOutOfRangeException">Sequencer specific event cannot be read since the size is
        /// negative number.</exception>
        protected override void ReadContent(MidiReader reader, ReadingSettings settings, int size)
        {
            ThrowIfArgument.IsNegative(
                nameof(size),
                size,
                "Sequencer specific event cannot be read since the size is negative number.");

            if (size == 0)
            {
                switch (settings.ZeroLengthDataPolicy)
                {
                case ZeroLengthDataPolicy.ReadAsEmptyObject:
                    Data = new byte[0];
                    break;

                case ZeroLengthDataPolicy.ReadAsNull:
                    Data = null;
                    break;
                }

                return;
            }

            Data = reader.ReadBytes(size);
        }
Exemplo n.º 10
0
        public MidiEvent Read(MidiReader reader, ReadingSettings settings, byte currentStatusByte)
        {
            var statusByte = reader.ReadByte();
            var size       = reader.ReadVlqNumber();

            //

            Type eventType;
            var  midiEvent = TryGetEventType(settings.CustomMetaEventTypes, statusByte, out eventType)
                ? (MetaEvent)Activator.CreateInstance(eventType)
                : new UnknownMetaEvent(statusByte);

            //

            var readerPosition = reader.Position;

            midiEvent.Read(reader, settings, size);

            var bytesRead   = reader.Position - readerPosition;
            var bytesUnread = size - bytesRead;

            if (bytesUnread > 0)
            {
                reader.Position += bytesUnread;
            }

            return(midiEvent);
        }
        public MidiEvent Read(MidiReader reader, ReadingSettings settings, byte currentStatusByte)
        {
            var size = reader.ReadVlqNumber();

            //

            SysExEvent sysExEvent = null;

            switch (currentStatusByte)
            {
            case EventStatusBytes.Global.NormalSysEx:
                sysExEvent = new NormalSysExEvent();
                break;

            case EventStatusBytes.Global.EscapeSysEx:
                sysExEvent = new EscapeSysExEvent();
                break;
            }

            if (sysExEvent == null)
            {
                Debug.Fail("Unknown SysEx event.");
            }

            //

            sysExEvent.Read(reader, settings, size);
            return(sysExEvent);
        }
Exemplo n.º 12
0
        internal override void Read(MidiReader reader, ReadingSettings settings, int size)
        {
            var data = reader.ReadByte();

            var midiTimeCodeComponent = (byte)data.GetHead();

            if (!Enum.IsDefined(typeof(MidiTimeCodeComponent), midiTimeCodeComponent))
            {
                throw new InvalidMidiTimeCodeComponentException(midiTimeCodeComponent);
            }

            Component = (MidiTimeCodeComponent)midiTimeCodeComponent;

            var componentValue = data.GetTail();

            if (componentValue > ComponentValueMasks[Component])
            {
                switch (settings.InvalidSystemCommonEventParameterValuePolicy)
                {
                case InvalidSystemCommonEventParameterValuePolicy.Abort:
                    throw new InvalidSystemCommonEventParameterValueException(EventType, $"{nameof(ComponentValue)} (component is {Component})", componentValue);

                case InvalidSystemCommonEventParameterValuePolicy.SnapToLimits:
                    componentValue = (FourBitNumber)ComponentValueMasks[Component];
                    break;
                }
            }

            ComponentValue = componentValue;
        }
Exemplo n.º 13
0
        /// <summary>
        /// Reads content of a MIDI event.
        /// </summary>
        /// <param name="reader">Reader to read the content with.</param>
        /// <param name="settings">Settings according to which the event's content must be read.</param>
        /// <param name="size">Size of the event's content.</param>
        internal sealed override void Read(MidiReader reader, ReadingSettings settings, int size)
        {
            ThrowIfArgument.IsNegative(nameof(size),
                                       size,
                                       "Non-negative size have to be specified in order to read SysEx event.");

            Data = reader.ReadBytes(size);
        }
Exemplo n.º 14
0
        /// <summary>
        /// Reads content of a MIDI meta event.
        /// </summary>
        /// <param name="reader">Reader to read the content with.</param>
        /// <param name="settings">Settings according to which the event's content must be read.</param>
        /// <param name="size">Size of the event's content.</param>
        /// <exception cref="ArgumentOutOfRangeException">Unknown meta event cannot be read since the size is
        /// negative number.</exception>
        protected override void ReadContent(MidiReader reader, ReadingSettings settings, int size)
        {
            ThrowIfArgument.IsNegative(nameof(size),
                                       size,
                                       "Unknown meta event cannot be read since the size is negative number.");

            Data = reader.ReadBytes(size);
        }
Exemplo n.º 15
0
        /// <summary>
        /// Reads content of a <see cref="TrackChunk"/>.
        /// </summary>
        /// <remarks>
        /// Content of a <see cref="TrackChunk"/> is collection of MIDI events.
        /// </remarks>
        /// <param name="reader">Reader to read the chunk's content with.</param>
        /// <param name="settings">Settings according to which the chunk's content must be read.</param>
        /// <param name="size">Expected size of the content taken from the chunk's header.</param>
        /// <exception cref="ObjectDisposedException">Method was called after the writer's underlying stream
        /// was disposed.</exception>
        /// <exception cref="IOException">An I/O error occurred on the writer's underlying stream.</exception>
        /// <exception cref="UnexpectedRunningStatusException">Unexpected running status is encountered.</exception>
        /// <exception cref="UnknownChannelEventException">Reader has encountered an unknown channel event.</exception>
        /// <exception cref="NotEnoughBytesException">Not enough bytes to read an event.</exception>
        /// <exception cref="InvalidChannelEventParameterValueException">Value of a channel event's parameter just
        /// read is invalid.</exception>
        /// <exception cref="MissedEndOfTrackEventException">Track chunk doesn't end with End Of Track event.</exception>
        protected override void ReadContent(MidiReader reader, ReadingSettings settings, uint size)
        {
            var useReadingHandlers = settings.UseReadingHandlers;

            if (useReadingHandlers)
            {
                foreach (var handler in settings.TrackChunkReadingHandlers)
                {
                    handler.OnStartTrackChunkContentReading(this);
                }
            }

            //

            var endReaderPosition   = reader.Position + size;
            var endOfTrackPresented = false;

            byte?currentChannelEventStatusByte = null;
            long absoluteTime = 0;

            //

            while (reader.Position < endReaderPosition && !reader.EndReached)
            {
                long deltaTime;

                var midiEvent = ReadEvent(reader, settings, ref currentChannelEventStatusByte, out deltaTime);
                if (midiEvent is EndOfTrackEvent)
                {
                    endOfTrackPresented = true;
                    break;
                }

                absoluteTime += deltaTime;

                if (midiEvent == null)
                {
                    continue;
                }

                if (useReadingHandlers)
                {
                    foreach (var handler in settings.EventReadingHandlers)
                    {
                        handler.OnFinishEventReading(midiEvent, absoluteTime);
                    }
                }

                Events.Add(midiEvent);
            }

            //

            if (settings.MissedEndOfTrackPolicy == MissedEndOfTrackPolicy.Abort && !endOfTrackPresented)
            {
                throw new MissedEndOfTrackEventException();
            }
        }
Exemplo n.º 16
0
        /// <summary>
        /// Reads an event from the reader's underlying stream.
        /// </summary>
        /// <param name="reader">Reader to read an event.</param>
        /// <param name="settings">Settings according to which an event must be read.</param>
        /// <param name="channelEventStatusByte">Current channel event status byte used as running status.</param>
        /// <returns>Instance of the <see cref="MidiEvent"/> representing a MIDI event.</returns>
        /// <exception cref="ObjectDisposedException">Method was called after the writer's underlying stream
        /// was disposed.</exception>
        /// <exception cref="IOException">An I/O error occurred on the writer's underlying stream.</exception>
        /// <exception cref="UnexpectedRunningStatusException">Unexpected running status is encountered.</exception>
        /// <exception cref="UnknownChannelEventException">Reader has encountered an unknown channel event.</exception>
        /// <exception cref="NotEnoughBytesException">Not enough bytes to read an event.</exception>
        /// <exception cref="InvalidChannelEventParameterValueException">Value of a channel event's parameter just
        /// read is invalid.</exception>
        private MidiEvent ReadEvent(MidiReader reader, ReadingSettings settings, ref byte?channelEventStatusByte)
        {
            var deltaTime = reader.ReadVlqLongNumber();

            if (deltaTime < 0)
            {
                deltaTime = 0;
            }

            //

            var statusByte = reader.ReadByte();

            if (statusByte <= SevenBitNumber.MaxValue)
            {
                if (channelEventStatusByte == null)
                {
                    throw new UnexpectedRunningStatusException();
                }

                statusByte = channelEventStatusByte.Value;
                reader.Position--;
            }

            //

            var eventReader = EventReaderFactory.GetReader(statusByte, smfOnly: true);
            var midiEvent   = eventReader.Read(reader, settings, statusByte);

            //

            if (settings.SilentNoteOnPolicy == SilentNoteOnPolicy.NoteOff)
            {
                var noteOnEvent = midiEvent as NoteOnEvent;
                if (noteOnEvent?.Velocity == 0)
                {
                    midiEvent = new NoteOffEvent
                    {
                        DeltaTime  = noteOnEvent.DeltaTime,
                        Channel    = noteOnEvent.Channel,
                        NoteNumber = noteOnEvent.NoteNumber
                    };
                }
            }

            //

            if (midiEvent is ChannelEvent)
            {
                channelEventStatusByte = statusByte;
            }

            //

            midiEvent.DeltaTime = deltaTime;
            return(midiEvent);
        }
Exemplo n.º 17
0
        public MidiEvent Read(MidiReader reader, ReadingSettings settings, byte currentStatusByte)
        {
            Type eventType;

            StandardEventTypes.SystemRealTime.TryGetType(currentStatusByte, out eventType);
            var systemRealTimeEvent = (SystemRealTimeEvent)Activator.CreateInstance(eventType);

            systemRealTimeEvent.Read(reader, settings, MidiEvent.UnknownContentSize);
            return(systemRealTimeEvent);
        }
Exemplo n.º 18
0
        private static void ValidateReadingSettings(ReadingSettings settings)
        {
            ValidateCustomMetaEventsStatusBytes(settings.CustomMetaEventTypes);
            ValidateCustomChunksIds(settings.CustomChunkTypes);

            if (settings.UnknownChannelEventPolicy == UnknownChannelEventPolicy.UseCallback && settings.UnknownChannelEventCallback == null)
            {
                throw new InvalidOperationException("Unknown channel event callback is not set.");
            }
        }
Exemplo n.º 19
0
        /// <summary>
        /// Reads content of a MIDI meta event.
        /// </summary>
        /// <param name="reader">Reader to read the content with.</param>
        /// <param name="settings">Settings according to which the event's content must be read.</param>
        /// <param name="size">Size of the event's content.</param>
        protected override void ReadContent(MidiReader reader, ReadingSettings settings, int size)
        {
            Numerator   = reader.ReadByte();
            Denominator = (byte)Math.Pow(2, reader.ReadByte());

            if (size >= 4)
            {
                ClocksPerClick           = reader.ReadByte();
                ThirtySecondNotesPerBeat = reader.ReadByte();
            }
        }
        /// <summary>
        /// Reads content of a <see cref="HeaderChunk"/>.
        /// </summary>
        /// <remarks>
        /// Content of a <see cref="HeaderChunk"/> is format of the file, number of track chunks and time division.
        /// </remarks>
        /// <param name="reader">Reader to read the chunk's content with.</param>
        /// <param name="settings">Settings according to which the chunk's content must be read.</param>
        /// <param name="size">Expected size of the content taken from the chunk's header.</param>
        /// <exception cref="ObjectDisposedException">Method was called after the reader's underlying stream was disposed.</exception>
        /// <exception cref="IOException">An I/O error occurred on the reader's underlying stream.</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>
        protected override void ReadContent(MidiReader reader, ReadingSettings settings, uint size)
        {
            var fileFormat = reader.ReadWord();

            if (settings.UnknownFileFormatPolicy == UnknownFileFormatPolicy.Abort && !Enum.IsDefined(typeof(MidiFileFormat), fileFormat))
            {
                throw new UnknownFileFormatException(fileFormat);
            }

            FileFormat   = fileFormat;
            TracksNumber = reader.ReadWord();
            TimeDivision = TimeDivisionFactory.GetTimeDivision(reader.ReadInt16());
        }
Exemplo n.º 21
0
        private MidiEvent ReadEvent(MidiReader reader, ReadingSettings settings, ref byte?channelEventStatusByte, out long deltaTime)
        {
            // LOGREAD: e a
            // LOGREAD: dt a

            deltaTime = reader.ReadVlqLongNumber();
            if (deltaTime < 0)
            {
                deltaTime = 0;
            }

            // LOGREAD: dt z <{deltaTime}>
            // LOGREAD: m a

            var statusByte = reader.ReadByte();

            if (statusByte <= SevenBitNumber.MaxValue)
            {
                if (channelEventStatusByte == null)
                {
                    throw new UnexpectedRunningStatusException();
                }

                statusByte = channelEventStatusByte.Value;
                reader.Position--;
            }

            //

            var eventReader = EventReaderFactory.GetReader(statusByte, smfOnly: true);
            var midiEvent   = eventReader.Read(reader, settings, statusByte);

            //

            if (midiEvent is ChannelEvent)
            {
                channelEventStatusByte = statusByte;
            }

            //

            if (midiEvent != null)
            {
                midiEvent._deltaTime = deltaTime;
            }

            // LOGREAD: m z
            // LOGREAD: e z <{midiEvent}>

            return(midiEvent);
        }
Exemplo n.º 22
0
        /// <summary>
        /// Reads content of a <see cref="UnknownChunk"/>.
        /// </summary>
        /// <remarks>
        /// Content of an <see cref="UnknownChunk"/> is array of bytes.
        /// </remarks>
        /// <param name="reader">Reader to read the chunk's content with.</param>
        /// <param name="settings">Settings according to which the chunk's content must be read.</param>
        /// <param name="size">Expected size of the content taken from the chunk's header.</param>
        /// <exception cref="ObjectDisposedException">Method was called after the reader's underlying stream was disposed.</exception>
        /// <exception cref="IOException">An I/O error occurred on the reader's underlying stream.</exception>
        protected override void ReadContent(MidiReader reader, ReadingSettings settings, uint size)
        {
            var availableSize = reader.Length - reader.Position;
            var bytes         = reader.ReadBytes((int)(availableSize < size ? availableSize : size));

            if (bytes.Length < size && settings.NotEnoughBytesPolicy == NotEnoughBytesPolicy.Abort)
            {
                throw new NotEnoughBytesException("Chunk's data cannot be read since the reader's underlying stream doesn't have enough bytes.",
                                                  size,
                                                  bytes.Length);
            }

            Data = bytes;
        }
Exemplo n.º 23
0
        /// <summary>
        /// Reads content of a MIDI meta event.
        /// </summary>
        /// <param name="reader">Reader to read the content with.</param>
        /// <param name="settings">Settings according to which the event's content must be read.</param>
        /// <param name="size">Size of the event's content.</param>
        protected override void ReadContent(MidiReader reader, ReadingSettings settings, int size)
        {
            var invalidMetaEventParameterValuePolicy = settings.InvalidMetaEventParameterValuePolicy;

            Key = (sbyte)ProcessValue(reader.ReadSByte(),
                                       nameof(Key),
                                       MinKey,
                                       MaxKey,
                                       invalidMetaEventParameterValuePolicy);

            Scale = (byte)ProcessValue(reader.ReadByte(),
                                        nameof(Scale),
                                        MinScale,
                                        MaxScale,
                                        invalidMetaEventParameterValuePolicy);
        }
Exemplo n.º 24
0
        public MidiEvent Read(MidiReader reader, ReadingSettings settings, byte currentStatusByte)
        {
            var statusByte = currentStatusByte.GetHead();
            var channel    = currentStatusByte.GetTail();

            Type eventType;

            if (!StandardEventTypes.Channel.TryGetType(statusByte, out eventType))
            {
                throw new UnknownChannelEventException(statusByte, channel);
            }

            var channelEvent = (ChannelEvent)Activator.CreateInstance(eventType);

            channelEvent.Read(reader, settings, MidiEvent.UnknownContentSize);
            channelEvent.Channel = channel;
            return(channelEvent);
        }
Exemplo n.º 25
0
        internal override void Read(MidiReader reader, ReadingSettings settings, int size)
        {
            var number = reader.ReadByte();

            if (number > SevenBitNumber.MaxValue)
            {
                switch (settings.InvalidSystemCommonEventParameterValuePolicy)
                {
                case InvalidSystemCommonEventParameterValuePolicy.Abort:
                    throw new InvalidSystemCommonEventParameterValueException(GetType(), nameof(Number), number);

                case InvalidSystemCommonEventParameterValuePolicy.SnapToLimits:
                    number = SevenBitNumber.MaxValue;
                    break;
                }
            }

            Number = (SevenBitNumber)number;
        }
Exemplo n.º 26
0
        /// <summary>
        /// Reads content of a MIDI meta event.
        /// </summary>
        /// <param name="reader">Reader to read the content with.</param>
        /// <param name="settings">Settings according to which the event's content must be read.</param>
        /// <param name="size">Size of the event's content.</param>
        /// <exception cref="ArgumentOutOfRangeException">Text event cannot be read since the size is
        /// negative number.</exception>
        protected sealed override void ReadContent(MidiReader reader, ReadingSettings settings, int size)
        {
            ThrowIfArgument.IsNegative(nameof(size),
                                       size,
                                       "Text event cannot be read since the size is negative number.");

            if (size == 0)
            {
                return;
            }

            var bytes    = reader.ReadBytes(size);
            var encoding = settings.TextEncoding ?? SmfConstants.DefaultTextEncoding;

            var decodeTextCallback = settings.DecodeTextCallback;

            Text = decodeTextCallback != null
                ? decodeTextCallback(bytes, settings)
                : encoding.GetString(bytes);
        }
Exemplo n.º 27
0
        public MidiEvent Read(MidiReader reader, ReadingSettings settings, byte currentStatusByte)
        {
            var size = reader.ReadVlqNumber();

            //

            Type eventType;
            var  midiEvent = StandardEventTypes.SysEx.TryGetType(currentStatusByte, out eventType)
                ? (SysExEvent)Activator.CreateInstance(eventType)
                : null;

            if (midiEvent == null)
            {
                Debug.Fail("Unknown SysEx event.");
            }

            //

            midiEvent.Read(reader, settings, size);
            return(midiEvent);
        }
        /// <summary>
        /// Reads channel event's data byte using the specified reader and settings.
        /// </summary>
        /// <param name="reader">Reader to read data byte with.</param>
        /// <param name="settings">Settings according to which a data byte should be read and processed.</param>
        /// <returns>A data byte read with <paramref name="reader"/>.</returns>
        protected byte ReadDataByte(MidiReader reader, ReadingSettings settings)
        {
            var value = reader.ReadByte();

            if (value > SevenBitNumber.MaxValue)
            {
                switch (settings.InvalidChannelEventParameterValuePolicy)
                {
                case InvalidChannelEventParameterValuePolicy.Abort:
                    throw new InvalidChannelEventParameterValueException(EventType, value);

                case InvalidChannelEventParameterValuePolicy.ReadValid:
                    value &= SevenBitNumber.MaxValue;
                    break;

                case InvalidChannelEventParameterValuePolicy.SnapToLimits:
                    value = SevenBitNumber.MaxValue;
                    break;
                }
            }

            return(value);
        }
Exemplo n.º 29
0
        /// <summary>
        /// Reads chunk from the <see cref="MidiReader"/>'s underlying stream according to
        /// specified <see cref="ReadingSettings"/>.
        /// </summary>
        /// <param name="reader">Reader to read the chunk's data with.</param>
        /// <param name="settings">Settings according to which the chunk's data must be read.</param>
        /// <exception cref="ObjectDisposedException">Method was called after <paramref name="reader"/>
        /// was disposed.</exception>
        /// <exception cref="IOException">An I/O error occurred on the <paramref name="reader"/>'s
        /// underlying stream.</exception>
        /// <exception cref="InvalidChunkSizeException">Actual chunk's size differs from the one declared
        /// in its header.</exception>
        /// <exception cref="NotEnoughBytesException">Size of the chunk cannot be read since the reader's
        /// underlying stream doesn't have enough bytes.</exception>
        internal void Read(MidiReader reader, ReadingSettings settings)
        {
            var size = reader.ReadDword();

            var readerPosition = reader.Position;

            ReadContent(reader, settings, size);

            var bytesRead = reader.Position - readerPosition;

            if (settings.InvalidChunkSizePolicy == InvalidChunkSizePolicy.Abort && bytesRead != size)
            {
                throw new InvalidChunkSizeException(size, bytesRead);
            }

            // Skip unread bytes

            var bytesUnread = size - bytesRead;

            if (bytesUnread > 0)
            {
                reader.Position += Math.Min(bytesUnread, reader.Length);
            }
        }
Exemplo n.º 30
0
        public MidiEvent Read(MidiReader reader, ReadingSettings settings, byte currentStatusByte)
        {
            var statusByte = reader.ReadByte();
            var size       = reader.ReadVlqNumber();

            //

            MetaEvent metaEvent;

            switch (statusByte)
            {
            case EventStatusBytes.Meta.Lyric:
                metaEvent = new LyricEvent();
                break;

            case EventStatusBytes.Meta.SetTempo:
                metaEvent = new SetTempoEvent();
                break;

            case EventStatusBytes.Meta.Text:
                metaEvent = new TextEvent();
                break;

            case EventStatusBytes.Meta.SequenceTrackName:
                metaEvent = new SequenceTrackNameEvent();
                break;

            case EventStatusBytes.Meta.PortPrefix:
                metaEvent = new PortPrefixEvent();
                break;

            case EventStatusBytes.Meta.TimeSignature:
                metaEvent = new TimeSignatureEvent();
                break;

            case EventStatusBytes.Meta.SequencerSpecific:
                metaEvent = new SequencerSpecificEvent();
                break;

            case EventStatusBytes.Meta.KeySignature:
                metaEvent = new KeySignatureEvent();
                break;

            case EventStatusBytes.Meta.Marker:
                metaEvent = new MarkerEvent();
                break;

            case EventStatusBytes.Meta.ChannelPrefix:
                metaEvent = new ChannelPrefixEvent();
                break;

            case EventStatusBytes.Meta.InstrumentName:
                metaEvent = new InstrumentNameEvent();
                break;

            case EventStatusBytes.Meta.CopyrightNotice:
                metaEvent = new CopyrightNoticeEvent();
                break;

            case EventStatusBytes.Meta.SmpteOffset:
                metaEvent = new SmpteOffsetEvent();
                break;

            case EventStatusBytes.Meta.DeviceName:
                metaEvent = new DeviceNameEvent();
                break;

            case EventStatusBytes.Meta.CuePoint:
                metaEvent = new CuePointEvent();
                break;

            case EventStatusBytes.Meta.ProgramName:
                metaEvent = new ProgramNameEvent();
                break;

            case EventStatusBytes.Meta.SequenceNumber:
                metaEvent = new SequenceNumberEvent();
                break;

            case EventStatusBytes.Meta.EndOfTrack:
                metaEvent = new EndOfTrackEvent();
                break;

            default:
            {
                Type eventType = null;
                metaEvent = settings.CustomMetaEventTypes?.TryGetType(statusByte, out eventType) == true && IsMetaEventType(eventType)
                            ? (MetaEvent)Activator.CreateInstance(eventType)
                            : new UnknownMetaEvent(statusByte);
            }
            break;
            }

            //

            var readerPosition = reader.Position;

            metaEvent.Read(reader, settings, size);

            var bytesRead   = reader.Position - readerPosition;
            var bytesUnread = size - bytesRead;

            if (bytesUnread > 0)
            {
                reader.Position += bytesUnread;
            }

            return(metaEvent);
        }