using System.Globalization; using System.IO.Ports; using System.Numerics; using System.Timers; using SoundFlow.Abstracts; using SoundFlow.Backends.MiniAudio; using SoundFlow.Components; using SoundFlow.Enums; using SoundFlow.Providers; namespace ConsolePlayer { public class Program { static SerialPort Port; static System.Timers.Timer FrameTimer; static int FramesPerTick = 6; static int ShowtapeIndex = 0; static int ControllerBits; static string ShowtapeName; static string ShowtapeFormattedLength; static bool DetectedController = false; static bool Playing = false; static bool TripFlag = false; static string[] ShowtapeFrames; public static void Main(string[] args) { Console.WriteLine("PinkConnection3 Console Player"); if (args.Length < 2) { Console.WriteLine("Not enough arguments!"); Console.WriteLine("Press any key to exit."); Console.ReadKey(); return; } if (!File.Exists(args[0])) { Console.WriteLine("Specified showtape does not exist!"); Console.WriteLine("Press any key to exit."); Console.ReadKey(); return; } if (!File.Exists(args[1])) { Console.WriteLine("Specified mapping file does not exist!"); Console.WriteLine("Press any key to exit."); Console.ReadKey(); return; } if (args.Length == 3) OpenSerialPortSpecific(args[2]); else OpenSerialPort(); if (TripFlag) return; LoadShowtape(args[0], args[1]); if (TripFlag) return; FrameTimer = new System.Timers.Timer((1000d/60d)*FramesPerTick); FrameTimer.Elapsed += PlayFrame; FrameTimer.AutoReset = true; using MiniAudioEngine audioEngine = new MiniAudioEngine(44100, Capability.Playback); using StreamDataProvider dataProvider = new StreamDataProvider(File.OpenRead("pc3playertempaudio.tmp")); SoundPlayer player = new SoundPlayer(dataProvider); Mixer.Master.AddComponent(player); Console.WriteLine($"Playing Showtape \"{ShowtapeName}\" ({ShowtapeFormattedLength})"); Playing = true; player.Play(); FrameTimer.Start(); while (Playing) Thread.Sleep(1000); Mixer.Master.RemoveComponent(player); } static void OpenSerialPortSpecific(string specifiedPortName) { string successPortName = ""; Console.WriteLine("Serial port was manually specified"); try { Console.Write("Waiting for controller"); Port = new SerialPort(specifiedPortName, 9600, Parity.None, 8, StopBits.One); Port.Open(); for (int i = 0; i < 10; i++) { if (i % 5 == 0) Console.Write("."); Port.Write("! "); Thread.Sleep(100); string readAttempt = Port.ReadExisting(); if (readAttempt.Split(",")[0] == "PC3") { ControllerBits = int.Parse(readAttempt.Split(",")[1]); DetectedController = true; successPortName = specifiedPortName; break; } } if (!DetectedController) { Console.WriteLine("\nCould not detect a PinkConnection3 controller on the specified serial port."); Console.WriteLine("Press any key to exit."); Console.ReadKey(); TripFlag = true; return; } } catch (Exception e) { Console.WriteLine("\nFailed to connect to the specified serial port."); Console.WriteLine(e.Message); Console.WriteLine("Press any key to exit."); Console.ReadKey(); TripFlag = true; return; } } static void OpenSerialPort() { string successPortName = ""; Console.Write("Searching for controller"); foreach (string portName in SerialPort.GetPortNames()) { if (DetectedController) break; try { Port = new SerialPort(portName, 9600, Parity.None, 8, StopBits.One); Port.Open(); for (int i = 0; i < 10; i++) { if (i % 5 == 0) Console.Write("."); Port.Write("! "); Thread.Sleep(100); string readAttempt = Port.ReadExisting(); if (readAttempt.Split(",")[0] == "PC3") { ControllerBits = int.Parse(readAttempt.Split(",")[1]); DetectedController = true; successPortName = portName; break; } } } catch (Exception) {} } if (!DetectedController) { Console.WriteLine("\nCould not detect a PinkConnection3 controller on any of your serial ports."); Console.WriteLine("Press any key to exit."); Console.ReadKey(); TripFlag = true; return; } Console.WriteLine("\nDetected PinkConnection3 Controller on " + successPortName); } static void LoadShowtape(string ustPath, string mappingPath) { Console.WriteLine("Loading showtape file..."); string tempMappingData = File.ReadAllText(mappingPath); if (!tempMappingData.StartsWith("PC3MAPPING;")) { Console.WriteLine("Specified mapping file is not a PinkConnection3 channel map."); Console.WriteLine("Press any key to exit."); Console.ReadKey(); TripFlag = true; return; } List targetBits = new List(); foreach (string s in tempMappingData.Split(";")[1].Split(",")) { targetBits.Add(int.Parse(s)); } if (targetBits.Count != ControllerBits) { Console.WriteLine("The mapped channel count is not equal to the connected controller's bit count."); Console.WriteLine("Press any key to exit."); Console.ReadKey(); TripFlag = true; return; } if (targetBits.Count % 4 != 0) { Console.WriteLine("The mapped channel count is not divisible by 4."); Console.WriteLine("Press any key to exit."); Console.ReadKey(); TripFlag = true; return; } string tempUSTData = File.ReadAllText(ustPath); if (!tempUSTData.StartsWith("UST,2,")) { Console.WriteLine("Specified showtape is not a UST version 2 showtape."); Console.WriteLine("Press any key to exit."); Console.ReadKey(); TripFlag = true; return; } string[] headerData = tempUSTData.Split(';')[0].Split(','); string[] stringyBits = tempUSTData.Split(';')[1].Split(','); File.WriteAllBytes("pc3playertempaudio.tmp", Convert.FromBase64String(tempUSTData.Split(';')[2])); tempUSTData = null; ShowtapeName = headerData[2]; TimeSpan time = TimeSpan.FromSeconds(stringyBits.Length/60); ShowtapeFormattedLength = time.ToString(@"hh\:mm\:ss"); List tempShowData = new List(); foreach (string stringyFrame in stringyBits) { BigInteger frame = BigInteger.Parse(stringyFrame, NumberStyles.HexNumber); int selectBit = 0; char[] frameStringOut = new char[64]; for (int i = 0; i < targetBits.Count / 4; i++) { byte quartet = 64; for (int j = 0; j < 4; j++) { if (targetBits[selectBit] == 0) continue; if ((frame & BigInteger.Pow(2, targetBits[selectBit]-1)) == BigInteger.Pow(2, targetBits[selectBit]-1)) quartet += (byte)Math.Pow(2, j); selectBit++; } frameStringOut[i] = (char)quartet; } tempShowData.Add(new string(frameStringOut).Trim()); } ShowtapeFrames = tempShowData.ToArray(); } static void PlayFrame(Object sender, ElapsedEventArgs e) { if (ShowtapeIndex >= ShowtapeFrames.Length) { FrameTimer.Stop(); Playing = false; Console.WriteLine("Complete!"); if (File.Exists("pc3playertempaudio.tmp")) File.Delete("pc3playertempaudio.tmp"); return; } Port.Write(ShowtapeFrames[ShowtapeIndex]); ShowtapeIndex += FramesPerTick; } } }