Skip to content

Commit

Permalink
Added ChordProcessingHint.NoteTimeOrLengthCanBeChanged
Browse files Browse the repository at this point in the history
  • Loading branch information
melanchall committed May 26, 2023
1 parent 49a40d9 commit 6e5a14c
Show file tree
Hide file tree
Showing 4 changed files with 127 additions and 10 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -319,6 +319,72 @@ public void ProcessChords_EventsCollection_WithPredicate_OneChord_Matched_Proces
},
expectedProcessedCount: 1);

[Test]
public void ProcessChords_EventsCollection_WithPredicate_OneChord_Matched_Processing_NoteTime_1([Values] ContainerType containerType) => ProcessChords_EventsCollection_WithPredicate(
containerType,
midiEvents: new MidiEvent[]
{
new NoteOnEvent(),
new NoteOffEvent(),
new TextEvent("A"),
new ControlChangeEvent(),
},
action: c => c.Notes.First().Time = 100,
match: c => true,
expectedMidiEvents: new MidiEvent[]
{
new TextEvent("A"),
new ControlChangeEvent(),
new NoteOnEvent { DeltaTime = 100 },
new NoteOffEvent(),
},
expectedProcessedCount: 1,
hint: ChordProcessingHint.NoteTimeOrLengthCanBeChanged);

[Test]
public void ProcessChords_EventsCollection_WithPredicate_OneChord_Matched_Processing_NoteTime_2([Values] ContainerType containerType) => ProcessChords_EventsCollection_WithPredicate(
containerType,
midiEvents: new MidiEvent[]
{
new NoteOnEvent(),
new NoteOnEvent((SevenBitNumber)70, SevenBitNumber.MaxValue),
new NoteOffEvent { DeltaTime = 100 },
new NoteOffEvent((SevenBitNumber)70, SevenBitNumber.MinValue),
},
action: c => c.Notes.Last().Time = 50,
match: c => true,
expectedMidiEvents: new MidiEvent[]
{
new NoteOnEvent(),
new NoteOnEvent((SevenBitNumber)70, SevenBitNumber.MaxValue) { DeltaTime = 50 },
new NoteOffEvent { DeltaTime = 50 },
new NoteOffEvent((SevenBitNumber)70, SevenBitNumber.MinValue) { DeltaTime = 50 },
},
expectedProcessedCount: 1,
hint: ChordProcessingHint.NoteTimeOrLengthCanBeChanged);

[Test]
public void ProcessChords_EventsCollection_WithPredicate_OneChord_Matched_Processing_NoteTime_3([Values] ContainerType containerType) => ProcessChords_EventsCollection_WithPredicate(
containerType,
midiEvents: new MidiEvent[]
{
new NoteOnEvent(),
new NoteOnEvent((SevenBitNumber)70, SevenBitNumber.MaxValue),
new NoteOffEvent((SevenBitNumber)70, SevenBitNumber.MinValue){ DeltaTime = 50 },
new NoteOffEvent { DeltaTime = 50 },
},
action: c => c.Notes.Last().Time = 50,
match: c => true,
expectedMidiEvents: new MidiEvent[]
{
new NoteOnEvent(),
new NoteOnEvent((SevenBitNumber)70, SevenBitNumber.MaxValue) { DeltaTime = 50 },
new NoteOffEvent((SevenBitNumber)70, SevenBitNumber.MinValue){ DeltaTime = 50 },
new NoteOffEvent(),
},
expectedProcessedCount: 1,
hint: ChordProcessingHint.NoteTimeOrLengthCanBeChanged);

[Test]
public void ProcessChords_EventsCollection_WithPredicate_OneChord_Matched_Processing_Time_HintNone([Values] ContainerType containerType) => ProcessChords_EventsCollection_WithPredicate(
containerType,
Expand Down
22 changes: 22 additions & 0 deletions DryWetMidi/Interaction/Chords/Chord.cs
Original file line number Diff line number Diff line change
Expand Up @@ -367,6 +367,28 @@ public SplitLengthedObject Split(long time)
return new SplitLengthedObject(leftPart, rightPart);
}

internal void GetTimeAndLength(out long time, out long length)
{
var startTime = long.MaxValue;
var endTime = long.MinValue;

var hasNotes = false;

foreach (var note in Notes)
{
var noteStartTime = note.Time;
startTime = Math.Min(noteStartTime, startTime);

var noteEndTime = noteStartTime + note.Length;
endTime = Math.Max(noteEndTime, endTime);

hasNotes = true;
}

time = hasNotes ? startTime : 0;
length = hasNotes ? endTime - startTime : 0;
}

