Example #1
0
        /// <summary>
        /// Starts playing of the MIDI data. This method is non-blocking.
        /// </summary>
        /// <exception cref="ObjectDisposedException">The current <see cref="Playback"/> is disposed.</exception>
        /// <exception cref="MidiDeviceException">An error occurred on device.</exception>
        public void Start()
        {
            EnsureIsNotDisposed();

            if (_clock.IsRunning)
            {
                return;
            }

            if (!_hasBeenStarted)
            {
                MoveToStart();
            }

            OutputDevice?.PrepareForEventsSending();
            SendTrackedData();
            StopStartNotes();
            _clock.Start();

            _hasBeenStarted = true;
            OnStarted();
        }
Example #2
0
        private void StopStartNotes()
        {
            if (!TrackNotes)
            {
                return;
            }

            var currentTime = _clock.CurrentTime;
            var notesToPlay = _notesMetadata.SkipWhile(m => m.EndTime <= currentTime)
                              .TakeWhile(m => m.StartTime < currentTime)
                              .Where(m => m.StartTime <currentTime && m.EndTime> currentTime)
                              .Distinct()
                              .ToArray();
            var onNotesMetadata  = notesToPlay.Where(n => !_activeNotesMetadata.Contains(n)).ToArray();
            var offNotesMetadata = _activeNotesMetadata.Where(n => !notesToPlay.Contains(n)).ToArray();

            OutputDevice?.PrepareForEventsSending();

            Note note;
            var  notes = new List <Note>();

            foreach (var noteMetadata in offNotesMetadata)
            {
                TryPlayNoteEvent(noteMetadata, false, currentTime, out note);
                notes.Add(note);
            }

            OnNotesPlaybackFinished(notes.ToArray());
            notes.Clear();

            foreach (var noteMetadata in onNotesMetadata)
            {
                TryPlayNoteEvent(noteMetadata, true, currentTime, out note);
                notes.Add(note);
            }

            OnNotesPlaybackStarted(notes.ToArray());
        }
        /// <summary>
        /// Retrieves an instance of the <see cref="Playback"/> for playing MIDI events contained in
        /// the specified <see cref="TrackChunk"/>.
        /// </summary>
        /// <param name="trackChunk"><see cref="TrackChunk"/> containing events to play.</param>
        /// <param name="tempoMap">Tempo map used to calculate events times.</param>
        /// <param name="outputDevice">Output MIDI device to play events through.</param>
        /// <returns>An instance of the <see cref="Playback"/> for playing MIDI events contained in
        /// the <paramref name="trackChunk"/>.</returns>
        /// <exception cref="ArgumentNullException"><paramref name="trackChunk"/> is null. -or-
        /// <paramref name="tempoMap"/> is null. -or- <paramref name="outputDevice"/> is null.</exception>
        public static Playback GetPlayback(this TrackChunk trackChunk, TempoMap tempoMap, OutputDevice outputDevice, MidiClockSettings clockSettings = null)
        {
            ThrowIfArgument.IsNull(nameof(trackChunk), trackChunk);
            ThrowIfArgument.IsNull(nameof(tempoMap), tempoMap);
            ThrowIfArgument.IsNull(nameof(outputDevice), outputDevice);

            return(new Playback(trackChunk.Events, tempoMap, outputDevice, clockSettings));
        }
        /// <summary>
        /// Plays MIDI events contained in the specified collection of <see cref="TrackChunk"/>.
        /// </summary>
        /// <param name="trackChunks">Collection of <see cref="TrackChunk"/> containing events to play.</param>
        /// <param name="tempoMap">Tempo map used to calculate events times.</param>
        /// <param name="outputDevice">Output MIDI device to play events through.</param>
        /// <exception cref="ArgumentNullException"><paramref name="trackChunks"/> is null. -or-
        /// <paramref name="tempoMap"/> is null. -or- <paramref name="outputDevice"/> is null.</exception>
        public static void Play(this IEnumerable <TrackChunk> trackChunks, TempoMap tempoMap, OutputDevice outputDevice, MidiClockSettings clockSettings = null)
        {
            ThrowIfArgument.IsNull(nameof(trackChunks), trackChunks);
            ThrowIfArgument.IsNull(nameof(tempoMap), tempoMap);
            ThrowIfArgument.IsNull(nameof(outputDevice), outputDevice);

            using (var playback = trackChunks.GetPlayback(tempoMap, outputDevice, clockSettings))
            {
                playback.Play();
            }
        }
        /// <summary>
        /// Retrieves an instance of the <see cref="Playback"/> for playing musical objects using
        /// the specified General MIDI 2 program.
        /// </summary>
        /// <typeparam name="TObject">The type of objects to play.</typeparam>
        /// <param name="objects">Objects to play.</param>
        /// <param name="tempoMap">Tempo map used to calculate events times.</param>
        /// <param name="outputDevice">Output MIDI device to play <paramref name="objects"/> through.</param>
        /// <param name="generalMidi2Program">Program that should be used to play <paramref name="objects"/>.</param>
        /// <returns>An instance of the <see cref="Playback"/> for playing <paramref name="objects"/>.</returns>
        /// <exception cref="ArgumentNullException"><paramref name="objects"/> is null. -or-
        /// <paramref name="tempoMap"/> is null. -or- <paramref name="outputDevice"/> is null.</exception>
        /// <exception cref="InvalidEnumArgumentException"><paramref name="generalMidi2Program"/> specified an invalid value.</exception>
        public static Playback GetPlayback <TObject>(this IEnumerable <TObject> objects, TempoMap tempoMap, OutputDevice outputDevice, GeneralMidi2Program generalMidi2Program, MidiClockSettings clockSettings = null)
            where TObject : IMusicalObject, ITimedObject
        {
            ThrowIfArgument.IsNull(nameof(objects), objects);
            ThrowIfArgument.IsNull(nameof(tempoMap), tempoMap);
            ThrowIfArgument.IsNull(nameof(outputDevice), outputDevice);
            ThrowIfArgument.IsInvalidEnumValue(nameof(generalMidi2Program), generalMidi2Program);

            return(GetMusicalObjectsPlayback(objects,
                                             tempoMap,
                                             outputDevice,
                                             channel => generalMidi2Program.GetProgramEvents(channel),
                                             clockSettings));
        }
        /// <summary>
        /// Retrieves an instance of the <see cref="Playback"/> for playing musical objects using
        /// the specified program.
        /// </summary>
        /// <typeparam name="TObject">The type of objects to play.</typeparam>
        /// <param name="objects">Objects to play.</param>
        /// <param name="tempoMap">Tempo map used to calculate events times.</param>
        /// <param name="outputDevice">Output MIDI device to play <paramref name="objects"/> through.</param>
        /// <param name="programNumber">Program that should be used to play <paramref name="objects"/>.</param>
        /// <returns>An instance of the <see cref="Playback"/> for playing <paramref name="objects"/>.</returns>
        /// <exception cref="ArgumentNullException"><paramref name="objects"/> is null. -or-
        /// <paramref name="tempoMap"/> is null. -or- <paramref name="outputDevice"/> is null.</exception>
        public static Playback GetPlayback <TObject>(this IEnumerable <TObject> objects, TempoMap tempoMap, OutputDevice outputDevice, SevenBitNumber programNumber, MidiClockSettings clockSettings = null)
            where TObject : IMusicalObject, ITimedObject
        {
            ThrowIfArgument.IsNull(nameof(objects), objects);
            ThrowIfArgument.IsNull(nameof(tempoMap), tempoMap);
            ThrowIfArgument.IsNull(nameof(outputDevice), outputDevice);

            return(GetMusicalObjectsPlayback(objects,
                                             tempoMap,
                                             outputDevice,
                                             channel => new[] { new ProgramChangeEvent(programNumber)
                                                                {
                                                                    Channel = channel
                                                                } },
                                             clockSettings));
        }
