/// <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(); }
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)); }
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(); } }
/// <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; }
/// <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)); }
/// <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); }
/// <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); }
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(); } }
/// <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)); }
/// <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; }
private void SendEvent(MidiEvent midiEvent) { OutputDevice?.SendEvent(midiEvent); OnEventPlayed(midiEvent); }
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; }