Skip to content

Commit

Permalink
Remove playback's blocking mode
Browse files Browse the repository at this point in the history
  • Loading branch information
melanchall committed Jan 18, 2025
1 parent 0780ebf commit 20d37b0
Show file tree
Hide file tree
Showing 6 changed files with 13 additions and 430 deletions.
12 changes: 0 additions & 12 deletions DryWetMidi.Benchmarks/Devices/Playback/PlaybackBenchmarks.Misc.cs
Original file line number Diff line number Diff line change
Expand Up @@ -46,18 +46,6 @@ public void IterationSetup()
_playback.MoveToStart();
_playbackWithNoteCallback.MoveToStart();
}

[Benchmark]
public void Play()
{
_playback.Play();
}

[Benchmark]
public void PlayWithNoteCallback()
{
_playbackWithNoteCallback.Play();
}
}

#endregion
Expand Down
164 changes: 0 additions & 164 deletions DryWetMidi.Tests/Multimedia/Playback/PlaybackTests.Misc.cs
Original file line number Diff line number Diff line change
Expand Up @@ -423,170 +423,6 @@ public void PlayRecordedData()
createPlayback: (outputDevice, playbackSettings) => recordedFile.GetPlayback(outputDevice, playbackSettings));
}

[Retry(RetriesNumber)]
[TestCase(1.0)]
[TestCase(2.0)]
[TestCase(0.5)]
public void CheckPlayback_Blocking(double speed)
{
var eventsToSend = new[]
{
new EventToSend(new NoteOnEvent((SevenBitNumber)100, (SevenBitNumber)20) { Channel = (FourBitNumber)5 }, TimeSpan.Zero),
new EventToSend(new NoteOffEvent((SevenBitNumber)100, (SevenBitNumber)10) { Channel = (FourBitNumber)5 }, TimeSpan.FromSeconds(2)),
new EventToSend(new NoteOnEvent(), TimeSpan.FromSeconds(1)),
new EventToSend(new NoteOnEvent((SevenBitNumber)30, (SevenBitNumber)50), TimeSpan.Zero),
new EventToSend(new NoteOffEvent(), TimeSpan.FromSeconds(3)),
new EventToSend(new NoteOffEvent((SevenBitNumber)30, (SevenBitNumber)50), TimeSpan.Zero)
};

CheckPlayback(
eventsToSend,
speed,
beforePlaybackStarted: NoPlaybackAction,
startPlayback: (context, playback) => playback.Play(),
afterPlaybackStarted: (context, playback) =>
{
Assert.GreaterOrEqual(context.Stopwatch.Elapsed, context.ExpectedTimes.Last(), "Playback doesn't block current thread.");
},
waiting: (context, playback) =>
{
var areEventsReceived = WaitOperations.Wait(() => context.ReceivedEvents.Count == eventsToSend.Length, SendReceiveUtilities.MaximumEventSendReceiveDelay);
Assert.IsTrue(areEventsReceived, $"Events are not received.");
},
finalChecks: NoPlaybackAction);
}

[Retry(RetriesNumber)]
[TestCase(1.0)]
[TestCase(2.0)]
[TestCase(0.5)]
public void CheckPlayback_Blocking_CustomPlaybackStart(double speed)
{
var eventsToSend = new[]
{
new EventToSend(new NoteOnEvent((SevenBitNumber)100, (SevenBitNumber)20) { Channel = (FourBitNumber)5 }, TimeSpan.Zero),
new EventToSend(new NoteOffEvent((SevenBitNumber)100, (SevenBitNumber)10) { Channel = (FourBitNumber)5 }, TimeSpan.FromSeconds(1)),

new EventToSend(new NoteOnEvent(), TimeSpan.FromSeconds(1)),
new EventToSend(new NoteOnEvent((SevenBitNumber)30, (SevenBitNumber)50), TimeSpan.Zero),
new EventToSend(new NoteOffEvent(), TimeSpan.FromSeconds(1)),
new EventToSend(new NoteOffEvent((SevenBitNumber)30, (SevenBitNumber)50), TimeSpan.Zero)
};

var expectedEventsTimes = new List<TimeSpan>
{
TimeSpan.FromMilliseconds(500),
TimeSpan.FromMilliseconds(500),
TimeSpan.FromSeconds(1.5),
TimeSpan.FromSeconds(1.5)
};

CheckPlayback(
eventsToSend,
speed,
beforePlaybackStarted: (context, playback) => playback.PlaybackStart = new MetricTimeSpan(0, 0, 1, 500),
startPlayback: (context, playback) => playback.Play(),
afterPlaybackStarted: (context, playback) =>
{
Assert.GreaterOrEqual(context.Stopwatch.Elapsed, expectedEventsTimes.Last(), "Playback doesn't block current thread.");
},
waiting: (context, playback) =>
{
var areEventsReceived = WaitOperations.Wait(() => context.ReceivedEvents.Count == expectedEventsTimes.Count, SendReceiveUtilities.MaximumEventSendReceiveDelay);
Assert.IsTrue(areEventsReceived, $"Events are not received.");
},
finalChecks: NoPlaybackAction,
expectedEventsTimes: expectedEventsTimes);
}