Example #7
0
        public static void Play(this IEnumerable <TrackChunk> trackChunks, TempoMap tempoMap, OutputDevice outputDevice)
        {
            ThrowIfArgument.IsNull(nameof(trackChunks), trackChunks);
            ThrowIfArgument.IsNull(nameof(tempoMap), tempoMap);
            ThrowIfArgument.IsNull(nameof(outputDevice), outputDevice);

            using (var playback = trackChunks.GetPlayback(tempoMap, outputDevice))
            {
                playback.Start();
            }
        }
        /// <summary>
        /// Plays musical objects using the specified General MIDI 2 program.
        /// </summary>
        /// <typeparam name="TObject">The type of objects to play.</typeparam>
        /// <param name="objects">Objects to play.</param>
        /// <param name="tempoMap">Tempo map used to calculate events times.</param>
        /// <param name="outputDevice">Output MIDI device to play <paramref name="objects"/> through.</param>
        /// <param name="generalMidi2Program">Program that should be used to play <paramref name="objects"/>.</param>
        /// <exception cref="ArgumentNullException"><paramref name="objects"/> is null. -or-
        /// <paramref name="tempoMap"/> is null. -or- <paramref name="outputDevice"/> is null.</exception>
        /// <exception cref="InvalidEnumArgumentException"><paramref name="generalMidi2Program"/> specified an invalid value.</exception>
        public static void Play <TObject>(this IEnumerable <TObject> objects, TempoMap tempoMap, OutputDevice outputDevice, GeneralMidi2Program generalMidi2Program, MidiClockSettings clockSettings = null)
            where TObject : IMusicalObject, ITimedObject
        {
            ThrowIfArgument.IsNull(nameof(objects), objects);
            ThrowIfArgument.IsNull(nameof(tempoMap), tempoMap);
            ThrowIfArgument.IsNull(nameof(outputDevice), outputDevice);
            ThrowIfArgument.IsInvalidEnumValue(nameof(generalMidi2Program), generalMidi2Program);

            using (var playback = objects.GetPlayback(tempoMap, outputDevice, generalMidi2Program, clockSettings))
            {
                playback.Play();
            }
        }
