PinkConnection2/ConsolePlayer/Program.cs

267 lines
9.8 KiB
C#

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<int> targetBits = new List<int>();
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<string> tempShowData = new List<string>();
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;
}
}
}