.NET library to read, write, process MIDI files and to work with MIDI devices
&color=5295D0)
&color=5295D0)
&message=v7.2.0&color=5295D0)
&message=v7.2.0&color=5295D0)
DryWetMIDI is the .NET library to work with MIDI data and MIDI devices. It allows:
Please see Getting started section below for quick jump into the library.
Warning
If you want to create an issue or a discussion, read this article first – Support.
Here the list of noticeable projects that use DryWetMIDI:
If you find that DryWetMIDI has been useful for your project, please put a link to the library in your project’s About section or something like that.
Let’s see some examples of what you can do with DryWetMIDI. Also you can check out sample applications from CIRCE-EYES (see the profile, VB.NET used).
To read a MIDI file you have to use Read
static method of the MidiFile
:
var midiFile = MidiFile.Read("Some Great Song.mid");
or, in more advanced form (visit Reading settings page on the library docs to learn more about how to adjust process of reading)
var midiFile = MidiFile.Read(
"Some Great Song.mid",
new ReadingSettings
{
NoHeaderChunkPolicy = NoHeaderChunkPolicy.Abort,
CustomChunkTypes = new ChunkTypesCollection
{
{ typeof(MyCustomChunk), "Cstm" }
}
});
To write MIDI data to a file you have to use Write
method of the MidiFile
:
midiFile.Write("My Great Song.mid");
or, in more advanced form (visit Writing settings page on the library docs to learn more about how to adjust process of writing)
midiFile.Write(
"My Great Song.mid",
true,
MidiFileFormat.SingleTrack,
new WritingSettings
{
UseRunningStatus = true,
NoteOffAsSilentNoteOn = true
});
Of course you can create a MIDI file from scratch by creating an instance of the MidiFile
and writing it:
var midiFile = new MidiFile(
new TrackChunk(
new SetTempoEvent(500000)),
new TrackChunk(
new TextEvent("It's just single note track..."),
new NoteOnEvent((SevenBitNumber)60, (SevenBitNumber)45),
new NoteOffEvent((SevenBitNumber)60, (SevenBitNumber)0)
{
DeltaTime = 400
}));
midiFile.Write("My Future Great Song.mid");
or
var midiFile = new MidiFile();
TempoMap tempoMap = midiFile.GetTempoMap();
var trackChunk = new TrackChunk();
using (var notesManager = trackChunk.ManageNotes())
{
NotesCollection notes = notesManager.Objects;
notes.Add(new Note(
NoteName.A,
4,
LengthConverter.ConvertFrom(
new MetricTimeSpan(hours: 0, minutes: 0, seconds: 10),
0,
tempoMap)));
}
midiFile.Chunks.Add(trackChunk);
midiFile.Write("My Future Great Song.mid");
If you want to speed up playing back a MIDI file by two times you can do it with this code:
foreach (var trackChunk in midiFile.Chunks.OfType<TrackChunk>())
{
foreach (var setTempoEvent in trackChunk.Events.OfType<SetTempoEvent>())
{
setTempoEvent.MicrosecondsPerQuarterNote /= 2;
}
}
Of course this code is simplified. In practice a MIDI file may not contain SetTempo event which means it has the default one (500,000 microseconds per beat).
Instead of modifying a MIDI file you can use Playback
class:
using (var outputDevice = OutputDevice.GetByName("Microsoft GS Wavetable Synth"))
using (var playback = midiFile.GetPlayback(outputDevice))
{
playback.Speed = 2.0;
playback.Play();
}
To get duration of a MIDI file as TimeSpan
use this code:
TempoMap tempoMap = midiFile.GetTempoMap();
TimeSpan midiFileDuration = midiFile
.GetTimedEvents()
.LastOrDefault(e => e.Event is NoteOffEvent)
?.TimeAs<MetricTimeSpan>(tempoMap) ?? new MetricTimeSpan();
or simply:
TimeSpan midiFileDuration = midiFile.GetDuration<MetricTimeSpan>();
Suppose you want to remove all C# notes from a MIDI file. It can be done with this code:
foreach (var trackChunk in midiFile.GetTrackChunks())
{
using (var notesManager = trackChunk.ManageNotes())
{
notesManager.Objects.RemoveAll(n => n.NoteName == NoteName.CSharp);
}
}
or
midiFile.RemoveNotes(n => n.NoteName == NoteName.CSharp);
To get all chords of a MIDI file at 20 seconds from the start of the file write this:
TempoMap tempoMap = midiFile.GetTempoMap();
IEnumerable<Chord> chordsAt20seconds = midiFile
.GetChords()
.AtTime(
new MetricTimeSpan(0, 0, 20),
tempoMap,
LengthedObjectPart.Entire);
To create a MIDI file with single note which length will be equal to length of two triplet eighth notes you can use this code:
var midiFile = new MidiFile();
var tempoMap = midiFile.GetTempoMap();
var trackChunk = new TrackChunk();
using (var notesManager = trackChunk.ManageNotes())
{
var length = LengthConverter.ConvertFrom(
2 * MusicalTimeSpan.Eighth.Triplet(),
0,
tempoMap);
var note = new Note(NoteName.A, 4, length);
notesManager.Objects.Add(note);
}
midiFile.Chunks.Add(trackChunk);
midiFile.Write("Single note great song.mid");
You can even build a musical composition:
Pattern pattern = new PatternBuilder()
// Insert a pause of 5 seconds
.StepForward(new MetricTimeSpan(0, 0, 5))
// Insert an eighth C# note of the 4th octave
.Note(Octave.Get(4).CSharp, MusicalTimeSpan.Eighth)
// Set default note length to triplet eighth and default octave to 5
.SetNoteLength(MusicalTimeSpan.Eighth.Triplet())
.SetOctave(Octave.Get(5))
// Now we can add triplet eighth notes of the 5th octave in a simple way
.Note(NoteName.A)
.Note(NoteName.B)
.Note(NoteName.GSharp)
// Insert a simple drum pattern
.PianoRoll(@"
F#2 ||||||||
D2 --|---|-
C2 |---|---")
.Repeat(9)
// Get pattern
.Build();
MidiFile midiFile = pattern.ToFile(TempoMap.Default);
DryWetMIDI provides devices API allowing to send MIDI events to and receive them from MIDI devices. Following example shows how to send events to MIDI device and handle them as they are received by the device:
using System;
using Melanchall.DryWetMidi.Multimedia;
using Melanchall.DryWetMidi.Core;
// ...
using (var outputDevice = OutputDevice.GetByName("MIDI Device"))
{
outputDevice.EventSent += OnEventSent;
using (var inputDevice = InputDevice.GetByName("MIDI Device"))
{
inputDevice.EventReceived += OnEventReceived;
inputDevice.StartEventsListening();
outputDevice.SendEvent(new NoteOnEvent());
outputDevice.SendEvent(new NoteOffEvent());
}
}
// ...
private void OnEventReceived(object sender, MidiEventReceivedEventArgs e)
{
var midiDevice = (MidiDevice)sender;
Console.WriteLine($"Event received from '{midiDevice.Name}' at {DateTime.Now}: {e.Event}");
}
private void OnEventSent(object sender, MidiEventSentEventArgs e)
{
var midiDevice = (MidiDevice)sender;
Console.WriteLine($"Event sent to '{midiDevice.Name}' at {DateTime.Now}: {e.Event}");
}