Search Results for

    Show / Hide Table of Contents

    Objects merging

    To merge nearby objects into one DryWetMIDI provides the Merger class. Quick example of merging in action:

    Objects merging

    Process of merging can be adjusted via ObjectsMergingSettings. By default two objects should have no gap between them to be merged. But you can specify any desired tolerance via settings:

    var newObjects = objects.MergeObjects(
        TempoMap.Default,
        new ObjectsMergingSettings
        {
            Tolerance = new MetricTimeSpan(0, 0, 1)
        });
    

    Now objects will be merged if the distance between them is from 0 to 1 second. So tolerance is the maximum distance between two objects to consider them as nearby. Please take a look at how tolerance (T) affects process of merging:

    Objects merging tolerance

    Of course merging is available not for objects collections only. You can use also MergeObjects methods on MidiFile and TrackChunk:

    midiFile.MergeObjects(
        ObjectType.Note | ObjectType.Chord,
        new ObjectsMergingSettings
        {
            Filter = obj => obj.Time > 100
        },
        new ObjectDetectionSettings
        {
            ChordDetectionSettings = new ChordDetectionSettings
            {
                NotesMinCount = 3
            }
        });
    

    The tool needs to determine somehow whether two objects have the same "key" or not to make a decision about merging them. For example, if we have a C note and D one, by default such notes are different in terms of their keys and thus won't be merged. To understand what the key is, please read MIDI file splitting: SplitByObjects article.

    Of course you can customize how objects are merged. For example, following picture shows how chords are merged using the default merging logic:

    Chords merging using default logic

    Now let's change the logic: chords can be merged only if there are notes in them without gaps. Also notes in the result chord need to start at the same time and have the same length. Following image shows how chords will be merged:

    Chords merging using custom logic

    We need to derive from the ObjectsMerger class to implement these rules:

    private sealed class ChordsMerger : ObjectsMerger
    {
        public ChordsMerger(ILengthedObject obj)
            : base(obj)
        { }
    
        public override bool CanAddObject(ILengthedObject obj, TempoMap tempoMap, ObjectsMergingSettings settings)
        {
            if (!base.CanAddObject(obj, tempoMap, settings))
                return false;
    
            var chordNotes = ((Chord)obj).Notes.ToArray();
            var lastChordNotes = ((Chord)_objects.Last()).Notes.ToArray();
    
            return Enumerable
                .Range(0, lastChordNotes.Length)
                .Any(i => lastChordNotes[i].EndTime == chordNotes[i].Time);
        }
    
        public override ILengthedObject MergeObjects(ObjectsMergingSettings settings)
        {
            var result = (Chord)base.MergeObjects(settings);
            var time = result.Time;
            var length = result.Length;
    
            foreach (var note in result.Notes)
            {
                note.Time = time;
                note.Length = length;
            }
            
            return result;
        }
    }
    

    And now we can merge objects using this class:

    midiFile.MergeObjects(
        ObjectType.Chord | ObjectType.Note,
        new ObjectsMergingSettings
        {
            ObjectsMergerFactory = obj => obj is Chord
                ? new ChordsMerger(obj)
                : new ObjectsMerger(obj)
        },
        new ObjectDetectionSettings
        {
            ChordDetectionSettings = new ChordDetectionSettings
            {
                NotesTolerance = 100
            }
        });
    

    So if the tool encounters a chord, it uses our custom merger; for any other object's type – default one.

    In this article
    Back to top 2024 / Generated by DocFX