Introduction
I had a need to create a MIDI file stream for my new app Seed:Loops . The app is written in C# using Xamarin.Forms as it targets Android. The .net MIDI libraries out in the wild either concentrate on reading midi files, or take a dependency on Windows.
My Solution
I wrote a small library to do this for me and have released it under the MIT open source licence (i.e. use it for whatever you want). It’s called Hearn.MIDI.MidiStreamWriter
and can be found on on GitHub at
https://github.com/behearn/Hearn.Midi
. The repo contains the sourcecode, unit tests and an example along with a ReadMe to explain it in more detail.
Installation
The library is available on nuget here Hearn.MIDI
Install it via the Package Manager Console
Install-Package Hearn.Midi
Example usage
Create a .net 6 C# console application, run the Install-Package command above and paste this code.
using Hearn.Midi;
using static Hearn.Midi.MidiConstants;
using static Hearn.Midi.MidiStreamWriter;
var midiStream = new FileStream("example.mid", FileMode.OpenOrCreate);
using (var midiStreamWriter = new MidiStreamWriter(midiStream))
{
midiStreamWriter
.WriteHeader(Formats.MultiSimultaneousTracks, 2);
midiStreamWriter
.WriteStartTrack()
.WriteTimeSignature(4, 4)
.WriteTempo(114)
.WriteString(StringTypes.TrackName, "Example Track")
.WriteEndTrack();
midiStreamWriter
.WriteStartTrack()
//Measure 1
.Tick(NoteDurations.HalfNoteDotted)
.WriteNoteAndTick(0, MidiNoteNumbers.C4, 127, NoteDurations.SixteenthNote)
.WriteNoteAndTick(0, MidiNoteNumbers.D4, 127, NoteDurations.SixteenthNote)
.WriteNoteAndTick(0, MidiNoteNumbers.F4, 127, NoteDurations.SixteenthNote)
.WriteNoteAndTick(0, MidiNoteNumbers.D4, 127, NoteDurations.SixteenthNote)
//Measure 2
.WriteNote(0, MidiNoteNumbers.D4, 127, NoteDurations.EighthNoteDotted)
.WriteNote(0, MidiNoteNumbers.F4, 127, NoteDurations.EighthNoteDotted)
.WriteNote(0, MidiNoteNumbers.A4, 127, NoteDurations.EighthNoteDotted)
.Tick(NoteDurations.EighthNoteDotted)
.WriteNote(0, MidiNoteNumbers.D4, 127, NoteDurations.EighthNoteDotted)
.WriteNote(0, MidiNoteNumbers.F4, 127, NoteDurations.EighthNoteDotted)
.WriteNote(0, MidiNoteNumbers.A4, 127, NoteDurations.EighthNoteDotted)
.Tick(NoteDurations.EighthNoteDotted)
.WriteNote(0, MidiNoteNumbers.C4, 127, NoteDurations.QuarterNoteDotted)
.WriteNote(0, MidiNoteNumbers.E4, 127, NoteDurations.QuarterNoteDotted)
.WriteNote(0, MidiNoteNumbers.G4, 127, NoteDurations.QuarterNoteDotted)
.Tick(NoteDurations.QuarterNoteDotted)
.WriteNoteAndTick(0, MidiNoteNumbers.C4, 127, NoteDurations.SixteenthNote)
.WriteNoteAndTick(0, MidiNoteNumbers.D4, 127, NoteDurations.SixteenthNote)
.WriteNoteAndTick(0, MidiNoteNumbers.F4, 127, NoteDurations.SixteenthNote)
.WriteNoteAndTick(0, MidiNoteNumbers.D4, 127, NoteDurations.SixteenthNote)
//Measure 3
.WriteNote(0, MidiNoteNumbers.C4, 127, NoteDurations.EighthNoteDotted)
.WriteNote(0, MidiNoteNumbers.E4, 127, NoteDurations.EighthNoteDotted)
.WriteNote(0, MidiNoteNumbers.G4, 127, NoteDurations.EighthNoteDotted)
.Tick(NoteDurations.EighthNoteDotted)
.WriteNote(0, MidiNoteNumbers.C4, 127, NoteDurations.EighthNoteDotted)
.WriteNote(0, MidiNoteNumbers.E4, 127, NoteDurations.EighthNoteDotted)
.WriteNote(0, MidiNoteNumbers.G4, 127, NoteDurations.EighthNoteDotted)
.Tick(NoteDurations.EighthNoteDotted)
.WriteNote(0, MidiNoteNumbers.A3, 127, NoteDurations.EighthNoteDotted)
.WriteNote(0, MidiNoteNumbers.D4, 127, NoteDurations.EighthNoteDotted)
.WriteNote(0, MidiNoteNumbers.F4, 127, NoteDurations.EighthNoteDotted)
.Tick(NoteDurations.EighthNoteDotted)
.WriteNoteAndTick(0, MidiNoteNumbers.E4, 127, NoteDurations.SixteenthNote)
.WriteNoteAndTick(0, MidiNoteNumbers.D4, 127, NoteDurations.EighthNote)
.WriteNoteAndTick(0, MidiNoteNumbers.C4, 127, NoteDurations.SixteenthNote)
.WriteNoteAndTick(0, MidiNoteNumbers.D4, 127, NoteDurations.SixteenthNote)
.WriteNoteAndTick(0, MidiNoteNumbers.F4, 127, NoteDurations.SixteenthNote)
.WriteNoteAndTick(0, MidiNoteNumbers.D4, 127, NoteDurations.SixteenthNote)
//Measure 4
.WriteNote(0, MidiNoteNumbers.ASBF3, 127, NoteDurations.QuarterNote)
.WriteNote(0, MidiNoteNumbers.D4, 127, NoteDurations.QuarterNote)
.WriteNote(0, MidiNoteNumbers.F4, 127, NoteDurations.QuarterNote)
.Tick(NoteDurations.QuarterNote)
.WriteNoteAndTick(0, MidiNoteNumbers.G4, 127, NoteDurations.EighthNote)
.WriteNote(0, MidiNoteNumbers.C4, 127, NoteDurations.EighthNoteDotted)
.WriteNote(0, MidiNoteNumbers.E4, 127, NoteDurations.EighthNoteDotted)
.Tick(NoteDurations.EighthNoteDotted)
.WriteNoteAndTick(0, MidiNoteNumbers.D4, 127, NoteDurations.SixteenthNote)
.WriteNoteAndTick(0, MidiNoteNumbers.C4, 127, NoteDurations.QuarterNote)
.WriteNoteAndTick(0, MidiNoteNumbers.C4, 127, NoteDurations.EighthNote)
//Measure 5
.WriteNote(0, MidiNoteNumbers.A3, 127, NoteDurations.QuarterNote)
.WriteNote(0, MidiNoteNumbers.C4, 127, NoteDurations.QuarterNote)
.WriteNote(0, MidiNoteNumbers.G4, 127, NoteDurations.QuarterNote)
.Tick(NoteDurations.QuarterNote)
.WriteNote(0, MidiNoteNumbers.A3, 127, NoteDurations.HalfNote)
.WriteNote(0, MidiNoteNumbers.D4, 127, NoteDurations.HalfNote)
.WriteNote(0, MidiNoteNumbers.F4, 127, NoteDurations.HalfNote)
.Tick(NoteDurations.HalfNote)
.WriteEndTrack();
}
The above code writes out a file called example.mid to the bin folder.
I think you’ll recognise it!