Iām not used to writing the full code to answer the question, but considering how bored I am right now, and given that the game was played, I could not fight the desire to make a small state machine.
public class Player { private Thread Thread { get; set; } private ManualResetEventSlim Mutex { get; set; } public Player() { this.Mutex = new ManualResetEventSlim(false); this.Thread = new Thread(this.PlayThread); this.Thread.Start(); } public void Play() { this.Mutex.Set(); } public void Stop() { this.Mutex.Reset(); } private static IEnumerable<Action> PlaySong() { yield return () => Console.Beep(659, 125); yield return () => Console.Beep(659, 125); yield return () => Thread.Sleep(125); yield return () => Console.Beep(659, 125); yield return () => Thread.Sleep(167); yield return () => Console.Beep(523, 125); yield return () => Console.Beep(659, 125); yield return () => Thread.Sleep(125); yield return () => Console.Beep(784, 125); yield return () => Thread.Sleep(375); yield return () => Console.Beep(392, 125); yield return () => Thread.Sleep(375); yield return () => Console.Beep(523, 125); yield return () => Thread.Sleep(250); yield return () => Console.Beep(392, 125); yield return () => Thread.Sleep(250); yield return () => Console.Beep(330, 125); yield return () => Thread.Sleep(250); yield return () => Console.Beep(440, 125); yield return () => Thread.Sleep(125); yield return () => Console.Beep(494, 125); yield return () => Thread.Sleep(125); yield return () => Console.Beep(466, 125); yield return () => Thread.Sleep(42); yield return () => Console.Beep(440, 125); yield return () => Thread.Sleep(125); yield return () => Console.Beep(392, 125); yield return () => Thread.Sleep(125); yield return () => Console.Beep(659, 125); yield return () => Thread.Sleep(125); yield return () => Console.Beep(784, 125); yield return () => Thread.Sleep(125); yield return () => Console.Beep(880, 125); yield return () => Thread.Sleep(125); yield return () => Console.Beep(698, 125); yield return () => Console.Beep(784, 125); yield return () => Thread.Sleep(125); yield return () => Console.Beep(659, 125); yield return () => Thread.Sleep(125); yield return () => Console.Beep(523, 125); yield return () => Thread.Sleep(125); yield return () => Console.Beep(587, 125); yield return () => Console.Beep(494, 125); yield return () => Thread.Sleep(125); yield return () => Console.Beep(523, 125); yield return () => Thread.Sleep(250); yield return () => Console.Beep(392, 125); yield return () => Thread.Sleep(250); yield return () => Console.Beep(330, 125); yield return () => Thread.Sleep(250); yield return () => Console.Beep(440, 125); yield return () => Thread.Sleep(125); yield return () => Console.Beep(494, 125); yield return () => Thread.Sleep(125); yield return () => Console.Beep(466, 125); yield return () => Thread.Sleep(42); yield return () => Console.Beep(440, 125); yield return () => Thread.Sleep(125); yield return () => Console.Beep(392, 125); yield return () => Thread.Sleep(125); yield return () => Console.Beep(659, 125); yield return () => Thread.Sleep(125); yield return () => Console.Beep(784, 125); yield return () => Thread.Sleep(125); yield return () => Console.Beep(880, 125); yield return () => Thread.Sleep(125); yield return () => Console.Beep(698, 125); yield return () => Console.Beep(784, 125); yield return () => Thread.Sleep(125); yield return () => Console.Beep(659, 125); yield return () => Thread.Sleep(125); yield return () => Console.Beep(523, 125); yield return () => Thread.Sleep(125); yield return () => Console.Beep(587, 125); yield return () => Console.Beep(494, 125); yield return () => Thread.Sleep(375); yield return () => Console.Beep(784, 125); yield return () => Console.Beep(740, 125); yield return () => Console.Beep(698, 125); yield return () => Thread.Sleep(42); yield return () => Console.Beep(622, 125); yield return () => Thread.Sleep(125); yield return () => Console.Beep(659, 125); yield return () => Thread.Sleep(167); yield return () => Console.Beep(415, 125); yield return () => Console.Beep(440, 125); yield return () => Console.Beep(523, 125); yield return () => Thread.Sleep(125); yield return () => Console.Beep(440, 125); yield return () => Console.Beep(523, 125); yield return () => Console.Beep(587, 125); yield return () => Thread.Sleep(250); yield return () => Console.Beep(784, 125); yield return () => Console.Beep(740, 125); yield return () => Console.Beep(698, 125); yield return () => Thread.Sleep(42); yield return () => Console.Beep(622, 125); yield return () => Thread.Sleep(125); yield return () => Console.Beep(659, 125); yield return () => Thread.Sleep(167); yield return () => Console.Beep(698, 125); yield return () => Thread.Sleep(125); yield return () => Console.Beep(698, 125); yield return () => Console.Beep(698, 125); yield return () => Thread.Sleep(625); yield return () => Console.Beep(784, 125); yield return () => Console.Beep(740, 125); yield return () => Console.Beep(698, 125); yield return () => Thread.Sleep(42); yield return () => Console.Beep(622, 125); yield return () => Thread.Sleep(125); yield return () => Console.Beep(659, 125); yield return () => Thread.Sleep(167); yield return () => Console.Beep(415, 125); yield return () => Console.Beep(440, 125); yield return () => Console.Beep(523, 125); yield return () => Thread.Sleep(125); yield return () => Console.Beep(440, 125); yield return () => Console.Beep(523, 125); yield return () => Console.Beep(587, 125); yield return () => Thread.Sleep(250); yield return () => Console.Beep(622, 125); yield return () => Thread.Sleep(250); yield return () => Console.Beep(587, 125); yield return () => Thread.Sleep(250); yield return () => Console.Beep(523, 125); yield return () => Thread.Sleep(1125); yield return () => Console.Beep(784, 125); yield return () => Console.Beep(740, 125); yield return () => Console.Beep(698, 125); yield return () => Thread.Sleep(42); yield return () => Console.Beep(622, 125); yield return () => Thread.Sleep(125); yield return () => Console.Beep(659, 125); yield return () => Thread.Sleep(167); yield return () => Console.Beep(415, 125); yield return () => Console.Beep(440, 125); yield return () => Console.Beep(523, 125); yield return () => Thread.Sleep(125); yield return () => Console.Beep(440, 125); yield return () => Console.Beep(523, 125); yield return () => Console.Beep(587, 125); yield return () => Thread.Sleep(250); yield return () => Console.Beep(784, 125); yield return () => Console.Beep(740, 125); yield return () => Console.Beep(698, 125); yield return () => Thread.Sleep(42); yield return () => Console.Beep(622, 125); yield return () => Thread.Sleep(125); yield return () => Console.Beep(659, 125); yield return () => Thread.Sleep(167); yield return () => Console.Beep(698, 125); yield return () => Thread.Sleep(125); yield return () => Console.Beep(698, 125); yield return () => Console.Beep(698, 125); yield return () => Thread.Sleep(625); yield return () => Console.Beep(784, 125); yield return () => Console.Beep(740, 125); yield return () => Console.Beep(698, 125); yield return () => Thread.Sleep(42); yield return () => Console.Beep(622, 125); yield return () => Thread.Sleep(125); yield return () => Console.Beep(659, 125); yield return () => Thread.Sleep(167); yield return () => Console.Beep(415, 125); yield return () => Console.Beep(440, 125); yield return () => Console.Beep(523, 125); yield return () => Thread.Sleep(125); yield return () => Console.Beep(440, 125); yield return () => Console.Beep(523, 125); yield return () => Console.Beep(587, 125); yield return () => Thread.Sleep(250); yield return () => Console.Beep(622, 125); yield return () => Thread.Sleep(250); yield return () => Console.Beep(587, 125); yield return () => Thread.Sleep(250); yield return () => Console.Beep(523, 125); yield return () => Thread.Sleep(625); } private void PlayThread() { foreach (var action in PlaySong()) { if (!this.Mutex.IsSet) { this.Mutex.Wait(); } action(); } } }
Usage: create an instance of the Player class. Use the play method to play and stop the Stop method. Ideally, you would need to cancel the mutex after the song ends.