267 lines
9.8 KiB
C#
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;
|
|
}
|
|
}
|
|
}
|