Creating MIDI files in C#

16 July 2022| Tags: code, midi
A midi sequencer and controller

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.

Example Output

I think you’ll recognise it!