Example #9
0
        /// <summary>
        /// Initializes a new instance of the <see cref="Playback"/> with the specified
        /// collection of MIDI events collections, tempo map and output MIDI device to play events through.
        /// </summary>
        /// <param name="events">Collection of MIDI events collections to play.</param>
        /// <param name="tempoMap">Tempo map used to calculate events times.</param>
        /// <param name="outputDevice">Output MIDI device to play <paramref name="events"/> through.</param>
        /// <exception cref="ArgumentNullException"><paramref name="events"/> is null. -or-
        /// <paramref name="tempoMap"/> is null. -or- <paramref name="outputDevice"/> is null.</exception>
        public Playback(IEnumerable <IEnumerable <MidiEvent> > events, TempoMap tempoMap, OutputDevice outputDevice)
        {
            ThrowIfArgument.IsNull(nameof(events), events);
            ThrowIfArgument.IsNull(nameof(tempoMap), tempoMap);
            ThrowIfArgument.IsNull(nameof(outputDevice), outputDevice);

            var playbackEvents = GetPlaybackEvents(events, tempoMap);

            _duration        = playbackEvents.LastOrDefault()?.Time ?? TimeSpan.Zero;
            _durationInTicks = playbackEvents.LastOrDefault()?.RawTime ?? 0;

            _eventsEnumerator = playbackEvents.GetEnumerator();
            _eventsEnumerator.MoveNext();

            TempoMap     = tempoMap;
            OutputDevice = outputDevice;

            _clock       = new MidiClock(ClockInterval);
            _clock.Tick += OnClockTick;
        }
