Skip to content

Commit

Permalink
Allow zero repeats number for Repeater
Browse files Browse the repository at this point in the history
  • Loading branch information
melanchall committed Mar 12, 2024
1 parent d65407b commit d0bb5e7
Show file tree
Hide file tree
Showing 4 changed files with 72 additions and 17 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,22 @@ public void CheckRepeat_MultipleCollections_TimedEvents() => CheckRepeat(
}
});

[Test]
public void CheckRepeat_MultipleCollections_ZeroRepeatsNumber() => CheckRepeat_ZeroRepeatsNumber(
new[]
{
new[]
{
new TimedEvent(new TextEvent("A"), 0),
new TimedEvent(new ControlChangeEvent(), 20),
},
new[]
{
new TimedEvent(new TextEvent("A"), 10),
new TimedEvent(new ControlChangeEvent(), 30),
}
});

[Test]
public void CheckRepeat_MultipleCollections_TimedEventsAndNotes() => CheckRepeat(
inputObjects: new[]
Expand Down Expand Up @@ -151,6 +167,15 @@ public void CheckRepeat_MultipleCollections_Custom() => CheckRepeat_Custom<Custo

#region Private methods

private void CheckRepeat_ZeroRepeatsNumber(
ICollection<ICollection<ITimedObject>> inputObjects) =>
CheckRepeat(
inputObjects,
0,
TempoMap.Default,
null,
inputObjects.Select(objects => objects.Select(o => o.Clone()).ToArray()).ToArray());

private void CheckRepeat(
ICollection<ICollection<ITimedObject>> inputObjects,
int repeatsNumber,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,18 @@ public void CheckRepeat_SingleCollection_EmptyCollection([Values(1, 10)] int rep
settings: null,
expectedObjects: Array.Empty<ITimedObject>());

[Test]
public void CheckRepeat_SingleCollection_ZeroRepeatsNumber_1() => CheckRepeat_ZeroRepeatsNumber(
new[] { new TimedEvent(new TextEvent("A")) });

[Test]
public void CheckRepeat_SingleCollection_ZeroRepeatsNumber_2() => CheckRepeat_ZeroRepeatsNumber(
new ITimedObject[]
{
new TimedEvent(new TextEvent("A")),
new Note(DryWetMidi.MusicTheory.NoteName.ASharp, 2),
});

[Test]
public void CheckRepeat_SingleCollection_SingleTimedEvent_DefaultSettings([Values(0, 10)] long eventTime, [Values(1, 10)] int repeatsNumber) => CheckRepeat(
inputObjects: new[]
Expand Down Expand Up @@ -512,7 +524,7 @@ public void CheckRepeat_SingleCollection_Nulls() => CheckRepeat(
});

[Test]
public void CheckRepeat_NonPositiveRepeatsNumber([Values(0, -1)] int repeatsNumber)
public void CheckRepeat_NegativeRepeatsNumber([Values(-1)] int repeatsNumber)
{
var repeater = new Repeater();

Expand Down Expand Up @@ -577,6 +589,12 @@ public void CheckRepeat_NullTempoMap()

#region Private methods

private void CheckRepeat_ZeroRepeatsNumber(ICollection<ITimedObject> inputObjects) => CheckRepeat(
inputObjects: inputObjects,
repeatsNumber: 0,
settings: null,
expectedObjects: inputObjects.Select(o => o.Clone()).ToArray());

private void CheckRepeat(
ICollection<ITimedObject> inputObjects,
int repeatsNumber,
Expand Down
28 changes: 20 additions & 8 deletions DryWetMidi/Tools/Repeater/Repeater.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,15 +24,18 @@ public class Repeater
/// <returns>A new instance of the <see cref="MidiFile"/> which is the <paramref name="midiFile"/>
/// repeated <paramref name="repeatsNumber"/> times using <paramref name="settings"/>.</returns>
/// <exception cref="ArgumentNullException"><paramref name="midiFile"/> is <c>null</c>.</exception>
/// <exception cref="ArgumentOutOfRangeException"><paramref name="repeatsNumber"/> is zero or negative.</exception>
/// <exception cref="ArgumentOutOfRangeException"><paramref name="repeatsNumber"/> is negative.</exception>
/// <exception cref="ArgumentException"><see cref="RepeatingSettings.Shift"/> of the <paramref name="settings"/>
/// is <c>null</c> for fixed-value shift.</exception>
public MidiFile Repeat(MidiFile midiFile, int repeatsNumber, RepeatingSettings settings = null)
{
ThrowIfArgument.IsNull(nameof(midiFile), midiFile);
ThrowIfArgument.IsNonpositive(nameof(repeatsNumber), repeatsNumber, "Repeats number is zero or negative.");
ThrowIfArgument.IsNegative(nameof(repeatsNumber), repeatsNumber, "Repeats number is negative.");
CheckSettings(settings);

if (repeatsNumber == 0)
return midiFile.Clone();

settings = settings ?? new RepeatingSettings();

var tempoMap = midiFile.GetTempoMap();
Expand Down Expand Up @@ -64,16 +67,19 @@ public MidiFile Repeat(MidiFile midiFile, int repeatsNumber, RepeatingSettings s
/// </item>
/// </list>
/// </exception>
/// <exception cref="ArgumentOutOfRangeException"><paramref name="repeatsNumber"/> is zero or negative.</exception>
/// <exception cref="ArgumentOutOfRangeException"><paramref name="repeatsNumber"/> is negative.</exception>
/// <exception cref="ArgumentException"><see cref="RepeatingSettings.Shift"/> of the <paramref name="settings"/>
/// is <c>null</c> for fixed-value shift.</exception>
public ICollection<TrackChunk> Repeat(IEnumerable<TrackChunk> trackChunks, int repeatsNumber, TempoMap tempoMap, RepeatingSettings settings = null)
{
ThrowIfArgument.IsNull(nameof(trackChunks), trackChunks);
ThrowIfArgument.IsNull(nameof(tempoMap), tempoMap);
ThrowIfArgument.IsNonpositive(nameof(repeatsNumber), repeatsNumber, "Repeats number is zero or negative.");
ThrowIfArgument.IsNegative(nameof(repeatsNumber), repeatsNumber, "Repeats number is negative.");
CheckSettings(settings);

if (repeatsNumber == 0)
return trackChunks.Select(c => (TrackChunk)c.Clone()).ToArray();

settings = settings ?? new RepeatingSettings();

var timedEventsCollections = trackChunks.Select(trackChunk => trackChunk.GetTimedEvents()).ToArray();
Expand Down Expand Up @@ -105,16 +111,19 @@ public ICollection<TrackChunk> Repeat(IEnumerable<TrackChunk> trackChunks, int r
/// </item>
/// </list>
/// </exception>
/// <exception cref="ArgumentOutOfRangeException"><paramref name="repeatsNumber"/> is zero or negative.</exception>
/// <exception cref="ArgumentOutOfRangeException"><paramref name="repeatsNumber"/> is negative.</exception>
/// <exception cref="ArgumentException"><see cref="RepeatingSettings.Shift"/> of the <paramref name="settings"/>
/// is <c>null</c> for fixed-value shift.</exception>
public TrackChunk Repeat(TrackChunk trackChunk, int repeatsNumber, TempoMap tempoMap, RepeatingSettings settings = null)
{
ThrowIfArgument.IsNull(nameof(trackChunk), trackChunk);
ThrowIfArgument.IsNull(nameof(tempoMap), tempoMap);
ThrowIfArgument.IsNonpositive(nameof(repeatsNumber), repeatsNumber, "Repeats number is zero or negative.");
ThrowIfArgument.IsNegative(nameof(repeatsNumber), repeatsNumber, "Repeats number is negative.");
CheckSettings(settings);

if (repeatsNumber == 0)
return (TrackChunk)trackChunk.Clone();

settings = settings ?? new RepeatingSettings();

var timedObjects = trackChunk.GetTimedEvents();
Expand Down Expand Up @@ -144,16 +153,19 @@ public TrackChunk Repeat(TrackChunk trackChunk, int repeatsNumber, TempoMap temp
/// </item>
/// </list>
/// </exception>
/// <exception cref="ArgumentOutOfRangeException"><paramref name="repeatsNumber"/> is zero or negative.</exception>
/// <exception cref="ArgumentOutOfRangeException"><paramref name="repeatsNumber"/> is negative.</exception>
/// <exception cref="ArgumentException"><see cref="RepeatingSettings.Shift"/> of the <paramref name="settings"/>
/// is <c>null</c> for fixed-value shift.</exception>
public ICollection<ITimedObject> Repeat(IEnumerable<ITimedObject> timedObjects, int repeatsNumber, TempoMap tempoMap, RepeatingSettings settings = null)
{
ThrowIfArgument.IsNull(nameof(timedObjects), timedObjects);
ThrowIfArgument.IsNull(nameof(tempoMap), tempoMap);
ThrowIfArgument.IsNonpositive(nameof(repeatsNumber), repeatsNumber, "Repeats number is zero or negative.");
ThrowIfArgument.IsNegative(nameof(repeatsNumber), repeatsNumber, "Repeats number is negative.");
CheckSettings(settings);

if (repeatsNumber == 0)
return timedObjects.Select(o => o.Clone()).ToArray();

settings = settings ?? new RepeatingSettings();

var maxTime = timedObjects.Select(obj => (obj?.Time ?? 0) + ((obj as ILengthedObject)?.Length ?? 0)).DefaultIfEmpty(0).Max();
Expand Down
16 changes: 8 additions & 8 deletions DryWetMidi/Tools/Repeater/RepeaterUtilities.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,13 @@ public static class RepeaterUtilities
/// <returns>A new instance of the <see cref="MidiFile"/> which is the <paramref name="midiFile"/>
/// repeated <paramref name="repeatsNumber"/> times using <paramref name="settings"/>.</returns>
/// <exception cref="ArgumentNullException"><paramref name="midiFile"/> is <c>null</c>.</exception>
/// <exception cref="ArgumentOutOfRangeException"><paramref name="repeatsNumber"/> is zero or negative.</exception>
/// <exception cref="ArgumentOutOfRangeException"><paramref name="repeatsNumber"/> is negative.</exception>
/// <exception cref="ArgumentException"><see cref="RepeatingSettings.Shift"/> of the <paramref name="settings"/>
/// is <c>null</c> for fixed-value shift.</exception>
public static MidiFile Repeat(this MidiFile midiFile, int repeatsNumber, RepeatingSettings settings = null)
{
ThrowIfArgument.IsNull(nameof(midiFile), midiFile);
ThrowIfArgument.IsNonpositive(nameof(repeatsNumber), repeatsNumber, "Repeats number is zero or negative.");
ThrowIfArgument.IsNegative(nameof(repeatsNumber), repeatsNumber, "Repeats number is negative.");

return new Repeater().Repeat(midiFile, repeatsNumber, settings);
}
Expand All @@ -56,14 +56,14 @@ public static MidiFile Repeat(this MidiFile midiFile, int repeatsNumber, Repeati
/// </item>
/// </list>
/// </exception>
/// <exception cref="ArgumentOutOfRangeException"><paramref name="repeatsNumber"/> is zero or negative.</exception>
/// <exception cref="ArgumentOutOfRangeException"><paramref name="repeatsNumber"/> is negative.</exception>
/// <exception cref="ArgumentException"><see cref="RepeatingSettings.Shift"/> of the <paramref name="settings"/>
/// is <c>null</c> for fixed-value shift.</exception>
public static TrackChunk Repeat(this TrackChunk trackChunk, int repeatsNumber, TempoMap tempoMap, RepeatingSettings settings = null)
{
ThrowIfArgument.IsNull(nameof(trackChunk), trackChunk);
ThrowIfArgument.IsNull(nameof(tempoMap), tempoMap);
ThrowIfArgument.IsNonpositive(nameof(repeatsNumber), repeatsNumber, "Repeats number is zero or negative.");
ThrowIfArgument.IsNegative(nameof(repeatsNumber), repeatsNumber, "Repeats number is negative.");

return new Repeater().Repeat(trackChunk, repeatsNumber, tempoMap, settings);
}
Expand All @@ -89,14 +89,14 @@ public static TrackChunk Repeat(this TrackChunk trackChunk, int repeatsNumber, T
/// </item>
/// </list>
/// </exception>
/// <exception cref="ArgumentOutOfRangeException"><paramref name="repeatsNumber"/> is zero or negative.</exception>
/// <exception cref="ArgumentOutOfRangeException"><paramref name="repeatsNumber"/> is negative.</exception>
/// <exception cref="ArgumentException"><see cref="RepeatingSettings.Shift"/> of the <paramref name="settings"/>
/// is <c>null</c> for fixed-value shift.</exception>
public static ICollection<TrackChunk> Repeat(this IEnumerable<TrackChunk> trackChunks, int repeatsNumber, TempoMap tempoMap, RepeatingSettings settings = null)
{
ThrowIfArgument.IsNull(nameof(trackChunks), trackChunks);
ThrowIfArgument.IsNull(nameof(tempoMap), tempoMap);
ThrowIfArgument.IsNonpositive(nameof(repeatsNumber), repeatsNumber, "Repeats number is zero or negative.");
ThrowIfArgument.IsNegative(nameof(repeatsNumber), repeatsNumber, "Repeats number is negative.");

return new Repeater().Repeat(trackChunks, repeatsNumber, tempoMap, settings);
}
Expand All @@ -122,14 +122,14 @@ public static ICollection<TrackChunk> Repeat(this IEnumerable<TrackChunk> trackC
/// </item>
/// </list>
/// </exception>
/// <exception cref="ArgumentOutOfRangeException"><paramref name="repeatsNumber"/> is zero or negative.</exception>
/// <exception cref="ArgumentOutOfRangeException"><paramref name="repeatsNumber"/> is negative.</exception>
/// <exception cref="ArgumentException"><see cref="RepeatingSettings.Shift"/> of the <paramref name="settings"/>
/// is <c>null</c> for fixed-value shift.</exception>
public static ICollection<ITimedObject> Repeat(this IEnumerable<ITimedObject> timedObjects, int repeatsNumber, TempoMap tempoMap, RepeatingSettings settings = null)
{
ThrowIfArgument.IsNull(nameof(timedObjects), timedObjects);
ThrowIfArgument.IsNull(nameof(tempoMap), tempoMap);
ThrowIfArgument.IsNonpositive(nameof(repeatsNumber), repeatsNumber, "Repeats number is zero or negative.");
ThrowIfArgument.IsNegative(nameof(repeatsNumber), repeatsNumber, "Repeats number is negative.");

return new Repeater().Repeat(timedObjects, repeatsNumber, tempoMap, settings);
}
Expand Down

0 comments on commit d0bb5e7

Please sign in to comment.