private void OnNotesCollectionChanged(TimedObjectsCollection<Note> collection, TimedObjectsCollectionChangedEventArgs<Note> args)
{
_channel = null;
Expand Down
5 changes: 5 additions & 0 deletions DryWetMidi/Interaction/Chords/ChordProcessingHint.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,13 @@ public enum ChordProcessingHint
{
TimeOrLengthCanBeChanged = 1,
NotesCollectionCanBeChanged = 2,
NoteTimeOrLengthCanBeChanged = 4,

None = 0,
Default = TimeOrLengthCanBeChanged,
AllPropertiesCanBeChanged =
TimeOrLengthCanBeChanged |
NotesCollectionCanBeChanged |
NoteTimeOrLengthCanBeChanged,
}
}
44 changes: 34 additions & 10 deletions DryWetMidi/Interaction/Chords/ChordsManagingUtilities.cs
Original file line number Diff line number Diff line change
Expand Up @@ -985,11 +985,13 @@ internal static int ProcessChordsInternal(

var timeOrLengthChanged = false;
var notesCollectionChanged = false;
var noteTimeOrLengthChanged = false;

var timeOrLengthCanBeChanged = hint.HasFlag(ChordProcessingHint.TimeOrLengthCanBeChanged);
var notesCollectionCanBeChanged = hint.HasFlag(ChordProcessingHint.NotesCollectionCanBeChanged);
var noteTimeOrLengthCanBeChanged = hint.HasFlag(ChordProcessingHint.NoteTimeOrLengthCanBeChanged);

var collectedTimedEvents = timeOrLengthCanBeChanged || notesCollectionCanBeChanged
var collectedTimedEvents = timeOrLengthCanBeChanged || notesCollectionCanBeChanged || noteTimeOrLengthCanBeChanged
? new List<TimedObjectAt<TimedEvent>>(eventsCount)
: null;

Expand All @@ -1002,23 +1004,43 @@ internal static int ProcessChordsInternal(
if (!match(chord))
continue;

var time = chord.Time;
var length = chord.Length;
var notes = notesCollectionCanBeChanged ? chord.Notes.ToArray() : null;
long time;
long length;
chord.GetTimeAndLength(out time, out length);

action(chord);
var notes = notesCollectionCanBeChanged || noteTimeOrLengthCanBeChanged
? chord.Notes.ToArray()
: null;

var addedNotes = notesCollectionCanBeChanged ? chord.Notes.Except(notes).ToArray() : null;
var removedNotes = notesCollectionCanBeChanged ? notes.Except(chord.Notes).ToArray() : null;
var notesTimes = noteTimeOrLengthCanBeChanged
? notes.ToDictionary(n => n, n => n.Time)
: null;
var notesLengths = noteTimeOrLengthCanBeChanged
? notes.ToDictionary(n => n, n => n.Length)
: null;

action(chord);

long newTime;
long newLength;
chord.GetTimeAndLength(out newTime, out newLength);
timeOrLengthChanged |=
chord.Time != time ||
chord.Length != length;
newTime != time ||
newLength != length;

var addedNotes = notesCollectionCanBeChanged ? chord.Notes.Except(notes).ToArray() : null;
var removedNotes = notesCollectionCanBeChanged ? notes.Except(chord.Notes).ToArray() : null;
notesCollectionChanged |=
addedNotes?.Length > 0 ||
removedNotes?.Length > 0;

var savedNotes = noteTimeOrLengthCanBeChanged
? (notesCollectionCanBeChanged ? (IEnumerable<Note>)notes.Intersect(chord.Notes).ToArray() : chord.Notes)
: null;
noteTimeOrLengthChanged |=
savedNotes?.Any(n => n.Time != notesTimes[n]) == true ||
savedNotes?.Any(n => n.Length != notesLengths[n]) == true;

if (notesCollectionChanged)
{
foreach (var note in addedNotes)
Expand All @@ -1040,7 +1062,9 @@ internal static int ProcessChordsInternal(
iMatched++;
}

if ((!timeOrLengthCanBeChanged || !timeOrLengthChanged) && (!notesCollectionCanBeChanged || !notesCollectionChanged))
if ((!timeOrLengthCanBeChanged || !timeOrLengthChanged) &&
(!notesCollectionCanBeChanged || !notesCollectionChanged) &&
(!noteTimeOrLengthCanBeChanged || !noteTimeOrLengthChanged))
return iMatched;

eventsCollections.SortAndUpdateEvents(collectedTimedEvents);
Expand Down

0 comments on commit 6e5a14c

Please sign in to comment.