using System; using System.Diagnostics; using Microsoft.VisualBasic.CompilerServices; namespace QuikDawEditor; public class MicroStopwatch : Stopwatch { private readonly double _microSecPerTick = 1000000.0 / Frequency; public MicroStopwatch() { if (!IsHighResolution) throw new Exception("On this system the high-resolution " + "performance counter is not available"); } public long ElapsedMicroseconds { get { return Conversions.ToLong(ElapsedTicks * _microSecPerTick); } } } public class MicroTimer { public delegate void MicroTimerElapsedEventHandler(object sender, MicroTimerEventArgs timerEventArgs); public event MicroTimerElapsedEventHandler MicroTimerElapsed; private System.Threading.Thread _threadTimer = null; private long _ignoreEventIfLateBy = long.MaxValue; private long _timerIntervalInMicroSec = 0; private bool _stopTimer = true; public MicroTimer() { } public MicroTimer(long timerIntervalInMicroseconds) { Interval = timerIntervalInMicroseconds; } public long Interval { get { return System.Threading.Interlocked.Read(ref _timerIntervalInMicroSec); } set { System.Threading.Interlocked.Exchange(ref _timerIntervalInMicroSec, value); } } public long IgnoreEventIfLateBy { get { return System.Threading.Interlocked.Read(ref _ignoreEventIfLateBy); } set { System.Threading.Interlocked.Exchange(ref _ignoreEventIfLateBy, value <= 0 ? long.MaxValue : value); } } public bool Enabled { get { return _threadTimer is object && _threadTimer.IsAlive; } set { if (value) Start(); else Stop(); } } public void Start() { if (Enabled || Interval <= 0) return; _stopTimer = false; System.Threading.ThreadStart threadStart = new System.Threading.ThreadStart(() => NotificationTimer(ref _timerIntervalInMicroSec, ref _ignoreEventIfLateBy, ref _stopTimer)); _threadTimer = new System.Threading.Thread(threadStart); _threadTimer.Priority = System.Threading.ThreadPriority.Highest; _threadTimer.Start(); } public void Stop() { _stopTimer = true; } public void StopAndWait() { StopAndWait(System.Threading.Timeout.Infinite); } public bool StopAndWait(int timeoutInMilliSec) { _stopTimer = true; if (!Enabled || _threadTimer.ManagedThreadId == System.Threading.Thread.CurrentThread.ManagedThreadId) return true; return _threadTimer.Join(timeoutInMilliSec); } public void Abort() { _stopTimer = true; if (Enabled) { _threadTimer.Abort(); } } private void NotificationTimer(ref long timerIntervalInMicroSec, ref long ignoreEventIfLateBy, ref bool stopTimer) { int timerCount = 0; long nextNotification = 0; var microStopwatch = new MicroStopwatch(); microStopwatch.Start(); while (!stopTimer) { long callbackFunctionExecutionTime = microStopwatch.ElapsedMicroseconds - nextNotification; long timerIntervalInMicroSecCurrent = System.Threading.Interlocked.Read(ref timerIntervalInMicroSec); long ignoreEventIfLateByCurrent = System.Threading.Interlocked.Read(ref ignoreEventIfLateBy); nextNotification += timerIntervalInMicroSecCurrent; timerCount += 1; long elapsedMicroseconds = 0; while (InlineAssignHelper(ref elapsedMicroseconds, microStopwatch.ElapsedMicroseconds) < nextNotification) System.Threading.Thread.SpinWait(10); long timerLateBy = elapsedMicroseconds - nextNotification; if (timerLateBy >= ignoreEventIfLateByCurrent) { continue; } var microTimerEventArgs = new MicroTimerEventArgs(timerCount, elapsedMicroseconds, timerLateBy, callbackFunctionExecutionTime); MicroTimerElapsed?.Invoke(this, microTimerEventArgs); } microStopwatch.Stop(); } private static T InlineAssignHelper(ref T target, T value) { target = value; return value; } } public class MicroTimerEventArgs : EventArgs { // Simple counter, number times timed event (callback function) executed public int TimerCount { get { return m_TimerCount; } private set { m_TimerCount = value; } } private int m_TimerCount; // Time when timed event was called since timer started public long ElapsedMicroseconds { get { return m_ElapsedMicroseconds; } private set { m_ElapsedMicroseconds = value; } } private long m_ElapsedMicroseconds; // How late the timer was compared to when it should have been called public long TimerLateBy { get { return m_TimerLateBy; } private set { m_TimerLateBy = value; } } private long m_TimerLateBy; // Time it took to execute previous call to callback function (OnTimedEvent) public long CallbackFunctionExecutionTime { get { return m_CallbackFunctionExecutionTime; } private set { m_CallbackFunctionExecutionTime = value; } } private long m_CallbackFunctionExecutionTime; public MicroTimerEventArgs(int timerCount__1, long elapsedMicroseconds__2, long timerLateBy__3, long callbackFunctionExecutionTime__4) { TimerCount = timerCount__1; ElapsedMicroseconds = elapsedMicroseconds__2; TimerLateBy = timerLateBy__3; CallbackFunctionExecutionTime = callbackFunctionExecutionTime__4; } }