DryWetMIDI is the .NET library to work with MIDI files. Visit Wiki to learn how to use the DryWetMIDI. You can get the latest version via NuGet:
DryWetMIDI was tested on 130,000 files taken from here. Thanks midi-man for this great collection.
With the DryWetMIDI you can:
- Read, write and create Standard MIDI Files (SMF). It is also possible to read RMID files where SMF wrapped to RIFF chunk.
- Finely adjust process of reading and writing. It allows, for example, to read corrupted files and repair them, or build MIDI file validators.
- Implement custom meta events and custom chunks that can be written to and read from MIDI files.
- Easily catch specific error when reading or writing MIDI file since all possible errors in a MIDI file are presented as separate exception classes.
- Manage content of a MIDI file either with low-level objects, like event, or high-level ones, like note (read the High-level data managing section of the Wiki).
- Build musical compositions (See Pattern page of the library Wiki).
Let's see some examples of what you can do with DryWetMIDI.
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 Wiki 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 Wiki to learn more about how to adjust process of writing)
midiFile.Write("My Great Song.mid",
true,
MidiFileFormat.SingleTrack,
new WritingSettings
{
CompressionPolicy = CompressionPolicy.Default
});
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.Notes;
notes.Add(new Note(NoteName.A,
4,
LengthConverter.ConvertFrom(new MetricLength(0, /* hours */
0, /* minutes */
10 /* seconds */),
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.MicrosecondsPerBeat /= 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).
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<MetricTime>(tempoMap) ?? new MetricTime();
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.Notes.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 MetricTime(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(new MusicalLength(2 * MusicalFraction.EighthTriplet),
0,
tempoMap);
var note = new Note(NoteName.A, 4, length);
notesManager.Notes.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 MetricLength(0, 0, 5))
// Insert an eighth C# note of the 4th octave
.Note(OctaveDefinition.Get(4).CSharp, (MusicalLength)MusicalFraction.Eighth)
// Set default note length to triplet eighth and default octave to 5
.SetNoteLength((MusicalLength)MusicalFraction.EighthTriplet)
.SetOctave(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)
// Get pattern
.Build();
MidiFile midiFile = pattern.ToFile(TempoMap.Default);