using System;
using System.Diagnostics;
using System.IO;
using System.Threading;
public class SoundLooper : IDisposable
{
private Process _proc;
private Thread _thread;
private volatile bool _running;
private string _path;
public event Action<string> Log;
public bool IsPlaying { get { return _running; } }
public void Start(string wavPath)
{
Stop();
if (string.IsNullOrEmpty(wavPath) || !File.Exists(wavPath))
{
Emit("Sound file not found: " + wavPath);
return;
}
_path = wavPath;
_running = true;
_thread = new Thread(LoopWorker);
_thread.IsBackground = true;
_thread.Start();
Emit("Looping started: " + wavPath);
}
public void Stop()
{
if (!_running) return;
_running = false;
try
{
var p = _proc;
if (p != null && !p.HasExited) p.Kill();
}
catch { }
_proc = null;
if (_thread != null && _thread.IsAlive)
_thread.Join(500);
_thread = null;
Emit("Looping stopped");
}
private void LoopWorker()
{
while (_running)
{
try
{
var psi = new ProcessStartInfo
{
FileName = PlayerCommand(),
Arguments = "\"" + _path + "\"",
UseShellExecute = false,
RedirectStandardError = true,
RedirectStandardOutput = true,
CreateNoWindow = true
};
_proc = Process.Start(psi);
_proc.WaitForExit();
}
catch (Exception ex)
{
Emit("Playback error: " + ex.Message);
_running = false;
return;
}
}
}
private static string _player;
private static string PlayerCommand()
{
if (_player != null) return _player;
_player = Exists("paplay") ? "paplay" : "aplay";
return _player;
}
private static bool Exists(string cmd)
{
try
{
var p = Process.Start(new ProcessStartInfo
{
FileName = "which",
Arguments = cmd,
UseShellExecute = false,
RedirectStandardOutput = true
});
p.WaitForExit();
return p.ExitCode == 0;
}
catch { return false; }
}
private void Emit(string msg)
{
var h = Log;
if (h != null) h(msg);
else Console.WriteLine("[SoundLooper] " + msg);
}
public void Dispose() { Stop(); }
}