Example #10
0
        /// <summary>
        /// Retrieves an instance of the <see cref="Playback"/> for playing MIDI events that will be
        /// produced by specified <see cref="Pattern"/>.
        /// </summary>
        /// <param name="pattern"><see cref="Pattern"/> producing events to play.</param>
        /// <param name="tempoMap">Tempo map used to calculate events times.</param>
        /// <param name="channel">MIDI channel to play channel events on.</param>
        /// <param name="outputDevice">Output MIDI device to play events through.</param>
        /// <returns>An instance of the <see cref="Playback"/> for playing MIDI events that will be
        /// produced by the <paramref name="pattern"/>.</returns>
        /// <exception cref="ArgumentNullException"><paramref name="pattern"/> is null. -or-
        /// <paramref name="tempoMap"/> is null. -or- <paramref name="outputDevice"/> is null.</exception>
        public static Playback GetPlayback(this Pattern pattern, TempoMap tempoMap, FourBitNumber channel, OutputDevice outputDevice)
        {
            ThrowIfArgument.IsNull(nameof(pattern), pattern);
            ThrowIfArgument.IsNull(nameof(tempoMap), tempoMap);
            ThrowIfArgument.IsNull(nameof(outputDevice), outputDevice);

            return(pattern.ToTrackChunk(tempoMap, channel).GetPlayback(tempoMap, outputDevice));
        }
Example #11
0
 /// <summary>
 /// Initializes a new instance of the <see cref="Playback"/> with the specified
 /// collection of MIDI events, tempo map and output MIDI device to play events through.
 /// </summary>
 /// <param name="events">Collection of MIDI events to play.</param>
 /// <param name="tempoMap">Tempo map used to calculate events times.</param>
 /// <param name="outputDevice">Output MIDI device to play <paramref name="events"/> through.</param>
 /// <exception cref="ArgumentNullException"><paramref name="events"/> is null. -or-
 /// <paramref name="tempoMap"/> is null. -or- <paramref name="outputDevice"/> is null.</exception>
 public Playback(IEnumerable <MidiEvent> events, TempoMap tempoMap, OutputDevice outputDevice, MidiClockSettings clockSettings = null)
     : this(new[] { events }, tempoMap, outputDevice, clockSettings)
 {
     ThrowIfArgument.IsNull(nameof(events), events);
 }
Example #12
0
 /// <summary>
 /// Initializes a new instance of the <see cref="Playback"/> with the specified
 /// collection of MIDI events collections, tempo map and output MIDI device to play events through.
 /// </summary>
 /// <param name="events">Collection of MIDI events collections to play.</param>
 /// <param name="tempoMap">Tempo map used to calculate events times.</param>
 /// <param name="outputDevice">Output MIDI device to play <paramref name="events"/> through.</param>
 /// <exception cref="ArgumentNullException"><paramref name="events"/> is null. -or-
 /// <paramref name="tempoMap"/> is null. -or- <paramref name="outputDevice"/> is null.</exception>
 public Playback(IEnumerable <IEnumerable <MidiEvent> > events, TempoMap tempoMap, OutputDevice outputDevice, MidiClockSettings clockSettings = null)
     : this(GetTimedObjects(events), tempoMap, outputDevice, clockSettings)
 {
 }
 /// <summary>
 /// Initializes a new instance of the <see cref="Playback"/> with the specified
 /// collection of MIDI events collections, tempo map and output MIDI device to play events through.
 /// </summary>
 /// <param name="events">Collection of MIDI events collections to play.</param>
 /// <param name="tempoMap">Tempo map used to calculate events times.</param>
 /// <param name="outputDevice">Output MIDI device to play <paramref name="events"/> through.</param>
 /// <exception cref="ArgumentNullException"><paramref name="events"/> is null. -or-
 /// <paramref name="tempoMap"/> is null. -or- <paramref name="outputDevice"/> is null.</exception>
 public Playback(IEnumerable <IEnumerable <MidiEvent> > events, TempoMap tempoMap, OutputDevice outputDevice)
     : this(GetTimedObjects(events), tempoMap, outputDevice)
 {
 }
        /// <summary>
        /// Plays MIDI events that will be produced by specified <see cref="Pattern"/>.
        /// </summary>
        /// <param name="pattern"><see cref="Pattern"/> producing events to play.</param>
        /// <param name="tempoMap">Tempo map used to calculate events times.</param>
        /// <param name="channel">MIDI channel to play channel events on.</param>
        /// <param name="outputDevice">Output MIDI device to play events through.</param>
        /// <exception cref="ArgumentNullException"><paramref name="pattern"/> is null. -or-
        /// <paramref name="tempoMap"/> is null. -or- <paramref name="outputDevice"/> is null.</exception>
        public static void Play(this Pattern pattern, TempoMap tempoMap, FourBitNumber channel, OutputDevice outputDevice, MidiClockSettings clockSettings = null)
        {
            ThrowIfArgument.IsNull(nameof(pattern), pattern);
            ThrowIfArgument.IsNull(nameof(tempoMap), tempoMap);
            ThrowIfArgument.IsNull(nameof(outputDevice), outputDevice);

            pattern.ToTrackChunk(tempoMap, channel).Play(tempoMap, outputDevice, clockSettings);
        }
