Search Results for

    Show / Hide Table of Contents

    MIDI file splitting

    You can split a MIDI file in different ways using extension methods from the Splitter class. Available methods are described below. Please note that the article doesn't cover all possible methods and their settings. Please read API documentation on Splitter to get complete information.

    SplitByChannel

    SplitByChannel method splits a MIDI file by channel so all channel events will be separated by channel and copied to corresponding new files. All meta and system exclusive events will be copied to all the new files (that's default behavior that can be turned off). Thus each new file will contain all meta and sysex events and channel ones for a single channel. The image below illustrates this process:

    Split MIDI file by channel

    SplitByObjects

    SplitByObjects method splits a MIDI file by objects. The process can be adjusted via SplitByObjectsSettings passed to the second parameter of the method.

    For example, to split a file by notes copying all MIDI events to each new file:

    var newFiles = midiFile.SplitByObjects(
        ObjectType.Note | ObjectType.TimedEvent,
        new SplitByObjectsSettings
        {
            WriteToAllFilesPredicate = obj => obj is TimedEvent
        });
    

    Here we specify that we need to split the file by notes and timed events, but every timed event must be written to all result files. So in fact we're splitting the file by notes having all non-notes timed events presented in each new file. The image below illustrates the process:

    Split MIDI file by objects

    To split a file by objects the tool needs to determine the key of each object. Objects with the same key will be outputted in a separate file. In the example above default logic of key calculation is used. The following table shows what a default key is for each type of an object:

    Object type Key
    TimedEvent The type of the underlying event (EventType of TimedEvent.Event).
    Note Pair of the channel and note number of a note.
    Chord Collection of keys of the underlying notes.

    You can alter key calculation logic by providing custom key selector. For example, to separate notes by only note number ignoring a note's channel:

    var newFiles = midiFile.SplitByObjects(
        ObjectType.Note | ObjectType.TimedEvent,
        new SplitByObjectsSettings
        {
            KeySelector = obj => (obj as Note)?.NoteNumber,
            WriteToAllFilesPredicate = obj => obj is TimedEvent
        });
    

    Here a key will be resolved to null if an object is not an instance of the Note. null key means to use the default key calculation logic shown above.

    If key selection is complex, you may decide to implement a class for such a key. Just for example, let's create the key class that identifies a chord by its shortest name:

    private sealed class ChordNameId
    {
        private readonly string _name;
        
        public ChordNameId(Chord chord)
        {
            _name = chord.GetMusicTheoryChord().GetNames().FirstOrDefault();
        }
    
        public override bool Equals(object obj) =>
            obj is ChordNameId chordNameId &&
            chordNameId._name == _name;
    
        public override int GetHashCode() =>
            _name.GetHashCode();
    }
    

    And now we can use it to split a file by chords of the same name:

    var newFiles = midiFile.SplitByObjects(
        ObjectType.Chord,
        new SplitByObjectsSettings
        {
            KeySelector = obj => new ChordNameId((Chord)obj)
        });
    

    Please see documentation on SplitByObjectsSettings to learn more about how you can adjust the process of splitting.

    SplitByGrid

    SplitByGrid method splits a MIDI file by the specified grid. Each file will preserve the original tempo map and all parameters changes (like a control value or program changes). The image below shows general case of splitting a MIDI file by grid:

    Split MIDI file by grid

    Splitting can be adjusted via the settings parameter of the SliceMidiFileSettings type. SplitNotes and PreserveTimes properties described below. Please see all available properties in documentation for SliceMidiFileSettings.

    SplitNotes

    SplitNotes indicates whether notes should be split at points of grid intersection or not. The default value is true. If false used, notes treated as just Note On / Note Off events rather than note objects. Splitting notes produces new Note On / Note Off events at points where grid intersects notes if the property set to true. The following image shows splitting by grid if SplitNotes set to false:

    Split MIDI file by grid without splitting notes

    PreserveTimes

    PreserveTimes indicates whether original times of events should be preserved or not. The default value is false. If false used, events will be moved to the start of a new file. If true used, events will be placed in new files at the same times as in the input file. The following image shows splitting in case of PreserveTimes set to true:

    Split MIDI file by grid preserving times

    SkipPart

    SkipPart method skips part of the specified length of a MIDI file and returns the remaining part as an instance of MidiFile. The image below shows general case of skipping a part of a MIDI file:

    Skip part of a MIDI file

    TakePart

    TakePart methods take part of the specified length of a MIDI file (starting at the start or at the specified time within the file) and return it as an instance of MidiFile. The image below shows both cases of taking a part of a MIDI file:

    Take part of a MIDI file at the start of the file

    Take part of a MIDI file at the middle of the file

    CutPart

    CutPart method cuts a part of the specified length from a MIDI file (starting at the specified time within the file) and returns a new instance of MidiFile which is the original file without the part. The image below shows how the method works:

    Cut part from a MIDI file

    In this article
    Back to top 2024 / Generated by DocFX