Search code examples
midimidi-interface

Convert MIDI file to list of notes with length and starting time


I am working on a game in Unity that will generate levels from music. I am planning to include simple text files (that don't have to be in a standard format) with the game and parse them to generate the levels. The problem is, I need to be able to convert MIDI files to a text format (preferably not something as complicated as MusicXML). The text files that I will include with the game would ideally consist of a list of notes, each with a length and a starting time (in arbitrary time units). I cannot simply include a music file, as my bullet-hell game will have to precisely time the bullets with the notes.

I do not care what programming language this is in, as this code will not be included with the game. Also, I have never worked with MIDI before in any form. I am happy to use any library and/or free program for this.

Thank you in advance for your help!


Solution

  • You can use any open-source library for parsing MIDI file and convert its data to text file in your desired format. For example, with the DryWetMIDI you can use this code:

    public static void ConvertMidiToText(string midiFilePath, string textFilePath)
    {
        var midiFile = MidiFile.Read(midiFilePath);
    
        File.WriteAllLines(textFilePath,
                           midiFile.GetNotes()
                                   .Select(n => $"{n.NoteNumber} {n.Time} {n.Length}"));
    }
    

    ConvertMidiToText method will produce text files like this:

    37 0 480
    37 960 480
    37 1920 480
    37 2400 480
    70 2640 192
    

    where first number is note number (60 = C4), second one is starting time in MIDI ticks and the third one is length in MIDI ticks.

    You can even write time and length in hours:minutes:seconds format. This code

    public static void ConvertMidiToText(string midiFilePath, string textFilePath)
    {
        var midiFile = MidiFile.Read(midiFilePath);
        TempoMap tempoMap = midiFile.GetTempoMap();
    
        File.WriteAllLines(textFilePath,
                            midiFile.GetNotes()
                                    .Select(n => $"{n.NoteNumber} {n.TimeAs<MetricTimeSpan>(tempoMap)} {n.LengthAs<MetricTimeSpan>(tempoMap)}"));
    }
    

    will produce text like this:

    37 00:00:00 00:00:00.4800000
    37 00:00:00.9600000 00:00:00.4800000
    37 00:00:01.9200000 00:00:00.4800000
    37 00:00:02.4000000 00:00:00.4800000
    70 00:00:02.6400000 00:00:00.1920000