Example #15
0
 private void SendEvent(MidiEvent midiEvent)
 {
     OutputDevice.SendEvent(midiEvent);
 }
        /// <summary>
        /// Plays musical objects using the specified program.
        /// </summary>
        /// <typeparam name="TObject">The type of objects to play.</typeparam>
        /// <param name="objects">Objects to play.</param>
        /// <param name="tempoMap">Tempo map used to calculate events times.</param>
        /// <param name="outputDevice">Output MIDI device to play <paramref name="objects"/> through.</param>
        /// <param name="programNumber">Program that should be used to play <paramref name="objects"/>.</param>
        /// <exception cref="ArgumentNullException"><paramref name="objects"/> is null. -or-
        /// <paramref name="tempoMap"/> is null. -or- <paramref name="outputDevice"/> is null.</exception>
        public static void Play <TObject>(this IEnumerable <TObject> objects, TempoMap tempoMap, OutputDevice outputDevice, SevenBitNumber programNumber, MidiClockSettings clockSettings = null)
            where TObject : IMusicalObject, ITimedObject
        {
            ThrowIfArgument.IsNull(nameof(objects), objects);
            ThrowIfArgument.IsNull(nameof(tempoMap), tempoMap);
            ThrowIfArgument.IsNull(nameof(outputDevice), outputDevice);

            using (var playback = objects.GetPlayback(tempoMap, outputDevice, programNumber, clockSettings))
            {
                playback.Play();
            }
        }
