Skip to content

Commit

Permalink
Added TimedObjectUtilities.ProcessObjects methods
Browse files Browse the repository at this point in the history
  • Loading branch information
melanchall committed Jul 1, 2024
1 parent 4af77ae commit 5983bdd
Show file tree
Hide file tree
Showing 12 changed files with 10,913 additions and 4 deletions.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -0,0 +1,252 @@
using Melanchall.DryWetMidi.Common;
using Melanchall.DryWetMidi.Core;
using Melanchall.DryWetMidi.Interaction;
using Melanchall.DryWetMidi.Tests.Utilities;
using NUnit.Framework;

namespace Melanchall.DryWetMidi.Tests.Interaction
{
[TestFixture]
public sealed partial class TimedObjectUtilitiesTests
{
#region Test methods

[Test]
public void ProcessObjects_TimedEventsAndNotes_WithPredicate_1([Values] ContainerType containerType) => ProcessObjects_EventsCollection_WithPredicate(
containerType: containerType,
objectType: ObjectType.TimedEvent | ObjectType.Note,
midiEvents: new MidiEvent[]
{
new TextEvent("A"),
new NoteOnEvent(),
new NoteOffEvent(),
new TextEvent("C"),
},
action: obj =>
{
if (obj is TimedEvent timedEvent && timedEvent.Event is TextEvent textEvent && textEvent.Text == "A")
textEvent.Text = "B";
else
obj.Time += 10;
},
match: obj => true,
expectedMidiEvents: new MidiEvent[]
{
new TextEvent("B"),
new NoteOnEvent { DeltaTime = 10 },
new NoteOffEvent(),
new TextEvent("C"),
},
expectedProcessedCount: 3);

[Test]
public void ProcessObjects_TimedEventsAndNotes_WithPredicate_2([Values] ContainerType containerType) => ProcessObjects_EventsCollection_WithPredicate(
containerType: containerType,
objectType: ObjectType.TimedEvent | ObjectType.Note,
midiEvents: new MidiEvent[]
{
new TextEvent("A"),
new NoteOnEvent(),
new NoteOffEvent(),
new TextEvent("C"),
},
action: obj => obj.Time += 10,
match: obj => obj is TimedEvent timedEvent && timedEvent.Event is TextEvent textEvent && textEvent.Text == "A",
expectedMidiEvents: new MidiEvent[]
{
new NoteOnEvent(),
new NoteOffEvent(),
new TextEvent("C"),
new TextEvent("A") { DeltaTime = 10 },
},
expectedProcessedCount: 1);

[Test]
public void ProcessObjects_TimedEventsAndChords_WithPredicate_1([Values] ContainerType containerType) => ProcessObjects_EventsCollection_WithPredicate(
containerType: containerType,
objectType: ObjectType.TimedEvent | ObjectType.Chord,
midiEvents: new MidiEvent[]
{
new TextEvent("A"),
new NoteOnEvent(),
new NoteOffEvent(),
new TextEvent("C"),
new NoteOnEvent { DeltaTime = 10 },
new NoteOffEvent(),
new NoteOnEvent((SevenBitNumber)70, SevenBitNumber.MaxValue),
new NoteOffEvent((SevenBitNumber)70, SevenBitNumber.MinValue),
},
action: obj => obj.Time += obj is TimedEvent ? 10 : 20,
match: obj => true,
expectedMidiEvents: new MidiEvent[]
{
new TextEvent("A") { DeltaTime = 10 },
new NoteOnEvent(),
new NoteOffEvent(),
new TextEvent("C"),
new NoteOnEvent { DeltaTime = 20 },
new NoteOffEvent(),
new NoteOnEvent((SevenBitNumber)70, SevenBitNumber.MaxValue),
new NoteOffEvent((SevenBitNumber)70, SevenBitNumber.MinValue),
},
expectedProcessedCount: 5,
settings: new ObjectDetectionSettings
{
ChordDetectionSettings = new ChordDetectionSettings
{
NotesMinCount = 2
}
});

[Test]
public void ProcessObjects_TimedEventsAndChords_WithPredicate_2([Values] ContainerType containerType) => ProcessObjects_EventsCollection_WithPredicate(
containerType: containerType,
objectType: ObjectType.TimedEvent | ObjectType.Chord,
midiEvents: new MidiEvent[]
{
new TextEvent("A"),
new NoteOnEvent(),
new NoteOffEvent(),
new TextEvent("C"),
new NoteOnEvent { DeltaTime = 10 },
new NoteOffEvent(),
new NoteOnEvent((SevenBitNumber)70, SevenBitNumber.MaxValue),
new NoteOffEvent((SevenBitNumber)70, SevenBitNumber.MinValue),
},
action: obj => obj.Time += obj is TimedEvent ? 10 : 20,
match: obj => true,
expectedMidiEvents: new MidiEvent[]
{
new TextEvent("A") { DeltaTime = 10 },
new TextEvent("C"),
new NoteOnEvent() { DeltaTime = 10 },
new NoteOffEvent(),
new NoteOnEvent { DeltaTime = 10 },
new NoteOffEvent(),
new NoteOnEvent((SevenBitNumber)70, SevenBitNumber.MaxValue),
new NoteOffEvent((SevenBitNumber)70, SevenBitNumber.MinValue),
},
expectedProcessedCount: 4);

[Test]
public void ProcessObjects_TimedEventsAndChords_WithPredicate_3([Values] ContainerType containerType) => ProcessObjects_EventsCollection_WithPredicate(
containerType: containerType,
objectType: ObjectType.TimedEvent | ObjectType.Chord,
midiEvents: new MidiEvent[]
{
new TextEvent("A"),
new NoteOnEvent(),
new NoteOffEvent(),
new TextEvent("C"),
new NoteOnEvent { DeltaTime = 10 },
new NoteOffEvent(),
new NoteOnEvent((SevenBitNumber)70, SevenBitNumber.MaxValue),
new NoteOffEvent((SevenBitNumber)70, SevenBitNumber.MinValue),
},
action: obj => obj.Time += 10,
match: obj => obj is Chord,
expectedMidiEvents: new MidiEvent[]
{
new TextEvent("A"),
new TextEvent("C"),
new NoteOnEvent() { DeltaTime = 10 },
new NoteOffEvent(),
new NoteOnEvent { DeltaTime = 10 },
new NoteOffEvent(),
new NoteOnEvent((SevenBitNumber)70, SevenBitNumber.MaxValue),
new NoteOffEvent((SevenBitNumber)70, SevenBitNumber.MinValue),
},
expectedProcessedCount: 2);

[Test]
public void ProcessObjects_TimedEventsAndNotes_WithoutPredicate([Values] ContainerType containerType) => ProcessObjects_EventsCollection_WithoutPredicate(
containerType: containerType,
objectType: ObjectType.TimedEvent | ObjectType.Note,
midiEvents: new MidiEvent[]
{
new TextEvent("A"),
new NoteOnEvent(),
new NoteOffEvent(),
new TextEvent("C"),
},
action: obj =>
{
if (obj is TimedEvent timedEvent && timedEvent.Event is TextEvent textEvent && textEvent.Text == "A")
textEvent.Text = "B";
else
obj.Time += 10;
},
expectedMidiEvents: new MidiEvent[]
{
new TextEvent("B"),
new NoteOnEvent { DeltaTime = 10 },
new NoteOffEvent(),
new TextEvent("C"),
});

[Test]
public void ProcessObjects_TimedEventsAndChords_WithoutPredicate_1([Values] ContainerType containerType) => ProcessObjects_EventsCollection_WithoutPredicate(
containerType: containerType,
objectType: ObjectType.TimedEvent | ObjectType.Chord,
midiEvents: new MidiEvent[]
{
new TextEvent("A"),
new NoteOnEvent(),
new NoteOffEvent(),
new TextEvent("C"),
new NoteOnEvent { DeltaTime = 10 },
new NoteOffEvent(),
new NoteOnEvent((SevenBitNumber)70, SevenBitNumber.MaxValue),
new NoteOffEvent((SevenBitNumber)70, SevenBitNumber.MinValue),
},
action: obj => obj.Time += obj is TimedEvent ? 10 : 20,
expectedMidiEvents: new MidiEvent[]
{
new TextEvent("A") { DeltaTime = 10 },
new NoteOnEvent(),
new NoteOffEvent(),
new TextEvent("C"),
new NoteOnEvent { DeltaTime = 20 },
new NoteOffEvent(),
new NoteOnEvent((SevenBitNumber)70, SevenBitNumber.MaxValue),
new NoteOffEvent((SevenBitNumber)70, SevenBitNumber.MinValue),
},
settings: new ObjectDetectionSettings
{
ChordDetectionSettings = new ChordDetectionSettings
{
NotesMinCount = 2
}
});

[Test]
public void ProcessObjects_TimedEventsAndChords_WithoutPredicate_2([Values] ContainerType containerType) => ProcessObjects_EventsCollection_WithoutPredicate(
containerType: containerType,
objectType: ObjectType.TimedEvent | ObjectType.Chord,
midiEvents: new MidiEvent[]
{
new TextEvent("A"),
new NoteOnEvent(),
new NoteOffEvent(),
new TextEvent("C"),
new NoteOnEvent { DeltaTime = 10 },
new NoteOffEvent(),
new NoteOnEvent((SevenBitNumber)70, SevenBitNumber.MaxValue),
new NoteOffEvent((SevenBitNumber)70, SevenBitNumber.MinValue),
},
action: obj => obj.Time += obj is TimedEvent ? 10 : 20,
expectedMidiEvents: new MidiEvent[]
{
new TextEvent("A") { DeltaTime = 10 },
new TextEvent("C"),
new NoteOnEvent() { DeltaTime = 10 },
new NoteOffEvent(),
new NoteOnEvent { DeltaTime = 10 },
new NoteOffEvent(),
new NoteOnEvent((SevenBitNumber)70, SevenBitNumber.MaxValue),
new NoteOffEvent((SevenBitNumber)70, SevenBitNumber.MinValue),
});

#endregion
}
}
1 change: 1 addition & 0 deletions DryWetMidi/Interaction/Notes/NotesManagingUtilities.cs
Original file line number Diff line number Diff line change
Expand Up @@ -910,6 +910,7 @@ internal static IEnumerable<TimedObjectAt<ITimedObject>> GetNotesAndTimedEventsL
foreach (var timedEventTuple in timedEvents)
{
var timedEvent = timedEventTuple.Object;

switch (timedEvent.Event.EventType)
{
case MidiEventType.NoteOn:
Expand Down
21 changes: 18 additions & 3 deletions DryWetMidi/Interaction/TimedEvents/TimedEventsManagingUtilities.cs
Original file line number Diff line number Diff line change
Expand Up @@ -760,7 +760,12 @@ internal static IEnumerable<TimedObjectAt<TimedEvent>> GetTimedEventsLazy(this I
return eventsCollections.GetTimedEventsLazy(eventsCount, settings, cloneEvent);
}

internal static IEnumerable<TimedObjectAt<TimedEvent>> GetTimedEventsLazy(this EventsCollection[] eventsCollections, int eventsCount, TimedEventDetectionSettings settings, bool cloneEvent = true)
internal static IEnumerable<TimedObjectAt<TimedEvent>> GetTimedEventsLazy(
this EventsCollection[] eventsCollections,
int eventsCount,
TimedEventDetectionSettings settings,
bool cloneEvent = true,
List<TimedObjectAt<TimedEvent>> collectedTimedEvents = null)
{
var eventsCollectionsCount = eventsCollections.Length;

Expand All @@ -771,7 +776,12 @@ internal static IEnumerable<TimedObjectAt<TimedEvent>> GetTimedEventsLazy(this E
{
foreach (var timedEvent in eventsCollections[0].GetTimedEventsLazy(settings, cloneEvent))
{
yield return new TimedObjectAt<TimedEvent>(timedEvent, 0);
var timedObjectAt = new TimedObjectAt<TimedEvent>(timedEvent, 0);

if (collectedTimedEvents != null)
collectedTimedEvents.Add(timedObjectAt);

yield return timedObjectAt;
}

yield break;
Expand Down Expand Up @@ -821,7 +831,12 @@ internal static IEnumerable<TimedObjectAt<TimedEvent>> GetTimedEventsLazy(this E
timedEvent._time = minTime;
}

yield return new TimedObjectAt<TimedEvent>(timedEvent, eventsCollectionIndex);
var timedObjectAt = new TimedObjectAt<TimedEvent>(timedEvent, eventsCollectionIndex);

if (collectedTimedEvents != null)
collectedTimedEvents.Add(timedObjectAt);

yield return timedObjectAt;

eventsCollectionTimes[eventsCollectionIndex] = minTime;
eventsCollectionIndices[eventsCollectionIndex]++;
Expand Down
16 changes: 16 additions & 0 deletions DryWetMidi/Interaction/TimedObject/ObjectProcessingHint.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
using System;

namespace Melanchall.DryWetMidi.Interaction
{
[Flags]
public enum ObjectProcessingHint
{
None = 0,

TimeOrLengthCanBeChanged = 1,
NotesCollectionCanBeChanged = 2,
NoteTimeOrLengthCanBeChanged = 4,

Default = TimeOrLengthCanBeChanged,
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ namespace Melanchall.DryWetMidi.Interaction
/// <summary>
/// Extension methods for objects that implement the <see cref="ITimedObject"/> interface.
/// </summary>
public static class TimedObjectUtilities
public static partial class TimedObjectUtilities
{
#region Methods

Expand Down
Loading

0 comments on commit 5983bdd

Please sign in to comment.