From a99ced1ad12507306f68e89d20bed3f8c12be277 Mon Sep 17 00:00:00 2001 From: Persephone Bubblegum-Holiday Date: Tue, 1 Jul 2025 19:04:25 -0700 Subject: [PATCH] add new player and new firmware --- .gitignore | 1 + .../Firmware-32Valve-Mega.ino | 6 +- .../Firmware-8Valve/Firmware-8Valve.ino | 6 +- .../Firmware-Servo-ChuckEHelenGuestStar.ino | 6 +- .../Firmware-Servo-HelenMitzi.ino | 6 +- ConsolePlayer/ConsolePlayer.csproj | 15 + ConsolePlayer/Program.cs | 267 ++++++++++++++++++ .../channel mappings/BeachBearJasper.pcm | 1 + ConsolePlayer/channel mappings/BillyBob.pcm | 1 + ConsolePlayer/channel mappings/CyberChuck.pcm | 1 + ConsolePlayer/channel mappings/CyberHelen.pcm | 1 + .../channel mappings/CyberJasper.pcm | 1 + ConsolePlayer/channel mappings/CyberMunch.pcm | 1 + .../channel mappings/CyberPasqually.pcm | 1 + .../channel mappings/DookPasqually.pcm | 1 + ConsolePlayer/channel mappings/FatzMunch.pcm | 1 + ConsolePlayer/channel mappings/MitziHelen.pcm | 1 + ConsolePlayer/channel mappings/RolfeChuck.pcm | 1 + Future Goals.md | 2 +- 19 files changed, 315 insertions(+), 5 deletions(-) create mode 100644 ConsolePlayer/ConsolePlayer.csproj create mode 100644 ConsolePlayer/Program.cs create mode 100644 ConsolePlayer/channel mappings/BeachBearJasper.pcm create mode 100644 ConsolePlayer/channel mappings/BillyBob.pcm create mode 100644 ConsolePlayer/channel mappings/CyberChuck.pcm create mode 100644 ConsolePlayer/channel mappings/CyberHelen.pcm create mode 100644 ConsolePlayer/channel mappings/CyberJasper.pcm create mode 100644 ConsolePlayer/channel mappings/CyberMunch.pcm create mode 100644 ConsolePlayer/channel mappings/CyberPasqually.pcm create mode 100644 ConsolePlayer/channel mappings/DookPasqually.pcm create mode 100644 ConsolePlayer/channel mappings/FatzMunch.pcm create mode 100644 ConsolePlayer/channel mappings/MitziHelen.pcm create mode 100644 ConsolePlayer/channel mappings/RolfeChuck.pcm diff --git a/.gitignore b/.gitignore index a320c3c..9f5642d 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,4 @@ */obj/ */*/*/bin/ */*/*/obj/ +*.tmp diff --git a/Arduino Firmware/Firmware-32Valve-Mega/Firmware-32Valve-Mega.ino b/Arduino Firmware/Firmware-32Valve-Mega/Firmware-32Valve-Mega.ino index 401c848..2dabcad 100644 --- a/Arduino Firmware/Firmware-32Valve-Mega/Firmware-32Valve-Mega.ino +++ b/Arduino Firmware/Firmware-32Valve-Mega/Firmware-32Valve-Mega.ino @@ -13,7 +13,6 @@ void setup() { for (int i = 22; i <= 53; i++) pinMode(i, OUTPUT); Serial.begin(9600); - Serial.write("PC2,32,Universal,END"); } void loop() @@ -29,6 +28,11 @@ void loop() byte7 = Serial.read(); byte8 = Serial.read(); + if ((byte1 & 32) && (byte2 & 32)) + { + if (byte1 & 1) Serial.write("PC3,32\n"); + } + if ((byte1 & 64) && (byte2 & 64) && (byte3 & 64) && (byte4 & 64) && (byte5 & 64) && (byte6 & 64) && (byte7 & 64) && (byte8 & 64)) { if (byte1 & 1) digitalWrite(22, 1); diff --git a/Arduino Firmware/Firmware-8Valve/Firmware-8Valve.ino b/Arduino Firmware/Firmware-8Valve/Firmware-8Valve.ino index 9c4fd69..6054452 100644 --- a/Arduino Firmware/Firmware-8Valve/Firmware-8Valve.ino +++ b/Arduino Firmware/Firmware-8Valve/Firmware-8Valve.ino @@ -14,7 +14,6 @@ void setup() pinMode(8, OUTPUT); pinMode(9, OUTPUT); Serial.begin(9600); - Serial.write("PC2,8,Universal,END"); } void loop() @@ -24,6 +23,11 @@ void loop() byte1 = Serial.read(); byte2 = Serial.read(); + if ((byte1 & 32) && (byte2 & 32)) + { + if (byte1 & 1) Serial.write("PC3,8\n"); + } + if ((byte1 & 64) && (byte2 & 64)) { if (byte1 & 1) digitalWrite(2, 1); diff --git a/Arduino Firmware/Servo/Firmware-Servo-ChuckEHelenGuestStar/Firmware-Servo-ChuckEHelenGuestStar.ino b/Arduino Firmware/Servo/Firmware-Servo-ChuckEHelenGuestStar/Firmware-Servo-ChuckEHelenGuestStar.ino index 17c095e..9b60dda 100644 --- a/Arduino Firmware/Servo/Firmware-Servo-ChuckEHelenGuestStar/Firmware-Servo-ChuckEHelenGuestStar.ino +++ b/Arduino Firmware/Servo/Firmware-Servo-ChuckEHelenGuestStar/Firmware-Servo-ChuckEHelenGuestStar.ino @@ -20,7 +20,6 @@ void setup() servoChannel[5].attach(7); for (int i = 0; i < 8; i++) servoChannel[mapping[i]].write(offDegrees[i]); Serial.begin(9600); - Serial.write("PC2,8,Chuck E./Helen/Guest Star,END"); } void loop() @@ -30,6 +29,11 @@ void loop() byte1 = Serial.read(); byte2 = Serial.read(); + if ((byte1 & 32) && (byte2 & 32)) + { + if (byte1 & 1) Serial.write("PC3,8\n"); + } + if ((byte1 & 64) && (byte2 & 64)) { if (byte1 & 1) servoChannel[mapping[0]].write(onDegrees[0]); diff --git a/Arduino Firmware/Servo/Firmware-Servo-HelenMitzi/Firmware-Servo-HelenMitzi.ino b/Arduino Firmware/Servo/Firmware-Servo-HelenMitzi/Firmware-Servo-HelenMitzi.ino index e17e30c..dc07f62 100644 --- a/Arduino Firmware/Servo/Firmware-Servo-HelenMitzi/Firmware-Servo-HelenMitzi.ino +++ b/Arduino Firmware/Servo/Firmware-Servo-HelenMitzi/Firmware-Servo-HelenMitzi.ino @@ -29,7 +29,6 @@ void setup() servoChannel[8].attach(10); for (int i = 0; i < 19; i++) servoChannel[mapping[i]].write(offDegrees[i]); Serial.begin(9600); - Serial.write("PC2,32,Mitzi/Helen,END"); } void loop() { @@ -44,6 +43,11 @@ void loop() { byte7 = Serial.read(); byte8 = Serial.read(); + if ((byte1 & 32) && (byte2 & 32)) + { + if (byte1 & 1) Serial.write("PC3,8\n"); + } + if ((byte1 & 64) && (byte2 & 64) && (byte3 & 64) && (byte4 & 64) && (byte5 & 64)) { if (byte1 & 1) servoChannel[mapping[0]].write(onDegrees[0]); diff --git a/ConsolePlayer/ConsolePlayer.csproj b/ConsolePlayer/ConsolePlayer.csproj new file mode 100644 index 0000000..c461e59 --- /dev/null +++ b/ConsolePlayer/ConsolePlayer.csproj @@ -0,0 +1,15 @@ + + + + Exe + net8.0 + enable + enable + + + + + + + + diff --git a/ConsolePlayer/Program.cs b/ConsolePlayer/Program.cs new file mode 100644 index 0000000..50616e1 --- /dev/null +++ b/ConsolePlayer/Program.cs @@ -0,0 +1,267 @@ +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; + } + } +} diff --git a/ConsolePlayer/channel mappings/BeachBearJasper.pcm b/ConsolePlayer/channel mappings/BeachBearJasper.pcm new file mode 100644 index 0000000..f25db0c --- /dev/null +++ b/ConsolePlayer/channel mappings/BeachBearJasper.pcm @@ -0,0 +1 @@ +PC3MAPPING;58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 diff --git a/ConsolePlayer/channel mappings/BillyBob.pcm b/ConsolePlayer/channel mappings/BillyBob.pcm new file mode 100644 index 0000000..d2f42d2 --- /dev/null +++ b/ConsolePlayer/channel mappings/BillyBob.pcm @@ -0,0 +1 @@ +PC3MAPPING;91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,0,0,0,0,0,0,0,0,0,0,0,0 diff --git a/ConsolePlayer/channel mappings/CyberChuck.pcm b/ConsolePlayer/channel mappings/CyberChuck.pcm new file mode 100644 index 0000000..7225c89 --- /dev/null +++ b/ConsolePlayer/channel mappings/CyberChuck.pcm @@ -0,0 +1 @@ +PC3MAPPING;1,2,3,4,5,6,7,8 diff --git a/ConsolePlayer/channel mappings/CyberHelen.pcm b/ConsolePlayer/channel mappings/CyberHelen.pcm new file mode 100644 index 0000000..71bd573 --- /dev/null +++ b/ConsolePlayer/channel mappings/CyberHelen.pcm @@ -0,0 +1 @@ +PC3MAPPING;9,10,11,12,13,14,15,16 diff --git a/ConsolePlayer/channel mappings/CyberJasper.pcm b/ConsolePlayer/channel mappings/CyberJasper.pcm new file mode 100644 index 0000000..103181b --- /dev/null +++ b/ConsolePlayer/channel mappings/CyberJasper.pcm @@ -0,0 +1 @@ +PC3MAPPING;25,26,27,28,29,30,31,32 diff --git a/ConsolePlayer/channel mappings/CyberMunch.pcm b/ConsolePlayer/channel mappings/CyberMunch.pcm new file mode 100644 index 0000000..8338e88 --- /dev/null +++ b/ConsolePlayer/channel mappings/CyberMunch.pcm @@ -0,0 +1 @@ +PC3MAPPING;17,18,19,20,21,22,23,24 diff --git a/ConsolePlayer/channel mappings/CyberPasqually.pcm b/ConsolePlayer/channel mappings/CyberPasqually.pcm new file mode 100644 index 0000000..eac80d9 --- /dev/null +++ b/ConsolePlayer/channel mappings/CyberPasqually.pcm @@ -0,0 +1 @@ +PC3MAPPING;33,34,35,36,37,38,39,40 diff --git a/ConsolePlayer/channel mappings/DookPasqually.pcm b/ConsolePlayer/channel mappings/DookPasqually.pcm new file mode 100644 index 0000000..19b2875 --- /dev/null +++ b/ConsolePlayer/channel mappings/DookPasqually.pcm @@ -0,0 +1 @@ +PC3MAPPING;74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 diff --git a/ConsolePlayer/channel mappings/FatzMunch.pcm b/ConsolePlayer/channel mappings/FatzMunch.pcm new file mode 100644 index 0000000..b9ea160 --- /dev/null +++ b/ConsolePlayer/channel mappings/FatzMunch.pcm @@ -0,0 +1 @@ +PC3MAPPING;42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 diff --git a/ConsolePlayer/channel mappings/MitziHelen.pcm b/ConsolePlayer/channel mappings/MitziHelen.pcm new file mode 100644 index 0000000..40eed4d --- /dev/null +++ b/ConsolePlayer/channel mappings/MitziHelen.pcm @@ -0,0 +1 @@ +PC3MAPPING;23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,0,0,0,0,0,0,0,0,0,0,0,0,0 diff --git a/ConsolePlayer/channel mappings/RolfeChuck.pcm b/ConsolePlayer/channel mappings/RolfeChuck.pcm new file mode 100644 index 0000000..72b6811 --- /dev/null +++ b/ConsolePlayer/channel mappings/RolfeChuck.pcm @@ -0,0 +1 @@ +PC3MAPPING;1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,0,0,0,0,0,0,0,0,0,0 diff --git a/Future Goals.md b/Future Goals.md index de584cb..54cdff2 100644 --- a/Future Goals.md +++ b/Future Goals.md @@ -9,7 +9,7 @@ ## PC2Player - - burn the damn thing to the ground and start over + - ~~burn the damn thing to the ground and start over~~ Done! ## Firmwares