Example #17
0
 /// <summary>
 /// Initializes a new instance of the <see cref="Playback"/> with the specified
 /// collection of MIDI events, tempo map and output MIDI device to play events through.
 /// </summary>
 /// <param name="events">Collection of MIDI events to play.</param>
 /// <param name="tempoMap">Tempo map used to calculate events times.</param>
 /// <param name="outputDevice">Output MIDI device to play <paramref name="events"/> through.</param>
 /// <exception cref="ArgumentNullException"><paramref name="events"/> is null. -or-
 /// <paramref name="tempoMap"/> is null. -or- <paramref name="outputDevice"/> is null.</exception>
 public Playback(IEnumerable <MidiEvent> events, TempoMap tempoMap, OutputDevice outputDevice)
     : this(new[] { events }, tempoMap, outputDevice)
 {
     ThrowIfArgument.IsNull(nameof(events), events);
 }
        /// <summary>
        /// Retrieves an instance of the <see cref="Playback"/> for playing MIDI events contained in
        /// the specified collection of <see cref="TrackChunk"/>.
        /// </summary>
        /// <param name="trackChunks">Collection of <see cref="TrackChunk"/> containing events to play.</param>
        /// <param name="tempoMap">Tempo map used to calculate events times.</param>
        /// <param name="outputDevice">Output MIDI device to play events through.</param>
        /// <returns>An instance of the <see cref="Playback"/> for playing MIDI events contained in
        /// the <paramref name="trackChunks"/>.</returns>
        /// <exception cref="ArgumentNullException"><paramref name="trackChunks"/> is null. -or-
        /// <paramref name="tempoMap"/> is null. -or- <paramref name="outputDevice"/> is null.</exception>
        public static Playback GetPlayback(this IEnumerable <TrackChunk> trackChunks, TempoMap tempoMap, OutputDevice outputDevice, MidiClockSettings clockSettings = null)
        {
            ThrowIfArgument.IsNull(nameof(trackChunks), trackChunks);
            ThrowIfArgument.IsNull(nameof(tempoMap), tempoMap);
            ThrowIfArgument.IsNull(nameof(outputDevice), outputDevice);

            return(new Playback(trackChunks.Select(c => c.Events), tempoMap, outputDevice, clockSettings));
        }
Example #19
0
        /// <summary>
        /// Initializes a new instance of the <see cref="Playback"/> with the specified
        /// collection of MIDI events collections, tempo map and output MIDI device to play events through.
        /// </summary>
        /// <param name="events">Collection of MIDI events collections to play.</param>
        /// <param name="tempoMap">Tempo map used to calculate events times.</param>
        /// <param name="outputDevice">Output MIDI device to play <paramref name="events"/> through.</param>
        /// <exception cref="ArgumentNullException"><paramref name="events"/> is null. -or-
        /// <paramref name="tempoMap"/> is null. -or- <paramref name="outputDevice"/> is null.</exception>
        public Playback(IEnumerable <IEnumerable <MidiEvent> > events, TempoMap tempoMap, OutputDevice outputDevice)
        {
            ThrowIfArgument.IsNull(nameof(events), events);
            ThrowIfArgument.IsNull(nameof(tempoMap), tempoMap);
            ThrowIfArgument.IsNull(nameof(outputDevice), outputDevice);

            var playbackEvents = GetPlaybackEvents(events, tempoMap);

            _eventsEnumerator = playbackEvents.GetEnumerator();
            _eventsEnumerator.MoveNext();

            var lastPlaybackEvent = playbackEvents.LastOrDefault();

            _duration        = lastPlaybackEvent?.Time ?? TimeSpan.Zero;
            _durationInTicks = lastPlaybackEvent?.RawTime ?? 0;

            _notesMetadata = playbackEvents.Select(e => e.Metadata.Note).Where(m => m != null).ToList();
            _notesMetadata.Sort((m1, m2) => Math.Sign(m1.StartTime.Ticks - m2.StartTime.Ticks));

            TempoMap     = tempoMap;
            OutputDevice = outputDevice;

            _clock       = new MidiClock(ClockInterval);
            _clock.Tick += OnClockTick;
        }
Example #20
0
 private void SendEvent(MidiEvent midiEvent)
 {
     OutputDevice?.SendEvent(midiEvent);
     OnEventPlayed(midiEvent);
 }
Example #21
0
        public Playback(IEnumerable <IEnumerable <MidiEvent> > events, TempoMap tempoMap, OutputDevice outputDevice)
        {
            ThrowIfArgument.IsNull(nameof(events), events);
            ThrowIfArgument.IsNull(nameof(tempoMap), tempoMap);
            ThrowIfArgument.IsNull(nameof(outputDevice), outputDevice);

            _eventsEnumerator = GetPlaybackEvents(events, tempoMap).GetEnumerator();
            _eventsEnumerator.MoveNext();

            _tempoMap     = tempoMap;
            _outputDevice = outputDevice;

            _clock       = new MidiClock(ClockInterval);
            _clock.Tick += OnClockTick;
        }