[Retry(RetriesNumber)]
[TestCase(1.0)]
[TestCase(2.0)]
[TestCase(0.5)]
public void CheckPlayback_Blocking_CustomPlaybackEnd(double speed)
{
var eventsToSend = new[]
{
new EventToSend(new NoteOnEvent((SevenBitNumber)100, (SevenBitNumber)20) { Channel = (FourBitNumber)5 }, TimeSpan.Zero),
new EventToSend(new NoteOffEvent((SevenBitNumber)100, (SevenBitNumber)10) { Channel = (FourBitNumber)5 }, TimeSpan.FromSeconds(1)),

new EventToSend(new NoteOnEvent(), TimeSpan.FromSeconds(1)),
new EventToSend(new NoteOnEvent((SevenBitNumber)30, (SevenBitNumber)50), TimeSpan.Zero),
new EventToSend(new NoteOffEvent(), TimeSpan.FromSeconds(1)),
new EventToSend(new NoteOffEvent((SevenBitNumber)30, (SevenBitNumber)50), TimeSpan.Zero)
};

var expectedEventsTimes = new List<TimeSpan>
{
TimeSpan.Zero,
TimeSpan.FromSeconds(1),
};

CheckPlayback(
eventsToSend,
speed,
beforePlaybackStarted: (context, playback) => playback.PlaybackEnd = new MetricTimeSpan(0, 0, 1, 500),
startPlayback: (context, playback) => playback.Play(),
afterPlaybackStarted: (context, playback) =>
{
Assert.GreaterOrEqual(context.Stopwatch.Elapsed, expectedEventsTimes.Last(), "Playback doesn't block current thread.");
},
waiting: (context, playback) =>
{
var areEventsReceived = WaitOperations.Wait(() => context.ReceivedEvents.Count == expectedEventsTimes.Count, SendReceiveUtilities.MaximumEventSendReceiveDelay);
Assert.IsTrue(areEventsReceived, $"Events are not received.");
},
finalChecks: NoPlaybackAction,
expectedEventsTimes: expectedEventsTimes);
}

[Retry(RetriesNumber)]
[TestCase(1.0)]
[TestCase(2.0)]
[TestCase(0.5)]
public void CheckPlayback_Blocking_CustomPlaybackStartAndEnd(double speed)
{
var eventsToSend = new[]
{
new EventToSend(new NoteOnEvent((SevenBitNumber)100, (SevenBitNumber)20) { Channel = (FourBitNumber)5 }, TimeSpan.Zero),
new EventToSend(new NoteOffEvent((SevenBitNumber)100, (SevenBitNumber)10) { Channel = (FourBitNumber)5 }, TimeSpan.FromSeconds(1)),

new EventToSend(new NoteOnEvent(), TimeSpan.FromSeconds(1)),
new EventToSend(new NoteOnEvent((SevenBitNumber)30, (SevenBitNumber)50), TimeSpan.Zero),
new EventToSend(new NoteOffEvent(), TimeSpan.FromSeconds(1)),

new EventToSend(new NoteOffEvent((SevenBitNumber)30, (SevenBitNumber)50), TimeSpan.FromSeconds(1))
};

var expectedEventsTimes = new List<TimeSpan>
{
TimeSpan.FromMilliseconds(500),
TimeSpan.FromMilliseconds(500),
TimeSpan.FromSeconds(1.5)
};

CheckPlayback(
eventsToSend,
speed,
beforePlaybackStarted: (context, playback) =>
{
playback.PlaybackStart = new MetricTimeSpan(0, 0, 1, 500);
playback.PlaybackEnd = new MetricTimeSpan(0, 0, 3, 500);
},
startPlayback: (context, playback) => playback.Play(),
afterPlaybackStarted: (context, playback) =>
{
Assert.GreaterOrEqual(context.Stopwatch.Elapsed, expectedEventsTimes.Last(), "Playback doesn't block current thread.");
},
waiting: (context, playback) =>
{
var areEventsReceived = WaitOperations.Wait(() => context.ReceivedEvents.Count == expectedEventsTimes.Count, SendReceiveUtilities.MaximumEventSendReceiveDelay);
Assert.IsTrue(areEventsReceived, $"Events are not received.");
},
finalChecks: NoPlaybackAction,
expectedEventsTimes: expectedEventsTimes);
}

[Retry(RetriesNumber)]
[TestCase(1)]
[TestCase(2)]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
using Melanchall.DryWetMidi.Interaction;
using Melanchall.DryWetMidi.Standards;
using NUnit.Framework;
using System.Threading;

namespace Melanchall.DryWetMidi.Tests.Multimedia
{
Expand Down Expand Up @@ -137,7 +138,9 @@ private static void CheckNotesPlayback(IEnumerable<Note> notes,
playback.NotesPlaybackFinished += (_, e) => receivedNotesFinished.AddRange(e.Notes.Select(n => new ReceivedNote(n, stopwatch.Elapsed)));

stopwatch.Start();
playback.Play();

playback.Start();
SpinWait.SpinUntil(() => !playback.IsRunning);

Assert.IsFalse(playback.IsRunning, "Playback is running after completed.");
}
Expand Down
17 changes: 0 additions & 17 deletions DryWetMidi/Multimedia/Playback/Playback.cs
Original file line number Diff line number Diff line change
Expand Up @@ -557,23 +557,6 @@ public void Stop()
OnStopped();
}

/// <summary>
/// Starts playing of the MIDI data. This method will block execution of a program until all
/// MIDI data is played.
/// </summary>
/// <remarks>
/// If <see cref="Loop"/> is set to <c>true</c>, this method will execute forever.
/// </remarks>
/// <exception cref="ObjectDisposedException">The current <see cref="Playback"/> is disposed.</exception>
/// <exception cref="MidiDeviceException">An error occurred on device.</exception>
public void Play()
{
EnsureIsNotDisposed();

Start();
SpinWait.SpinUntil(() => !_clock.IsRunning);
}

/// <summary>
/// Sets playback position to the time of the specified snap point.
/// </summary>
Expand Down
Loading

0 comments on commit 20d37b0

Please sign in to comment.