diff --git a/program/SoundLopper.cs b/program/SoundLopper.cs index a0e79cf..311d4b6 100644 --- a/program/SoundLopper.cs +++ b/program/SoundLopper.cs @@ -1,19 +1,33 @@ using System; using System.Diagnostics; using System.IO; +using System.Media; using System.Threading; public class SoundLooper : IDisposable { + // ── unix backend ── private Process _proc; - private Thread _thread; + private Thread _thread; private volatile bool _running; - private string _path; + private string _path; + + // ── windows backend ── + private SoundPlayer _player; public event Action Log; public bool IsPlaying { get { return _running; } } + private static bool IsWindows + { + get + { + var p = Environment.OSVersion.Platform; + return p != PlatformID.Unix && p != PlatformID.MacOSX; + } + } + public void Start(string wavPath) { Stop(); @@ -25,11 +39,9 @@ } _path = wavPath; - _running = true; - _thread = new Thread(LoopWorker); - _thread.IsBackground = true; - _thread.Start(); - Emit("Looping started: " + wavPath); + + if (IsWindows) StartWindows(); + else StartUnix(); } public void Stop() @@ -37,22 +49,58 @@ if (!_running) return; _running = false; + if (_player != null) + { + try { _player.Stop(); } catch { } + try { _player.Dispose(); } catch { } + _player = null; + } + try { var p = _proc; if (p != null && !p.HasExited) p.Kill(); } catch { } - _proc = null; - if (_thread != null && _thread.IsAlive) - _thread.Join(500); - + if (_thread != null && _thread.IsAlive) _thread.Join(500); _thread = null; + Emit("Looping stopped"); } + // ── windows: SoundPlayer loops natively, no thread needed ────────── + + private void StartWindows() + { + try + { + _player = new SoundPlayer(_path); + _player.Load(); // throws here if the WAV isn't plain PCM + _player.PlayLooping(); // gapless, runs until Stop() + _running = true; + Emit("Looping started (SoundPlayer): " + _path); + } + catch (Exception ex) + { + Emit("SoundPlayer failed for " + _path + ": " + ex.Message); + _player = null; + _running = false; + } + } + + // ── unix: respawn a CLI player each pass ─────────────────────────── + + private void StartUnix() + { + _running = true; + _thread = new Thread(LoopWorker); + _thread.IsBackground = true; + _thread.Start(); + Emit("Looping started (" + PlayerCommand() + "): " + _path); + } + private void LoopWorker() { while (_running) @@ -81,12 +129,12 @@ } } - private static string _player; + private static string _player_cmd; private static string PlayerCommand() { - if (_player != null) return _player; - _player = Exists("paplay") ? "paplay" : "aplay"; - return _player; + if (_player_cmd != null) return _player_cmd; + _player_cmd = Exists("paplay") ? "paplay" : "aplay"; + return _player_cmd; } private static bool Exists(string cmd)