Playback – Overview
Playback class allows to play MIDI events via an IOutputDevice (see Output device article) or without a device at all (see Playback without device). To get an instance of the Playback
you can use its constructors or GetPlayback
extension methods in PlaybackUtilities.
Following example shows a simple console app where the specified MIDI file is played until the end of the file reached or B
note is about to be played. So in our example B
note means to stop playback.
using System;
using System.Linq;
using System.Threading;
using Melanchall.DryWetMidi.Core;
using Melanchall.DryWetMidi.Multimedia;
namespace SimplePlaybackApp
{
class Program
{
private static Playback _playback;
static void Main(string[] args)
{
var midiFile = MidiFile.Read("The Greatest Song Ever.mid");
var outputDevice = OutputDevice.GetByName("Microsoft GS Wavetable Synth");
_playback = midiFile.GetPlayback(outputDevice);
_playback.NotesPlaybackStarted += OnNotesPlaybackStarted;
_playback.Start();
SpinWait.SpinUntil(() => !_playback.IsRunning);
Console.WriteLine("Playback stopped or finished.");
outputDevice.Dispose();
_playback.Dispose();
}
private static void OnNotesPlaybackStarted(object sender, NotesEventArgs e)
{
if (e.Notes.Any(n => n.NoteName == Melanchall.DryWetMidi.MusicTheory.NoteName.B))
_playback.Stop();
}
}
}
Please read Tick generator article and PlaybackSettings class documentation to learn how you can adjust playback's internals.
Playback without device
There are constructors of Playback that don't accept IOutputDevice as an argument. It can be useful, for example, for notes visualization without sound. Playback provides events that will be fired with or without an output device (see Events section of the Playback API page). Also all GetPlayback
extensions methods have overloads without the outputDevice
parameter.
Also if you don't specify an output device and use a tick generator other than HighPrecisionTickGenerator, you can use Playback
in a cross-platform app like Unity game that is supposed to be built for different platforms.
Blocking playback
If you call the Play method of the Playback
, the calling thread will be blocked until the entire collection of MIDI events is played. Note that execution of this method will be infinite if the Loop property is set to true
.
There are also extension methods Play
in PlaybackUtilities:
using (var outputDevice = OutputDevice.GetByName("Output MIDI device"))
{
MidiFile.Read("Some MIDI file.mid").Play(outputDevice);
// ...
}
Non-blocking playback
If you call the Start method of the Playback, execution of the calling thread will continue immediately after the method is called. To stop playback use the Stop method. Note that there is no any pausing method since it's useless. Stop
leaves playback at the point where the method was called. To move to the start of the playback use the MoveToStart method.
Important
You should be very careful with this approach and using
block. Example below shows the case where part of MIDI data will not be played because of playback is disposed before the last MIDI event will be played:
using (var outputDevice = OutputDevice.GetByName("Output MIDI device"))
using (var playback = MidiFile.Read("Some MIDI file.mid").GetPlayback(outputDevice))
{
playback.Start();
// ...
}
With the non-blocking approach you must call Dispose
manually after you've finished work with the playback object.