Skip to content

Instantly share code, notes, and snippets.

@Ruffo324
Last active October 30, 2020 23:05
Show Gist options
  • Save Ruffo324/f998c38ceff27c1eaebe5b489188c66d to your computer and use it in GitHub Desktop.
Save Ruffo324/f998c38ceff27c1eaebe5b489188c66d to your computer and use it in GitHub Desktop.
AfLooper - Simple 'afplay' wrapper with looping function for .NET Core
using System;
using System.Diagnostics;
using System.Threading;
using System.Threading.Tasks;
public class AfLooper
{
// Value between 0 - 100.
public decimal Volume
{
get => _volume;
set
{
if (value == Volume) return;
_volume = value;
UpdateAfPlayArgs();
}
}
public string FilePath
{
get => _filePath;
set
{
if (value == FilePath) return;
_filePath = value;
UpdateAfPlayArgs();
}
}
public bool Loop
{
get => _loop;
set
{
if (value == Loop) return;
_loop = value;
}
}
private CancellationTokenSource _cancellation = new CancellationTokenSource();
private string _filePath;
private decimal _volume;
private readonly ProcessStartInfo _processInfo = new ProcessStartInfo
{
FileName = "afplay",
ErrorDialog = false,
UseShellExecute = true
};
private Process _process;
private bool _loop;
public bool IsRunning => !_cancellation.IsCancellationRequested;
public AfLooper(string filePath, decimal volume = 50, bool loop = true)
{
_filePath = filePath ?? throw new ArgumentNullException(nameof(filePath));
_volume = volume;
_loop = loop;
UpdateAfPlayArgs();
}
private void UpdateAfPlayArgs()
{
_processInfo.Arguments = $"-v {_volume / 100:F3} '{_filePath}'";
if (IsRunning)
ReStart();
}
public void ReStart() => Start();
public void Start()
{
Stop();
_cancellation = new CancellationTokenSource();
new Task(() =>
{
while (!_cancellation.IsCancellationRequested)
try
{
_process = Process.Start(_processInfo);
_process?.WaitForExit();
if (!_loop)
Stop();
}
catch (Exception)
{
// ignored.
}
}).Start();
}
/// <summary>
/// Forces the current playback to stop immediately.
/// </summary>
public void Stop()
{
_cancellation?.Cancel();
if (_process is Process p && !p.HasExited)
p.Kill();
}
/// <summary>
/// Just stops repeating the audio file,
/// and waits until 'afplay' is done with the playback.
/// </summary>
public void SoftStop()
{
_cancellation?.Cancel();
}
}
using System;
using System.Threading.Tasks;
namespace ConsolePlayground
{
// Example class
internal static class MainClass
{
public static async Task Main(string[] args)
{
var frog = @"/System/Library/Sounds/Frog.aiff";
var submarine = @"/System/Library/Sounds/Submarine.aiff";
var purr = @"/System/Library/Sounds/Purr.aiff";
var audioPlayer = new AfLooper(purr, 10);
// Loop disabled play.
audioPlayer.Loop = true;
audioPlayer.Start();
await Task.Delay(TimeSpan.FromSeconds(2));
// Re-enabled looping play.
audioPlayer.Loop = false;
audioPlayer.Start();
// Stop Start test.
await Task.Delay(TimeSpan.FromSeconds(2));
audioPlayer.Stop();
await Task.Delay(TimeSpan.FromSeconds(2));
audioPlayer.Start();
// Change file runtime test.
await Task.Delay(TimeSpan.FromSeconds(2));
audioPlayer.FilePath = submarine;
await Task.Delay(TimeSpan.FromSeconds(2));
audioPlayer.FilePath = frog;
await Task.Delay(TimeSpan.FromSeconds(2));
audioPlayer.SoftStop();
audioPlayer.FilePath = purr;
await Task.Delay(TimeSpan.FromSeconds(2));
audioPlayer.Start();
// change volume up, and down after.
for (var i = 0; i < 100; i++)
{
audioPlayer.Volume = i;
await Task.Delay(TimeSpan.FromMilliseconds(50));
}
for (var i = 100 - 1; i >= 0; i--)
{
audioPlayer.Volume = i;
await Task.Delay(TimeSpan.FromMilliseconds(50));
}
audioPlayer.SoftStop();
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment