diff --git a/DryWetMidi.Tests/Devices/Playback/PlaybackTests.TickGenerator.cs b/DryWetMidi.Tests/Devices/Playback/PlaybackTests.TickGenerator.cs index 892126a0c..6e7be610a 100644 --- a/DryWetMidi.Tests/Devices/Playback/PlaybackTests.TickGenerator.cs +++ b/DryWetMidi.Tests/Devices/Playback/PlaybackTests.TickGenerator.cs @@ -6,6 +6,9 @@ using Melanchall.DryWetMidi.Core; using NUnit.Framework; using System.Diagnostics; +using Melanchall.DryWetMidi.Interaction; +using System.IO; +using Melanchall.DryWetMidi.Tests.Common; namespace Melanchall.DryWetMidi.Tests.Devices { @@ -22,9 +25,6 @@ private sealed class ThreadTickGenerator : TickGenerator protected override void Start(TimeSpan interval) { - if (_thread != null) - return; - _thread = new Thread(() => { var stopwatch = new Stopwatch(); @@ -47,6 +47,11 @@ protected override void Start(TimeSpan interval) _thread.Start(); } + protected override void Stop() + { + _isRunning = false; + } + protected override void Dispose(bool disposing) { if (_disposed) @@ -72,6 +77,32 @@ public void CheckPlayback_HighPrecisionTickGenerator() CheckPlayback_TickGenerator(() => new HighPrecisionTickGenerator(), TimeSpan.FromMilliseconds(30)); } + [Retry(RetriesNumber)] + [Test] + public void CheckPlayback_HighPrecisionTickGenerator_DiscardResolutionIncreasingOnStop() + { + var processId = Process.GetCurrentProcess().Id; + + using (var playback = new Playback(new MidiEvent[] { new NoteOnEvent(), new NoteOffEvent { DeltaTime = 100000 } }, TempoMap.Default)) + { + Assert.IsFalse(IsProcessIdInPowerCfgReport(processId), "Process ID is in PowerCfg report before playback started."); + + playback.Start(); + Assert.IsTrue(IsProcessIdInPowerCfgReport(processId), "Process ID isn't in PowerCfg report after playback started."); + + playback.Stop(); + Assert.IsFalse(IsProcessIdInPowerCfgReport(processId), "Process ID is in PowerCfg report after playback stopped."); + + playback.Start(); + Assert.IsTrue(IsProcessIdInPowerCfgReport(processId), "Process ID isn't in PowerCfg report after playback started again."); + + playback.Stop(); + Assert.IsFalse(IsProcessIdInPowerCfgReport(processId), "Process ID is in PowerCfg report after playback stopped again."); + } + + Assert.IsFalse(IsProcessIdInPowerCfgReport(processId), "Process ID is in PowerCfg report after playback disposed."); + } + [Retry(RetriesNumber)] [Test] public void CheckPlayback_RegularPrecisionTickGenerator() @@ -143,6 +174,30 @@ public void CheckPlayback_ManualTicking() #region Private methods + private bool IsProcessIdInPowerCfgReport(int processId) + { + var reportFilePath = Path.Combine(Path.GetTempPath(), "powercfg_report.html"); + + try + { + var process = Process.Start(new ProcessStartInfo + { + FileName = "cmd.exe", + Arguments = $"/C powercfg /energy /output \"{reportFilePath}\" /duration 3" + }); + Assert.IsNotNull(process, "PowerCfg process is null."); + + process.WaitForExit(); + + var report = FileOperations.ReadAllFileText(reportFilePath); + return report.Contains(processId.ToString()); + } + finally + { + FileOperations.DeleteFile(reportFilePath); + } + } + private void CheckPlayback_TickGenerator(Func createTickGeneratorCallback, TimeSpan maximumEventSendReceiveDelay) { var eventsToSend = new[] diff --git a/DryWetMidi/Devices/Clock/MidiClock.cs b/DryWetMidi/Devices/Clock/MidiClock.cs index 66de3209b..a1dacffce 100644 --- a/DryWetMidi/Devices/Clock/MidiClock.cs +++ b/DryWetMidi/Devices/Clock/MidiClock.cs @@ -34,8 +34,6 @@ public sealed class MidiClock : IDisposable private double _speed = DefaultSpeed; - private bool _started; - private readonly TickGenerator _tickGenerator; #endregion @@ -136,15 +134,11 @@ public void Start() if (IsRunning) return; - if (!_started) - _tickGenerator?.TryStart(Interval); - + _tickGenerator?.TryStart(Interval); _stopwatch.Start(); if (_startImmediately) OnTicked(); - - _started = true; } /// @@ -156,6 +150,7 @@ public void Stop() EnsureIsNotDisposed(); _stopwatch.Stop(); + _tickGenerator?.TryStop(); } /// @@ -208,6 +203,11 @@ public void Tick() OnTicked(); } + internal void StopShortly() + { + _stopwatch.Stop(); + } + private void OnTickGenerated(object sender, EventArgs e) { Tick(); diff --git a/DryWetMidi/Devices/Clock/TickGenerator/HighPrecisionTickGenerator.cs b/DryWetMidi/Devices/Clock/TickGenerator/HighPrecisionTickGenerator.cs index 8421f9559..f57543209 100644 --- a/DryWetMidi/Devices/Clock/TickGenerator/HighPrecisionTickGenerator.cs +++ b/DryWetMidi/Devices/Clock/TickGenerator/HighPrecisionTickGenerator.cs @@ -82,6 +82,12 @@ protected override void Start(TimeSpan interval) } } + protected override void Stop() + { + MidiTimerWinApi.timeEndPeriod(_resolution); + MidiTimerWinApi.timeKillEvent(_timerId); + } + #endregion #region Methods @@ -130,10 +136,7 @@ protected override void Dispose(bool disposing) } if (IsRunning) - { - MidiTimerWinApi.timeEndPeriod(_resolution); - MidiTimerWinApi.timeKillEvent(_timerId); - } + Stop(); _disposed = true; } diff --git a/DryWetMidi/Devices/Clock/TickGenerator/RegularPrecisionTickGenerator.cs b/DryWetMidi/Devices/Clock/TickGenerator/RegularPrecisionTickGenerator.cs index b23507942..e8896f12f 100644 --- a/DryWetMidi/Devices/Clock/TickGenerator/RegularPrecisionTickGenerator.cs +++ b/DryWetMidi/Devices/Clock/TickGenerator/RegularPrecisionTickGenerator.cs @@ -51,6 +51,11 @@ protected override void Start(TimeSpan interval) _timer.Start(); } + protected override void Stop() + { + _timer.Stop(); + } + #endregion #region Methods diff --git a/DryWetMidi/Devices/Clock/TickGenerator/TickGenerator.cs b/DryWetMidi/Devices/Clock/TickGenerator/TickGenerator.cs index df06f46d3..988275b5e 100644 --- a/DryWetMidi/Devices/Clock/TickGenerator/TickGenerator.cs +++ b/DryWetMidi/Devices/Clock/TickGenerator/TickGenerator.cs @@ -33,6 +33,15 @@ internal void TryStart(TimeSpan interval) IsRunning = true; } + internal void TryStop() + { + if (!IsRunning) + return; + + Stop(); + IsRunning = false; + } + /// /// Generates a tick firing the event. /// @@ -47,6 +56,8 @@ protected void GenerateTick() /// Interval between ticks. protected abstract void Start(TimeSpan interval); + protected abstract void Stop(); + #endregion #region IDisposable diff --git a/DryWetMidi/Devices/Playback/Playback.cs b/DryWetMidi/Devices/Playback/Playback.cs index 9ac8eca76..00c343355 100644 --- a/DryWetMidi/Devices/Playback/Playback.cs +++ b/DryWetMidi/Devices/Playback/Playback.cs @@ -855,7 +855,7 @@ private void OnClockTicked(object sender, EventArgs e) return; } - _clock.Stop(); + _clock.StopShortly(); _clock.ResetCurrentTime(); _eventsEnumerator.Reset(); _eventsEnumerator.MoveNext();