Compare commits

...

27 commits

Author SHA1 Message Date
d7c01b93d5 various improvements and fixes 2025-07-07 20:36:00 -07:00
72cc742e84 the future looks bright to me 2025-07-07 16:18:33 -07:00
50043fd750 fix some small bugs, add the ability to pause, add a resync timer 2025-07-01 21:00:15 -07:00
e696efbddd small fix for 32 channel firmwares 2025-07-01 19:10:42 -07:00
a99ced1ad1 add new player and new firmware 2025-07-01 19:04:25 -07:00
b9fd99de54 Update MainForm.cs 2025-06-01 14:10:28 -07:00
d44ae82757 further clean up stuff 2025-06-01 14:00:22 -07:00
5d216840db discontinue single character file format 2025-06-01 13:55:57 -07:00
4ec6533971 add studio c bit maps to converter 2025-06-01 13:23:21 -07:00
7896e1d0a3 oops 2025-06-01 13:04:15 -07:00
424d9331cd studio c 2025-06-01 13:00:52 -07:00
91aa378769 Update MainForm.cs 2025-05-31 23:28:48 -07:00
a79a5e54c5 cybers bit mappings in converter 2025-05-31 23:28:23 -07:00
1d387b5679 finish cybers bit mapping 2025-05-31 20:19:26 -07:00
6678780ef6 full 3 stage bit map and 256 bit conversion 2025-05-26 19:21:00 -07:00
1cb4b77f9a complete bit mapping for 3st/rae 2025-05-26 18:25:47 -07:00
0ed3491e3f add option to compress audio to mp3 when converting rshw 2025-05-26 08:59:59 -07:00
29799820e2 update goals file 2025-05-18 11:07:18 -07:00
f756c70c1c arduino mega 2025-05-11 12:39:24 -07:00
f167c0fcb1 i should maybe actually test these things 2025-05-11 09:38:50 -07:00
6f53e6dab4 thank you lexi for your wonderful improvement 2025-05-10 22:02:21 -07:00
31bedffa29 fix helen fw mappings 2025-05-10 17:25:48 -07:00
854d6e4c37 handle on process 2025-05-10 14:11:37 -07:00
1fb697626e player kinda works 2025-05-10 14:02:28 -07:00
8ef01ea1aa Update ServoWorker.ino 2025-05-05 19:38:13 -07:00
271be04b98 Update Firmware-Servo-ChuckEHelenGuestStar.ino 2025-05-05 19:36:58 -07:00
7ee8214615 update firmwares to send info to controlling computer 2025-05-05 19:08:45 -07:00
75 changed files with 7513 additions and 664 deletions

1
.gitignore vendored
View file

@ -4,3 +4,4 @@
*/obj/ */obj/
*/*/*/bin/ */*/*/bin/
*/*/*/obj/ */*/*/obj/
*.tmp

View file

@ -0,0 +1,146 @@
// PINKCONNECTION2 Client Program for 32 Valve Systems (Arduino Mega)
int byte1 = 0;
int byte2 = 0;
int byte3 = 0;
int byte4 = 0;
int byte5 = 0;
int byte6 = 0;
int byte7 = 0;
int byte8 = 0;
void setup()
{
for (int i = 22; i <= 53; i++) pinMode(i, OUTPUT);
Serial.begin(9600);
}
void loop()
{
if (Serial.available() > 7)
{
byte1 = Serial.read();
byte2 = Serial.read();
if ((byte1 & 32) && (byte2 & 32))
{
if (byte1 & 1) Serial.write("PC3,32\n");
}
else
{
byte3 = Serial.read();
byte4 = Serial.read();
byte5 = Serial.read();
byte6 = Serial.read();
byte7 = Serial.read();
byte8 = Serial.read();
}
if ((byte1 & 64) && (byte2 & 64) && (byte3 & 64) && (byte4 & 64) && (byte5 & 64) && (byte6 & 64) && (byte7 & 64) && (byte8 & 64))
{
if (byte1 & 1) digitalWrite(22, 1);
else digitalWrite(22, 0);
if (byte1 & 2) digitalWrite(23, 1);
else digitalWrite(23, 0);
if (byte1 & 4) digitalWrite(24, 1);
else digitalWrite(24, 0);
if (byte1 & 8) digitalWrite(25, 1);
else digitalWrite(25, 0);
if (byte2 & 1) digitalWrite(26, 1);
else digitalWrite(26, 0);
if (byte2 & 2) digitalWrite(27, 1);
else digitalWrite(27, 0);
if (byte2 & 4) digitalWrite(28, 1);
else digitalWrite(28, 0);
if (byte2 & 8) digitalWrite(29, 1);
else digitalWrite(29, 0);
if (byte3 & 1) digitalWrite(30, 1);
else digitalWrite(30, 0);
if (byte3 & 2) digitalWrite(31, 1);
else digitalWrite(31, 0);
if (byte3 & 4) digitalWrite(32, 1);
else digitalWrite(32, 0);
if (byte3 & 8) digitalWrite(33, 1);
else digitalWrite(33, 0);
if (byte4 & 1) digitalWrite(34, 1);
else digitalWrite(34, 0);
if (byte4 & 2) digitalWrite(35, 1);
else digitalWrite(35, 0);
if (byte4 & 4) digitalWrite(36, 1);
else digitalWrite(36, 0);
if (byte4 & 8) digitalWrite(37, 1);
else digitalWrite(37, 0);
if (byte5 & 1) digitalWrite(38, 1);
else digitalWrite(22, 0);
if (byte5 & 2) digitalWrite(39, 1);
else digitalWrite(23, 0);
if (byte5 & 4) digitalWrite(40, 1);
else digitalWrite(24, 0);
if (byte5 & 8) digitalWrite(41, 1);
else digitalWrite(25, 0);
if (byte6 & 1) digitalWrite(42, 1);
else digitalWrite(42, 0);
if (byte6 & 2) digitalWrite(43, 1);
else digitalWrite(43, 0);
if (byte6 & 4) digitalWrite(44, 1);
else digitalWrite(44, 0);
if (byte6 & 8) digitalWrite(45, 1);
else digitalWrite(45, 0);
if (byte7 & 1) digitalWrite(46, 1);
else digitalWrite(46, 0);
if (byte7 & 2) digitalWrite(47, 1);
else digitalWrite(47, 0);
if (byte7 & 4) digitalWrite(48, 1);
else digitalWrite(48, 0);
if (byte7 & 8) digitalWrite(49, 1);
else digitalWrite(49, 0);
if (byte8 & 1) digitalWrite(50, 1);
else digitalWrite(50, 0);
if (byte8 & 2) digitalWrite(51, 1);
else digitalWrite(51, 0);
if (byte8 & 4) digitalWrite(52, 1);
else digitalWrite(52, 0);
if (byte8 & 8) digitalWrite(53, 1);
else digitalWrite(53, 0);
}
}
}

View file

@ -1,9 +1,10 @@
// PINKCONNECTION2 Client Program for Valve Systems // PINKCONNECTION2 Client Program for 8 Valve Systems
int byte1 = 0; int byte1 = 0;
int byte2 = 0; int byte2 = 0;
void setup() { void setup()
{
pinMode(2, OUTPUT); pinMode(2, OUTPUT);
pinMode(3, OUTPUT); pinMode(3, OUTPUT);
pinMode(4, OUTPUT); pinMode(4, OUTPUT);
@ -15,11 +16,20 @@ void setup() {
Serial.begin(9600); Serial.begin(9600);
} }
void loop() { void loop()
if (Serial.available() > 1) { {
if (Serial.available() > 1)
{
byte1 = Serial.read(); byte1 = Serial.read();
byte2 = Serial.read(); byte2 = Serial.read();
if ((byte1 & 64) && (byte2 & 64)) {
if ((byte1 & 32) && (byte2 & 32))
{
if (byte1 & 1) Serial.write("PC3,8\n");
}
if ((byte1 & 64) && (byte2 & 64))
{
if (byte1 & 1) digitalWrite(2, 1); if (byte1 & 1) digitalWrite(2, 1);
else digitalWrite(2, 0); else digitalWrite(2, 0);

View file

@ -1,104 +0,0 @@
// PINKCONNECTION2 Client Program for Helen Henny/Chuck E./Guest Star Cyberamic Servo
#include <Servo.h>
#include <string.h>
Servo servoChannel[8];
byte onDegrees[8] = { 90, 0, 0, 0, 45, 135, 0, 0 }; // these are incomplete, i need to tune them when i get the servos in
byte offDegrees[8] = { 0, 0, 0, 0, 90, 90, 0, 0 };
int byte1 = 0;
int byte2 = 0;
void setup() {
servoChannel[0].attach(2);
servoChannel[1].attach(3);
servoChannel[2].attach(4);
servoChannel[3].attach(5);
servoChannel[4].attach(6);
servoChannel[5].attach(7);
servoChannel[6].attach(8);
servoChannel[7].attach(9);
pinMode(A0, OUTPUT);
pinMode(A1, OUTPUT);
pinMode(A2, OUTPUT);
pinMode(A3, OUTPUT);
pinMode(A4, OUTPUT);
pinMode(A5, OUTPUT);
pinMode(10, OUTPUT);
pinMode(11, OUTPUT);
for (int i = 0; i < 8; i++) servoChannel[i].write(offDegrees[i]);
Serial.begin(9600);
}
void loop() {
if (Serial.available() > 1) {
byte1 = Serial.read();
byte2 = Serial.read();
if ((byte1 & 64) && (byte2 & 64))
if (byte1 & 1) {
servoChannel[0].write(onDegrees[0]);
digitalWrite(A0, 1);
} else {
servoChannel[0].write(offDegrees[0]);
digitalWrite(A0, 0);
}
if (byte1 & 2) {
servoChannel[1].write(onDegrees[1]);
digitalWrite(A1, 1);
} else {
servoChannel[1].write(offDegrees[1]);
digitalWrite(A1, 0);
}
if (byte1 & 4) {
servoChannel[2].write(onDegrees[2]);
digitalWrite(A2, 1);
} else {
servoChannel[2].write(offDegrees[2]);
digitalWrite(A2, 0);
}
if (byte1 & 8) {
servoChannel[2].write(onDegrees[3]);
digitalWrite(A3, 1);
} else {
//servoChannel[2].write(offDegrees[3]); dont
digitalWrite(A3, 0);
}
if (byte2 & 1) {
servoChannel[4].write(onDegrees[4]);
digitalWrite(A4, 1);
} else {
servoChannel[4].write(offDegrees[4]);
digitalWrite(A4, 0);
}
if (byte2 & 2) {
servoChannel[4].write(onDegrees[5]);
digitalWrite(A5, 1);
} else {
//servoChannel[4].write(offDegrees[5]); dont
digitalWrite(A5, 0);
}
if (byte2 & 4) {
servoChannel[6].write(onDegrees[6]);
digitalWrite(10, 1);
} else {
servoChannel[6].write(offDegrees[6]);
digitalWrite(10, 0);
}
if (byte2 & 8) {
servoChannel[7].write(onDegrees[7]);
digitalWrite(11, 1);
} else {
servoChannel[7].write(offDegrees[7]);
digitalWrite(11, 0);
}
}
}

View file

@ -0,0 +1,65 @@
// PINKCONNECTION2 Client Program for Helen Henny/Chuck E./Guest Star Cyberamic Servo
#include <Servo.h>
Servo servoChannel[6];
byte onDegrees[8] = { 90, 0, 0, 0, 45, 135, 0, 0 }; // these are incomplete
byte offDegrees[8] = { 0 , 0, 0, 0, 90, 90 , 0, 0 };
byte mapping[8] = { 0 , 1, 1, 2, 3 , 3 , 4, 5 };
int byte1 = 0;
int byte2 = 0;
void setup()
{
servoChannel[0].attach(2);
servoChannel[1].attach(3);
servoChannel[2].attach(4);
servoChannel[3].attach(5);
servoChannel[4].attach(6);
servoChannel[5].attach(7);
for (int i = 0; i < 8; i++) servoChannel[mapping[i]].write(offDegrees[i]);
Serial.begin(9600);
}
void loop()
{
if (Serial.available() > 1)
{
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]);
else servoChannel[mapping[0]].write(offDegrees[0]);
if (byte1 & 2) servoChannel[mapping[1]].write(onDegrees[1]);
else servoChannel[mapping[1]].write(offDegrees[1]);
if (byte1 & 4) servoChannel[mapping[2]].write(onDegrees[2]);
else servoChannel[mapping[2]].write(offDegrees[2]);
if (byte1 & 8) servoChannel[mapping[3]].write(onDegrees[3]);
else servoChannel[mapping[3]].write(offDegrees[3]);
if (byte2 & 1) servoChannel[mapping[4]].write(onDegrees[4]);
else servoChannel[mapping[4]].write(offDegrees[4]);
if (byte2 & 2) servoChannel[mapping[5]].write(onDegrees[5]);
else servoChannel[mapping[5]].write(offDegrees[5]);
if (byte2 & 4) servoChannel[mapping[6]].write(onDegrees[6]);
else servoChannel[mapping[6]].write(offDegrees[6]);
if (byte2 & 8) servoChannel[mapping[7]].write(onDegrees[7]);
else servoChannel[mapping[7]].write(offDegrees[7]);
}
}
}

View file

@ -1,20 +1,23 @@
// PINKCONNECTION2 Client Program for Helen Henny/Mitzi Mozzarella Servo // PINKCONNECTION2 Client Program for Helen Henny/Mitzi Mozzarella Servo
#include <Servo.h> #include <Servo.h>
#include <string.h>
Servo servoChannel[11]; // mouth earL earR eyelidL eyelidR eyeL eyeR headR headL headUp armUpL armUpR elbowR elbowL armTwistL armTwistR bodyTwistR bodyTwistL bodyLean Servo servoChannel[11]; // mouth earL earR eyelidL eyelidR eyeL eyeR headL headR headUp armUpL armTwistL elbowL armUpR armTwistR elbowR bodyTwistR bodyTwistL bodyLean
byte onDegrees[19] = { 45, 0, 0, 0, 0, 0, 0, 45, 135, 135, 90, 90, 90, 90, 90, 90, 0, 0, 0 }; byte onDegrees[19] = { 45, 0, 0, 0, 0, 0, 0, 135, 45, 135, 90, 90, 90, 90, 90, 90, 0, 0, 0 };
byte offDegrees[19] = { 0, 0, 0, 0, 0, 0, 0, 90, 90, 90, 180, 0, 0, 180, 180, 0 , 0, 0, 0 }; byte offDegrees[19] = { 0, 0, 0, 0, 0, 0, 0, 90, 90, 90, 180, 180, 180, 0, 0, 0 , 0, 0, 0 };
byte mapping[19] = { 0, 0, 0, 0, 0, 0, 0, 2, 2, 1, 6, 3, 4, 7, 8, 5, 0, 0, 0 }; byte mapping[19] = { 0, 0, 0, 0, 0, 0, 0, 2, 2, 1, 3, 4, 5, 6, 7, 8, 9, 9, 10 };
int byte1 = 0; int byte1 = 0;
int byte2 = 0; int byte2 = 0;
int byte3 = 0; int byte3 = 0;
int byte4 = 0; int byte4 = 0;
int byte5 = 0; int byte5 = 0;
int byte6 = 0;
int byte7 = 0;
int byte8 = 0;
void setup() { void setup()
{
servoChannel[0].attach(2); servoChannel[0].attach(2);
servoChannel[1].attach(3); servoChannel[1].attach(3);
servoChannel[2].attach(4); servoChannel[2].attach(4);
@ -29,12 +32,25 @@ void setup() {
} }
void loop() { void loop() {
if (Serial.available() > 4) { if (Serial.available() > 7)
{
byte1 = Serial.read(); byte1 = Serial.read();
byte2 = Serial.read(); byte2 = Serial.read();
byte3 = Serial.read();
byte4 = Serial.read(); if ((byte1 & 32) && (byte2 & 32))
byte5 = Serial.read(); {
if (byte1 & 1) Serial.write("PC3,8\n");
}
else
{
byte3 = Serial.read();
byte4 = Serial.read();
byte5 = Serial.read();
byte6 = Serial.read();
byte7 = Serial.read();
byte8 = Serial.read();
}
if ((byte1 & 64) && (byte2 & 64) && (byte3 & 64) && (byte4 & 64) && (byte5 & 64)) if ((byte1 & 64) && (byte2 & 64) && (byte3 & 64) && (byte4 & 64) && (byte5 & 64))
{ {

View file

@ -1,4 +1,4 @@
// tp1sm // Ensure that a servo works, and get it to its 0 position
#include <Servo.h> #include <Servo.h>
@ -14,5 +14,5 @@ void loop()
servoChannel.write(0); servoChannel.write(0);
delay(1000); delay(1000);
servoChannel.write(180); servoChannel.write(180);
delay(1000); delay(2000);
} }

View file

@ -1,4 +1,4 @@
# PINKCONNECTION2 Bit Mappings # UST Bit Mappings
This information was sourced from Cheese-E-Pedia, the Showbiz Pizza Cyberstar Install Manual, and the Chuck E. Cheese 2-Stage Install Manual. This information was sourced from Cheese-E-Pedia, the Showbiz Pizza Cyberstar Install Manual, and the Chuck E. Cheese 2-Stage Install Manual.
@ -6,7 +6,7 @@ This information was sourced from Cheese-E-Pedia, the Showbiz Pizza Cyberstar In
### Rolfe Dewolfe & Earl Schmerle/Chuck E. Cheese ### Rolfe Dewolfe & Earl Schmerle/Chuck E. Cheese
| Movement Name | UST Single Character Bit | UST Full Stage Bit | RR Engine Bit | Greybox Bit | R12 Bit | R12 Inverted | | Movement Name | UST Character Bit | UST Full Stage Bit | RR Engine Bit | Greybox Bit | R12 Bit | R12 Inverted |
| --------------- | ------------------------ | ------------------ | ------------- | ----------- | ------------ | ------------ | | --------------- | ------------------------ | ------------------ | ------------- | ----------- | ------------ | ------------ |
| Mouth | 1 | 1 | 1 | 1-1 | TB1 1-2 H1 | No | | Mouth | 1 | 1 | 1 | 1-1 | TB1 1-2 H1 | No |
| Left Ear | 2 | 2 | 9 | 1-9 | | | | Left Ear | 2 | 2 | 9 | 1-9 | | |
@ -17,7 +17,7 @@ This information was sourced from Cheese-E-Pedia, the Showbiz Pizza Cyberstar In
| Eyes Right | 7 | 7 | 5 | 1-5 | TB1 9-10 H1 | No | | Eyes Right | 7 | 7 | 5 | 1-5 | TB1 9-10 H1 | No |
| Head Left | 8 | 8 | 6 | 1-6 | TB1 3-4 H1 | No | | Head Left | 8 | 8 | 6 | 1-6 | TB1 3-4 H1 | No |
| Head Right | 9 | 9 | 7 | 1-7 | TB1 5-6 H1 | No | | Head Right | 9 | 9 | 7 | 1-7 | TB1 5-6 H1 | No |
| Head Up | 10 | 10 | 8 | 1-8 | TB1 7-8 H1 | Yes | | Head Up | 10 | 10 | 8 | 1-8 | TB1 7-8 H1 | No |
| Left Arm Up | 11 | 11 | 11 | 1-11 | | | | Left Arm Up | 11 | 11 | 11 | 1-11 | | |
| Left Arm Twist | 12 | 12 | 12 | 1-12 | | | | Left Arm Twist | 12 | 12 | 12 | 1-12 | | |
| Left Elbow | 13 | 13 | 13 | 1-13 | | | | Left Elbow | 13 | 13 | 13 | 1-13 | | |
@ -35,7 +35,7 @@ Earl's movements were removed during Concept Unification.
### Mitzi Mozzarella/Helen Henny ### Mitzi Mozzarella/Helen Henny
| Movement Name | UST Single Character Bit | UST Full Stage Bit | RR Engine Bit | Greybox Bit | R12 Bit | R12 Inverted | | Movement Name | UST Character Bit | UST Full Stage Bit | RR Engine Bit | Greybox Bit | R12 Bit | R12 Inverted |
| --------------- | ------------------------ | ------------------ | ------------- | ----------- | ------------ | ------------ | | --------------- | ------------------------ | ------------------ | ------------- | ----------- | ------------ | ------------ |
| Mouth | 1 | 23 | 185 | 2-35 | TB1 1-2 H5 | No | | Mouth | 1 | 23 | 185 | 2-35 | TB1 1-2 H5 | No |
| Left Ear | 2 | 24 | 176 | 2-26 | | | | Left Ear | 2 | 24 | 176 | 2-26 | | |
@ -46,7 +46,7 @@ Earl's movements were removed during Concept Unification.
| Eyes Right | 7 | 29 | 184 | 2-34 | TB1 9-10 H5 | No | | Eyes Right | 7 | 29 | 184 | 2-34 | TB1 9-10 H5 | No |
| Head Left | 8 | 30 | 178 | 2-28 | TB1 3-4 H5 | No | | Head Left | 8 | 30 | 178 | 2-28 | TB1 3-4 H5 | No |
| Head Right | 9 | 31 | 179 | 2-29 | TB1 5-6 H5 | No | | Head Right | 9 | 31 | 179 | 2-29 | TB1 5-6 H5 | No |
| Head Up | 10 | 32 | 180 | 2-30 | TB1 7-8 H5 | Yes | | Head Up | 10 | 32 | 180 | 2-30 | TB1 7-8 H5 | No |
| Left Arm Up | 11 | 33 | 173 | 2-23 | | | | Left Arm Up | 11 | 33 | 173 | 2-23 | | |
| Left Arm Twist | 12 | 34 | 175 | 2-25 | | | | Left Arm Twist | 12 | 34 | 175 | 2-25 | | |
| Left Elbow | 13 | 35 | 174 | 2-24 | | | | Left Elbow | 13 | 35 | 174 | 2-24 | | |
@ -61,7 +61,7 @@ No movements were removed during Concept Unification.
### Fatz Geronimo/Mr. Munch ### Fatz Geronimo/Mr. Munch
| Movement Name | UST Single Character Bit | UST Full Stage Bit | RR Engine Bit | Greybox Bit | R12 Bit | R12 Inverted | | Movement Name | UST Character Bit | UST Full Stage Bit | RR Engine Bit | Greybox Bit | R12 Bit | R12 Inverted |
| --------------- | ------------------------ | ------------------ | ------------- | ----------- | ------------ | ------------ | | --------------- | ------------------------ | ------------------ | ------------- | ----------- | ------------ | ------------ |
| Mouth | 1 | 42 | 45 | 1-45 | TB1 1-2 H4 | No | | Mouth | 1 | 42 | 45 | 1-45 | TB1 1-2 H4 | No |
| Left Eyelid | 2 | 43 | 41 | 1-41 | TB1 11-12 H4 | Yes | | Left Eyelid | 2 | 43 | 41 | 1-41 | TB1 11-12 H4 | Yes |
@ -84,7 +84,7 @@ No movements were removed during Concept Unification.
### Beach Bear/Jasper T. Jowls ### Beach Bear/Jasper T. Jowls
| Movement Name | UST Single Character Bit | UST Full Stage Bit | RR Engine Bit | Greybox Bit | R12 Bit | R12 Inverted | | Movement Name | UST Character Bit | UST Full Stage Bit | RR Engine Bit | Greybox Bit | R12 Bit | R12 Inverted |
| --------------- | ------------------------ | ------------------ | ------------- | ----------- | ------------------------- | ------------ | | --------------- | ------------------------ | ------------------ | ------------- | ----------- | ------------------------- | ------------ |
| Mouth | 1 | 58 | 166 | 2-16 | TB1 1-2 H2 | No | | Mouth | 1 | 58 | 166 | 2-16 | TB1 1-2 H2 | No |
| Left Eyelid | 2 | 59 | 151 | 2-1 | TB1 11-12 H2 | Yes | | Left Eyelid | 2 | 59 | 151 | 2-1 | TB1 11-12 H2 | Yes |
@ -92,7 +92,7 @@ No movements were removed during Concept Unification.
| Eyes Cross | 4 | 61 | 153 | 2-3 | | | | Eyes Cross | 4 | 61 | 153 | 2-3 | | |
| Head Left | 5 | 62 | 156 | 2-6 | TB1 3-4 H2 & TB1 15-16 H2 | No | | Head Left | 5 | 62 | 156 | 2-6 | TB1 3-4 H2 & TB1 15-16 H2 | No |
| Head Right | 6 | 63 | 157 | 2-7 | TB1 5-6 H2 & TB1 9-10 H2 | No | | Head Right | 6 | 63 | 157 | 2-7 | TB1 5-6 H2 & TB1 9-10 H2 | No |
| Head Up | 7 | 64 | 158 | 2-8 | TB1 7-8 H2 | Yes | | Head Up | 7 | 64 | 158 | 2-8 | TB1 7-8 H2 | No |
| Right Arm Raise | 8 | 65 | 161 | 2-11 | | | | Right Arm Raise | 8 | 65 | 161 | 2-11 | | |
| Right Arm Twist | 9 | 66 | 162 | 2-12 | | | | Right Arm Twist | 9 | 66 | 162 | 2-12 | | |
| Right Elbow | 10 | 67 | 163 | 2-13 | TB1 13-14 H2 | No | | Right Elbow | 10 | 67 | 163 | 2-13 | TB1 13-14 H2 | No |
@ -107,7 +107,7 @@ No movements were removed during Concept Unification.
### Dook Larue/Pasqually ### Dook Larue/Pasqually
| Movement Name | UST Single Character Bit | UST Full Stage Bit | RR Engine Bit | Greybox Bit | R12 Bit | R12 Inverted | | Movement Name | UST Character Bit | UST Full Stage Bit | RR Engine Bit | Greybox Bit | R12 Bit | R12 Inverted |
| --------------- | ------------------------ | ------------------ | ------------- | ----------- | ------------ | ------------ | | --------------- | ------------------------ | ------------------ | ------------- | ----------- | ------------ | ------------ |
| Mouth | 1 | 74 | 30 | 1-30 | TB1 1-2 H3 | No | | Mouth | 1 | 74 | 30 | 1-30 | TB1 1-2 H3 | No |
| Left Ear | 2 | 75 | 23 | 1-23 | | | | Left Ear | 2 | 75 | 23 | 1-23 | | |
@ -131,7 +131,7 @@ Ear movements and Kick Drum were removed during Concept Unification.
### Billy Bob ### Billy Bob
| Movement Name | UST Single Character Bit | UST Full Stage Bit | RR Engine Bit | Greybox Bit | | Movement Name | UST Character Bit | UST Full Stage Bit | RR Engine Bit | Greybox Bit |
| --------------- | ------------------------ | ------------------ | ------------- | ----------- | | --------------- | ------------------------ | ------------------ | ------------- | ----------- |
| Mouth | 1 | 91 | 196 | 2-46 | | Mouth | 1 | 91 | 196 | 2-46 |
| Left Eyelid | 2 | 92 | 197 | 2-47 | | Left Eyelid | 2 | 92 | 197 | 2-47 |
@ -158,7 +158,7 @@ Entire bot was removed during Concept Unification.
### Looney Bird/Pizzacam ### Looney Bird/Pizzacam
| Movement Name | UST Single Character Bit | UST Full Stage Bit | RR Engine Bit | Greybox Bit | | Movement Name | UST Character Bit | UST Full Stage Bit | RR Engine Bit | Greybox Bit |
| --------------- | ------------------------ | ------------------ | ------------- | ----------- | | --------------- | ------------------------ | ------------------ | ------------- | ----------- |
| Mouth | 1 | 111 | 167 | 2-17 | | Mouth | 1 | 111 | 167 | 2-17 |
| Left Eyelid | 2 | 112 | 191 | 2-41 | | Left Eyelid | 2 | 112 | 191 | 2-41 |
@ -170,11 +170,114 @@ Entire bot was removed during Concept Unification.
Hand movement was removed during Concept Unification. Hand movement was removed during Concept Unification.
## R12 (Road/1-Stage/2-Stage) ### Props
| Name | UST Full Stage Bit | RR Engine Bit | Greybox Bit | R12 Bit | R12 Inverted |
| ------------------- | ------------------ | ------------- | ----------- | ---------- | ------------ |
| Sun/Building Raise | 118 | 39 | 1-39 | | |
| Sun/Building Mouth | 119 | 38 | 1-38 | | |
| Moon Raise | 120 | 47 | 1-47 | | |
| Moon Mouth | 121 | 46 | 1-46 | | |
| Antioch/Wink | 122 | 49 | 1-49 | TB2 3-4 H1 | No |
| Choo-Choo/Munch Jr. | 123 | 50 | 1-50 | | |
### Spots
| Name | UST Full Stage Bit | RR Engine Bit | Greybox Bit | R12 Bit | R12 Inverted |
| --------------------------------- | ------------------ | ------------- | ----------- | ------------ | ------------ |
| Rolfe/Chuck E. Spot | 124 | 88 | 1-88 | TB1 15-16 H7 | No |
| Dook/Helen Spot | 125 | 86 | 1-86 | TB1 11-12 H7 | No |
| Fatz/Munch Spot | 126 | 85 | 1-85 | TB2 9-10 H7 | No |
| Beach Bear/Jasper Spot | 127 | 82 | 1-82 | TB2 5-6 H7 | No |
| Beach Bear/Jasper Guitar Spot | 128 | 242 | 2-96 | | |
| Billy Bob/Pasqually Spot | 129 | 84 | 1-84 | TB1 7-8 H7 | No |
| Looney Bird/Pizzacam Spot | 130 | 83 | 1-83 | | |
| Mitzi/Wink Spot | 131 | 81 | 1-81 | TB2 5-6 H8 | No |
| Sun/Building Spot | 132 | 238 | 2-88 | | |
| Moon Spot | 133 | 239 | 2-89 | | |
| Antioch/Munch Jr. Spot/Gobo Light | 134 | 240 | 2-90 | TB1 7-8 H8 | No |
| Earl Spot/Helicopter Light/Gemini | 135 | 87 | 1-87 | TB2 3-4 H8 | No |
### Curtains
| Name | UST Full Stage Bit | RR Engine Bit | Greybox Bit | R12 Bit | R12 Inverted |
| ------------------ | ------------------ | ------------- | ----------- | ------------------------- | ------------ |
| Stage Left Open | 136 | 93 | 1-93 | TB2 5-6 H2 & TB2 1-2 H2 | No |
| Stage Left Close | 137 | 94 | 1-94 | TB2 7-8 H2 & TB2 3-4 H2 | No |
| Center Stage Open | 138 | 91 | 1-91 | TB2 9-10 H2 & TB2 1-2 H2 | No |
| Center Stage Close | 139 | 92 | 1-92 | TB2 11-12 H2 & TB2 3-4 H2 | No |
| Stage Right Open | 140 | 89 | 1-89 | TB2 9-10 H2 & TB2 1-2 H2 | No |
| Stage Right Close | 141 | 90 | 1-90 | TB2 11-12 H2 & TB2 3-4 H2 | No |
### Floods
| Name | UST Full Stage Bit | RR Engine Bit | Greybox Bit | R12 Bit | R12 Inverted |
| ------------------ | ------------------ | ------------- | ----------- | ------------ | ------------ |
| Stage Left Red | 142 | 229 | 2-79 | TB1 15-16 H8 | No |
| Stage Left Amber | 143 | 228 | 2-78 | TB1 7-8 H8 | No |
| Stage Left Green | 144 | 227 | 2-77 | | |
| Stage Left Blue | 145 | 226 | 2-76 | TB2 13-14 H8 | No |
| Center Stage Red | 146 | 224 | 2-74 | TB1 11-12 H8 | No |
| Center Stage Amber | 147 | 223 | 2-73 | TB1 9-10 H8 | No |
| Center Stage Blue | 148 | 221 | 2-71 | TB1 13-14 H8 | No |
| Stage Right Red | 149 | 219 | 2-69 | | |
| Stage Right Amber | 150 | 218 | 2-68 | | |
| Stage Right Green | 151 | 217 | 2-67 | | |
| Stage Right Blue | 152 | 216 | 2-66 | | |
| Live Flood | 153 | 222 | 2-72 | TB1 1-2 H7 | No |
### Backdrop
| Name | UST Full Stage Bit | RR Engine Bit | Greybox Bit | R12 Bit | R12 Inverted |
| ---------------------- | ------------------ | ------------- | ----------- | ---------- | ------------ |
| Backdrop Red | 154 | 235 | 2-85 | TB1 3-4 H8 | No |
| Backdrop Yellow | 155 | 232 | 2-82 | TB1 1-2 H8 | No |
| Backdrop Green | 156 | 231 | 2-81 | | |
| Backdrop Blue | 157 | 234 | 2-84 | TB2 5-6 H8 | No |
| Backdrop Red Outer | 158 | 236 | 2-86 | | |
| Backdrop Blue Outer | 159 | 237 | 2-87 | | |
| Backdrop Red Buildings | 160 | 233 | 2-83 | | |
| Stage Right Red Floor | 161 | 242 | 2-92 | | |
| Stage Right Blue Floor | 162 | 243 | 2-93 | | |
### Organ
| Name | UST Full Stage Bit | RR Engine Bit | Greybox Bit | R12 Bit | R12 Inverted |
| ----------------- | ------------------ | ------------- | ----------- | ------------ | ------------ |
| Organ Face Red | 163 | 67 | 1-67 | TB2 11-12 H7 | No |
| Organ Face Amber | 164 | 68 | 1-68 | TB2 7-8 H7 | No |
| Organ Face Green | 165 | 69 | 1-69 | | |
| Organ Face Blue | 166 | 66 | 1-66 | | |
| Organ Legs Top | 167 | 71 | 1-71 | TB1 9-10 H7 | No |
| Organ Legs Middle | 168 | 72 | 1-72 | TB2 3-4 H7 | No |
| Organ Legs Bottom | 169 | 73 | 1-73 | TB2 13-14 H7 | No |
### Sign
| Name | UST Full Stage Bit | RR Engine Bit | Greybox Bit | R12 Bit | R12 Inverted |
| ----------- | ------------------ | ------------- | ----------- | ------------ | ------------ |
| Sign Outer | 170 | 78 | 1-78 | | |
| Sign Middle | 171 | 77 | 1-77 | TB2 11-12 H8 | No |
| Sign Inner | 172 | 76 | 1-76 | | |
| Sign Strobe | 173 | 79 | 1-79 | | |
| Sign Flash | 174 | 80 | 1-80 | | |
### Special
| Name | UST Full Stage Bit | RR Engine Bit | Greybox Bit | R12 Bit | R12 Inverted |
| ------------------- | ------------------ | ------------- | ----------- | ------------ | ------------ |
| Chuck E. Star | 175 | 220 | 2-70 | TB1 13-14 H7 | No |
| Chuck E. Neon | 176 | 244 | 2-94 | TB2 1-2 H7 | No |
| Jukebox Topper | 177 | 245 | 2-95 | TB2 9-10 H8 | No |
| Fiber Optic Curtain | 178 | 225 | 2-75 | TB2 1-2 H8 | No |
| Snare Drum Light | 179 | 230 | 2-80 | | |
| Kick Drum Light | 180 | 241 | 2-91 | TB1 5-6 H7 | No |
## Cyberamics
### Chuck E. Cheese ### Chuck E. Cheese
| Movement Name | UST Single Character Bit | UST Full Stage Bit | RR Engine Bit | CCS Bit | | Movement Name | Character Bit | UST Full Stage Bit | RR Engine Bit | CCS Bit |
| ------------- | ------------------------ | ------------------ | ------------- | ------------ | | ------------- | ------------------------ | ------------------ | ------------- | ------------ |
| Mouth | 1 | 1 | 1 | TB1 1-2 H1 | | Mouth | 1 | 1 | 1 | TB1 1-2 H1 |
| Head Left | 2 | 2 | 2 | TB1 3-4 H1 | | Head Left | 2 | 2 | 2 | TB1 3-4 H1 |
@ -187,7 +290,7 @@ Hand movement was removed during Concept Unification.
### Helen Henny/Guest Star ### Helen Henny/Guest Star
| Movement Name | UST Single Character Bit | UST Full Stage Bit | RR Engine Bit | CCS Bit | | Movement Name | UST Character Bit | UST Full Stage Bit | RR Engine Bit | CCS Bit |
| ------------- | ------------------------ | ------------------ | ------------- | ------------ | | ------------- | ------------------------ | ------------------ | ------------- | ------------ |
| Mouth | 1 | 9 | 65 | TB1 1-2 H5 | | Mouth | 1 | 9 | 65 | TB1 1-2 H5 |
| Head Left | 2 | 10 | 66 | TB1 3-4 H5 | | Head Left | 2 | 10 | 66 | TB1 3-4 H5 |
@ -200,7 +303,7 @@ Hand movement was removed during Concept Unification.
### Mr. Munch ### Mr. Munch
| Movement Name | UST Single Character Bit | UST Full Stage Bit | RR Engine Bit | CCS Bit | | Movement Name | UST Character Bit | UST Full Stage Bit | RR Engine Bit | CCS Bit |
| ------------- | ------------------------ | ------------------ | ------------- | ------------ | | ------------- | ------------------------ | ------------------ | ------------- | ------------ |
| Mouth | 1 | 17 | 49 | TB1 1-2 H4 | | Mouth | 1 | 17 | 49 | TB1 1-2 H4 |
| Head Left | 2 | 18 | 50 | TB1 3-4 H4 | | Head Left | 2 | 18 | 50 | TB1 3-4 H4 |
@ -213,7 +316,7 @@ Hand movement was removed during Concept Unification.
### Jasper T. Jowls ### Jasper T. Jowls
| Movement Name | UST Single Character Bit | UST Full Stage Bit | RR Engine Bit | CCS Bit | | Movement Name | UST Character Bit | UST Full Stage Bit | RR Engine Bit | CCS Bit |
| ------------- | ------------------------ | ------------------ | ------------- | ------------ | | ------------- | ------------------------ | ------------------ | ------------- | ------------ |
| Mouth | 1 | 25 | 17 | TB1 1-2 H2 | | Mouth | 1 | 25 | 17 | TB1 1-2 H2 |
| Head Left | 2 | 26 | 18 | TB1 3-4 H2 | | Head Left | 2 | 26 | 18 | TB1 3-4 H2 |
@ -226,7 +329,7 @@ Hand movement was removed during Concept Unification.
### Pasqually ### Pasqually
| Movement Name | UST Single Character Bit | UST Full Stage Bit | RR Engine Bit | CCS Bit | | Movement Name | UST Character Bit | UST Full Stage Bit | RR Engine Bit | CCS Bit |
| ------------- | ------------------------ | ------------------ | ------------- | ------------ | | ------------- | ------------------------ | ------------------ | ------------- | ------------ |
| Mouth | 1 | 33 | 33 | TB1 1-2 H3 | | Mouth | 1 | 33 | 33 | TB1 1-2 H3 |
| Head Left | 2 | 34 | 34 | TB1 3-4 H3 | | Head Left | 2 | 34 | 34 | TB1 3-4 H3 |
@ -236,3 +339,197 @@ Hand movement was removed during Concept Unification.
| Eyelids | 6 | 38 | 38 | TB1 11-12 H3 | | Eyelids | 6 | 38 | 38 | TB1 11-12 H3 |
| Right Arm | 7 | 39 | 39 | TB1 13-14 H3 | | Right Arm | 7 | 39 | 39 | TB1 13-14 H3 |
| Left Arm | 8 | 40 | 36 | TB1 7-8 H3 | | Left Arm | 8 | 40 | 36 | TB1 7-8 H3 |
### Props
| Name | UST Full Stage Bit | RR Engine Bit | CCS Bit |
| ------------------------- | ------------------ | ------------- | ------------ |
| Warblettes/Flower Mouth 1 | 41 | 9 | TB2 1-2 H1 |
| Flower Mouth 2 | 42 | 46 | TB2 11-12 H3 |
| Flower Mouth 3 | 43 | 62 | TB2 11-12 H4 |
| Warblettes Body Rock/Wink | 44 | 10 | TB2 3-4 H1 |
| Flag 1 | 45 | 74 | TB2 3-4 H5 |
| Flag 2 | 46 | 75 | TB2 5-6 H5 |
| Flag 3 | 47 | 76 | TB2 7-8 H5 |
| Flag 4 | 48 | 77 | TB2 9-10 H5 |
| Flag 5 | 49 | 78 | TB2 11-12 H5 |
### Spots
| Name | UST Full Stage Bit | RR Engine Bit | CCS Bit |
| ----------------------- | ------------------ | ------------- | ------------ |
| Chuck E. Spot | 50 | 104 | TB1 15-16 H7 |
| Helen Spot | 51 | 102 | TB1 11-12 H7 |
| Munch Spot | 52 | 109 | TB2 9-10 H7 |
| Jasper Spot | 53 | 107 | TB2 5-6 H7 |
| Pasqually Spot | 54 | 100 | TB1 7-8 H7 |
| Wink Spot | 55 | 123 | TB2 5-6 H8 |
| Flowers/Warblettes Spot | 56 | 41 | TB2 1-2 H3 |
### Curtains
| Name | UST Full Stage Bit | RR Engine Bit | CCS Bit |
| ------------------------ | ------------------ | ------------- | ------------ |
| CEC Stage Curtain Open | 57 | 27 | TB2 5-6 H2 |
| CEC Stage Curtain Close | 58 | 28 | TB2 7-8 H2 |
| Main Stage Curtain Open | 59 | 29 | TB2 9-10 H2 |
| Main Stage Curtain Close | 60 | 30 | TB2 11-12 H2 |
| 1-Stage Curtain Open | 61 | 25 | TB2 1-2 H2 |
| 1-Stage Curtain Close | 62 | 26 | TB2 3-4 H2 |
| Turntable Bot Side | 63 | 57 | TB2 1-2 H4 |
| Turntable Live Side | 64 | 58 | TB2 3-4 H4 |
### Floods
| Name | UST Full Stage Bit | RR Engine Bit | CCS Bit |
| ------------------------- | ------------------ | ------------- | ------------ |
| CEC Stage Red Overhead | 65 | 120 | TB1 15-16 H8 |
| CEC Stage Amber Overhead | 66 | 116 | TB1 7-8 H8 |
| CEC Stage Blue Overhead | 67 | 127 | TB2 13-14 H8 |
| Main Stage Red Overhead | 68 | 118 | TB1 11-12 H8 |
| Main Stage Amber Overhead | 69 | 117 | TB1 9-10 H8 |
| Main Stage Blue Overhead | 70 | 119 | TB1 13-14 H8 |
### Backdrop
| Name | UST Full Stage Bit | RR Engine Bit | CCS Bit |
| -------------- | ------------------ | ------------- | ---------- |
| Red Backdrop | 71 | 114 | TB1 3-4 H8 |
| Amber Backdrop | 72 | 113 | TB1 1-2 H8 |
| Blue Backdrop | 73 | 115 | TB1 5-6 H8 |
### Organ
| Name | UST Full Stage Bit | RR Engine Bit | CCS Bit |
| ----------------- | ------------------ | ------------- | ------------ |
| Organ Face Amber | 74 | 110 | TB2 11-12 H7 |
| Organ Face Blue | 75 | 108 | TB2 7-8 H7 |
| Organ Legs Outer | 76 | 101 | TB1 9-10 H7 |
| Organ Legs Middle | 77 | 106 | TB2 3-4 H7 |
| Organ Legs Inner | 78 | 111 | TB2 13-14 H7 |
### Special
| Name | UST Full Stage Bit | RR Engine Bit | CCS Bit |
| -------------------- | ------------------ | ------------- | ------------ |
| CEC Star/Rope Lights | 79 | 103 | TB1 13-14 H7 |
| CEC Sign | 80 | 105 | TB2 1-2 H7 |
| Jukebox Topper | 81 | 125 | TB2 9-10 H8 |
| Fiber Curtain | 82 | 121 | TB2 1-2 H8 |
| Band Sign | 83 | 126 | TB2 11-12 H8 |
| Kick Drum | 84 | 99 | TB1 5-6 H7 |
| Gobo Light | 85 | 124 | TB2 7-8 H8 |
| Helicopter/Gemini | 86 | 122 | TB2 3-4 H8 |
| Live Flood | 87 | 97 | TB1 1-2 H7 |
| Live Strobe | 88 | 98 | TB1 3-4 H7 |
## Studio C
### Chuck E.
| Movement Name | UST Character Bit | UST Full Stage Bit | RR Engine Bit | DTU Bit | 16M |
| ----------------- | ------------------------ | ------------------ | ------------- | ------- | --- |
| Mouth | 1 | 1 | 21 | 1-21 | Yes |
| Nose | 2 | 2 | 28 | 1-28 | No |
| Eyelids Up | 3 | 3 | 25 | 1-25 | No |
| Eyelids Down | 4 | 4 | 24 | 1-24 | Yes |
| Eyes Left | 5 | 5 | 26 | 1-26 | Yes |
| Eyes Right | 6 | 6 | 27 | 1-27 | Yes |
| Eyebrows Up | 7 | 7 | 29 | 1-29 | No |
| Eyebrows Down | 8 | 8 | 30 | 1-30 | No |
| Ears | 9 | 9 | 31 | 1-31 | No |
| Head Turn Left | 10 | 10 | 18 | 1-18 | Yes |
| Head Turn Right | 11 | 11 | 19 | 1-19 | Yes |
| Head Tilt Left | 12 | 12 | 23 | 1-23 | No |
| Head Tilt Right | 13 | 13 | 22 | 1-22 | No |
| Head Up | 14 | 14 | 20 | 1-20 | Yes |
| Left Arm Out | 15 | 15 | 6 | 1-6 | No |
| Left Arm Swing | 16 | 16 | 7 | 1-7 | Yes |
| Left Arm Forward | 17 | 17 | 11 | 1-11 | No |
| Left Elbow | 18 | 18 | 8 | 1-8 | Yes |
| Left Wrist | 19 | 19 | 9 | 1-9 | No |
| Left Hand Wave | 20 | 20 | 10 | 1-10 | Yes |
| Right Arm Out | 21 | 21 | 1 | 1-1 | No |
| Right Arm Swing | 22 | 22 | 2 | 1-2 | Yes |
| Right Arm Forward | 23 | 23 | 17 | 1-17 | No |
| Right Elbow | 24 | 24 | 3 | 1-3 | Yes |
| Right Wrist | 25 | 25 | 4 | 1-4 | No |
| Right Hand Wave | 26 | 26 | 5 | 1-5 | Yes |
| Body Forward | 27 | 27 | 12 | 1-12 | Yes |
| Body Turn Left | 28 | 28 | 16 | 1-16 | Yes |
| Body Turn Right | 29 | 29 | 15 | 1-15 | Yes |
| Body Tilt Left | 30 | 30 | 13 | 1-13 | No |
| Body Tilt Right | 31 | 31 | 14 | 1-14 | No |
| Foot Tap | 32 | 32 | 32 | 1-32 | No |
### Props
| Name | UST Full Stage Bit | RR Engine Bit | DTU Bit |
| ------------- | ------------------ | ------------- | ------- |
| Bird Mouth | 33 | 33 | 1-33 |
| Bird Wings | 34 | 36 | 1-36 |
| Bird Bow | 35 | 34 | 1-34 |
| Bird Turn | 36 | 35 | 1-35 |
| Phone Swing | 37 | 40 | 1-40 |
| Clock Forward | 38 | 160 | 2-10 |
| Clock Reverse | 39 | 161 | 2-11 |
### Spots
| Name | UST Full Stage Bit | RR Engine Bit | DTU Bit |
| ------------- | ------------------ | ------------- | ------- |
| Chuck E. Spot | 40 | 177 | 2-27 |
| Bird Spot | 41 | 178 | 2-28 |
### Curtains
| Name | UST Full Stage Bit | RR Engine Bit | DTU Bit |
| -------------- | ------------------ | ------------- | ------- |
| Curtains Open | 42 | 44 | 1-44 |
| Curtains Close | 43 | 45 | 1-45 |
### Floods
| Name | UST Full Stage Bit | RR Engine Bit | DTU Bit |
| ------------------------ | ------------------ | ------------- | ------- |
| CEC Red Floods | 44 | 151 | 2-1 |
| CEC Amber Floods | 45 | 154 | 2-4 |
| CEC Green Floods | 46 | 152 | 2-2 |
| CEC Blue Floods | 47 | 153 | 2-3 |
| Blue Screen Red Floods | 48 | 155 | 2-5 |
| Blue Screen Amber Floods | 49 | 157 | 2-7 |
| Blue Screen Green Floods | 50 | 156 | 2-6 |
| Room Pink Floods | 51 | 181 | 2-31 |
| Room Amber Floods | 52 | 180 | 2-30 |
| Room Blue Floods | 53 | 182 | 2-32 |
### Monitor
| Name | UST Full Stage Bit | RR Engine Bit | DTU Bit |
| ------------- | ------------------ | ------------- | ------- |
| Monitor Pink | 54 | 172 | 2-22 |
| Monitor Green | 55 | 174 | 2-24 |
| Monitor Blue | 56 | 173 | 2-23 |
| Monitor Chase | 57 | 171 | 2-21 |
### Desk
| Name | UST Full Stage Bit | RR Engine Bit | DTU Bit |
| ----------- | ------------------ | ------------- | ------- |
| Desk Outer | 58 | 166 | 2-16 |
| Desk Middle | 59 | 165 | 2-15 |
| Desk Inner | 60 | 164 | 2-14 |
### Special
| Name | UST Full Stage Bit | RR Engine Bit | DTU Bit |
| -------------------- | ------------------ | ------------- | ------- |
| Clock Neon | 61 | 159 | 2-9 |
| City Lights | 62 | 163 | 2-13 |
| Phone Handset Lights | 63 | 167 | 2-17 |
| Phone Dial Lights | 64 | 168 | 2-18 |
| Gemini | 65 | 176 | 2-26 |
| On Air Sign | 66 | 169 | 2-19 |
| Applause Sign | 67 | 170 | 2-20 |
| Strobe | 68 | 162 | 2-12 |
| Live Floods | 69 | 179 | 2-29 |

View file

@ -0,0 +1,15 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="SoundFlow" Version="1.1.1" />
<PackageReference Include="System.IO.Ports" Version="9.0.4" />
</ItemGroup>
</Project>

308
ConsolePlayer/Program.cs Normal file
View file

@ -0,0 +1,308 @@
using System.Globalization;
using System.IO.Ports;
using System.Numerics;
using System.Timers;
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 System.Timers.Timer ResyncTimer;
static SoundPlayer AudioPlayer;
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 bool Paused = false;
static bool SyncMsg = 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;
ResyncTimer = new System.Timers.Timer(15000);
ResyncTimer.Elapsed += Resync;
ResyncTimer.AutoReset = true;
using MiniAudioEngine audioEngine = new MiniAudioEngine(48000, Capability.Playback);
using StreamDataProvider dataProvider = new StreamDataProvider(File.OpenRead("pc3playertempaudio.tmp"));
AudioPlayer = new SoundPlayer(dataProvider);
Mixer.Master.AddComponent(AudioPlayer);
Console.WriteLine($"Playing Showtape \"{ShowtapeName}\" ({ShowtapeFormattedLength})");
Console.WriteLine("Controls:\n[SPACE] to pause and unpause\n[TAB] to toggle sync messages");
Playing = true;
AudioPlayer.Play();
FrameTimer.Start();
ResyncTimer.Start();
while (Playing)
{
ConsoleKeyInfo input = Console.ReadKey();
if (Playing)
{
if (input.Key == ConsoleKey.Spacebar)
{
if (Paused)
{
Paused = false;
FrameTimer.Start();
ResyncTimer.Start();
AudioPlayer.Seek((float)(((float)ShowtapeIndex) / 60.0));
AudioPlayer.Play();
}
else
{
Paused = true;
FrameTimer.Stop();
ResyncTimer.Stop();
AudioPlayer.Pause();
}
}
else if (input.Key == ConsoleKey.Tab) SyncMsg = !SyncMsg;
}
else if (!Playing) break;
}
Mixer.Master.RemoveComponent(AudioPlayer);
}
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) { continue; }
}
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! Press any key to exit.");
if (File.Exists("pc3playertempaudio.tmp")) File.Delete("pc3playertempaudio.tmp");
return;
}
Port.Write(ShowtapeFrames[ShowtapeIndex]);
ShowtapeIndex += FramesPerTick;
}
static void Resync(Object sender, ElapsedEventArgs e)
{
if (SyncMsg) Console.WriteLine($"Resynced by {(int)(AudioPlayer.Time * 60) - ShowtapeIndex} frames");
ShowtapeIndex = (int)(AudioPlayer.Time * 60);
}
}
}

View file

@ -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

View file

@ -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

View file

@ -0,0 +1 @@
PC3MAPPING;1,2,3,4,5,6,7,8

View file

@ -0,0 +1 @@
PC3MAPPING;9,10,11,12,13,14,15,16

View file

@ -0,0 +1 @@
PC3MAPPING;25,26,27,28,29,30,31,32

View file

@ -0,0 +1 @@
PC3MAPPING;17,18,19,20,21,22,23,24

View file

@ -0,0 +1 @@
PC3MAPPING;33,34,35,36,37,38,39,40

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -1,17 +1,16 @@
# Future Goals # Future Goals
## PC2Converter ## USTConverter
- .SHW (ProgramBlue) input format - .SHW (ProgramBlue) input format
- .3ST/.R12/.C&R (APS) input format - .3ST/.R12/.C&R (APS) input format
- Biphase (Pianocorder and Cyberstar) from tape input format (unlikely) - Biphase (Pianocorder and Cyberstar) from tape input format
- Studio C from Floppy Disk input format - Studio C from Floppy Disk input format
- UST Full Stage to Single Character Stripper
## PC2Player ## PC2Player
- Make the program. - ~~burn the damn thing to the ground and start over~~ Done!
## Firmwares ## Firmwares
- Send controlling computer information about the number of outputs and which character it is set up for - ~~Send controlling computer information about the number of outputs and which character it is set up for~~ Done!

View file

@ -0,0 +1,308 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.IO.Ports;
using System.Timers;
using Eto.Forms;
using Eto.Drawing;
namespace PC2Player
{
public partial class MainForm : Form
{
SerialPort Port = null;
string[] Signals;
System.Timers.Timer FrameTimer;
long Index = 0;
int FrameSkip = 6;
byte[] AudioData;
Process MPVProcess;
int SkipSeconds = 0;
string ShowtapeName = "";
string ShowtapeStageType = "";
string ShowtapeCharacter = "";
string ShowtapeBits = "";
string ShowtapeFormattedLength = "";
string ControllerCharacter = "";
string ControllerBits = "";
string ControllerHeader = "";
bool ControllerConnected = false;
bool ShowtapeLoaded = false;
bool Playing = false;
DropDown SerialPortDropDown = new DropDown();
Label ShowtapeNameLabel = new Label { Text = "Show Name: Not Loaded" };
Label ShowtapeStageTypeLabel = new Label { Text = "Stage Type: Not Loaded" };
Label ShowtapeCharacterLabel = new Label { Text = "Character: Not Loaded" };
Label ShowtapeBitsLabel = new Label { Text = "Bits: Not Loaded" };
Label ShowtapeLengthLabel = new Label { Text = "Length: Not Loaded" };
Label ControllerCharacterLabel = new Label { Text = "Character: Disconnected" };
Label ControllerBitsLabel = new Label { Text = "Bits: Disconnected" };
Button RefreshPortsButton = new Button { Text = "Refresh Ports", Width = 150 };
Button LoadShowtapeButton = new Button { Text = "Load Showtape", Width = 150 };
Button PlayButton = new Button { Text = "Play" };
Button StopButton = new Button { Text = "Stop" };
public MainForm()
{
Title = "PinkConnection2 Showtape Player";
Size = new Size(500, 450);
Maximizable = false;
Resizable = false;
foreach (string s in SerialPort.GetPortNames())
{
SerialPortDropDown.Items.Add(s);
}
SerialPortDropDown.SelectedValueChanged += (sender, e) => Event_SelectSerialPort();
MPVProcess = new Process();
MPVProcess.StartInfo.FileName = "mpv";
MPVProcess.StartInfo.Arguments = $"--start={SkipSeconds} tmp.wav";
FrameTimer = new System.Timers.Timer((1000d/60d)*FrameSkip);
FrameTimer.Elapsed += Event_FrameTimerTick;
FrameTimer.AutoReset = true;
PlayButton.Enabled = false;
StopButton.Enabled = false;
PlayButton.Command = new Command( (sender, e) => Event_PlayButton() );
StopButton.Command = new Command( (sender, e) => Event_StopButton() );
RefreshPortsButton.Command = new Command( (sender, e) => Event_RefreshPortsButton() );
LoadShowtapeButton.Command = new Command( (sender, e) => Event_LoadShowtapeButton() );
Content = BuildLayout();
}
DynamicLayout BuildLayout()
{
GroupBox showtapeInfoGroupBox = new GroupBox{ Text = "Showtape" };
DynamicLayout showtapeInfoGroupLayout = new DynamicLayout { DefaultSpacing = new Size(5, 5), DefaultPadding = new Padding(5, 5, 5, 5) };
showtapeInfoGroupLayout.AddRow(ShowtapeNameLabel);
showtapeInfoGroupLayout.AddRow(ShowtapeStageTypeLabel);
showtapeInfoGroupLayout.AddRow(ShowtapeCharacterLabel);
showtapeInfoGroupLayout.AddRow(ShowtapeBitsLabel);
showtapeInfoGroupLayout.AddRow(ShowtapeLengthLabel);
showtapeInfoGroupBox.Content = showtapeInfoGroupLayout;
GroupBox controllerInfoGroupBox = new GroupBox{ Text = "Controller" };
DynamicLayout controllerInfoGroupLayout = new DynamicLayout { DefaultSpacing = new Size(5, 5), DefaultPadding = new Padding(5, 5, 5, 5) };
controllerInfoGroupLayout.AddRow(ControllerCharacterLabel);
controllerInfoGroupLayout.AddRow(ControllerBitsLabel);
controllerInfoGroupBox.Content = controllerInfoGroupLayout;
DynamicLayout layout = new DynamicLayout { DefaultSpacing = new Size(10, 10), DefaultPadding = new Padding(5, 5, 5, 5) };
layout.BeginVertical();
layout.BeginHorizontal();
layout.Add(PlayButton, true);
layout.Add(StopButton, true);
layout.EndHorizontal();
layout.EndVertical();
layout.BeginVertical();
layout.BeginHorizontal();
layout.Add(new Label { Text = "Serial Port" });
layout.EndHorizontal();
layout.BeginHorizontal();
layout.Add(SerialPortDropDown, true);
layout.EndHorizontal();
layout.BeginHorizontal();
layout.Add(showtapeInfoGroupBox, true);
layout.EndHorizontal();
layout.BeginHorizontal();
layout.Add(controllerInfoGroupBox, true);
layout.EndHorizontal();
layout.EndVertical();
layout.BeginVertical();
layout.BeginHorizontal();
layout.Add(null, true);
layout.Add(RefreshPortsButton);
layout.Add(LoadShowtapeButton);
layout.EndHorizontal();
layout.EndVertical();
layout.BeginVertical();
layout.Add(null, true);
layout.EndVertical();
return layout;
}
void CheckReady()
{
if (ControllerConnected && ShowtapeLoaded)
{
PlayButton.Enabled = true;
StopButton.Enabled = true;
}
else
{
PlayButton.Enabled = false;
StopButton.Enabled = false;
}
}
void Event_SelectSerialPort()
{
if (Port != null) Port.Close();
Port = new SerialPort((string)SerialPortDropDown.SelectedKey, 9600, Parity.None, 8, StopBits.One);
Port.DataReceived += new SerialDataReceivedEventHandler(Event_PortRecievedData);
ControllerHeader = "";
ControllerCharacterLabel.Text = "Character: Disconnected";
ControllerBitsLabel.Text = "Bits: Disconnected";
ControllerConnected = false;
CheckReady();
Port.Open();
}
void Event_PortRecievedData(object sender, SerialDataReceivedEventArgs e)
{
ControllerHeader += Port.ReadExisting();
if (ControllerHeader.EndsWith(",END"))
{
ControllerBits = ControllerHeader.Split(',')[1];
ControllerCharacter = ControllerHeader.Split(',')[2];
ControllerCharacterLabel.Text = $"Character: {ControllerCharacter}";
ControllerBitsLabel.Text = $"Bits: {ControllerBits}";
ControllerConnected = true;
CheckReady();
}
}
void Event_RefreshPortsButton()
{
foreach (string s in SerialPort.GetPortNames())
{
SerialPortDropDown.Items.Add(s);
}
}
void Event_LoadShowtapeButton()
{
OpenFileDialog fileDialog = new OpenFileDialog();
fileDialog.Filters.Add(new FileFilter("UST Files (.ust)", new string[]{ ".ust" }));
fileDialog.Title = "Select Show File.";
fileDialog.ShowDialog(this);
string tempUSTData = File.ReadAllText(fileDialog.FileName);
if (!tempUSTData.StartsWith("UST,1,"))
{
MessageBox.Show("This is not a UST Version 1 showtape.");
return;
}
string[] headerData = tempUSTData.Split(';')[0].Split(',');
string[] stringyBits = tempUSTData.Split(';')[1].Split(',');
AudioData = Convert.FromBase64String(tempUSTData.Split(';')[2]);
ShowtapeName = headerData[2];
ShowtapeBits = headerData[3];
ShowtapeStageType = headerData[4];
ShowtapeCharacter = headerData[5];
if (headerData[3] == "256")
{
MessageBox.Show("Can't load a full stage showtape right now!");
return;
}
TimeSpan time = TimeSpan.FromSeconds(stringyBits.Length/60);
ShowtapeFormattedLength = time.ToString(@"hh\:mm\:ss");
ShowtapeNameLabel.Text = $"Show Name: {ShowtapeName}";
ShowtapeStageTypeLabel.Text = $"Stage Type: {ShowtapeStageType}";
ShowtapeCharacterLabel.Text = $"Character: {ShowtapeCharacter}";
ShowtapeBitsLabel.Text = $"Bits: {ShowtapeBits}";
ShowtapeLengthLabel.Text = $"Length: {ShowtapeFormattedLength}";
List<string> tmpOut = new List<string>();
foreach (string frame in stringyBits)
{
int b = int.Parse(frame, NumberStyles.HexNumber);
char[] bytesOut = new char[8];
int bytes = int.Parse(ShowtapeBits)/4;
for (int i = 0; i < bytes; i++)
{
int offset = 4 * i;
int mask = 0b1111 << offset;
int masked_value = (b & mask) >> offset;
bytesOut[i] = (char)(64 | masked_value);
}
tmpOut.Add(new string(bytesOut));
}
Signals = tmpOut.ToArray();
ShowtapeLoaded = true;
CheckReady();
}
void Event_PlayButton()
{
if (Playing) return;
if (ShowtapeBits != ControllerBits)
{
MessageBox.Show("This showtape does not have the correct amount of bits for your controller.");
return;
}
File.WriteAllBytes("tmp.wav", AudioData);
Index = SkipSeconds*60;
MPVProcess.StartInfo.Arguments = $"--start={SkipSeconds} tmp.wav";
MPVProcess.Start();
FrameTimer.Start();
Playing = true;
PlayButton.Enabled = false;
RefreshPortsButton.Enabled = false;
LoadShowtapeButton.Enabled = false;
SerialPortDropDown.Enabled = false;
}
void Event_StopButton()
{
FrameTimer.Stop();
MPVProcess.Kill();
File.Delete("tmp.wav");
Playing = false;
PlayButton.Enabled = true;
RefreshPortsButton.Enabled = true;
LoadShowtapeButton.Enabled = true;
SerialPortDropDown.Enabled = true;
Index = 0;
}
void Event_FrameTimerTick(Object sender, ElapsedEventArgs e)
{
if (Index >= Signals.Length)
{
Event_StopButton();
return;
}
Port.Write(Signals[Index]);
Index += FrameSkip;
}
}
}

View file

@ -6,6 +6,7 @@
<ItemGroup> <ItemGroup>
<PackageReference Include="Eto.Forms" Version="2.9.0" /> <PackageReference Include="Eto.Forms" Version="2.9.0" />
<PackageReference Include="System.IO.Ports" Version="9.0.4" />
</ItemGroup> </ItemGroup>
</Project> </Project>

View file

@ -11,7 +11,7 @@ namespace PinkConnection2_TestApp
SerialPort port = null; SerialPort port = null;
byte b = 0; byte b = 0;
TextBox CommandTextBox = new TextBox { MaxLength = 2 }; TextBox CommandTextBox = new TextBox { MaxLength = 8 };
DropDown SerialPortDropDown = new DropDown(); DropDown SerialPortDropDown = new DropDown();
public MainForm() public MainForm()
@ -92,9 +92,9 @@ namespace PinkConnection2_TestApp
void sendRawSafe() void sendRawSafe()
{ {
if (CommandTextBox.Text.Length != 2) if (CommandTextBox.Text.Length != 8)
{ {
MessageBox.Show("Command length must not be less than 2"); MessageBox.Show("Command length must not be less than 8");
return; return;
} }
if (port == null) if (port == null)

View file

@ -1,448 +0,0 @@
using System;
using System.Collections;
using System.IO;
using Eto.Forms;
using Eto.Drawing;
namespace PC2Converter
{
public partial class MainForm : Form
{
DropDown InputTypeSelector = new DropDown();
DropDown OutputTypeSelector = new DropDown();
DropDown CharacterSelector = new DropDown();
TextBox FilePathTextBox = new TextBox();
Button BrowseFileButton = new Button { Text = "Browse", Width = 100 };
Button ConvertButton = new Button { Text = "Convert", Width = 100 };
string[] InputTypes = { "RSHW File (RR Engine)", "CSHW File (RR Engine)", "SSHW File (RR Engine)" };
string[] RSHWOutputTypes = { "UST 32 Bits (Single Bot RAE/3st)", "UST 8 Bits (Single Bot Cybers Rosetta)", "UST 256 Bits (Full RAE/3st)" , "UST 256 Bits (Full Cybers Rosetta)" };
string[] CSHWOutputTypes = { "UST 8 Bits (Single Bot Cybers)", "UST 256 Bits (Full Cybers)" };
string[] SSHWOutputTypes = { "UST 32 Bits (Single Bot Studio C)", "UST 256 Bits (Full Studio C)" };
string[] RAE3stCharacters = { "Rolfe/Chuck E.", "Mitzi/Helen", "Fatz/Munch", "Beach Bear/Jasper", "Dook/Pasqually", "Billy Bob", "Looney Bird/PizzaCam"};
string[] CyberCharacters = { "Chuck E.", "Helen/Guest Star", "Munch", "Jasper", "Pasqually" };
string[] StudioCCharacters = { "Chuck E." };
int[][] SC_CyberBitMapR12 =
{
/* chuck */ new int[]{ 1, 2, 3, 4, 8, 5, 6, 7 },
/* helen */ new int[]{ 65, 66, 67, 68, 72, 69, 70, 71 },
/* munch */ new int[]{ 49, 50, 51, 56, 53, 54, 55, 52 },
/* jasper */ new int[]{ 17, 18, 19, 20, 24, 21, 22, 23 },
/* pasqually */ new int[]{ 33, 34, 35, 40, 37, 38, 39, 36 }
};
int[][] SC_CyberBitMapRosetta =
{
/* chuck */ new int[]{ 1, 6, 7, 8, 4, 5, 2, 19 },
/* helen */ new int[]{ 185, 178, 179, 180, 183, 184, 181, 169 },
/* munch */ new int[]{ 45, 54, 55, 43, 44, 41, 58, 59 },
/* jasper */ new int[]{ 166, 156, 157, 158, 156, 157, 151, 163 },
/* pasqually */ new int[]{ 30, 25, 21, 28, 29, 26, 31, 35 }
};
int[] CyberRosettaInvertedBits = { 2, 8, 181, 169, 41, 59, 58, 151, 158, 26, 35, 31 };
int[][] SC_RAE3stBitMap =
{
/* rolfe/chuck */ new int[]{ 1, 9, 10, 2, 3, 4, 5, 6, 7, 8, 11, 12, 13, 17, 18, 19, 14, 15, 16, 20, 36, 37 },
/* mitzi/helen */ new int[]{ 185, 176, 177, 181, 182, 183, 184, 178, 179, 180, 173, 175, 174, 168, 170, 169, 186, 187, 188 },
/* fatz/munch */ new int[]{ 45, 41, 42, 43, 44, 54, 55, 51, 52, 53, 57, 59, 58, 60, 61, 62 },
/* beach bear/jasper */ new int[]{ 166, 151, 152, 153, 156, 157, 158, 161, 162, 163, 164, 154, 155, 159, 160, 165 },
/* dook/pasqually */ new int[]{ 30, 23, 24, 26, 27, 28, 29, 25, 21, 22, 33, 35, 34, 31, 32, 63, 64 },
/* billy bob */ new int[]{ 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 189, 190, 194, 211, 212, 213 },
/* looney/pizzacam */ new int[]{ 167, 191, 192, 193, 171, 172, 48 }
};
int[][] SC_StudioCBitMap =
{
/* chuck e. */ new int[]{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32 }
};
bool FullStage = false;
const int USTVersion = 1;
public MainForm()
{
Title = "PinkConnection2 Showtape Converter";
Size = new Size(512, 384);
Maximizable = false;
Resizable = false;
BrowseFileButton.Command = new Command((sender, e) => { Event_BrowseFileButton(); });
ConvertButton.Command = new Command((sender, e) => { Event_ConvertFileButton(); });
InputTypeSelector.SelectedValueChanged += (sender, e) => Event_ChangeInputType();
OutputTypeSelector.SelectedValueChanged += (sender, e) => Event_ChangeOutputType();
foreach (string s in InputTypes)
{
InputTypeSelector.Items.Add(s);
}
Content = BuildLayout();
}
DynamicLayout BuildLayout()
{
DynamicLayout layout = new DynamicLayout { DefaultSpacing = new Size(10, 10), DefaultPadding = new Padding(5, 5, 5, 5) };
layout.BeginVertical();
layout.BeginHorizontal();
layout.Add(new Label { Text = "Input Format" });
layout.EndHorizontal();
layout.BeginHorizontal();
layout.Add(InputTypeSelector, true);
layout.EndHorizontal();
layout.BeginHorizontal();
layout.Add(new Label { Text = "Output Type" });
layout.EndHorizontal();
layout.BeginHorizontal();
layout.Add(OutputTypeSelector, true);
layout.EndHorizontal();
layout.BeginHorizontal();
layout.Add(new Label { Text = "Character" });
layout.EndHorizontal();
layout.BeginHorizontal();
layout.Add(CharacterSelector, true);
layout.EndHorizontal();
layout.EndVertical();
layout.BeginVertical();
layout.BeginHorizontal();
layout.Add(new Label { Text = "File to convert" });
layout.EndHorizontal();
layout.BeginHorizontal();
layout.Add(FilePathTextBox, true);
layout.Add(BrowseFileButton);
layout.EndHorizontal();
layout.EndVertical();
layout.BeginVertical();
layout.BeginHorizontal();
layout.Add(null, true);
layout.Add(ConvertButton);
layout.EndHorizontal();
layout.EndVertical();
layout.BeginVertical();
layout.Add(null, true);
layout.EndVertical();
return layout;
}
string MakeHeader(string showName, string outputType, string character)
{
string headerOut = $"UST,{USTVersion.ToString()},{showName.Replace(",", "_").Replace(";", "_")},";
bool fullStage = false;
switch (outputType)
{
case "UST 32 Bits (Single Bot RAE/3st)":
headerOut += "32,";
headerOut += "Rockafire Explosion/3-Stage (Single Character),";
break;
case "UST 8 Bits (Single Bot Cybers Rosetta)":
headerOut += "8,";
headerOut += "Cyberamics (Single Character),";
break;
case "UST 256 Bits (Full RAE/3st)":
headerOut += "256,";
headerOut += "Rockafire Explosion/3-Stage (Full Stage),";
fullStage = true;
break;
case "UST 256 Bits (Full Cybers Rosetta)":
headerOut += "256,";
headerOut += "Cyberamics (Full Stage),";
fullStage = true;
break;
case "UST 8 Bits (Single Bot Cybers)":
headerOut += "8,";
headerOut += "Cyberamics (Single Character),";
break;
case "UST 256 Bits (Full Cybers)":
headerOut += "256,";
headerOut += "Cyberamics (Full Stage),";
fullStage = true;
break;
case "UST 32 Bits (Single Bot Studio C)":
headerOut += "32,";
headerOut += "Studio C (Single Character),";
break;
case "UST 256 Bits (Full Studio C)":
headerOut += "256,";
headerOut += "Studio C (Full Stage),";
fullStage = true;
break;
}
if (fullStage) headerOut += "N/A,";
else headerOut += character + ";";
return headerOut;
}
void Event_ChangeInputType()
{
switch(InputTypeSelector.SelectedIndex)
{
case 0:
OutputTypeSelector.Items.Clear();
CharacterSelector.Items.Clear();
foreach (string s in RSHWOutputTypes)
{
OutputTypeSelector.Items.Add(s);
}
break;
case 1:
OutputTypeSelector.Items.Clear();
CharacterSelector.Items.Clear();
foreach (string s in CSHWOutputTypes)
{
OutputTypeSelector.Items.Add(s);
}
break;
case 2:
OutputTypeSelector.Items.Clear();
CharacterSelector.Items.Clear();
foreach (string s in SSHWOutputTypes)
{
OutputTypeSelector.Items.Add(s);
}
break;
}
}
void Event_ChangeOutputType()
{
switch(InputTypeSelector.SelectedIndex)
{
case 0:
switch(OutputTypeSelector.SelectedIndex)
{
case 0:
CharacterSelector.Items.Clear();
foreach (string s in RAE3stCharacters)
{
CharacterSelector.Items.Add(s);
}
CharacterSelector.Enabled = true;
FullStage = false;
break;
case 1:
CharacterSelector.Items.Clear();
foreach (string s in CyberCharacters)
{
CharacterSelector.Items.Add(s);
}
CharacterSelector.Enabled = true;
FullStage = false;
break;
case 2:
CharacterSelector.Items.Clear();
CharacterSelector.Enabled = false;
FullStage = true;
break;
case 3:
CharacterSelector.Items.Clear();
CharacterSelector.Enabled = false;
FullStage = true;
break;
}
break;
case 1:
switch(OutputTypeSelector.SelectedIndex)
{
case 0:
CharacterSelector.Items.Clear();
foreach (string s in CyberCharacters)
{
CharacterSelector.Items.Add(s);
}
CharacterSelector.Enabled = true;
FullStage = false;
break;
case 1:
CharacterSelector.Items.Clear();
CharacterSelector.Enabled = false;
FullStage = true;
break;
}
break;
case 2:
switch(OutputTypeSelector.SelectedIndex)
{
case 0:
CharacterSelector.Items.Clear();
foreach (string s in StudioCCharacters)
{
CharacterSelector.Items.Add(s);
}
CharacterSelector.Enabled = true;
FullStage = false;
break;
case 1:
CharacterSelector.Items.Clear();
CharacterSelector.Enabled = false;
FullStage = true;
break;
}
break;
}
}
void Event_BrowseFileButton()
{
OpenFileDialog fileDialog = new OpenFileDialog();
string[] showFiles = { ".rshw", ".cshw", ".sshw" };
string[] allFiles = { ".*" };
fileDialog.Filters.Add(new FileFilter("Show Files (.rshw, .cshw, .sshw)", showFiles));
fileDialog.Filters.Add(new FileFilter("All Files", allFiles));
fileDialog.Title = "Select Show File.";
fileDialog.ShowDialog(this);
if (File.Exists(fileDialog.FileName)) FilePathTextBox.Text = fileDialog.FileName;
}
void Event_ConvertFileButton()
{
// safeties
if (InputTypeSelector.SelectedIndex == -1)
{
MessageBox.Show("Fatal: You must select an input type.");
return;
}
if (OutputTypeSelector.SelectedIndex == -1)
{
MessageBox.Show("Fatal: You must select an output type.");
return;
}
if (CharacterSelector.SelectedIndex == -1 && !FullStage)
{
MessageBox.Show("Fatal: You must select a character.");
return;
}
if (FilePathTextBox.Text.Trim() == "")
{
MessageBox.Show("Fatal: You must select an input file.");
return;
}
if (!File.Exists(FilePathTextBox.Text.Trim()))
{
MessageBox.Show("Fatal: Specified input file does not exist.");
return;
}
if (FullStage)
{
MessageBox.Show("Fatal: Full Stage mode is not supported at this time.");
return;
}
SaveFileDialog fileDialog = new SaveFileDialog();
fileDialog.Filters.Add(new FileFilter("UST Files (.ust)", new string[]{".ust"}));
fileDialog.Title = "Select Show File.";
fileDialog.ShowDialog(this);
if (fileDialog.FileName.Trim() == "") return;
string outFilePath = fileDialog.FileName;
// now its actually time to start doing some shit
string inputType = InputTypeSelector.SelectedKey;
string outputType = OutputTypeSelector.SelectedKey;
string filePath = FilePathTextBox.Text.Trim();
if (inputType == "RSHW File (RR Engine)" || inputType == "CSHW File (RR Engine)" || inputType == "SSHW File (RR Engine)")
{
// at some point there should be a warning displayed if the input type does not match the file extension but i dont feel like doing that right now
// rshw time
RSHWFile file = RSHWLoader.Load(filePath);
if (file.signalData == null)
{
MessageBox.Show("Fatal: This file contains no signal data.");
return;
}
if (file.audioData == null)
{
MessageBox.Show("Fatal: This file contains no audio data.");
return;
}
List<BitArray> rshwBits = new List<BitArray>();
int countlength = 0;
if (file.signalData[0] != 0)
{
countlength = 1;
BitArray bit = new BitArray(300);
rshwBits.Add(bit);
}
for (int i = 0; i < file.signalData.Length; i++)
{
if (file.signalData[i] == 0)
{
countlength += 1;
BitArray bit = new BitArray(300);
rshwBits.Add(bit);
}
else
{
rshwBits[countlength - 1].Set(file.signalData[i], true);
}
}
// pick which target bits to use and how many bytes the output should be
int bitsCount = 0;
int[] targetBits = { 0 };
switch (outputType)
{
case "UST 32 Bits (Single Bot RAE/3st)":
bitsCount = 32;
targetBits = SC_RAE3stBitMap[Array.IndexOf(RAE3stCharacters, CharacterSelector.SelectedKey)];
break;
case "UST 8 Bits (Single Bot Cybers Rosetta)":
bitsCount = 8;
targetBits = SC_CyberBitMapRosetta[Array.IndexOf(CyberCharacters, CharacterSelector.SelectedKey)];
break;
case "UST 256 Bits (Full RAE/3st)":
bitsCount = 256;
break;
case "UST 256 Bits (Full Cybers Rosetta)":
bitsCount = 256;
break;
case "UST 8 Bits (Single Bot Cybers)":
bitsCount = 8;
targetBits = SC_CyberBitMapR12[Array.IndexOf(CyberCharacters, CharacterSelector.SelectedKey)];
break;
case "UST 256 Bits (Full Cybers)":
bitsCount = 256;
break;
case "UST 32 Bits (Single Bot Studio C)":
bitsCount = 32;
targetBits = SC_StudioCBitMap[Array.IndexOf(StudioCCharacters, CharacterSelector.SelectedKey)];
break;
case "UST 256 Bits (Full Studio C)":
bitsCount = 256;
break;
}
List<string> writeOut = new List<string>();
foreach (BitArray bits in rshwBits)
{
int frameByte = 0;
for (int i = 0; i < targetBits.Length; i++)
{
if (bits.Get(targetBits[i])) frameByte += 1 << i;
}
writeOut.Add(frameByte.ToString($"X{(bitsCount/4).ToString()}"));
}
File.WriteAllText(outFilePath, MakeHeader(Path.GetFileNameWithoutExtension(outFilePath), outputType, CharacterSelector.SelectedKey)+String.Join(",", writeOut.ToArray())+";"+Convert.ToBase64String(file.audioData));
}
MessageBox.Show("Conversion complete!");
}
}
}

View file

@ -1,57 +0,0 @@
using System;
using Eto.Forms;
using Eto.Drawing;
namespace PC2Player
{
public partial class MainForm : Form
{
public MainForm()
{
Title = "My Eto Form";
MinimumSize = new Size(200, 200);
Content = new StackLayout
{
Padding = 10,
Items =
{
"Hello World!",
// add more controls here
}
};
// create a few commands that can be used for the menu and toolbar
var clickMe = new Command { MenuText = "Click Me!", ToolBarText = "Click Me!" };
clickMe.Executed += (sender, e) => MessageBox.Show(this, "I was clicked!");
var quitCommand = new Command { MenuText = "Quit", Shortcut = Application.Instance.CommonModifier | Keys.Q };
quitCommand.Executed += (sender, e) => Application.Instance.Quit();
var aboutCommand = new Command { MenuText = "About..." };
aboutCommand.Executed += (sender, e) => new AboutDialog().ShowDialog(this);
// create menu
Menu = new MenuBar
{
Items =
{
// File submenu
new SubMenuItem { Text = "&File", Items = { clickMe } },
// new SubMenuItem { Text = "&Edit", Items = { /* commands/items */ } },
// new SubMenuItem { Text = "&View", Items = { /* commands/items */ } },
},
ApplicationItems =
{
// application (OS X) or file menu (others)
new ButtonMenuItem { Text = "&Preferences..." },
},
QuitItem = quitCommand,
AboutItem = aboutCommand
};
// create toolbar
ToolBar = new ToolBar { Items = { clickMe } };
}
}
}

25
PC3Player/PC3Player.sln Normal file
View file

@ -0,0 +1,25 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.14.36221.1 d17.14
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PC3Player", "PC3Player\PC3Player.csproj", "{13092811-9CBA-4FD5-B780-E67E14221992}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{13092811-9CBA-4FD5-B780-E67E14221992}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{13092811-9CBA-4FD5-B780-E67E14221992}.Debug|Any CPU.Build.0 = Debug|Any CPU
{13092811-9CBA-4FD5-B780-E67E14221992}.Release|Any CPU.ActiveCfg = Release|Any CPU
{13092811-9CBA-4FD5-B780-E67E14221992}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {7BE19417-D601-45AA-B189-5AC9C4B041B6}
EndGlobalSection
EndGlobal

View file

@ -0,0 +1,829 @@
namespace PC3Player
{
partial class AdvancedSettingsForm
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
components = new System.ComponentModel.Container();
PlaylistPlaybackGroupBox = new GroupBox();
LoopCheckBox = new CheckBox();
IntermissionUnitDropDown = new ComboBox();
IntermissionTimeCounter = new NumericUpDown();
IntermissionCheckBox = new CheckBox();
label2 = new Label();
ShowEndedDropDown = new ComboBox();
label1 = new Label();
PlaylistStartedDropDown = new ComboBox();
ShowSelectorGroupBox = new GroupBox();
AddSkitButton = new Button();
SkitCheckBox = new CheckBox();
label5 = new Label();
AlreadyPlayingDropDown = new ComboBox();
CooldownUnitDropDown = new ComboBox();
CooldownTimeCounter = new NumericUpDown();
CooldownCheckBox = new CheckBox();
label3 = new Label();
SelectedShowEndDropDown = new ComboBox();
label4 = new Label();
ButtonPressDropDown = new ComboBox();
ShowSelectorAssignmentGroupBox = new GroupBox();
AssignmentPanel = new Panel();
ButtonAssignDropDown1 = new ComboBox();
ButtonAssignDropDown2 = new ComboBox();
ButtonAssignDropDown3 = new ComboBox();
ButtonAssignDropDown4 = new ComboBox();
ButtonAssignDropDown5 = new ComboBox();
ButtonAssignDropDown6 = new ComboBox();
ButtonAssignDropDown7 = new ComboBox();
ButtonAssignDropDown8 = new ComboBox();
ButtonAssignDropDown9 = new ComboBox();
ButtonAssignDropDown10 = new ComboBox();
ButtonAssignDropDown11 = new ComboBox();
ButtonAssignDropDown12 = new ComboBox();
label14 = new Label();
label15 = new Label();
label16 = new Label();
label17 = new Label();
label10 = new Label();
label11 = new Label();
label12 = new Label();
label13 = new Label();
label8 = new Label();
label9 = new Label();
label7 = new Label();
label6 = new Label();
SkitListView = new ListView();
NameColumnHeader = new ColumnHeader();
LengthColumnHeader = new ColumnHeader();
SkitContextMenu = new ContextMenuStrip(components);
RemoveButton = new ToolStripMenuItem();
SaveButton = new Button();
CancelButton = new Button();
SelectShowFileDialog = new OpenFileDialog();
PlaybackGroupBox = new GroupBox();
label20 = new Label();
label19 = new Label();
label18 = new Label();
ResyncTimeOption = new NumericUpDown();
FrameShiftOption = new NumericUpDown();
FrameSkipOption = new NumericUpDown();
PlaylistPlaybackGroupBox.SuspendLayout();
((System.ComponentModel.ISupportInitialize)IntermissionTimeCounter).BeginInit();
ShowSelectorGroupBox.SuspendLayout();
((System.ComponentModel.ISupportInitialize)CooldownTimeCounter).BeginInit();
ShowSelectorAssignmentGroupBox.SuspendLayout();
AssignmentPanel.SuspendLayout();
SkitContextMenu.SuspendLayout();
PlaybackGroupBox.SuspendLayout();
((System.ComponentModel.ISupportInitialize)ResyncTimeOption).BeginInit();
((System.ComponentModel.ISupportInitialize)FrameShiftOption).BeginInit();
((System.ComponentModel.ISupportInitialize)FrameSkipOption).BeginInit();
SuspendLayout();
//
// PlaylistPlaybackGroupBox
//
PlaylistPlaybackGroupBox.Controls.Add(LoopCheckBox);
PlaylistPlaybackGroupBox.Controls.Add(IntermissionUnitDropDown);
PlaylistPlaybackGroupBox.Controls.Add(IntermissionTimeCounter);
PlaylistPlaybackGroupBox.Controls.Add(IntermissionCheckBox);
PlaylistPlaybackGroupBox.Controls.Add(label2);
PlaylistPlaybackGroupBox.Controls.Add(ShowEndedDropDown);
PlaylistPlaybackGroupBox.Controls.Add(label1);
PlaylistPlaybackGroupBox.Controls.Add(PlaylistStartedDropDown);
PlaylistPlaybackGroupBox.Location = new Point(12, 12);
PlaylistPlaybackGroupBox.Name = "PlaylistPlaybackGroupBox";
PlaylistPlaybackGroupBox.Size = new Size(350, 138);
PlaylistPlaybackGroupBox.TabIndex = 0;
PlaylistPlaybackGroupBox.TabStop = false;
PlaylistPlaybackGroupBox.Text = "Playlist Playback";
//
// LoopCheckBox
//
LoopCheckBox.AutoSize = true;
LoopCheckBox.Location = new Point(6, 111);
LoopCheckBox.Name = "LoopCheckBox";
LoopCheckBox.Size = new Size(162, 19);
LoopCheckBox.TabIndex = 5;
LoopCheckBox.Text = "Loop when Playlist is over";
LoopCheckBox.UseVisualStyleBackColor = true;
//
// IntermissionUnitDropDown
//
IntermissionUnitDropDown.DropDownStyle = ComboBoxStyle.DropDownList;
IntermissionUnitDropDown.FormattingEnabled = true;
IntermissionUnitDropDown.Items.AddRange(new object[] { "Minutes", "Seconds" });
IntermissionUnitDropDown.Location = new Point(250, 80);
IntermissionUnitDropDown.Name = "IntermissionUnitDropDown";
IntermissionUnitDropDown.Size = new Size(94, 23);
IntermissionUnitDropDown.TabIndex = 4;
//
// IntermissionTimeCounter
//
IntermissionTimeCounter.Location = new Point(194, 80);
IntermissionTimeCounter.Maximum = new decimal(new int[] { 60, 0, 0, 0 });
IntermissionTimeCounter.Name = "IntermissionTimeCounter";
IntermissionTimeCounter.Size = new Size(50, 23);
IntermissionTimeCounter.TabIndex = 3;
//
// IntermissionCheckBox
//
IntermissionCheckBox.AutoSize = true;
IntermissionCheckBox.Location = new Point(6, 82);
IntermissionCheckBox.Name = "IntermissionCheckBox";
IntermissionCheckBox.Size = new Size(135, 19);
IntermissionCheckBox.TabIndex = 2;
IntermissionCheckBox.Text = "Wait between Shows";
IntermissionCheckBox.UseVisualStyleBackColor = true;
IntermissionCheckBox.CheckedChanged += IntermissionCheckBox_CheckedChanged;
//
// label2
//
label2.AutoSize = true;
label2.Location = new Point(6, 54);
label2.Name = "label2";
label2.Size = new Size(107, 15);
label2.TabIndex = 3;
label2.Text = "When a Show ends";
//
// ShowEndedDropDown
//
ShowEndedDropDown.DropDownStyle = ComboBoxStyle.DropDownList;
ShowEndedDropDown.FormattingEnabled = true;
ShowEndedDropDown.Items.AddRange(new object[] { "Play Next Show", "Play Random Show", "Repeat Show", "Stop Playlist" });
ShowEndedDropDown.Location = new Point(194, 51);
ShowEndedDropDown.Name = "ShowEndedDropDown";
ShowEndedDropDown.Size = new Size(150, 23);
ShowEndedDropDown.TabIndex = 1;
//
// label1
//
label1.AutoSize = true;
label1.Location = new Point(6, 25);
label1.Name = "label1";
label1.Size = new Size(128, 15);
label1.TabIndex = 1;
label1.Text = "When Playlist is started";
//
// PlaylistStartedDropDown
//
PlaylistStartedDropDown.DropDownStyle = ComboBoxStyle.DropDownList;
PlaylistStartedDropDown.FormattingEnabled = true;
PlaylistStartedDropDown.Items.AddRange(new object[] { "Play First Show", "Play Random Show" });
PlaylistStartedDropDown.Location = new Point(194, 22);
PlaylistStartedDropDown.Name = "PlaylistStartedDropDown";
PlaylistStartedDropDown.Size = new Size(150, 23);
PlaylistStartedDropDown.TabIndex = 0;
//
// ShowSelectorGroupBox
//
ShowSelectorGroupBox.Controls.Add(AddSkitButton);
ShowSelectorGroupBox.Controls.Add(SkitCheckBox);
ShowSelectorGroupBox.Controls.Add(label5);
ShowSelectorGroupBox.Controls.Add(AlreadyPlayingDropDown);
ShowSelectorGroupBox.Controls.Add(CooldownUnitDropDown);
ShowSelectorGroupBox.Controls.Add(CooldownTimeCounter);
ShowSelectorGroupBox.Controls.Add(CooldownCheckBox);
ShowSelectorGroupBox.Controls.Add(label3);
ShowSelectorGroupBox.Controls.Add(SelectedShowEndDropDown);
ShowSelectorGroupBox.Controls.Add(label4);
ShowSelectorGroupBox.Controls.Add(ButtonPressDropDown);
ShowSelectorGroupBox.Location = new Point(12, 156);
ShowSelectorGroupBox.Name = "ShowSelectorGroupBox";
ShowSelectorGroupBox.Size = new Size(350, 165);
ShowSelectorGroupBox.TabIndex = 1;
ShowSelectorGroupBox.TabStop = false;
ShowSelectorGroupBox.Text = "Show Selector";
//
// AddSkitButton
//
AddSkitButton.Location = new Point(250, 136);
AddSkitButton.Name = "AddSkitButton";
AddSkitButton.Size = new Size(94, 23);
AddSkitButton.TabIndex = 7;
AddSkitButton.Text = "Add Skit";
AddSkitButton.UseVisualStyleBackColor = true;
AddSkitButton.Click += AddSkitButton_Click;
//
// SkitCheckBox
//
SkitCheckBox.AutoSize = true;
SkitCheckBox.Location = new Point(6, 138);
SkitCheckBox.Name = "SkitCheckBox";
SkitCheckBox.Size = new Size(231, 19);
SkitCheckBox.TabIndex = 6;
SkitCheckBox.Text = "Play random Skit before Selected Show";
SkitCheckBox.UseVisualStyleBackColor = true;
//
// label5
//
label5.AutoSize = true;
label5.Location = new Point(6, 54);
label5.Name = "label5";
label5.Size = new Size(149, 15);
label5.TabIndex = 8;
label5.Text = "If a Show is already playing";
//
// AlreadyPlayingDropDown
//
AlreadyPlayingDropDown.DropDownStyle = ComboBoxStyle.DropDownList;
AlreadyPlayingDropDown.FormattingEnabled = true;
AlreadyPlayingDropDown.Items.AddRange(new object[] { "Stop current", "Play after finished", "Ignore button" });
AlreadyPlayingDropDown.Location = new Point(194, 51);
AlreadyPlayingDropDown.Name = "AlreadyPlayingDropDown";
AlreadyPlayingDropDown.Size = new Size(150, 23);
AlreadyPlayingDropDown.TabIndex = 1;
//
// CooldownUnitDropDown
//
CooldownUnitDropDown.DropDownStyle = ComboBoxStyle.DropDownList;
CooldownUnitDropDown.FormattingEnabled = true;
CooldownUnitDropDown.Items.AddRange(new object[] { "Minutes", "Seconds" });
CooldownUnitDropDown.Location = new Point(250, 107);
CooldownUnitDropDown.Name = "CooldownUnitDropDown";
CooldownUnitDropDown.Size = new Size(94, 23);
CooldownUnitDropDown.TabIndex = 5;
//
// CooldownTimeCounter
//
CooldownTimeCounter.Location = new Point(194, 107);
CooldownTimeCounter.Maximum = new decimal(new int[] { 60, 0, 0, 0 });
CooldownTimeCounter.Name = "CooldownTimeCounter";
CooldownTimeCounter.Size = new Size(50, 23);
CooldownTimeCounter.TabIndex = 4;
//
// CooldownCheckBox
//
CooldownCheckBox.AutoSize = true;
CooldownCheckBox.Location = new Point(6, 109);
CooldownCheckBox.Name = "CooldownCheckBox";
CooldownCheckBox.Size = new Size(185, 19);
CooldownCheckBox.TabIndex = 3;
CooldownCheckBox.Text = "Cooldown between Selections";
CooldownCheckBox.UseVisualStyleBackColor = true;
CooldownCheckBox.CheckedChanged += CooldownCheckBox_CheckedChanged;
//
// label3
//
label3.AutoSize = true;
label3.Location = new Point(6, 83);
label3.Name = "label3";
label3.Size = new Size(154, 15);
label3.TabIndex = 3;
label3.Text = "When a Selected Show ends";
//
// SelectedShowEndDropDown
//
SelectedShowEndDropDown.DropDownStyle = ComboBoxStyle.DropDownList;
SelectedShowEndDropDown.FormattingEnabled = true;
SelectedShowEndDropDown.Items.AddRange(new object[] { "Return to Playlist", "Do Nothing" });
SelectedShowEndDropDown.Location = new Point(194, 80);
SelectedShowEndDropDown.Name = "SelectedShowEndDropDown";
SelectedShowEndDropDown.Size = new Size(150, 23);
SelectedShowEndDropDown.TabIndex = 2;
//
// label4
//
label4.AutoSize = true;
label4.Location = new Point(6, 25);
label4.Name = "label4";
label4.Size = new Size(140, 15);
label4.TabIndex = 1;
label4.Text = "When a Button is pressed";
//
// ButtonPressDropDown
//
ButtonPressDropDown.DropDownStyle = ComboBoxStyle.DropDownList;
ButtonPressDropDown.FormattingEnabled = true;
ButtonPressDropDown.Items.AddRange(new object[] { "Play Assigned Show", "Play Random Show" });
ButtonPressDropDown.Location = new Point(194, 22);
ButtonPressDropDown.Name = "ButtonPressDropDown";
ButtonPressDropDown.Size = new Size(150, 23);
ButtonPressDropDown.TabIndex = 0;
//
// ShowSelectorAssignmentGroupBox
//
ShowSelectorAssignmentGroupBox.Controls.Add(AssignmentPanel);
ShowSelectorAssignmentGroupBox.Controls.Add(label14);
ShowSelectorAssignmentGroupBox.Controls.Add(label15);
ShowSelectorAssignmentGroupBox.Controls.Add(label16);
ShowSelectorAssignmentGroupBox.Controls.Add(label17);
ShowSelectorAssignmentGroupBox.Controls.Add(label10);
ShowSelectorAssignmentGroupBox.Controls.Add(label11);
ShowSelectorAssignmentGroupBox.Controls.Add(label12);
ShowSelectorAssignmentGroupBox.Controls.Add(label13);
ShowSelectorAssignmentGroupBox.Controls.Add(label8);
ShowSelectorAssignmentGroupBox.Controls.Add(label9);
ShowSelectorAssignmentGroupBox.Controls.Add(label7);
ShowSelectorAssignmentGroupBox.Controls.Add(label6);
ShowSelectorAssignmentGroupBox.Location = new Point(368, 12);
ShowSelectorAssignmentGroupBox.Name = "ShowSelectorAssignmentGroupBox";
ShowSelectorAssignmentGroupBox.Size = new Size(256, 370);
ShowSelectorAssignmentGroupBox.TabIndex = 3;
ShowSelectorAssignmentGroupBox.TabStop = false;
ShowSelectorAssignmentGroupBox.Text = "Show Selector Assignment";
//
// AssignmentPanel
//
AssignmentPanel.Controls.Add(ButtonAssignDropDown1);
AssignmentPanel.Controls.Add(ButtonAssignDropDown2);
AssignmentPanel.Controls.Add(ButtonAssignDropDown3);
AssignmentPanel.Controls.Add(ButtonAssignDropDown4);
AssignmentPanel.Controls.Add(ButtonAssignDropDown5);
AssignmentPanel.Controls.Add(ButtonAssignDropDown6);
AssignmentPanel.Controls.Add(ButtonAssignDropDown7);
AssignmentPanel.Controls.Add(ButtonAssignDropDown8);
AssignmentPanel.Controls.Add(ButtonAssignDropDown9);
AssignmentPanel.Controls.Add(ButtonAssignDropDown10);
AssignmentPanel.Controls.Add(ButtonAssignDropDown11);
AssignmentPanel.Controls.Add(ButtonAssignDropDown12);
AssignmentPanel.Location = new Point(100, 22);
AssignmentPanel.Name = "AssignmentPanel";
AssignmentPanel.Size = new Size(150, 342);
AssignmentPanel.TabIndex = 0;
//
// ButtonAssignDropDown1
//
ButtonAssignDropDown1.DropDownStyle = ComboBoxStyle.DropDownList;
ButtonAssignDropDown1.FormattingEnabled = true;
ButtonAssignDropDown1.Items.AddRange(new object[] { "(None)" });
ButtonAssignDropDown1.Location = new Point(0, 0);
ButtonAssignDropDown1.Name = "ButtonAssignDropDown1";
ButtonAssignDropDown1.Size = new Size(150, 23);
ButtonAssignDropDown1.TabIndex = 0;
//
// ButtonAssignDropDown2
//
ButtonAssignDropDown2.DropDownStyle = ComboBoxStyle.DropDownList;
ButtonAssignDropDown2.FormattingEnabled = true;
ButtonAssignDropDown2.Items.AddRange(new object[] { "(None)" });
ButtonAssignDropDown2.Location = new Point(0, 29);
ButtonAssignDropDown2.Name = "ButtonAssignDropDown2";
ButtonAssignDropDown2.Size = new Size(150, 23);
ButtonAssignDropDown2.TabIndex = 1;
//
// ButtonAssignDropDown3
//
ButtonAssignDropDown3.DropDownStyle = ComboBoxStyle.DropDownList;
ButtonAssignDropDown3.FormattingEnabled = true;
ButtonAssignDropDown3.Items.AddRange(new object[] { "(None)" });
ButtonAssignDropDown3.Location = new Point(0, 58);
ButtonAssignDropDown3.Name = "ButtonAssignDropDown3";
ButtonAssignDropDown3.Size = new Size(150, 23);
ButtonAssignDropDown3.TabIndex = 2;
//
// ButtonAssignDropDown4
//
ButtonAssignDropDown4.DropDownStyle = ComboBoxStyle.DropDownList;
ButtonAssignDropDown4.FormattingEnabled = true;
ButtonAssignDropDown4.Items.AddRange(new object[] { "(None)" });
ButtonAssignDropDown4.Location = new Point(0, 87);
ButtonAssignDropDown4.Name = "ButtonAssignDropDown4";
ButtonAssignDropDown4.Size = new Size(150, 23);
ButtonAssignDropDown4.TabIndex = 3;
//
// ButtonAssignDropDown5
//
ButtonAssignDropDown5.DropDownStyle = ComboBoxStyle.DropDownList;
ButtonAssignDropDown5.FormattingEnabled = true;
ButtonAssignDropDown5.Items.AddRange(new object[] { "(None)" });
ButtonAssignDropDown5.Location = new Point(0, 116);
ButtonAssignDropDown5.Name = "ButtonAssignDropDown5";
ButtonAssignDropDown5.Size = new Size(150, 23);
ButtonAssignDropDown5.TabIndex = 4;
//
// ButtonAssignDropDown6
//
ButtonAssignDropDown6.DropDownStyle = ComboBoxStyle.DropDownList;
ButtonAssignDropDown6.FormattingEnabled = true;
ButtonAssignDropDown6.Items.AddRange(new object[] { "(None)" });
ButtonAssignDropDown6.Location = new Point(0, 145);
ButtonAssignDropDown6.Name = "ButtonAssignDropDown6";
ButtonAssignDropDown6.Size = new Size(150, 23);
ButtonAssignDropDown6.TabIndex = 5;
//
// ButtonAssignDropDown7
//
ButtonAssignDropDown7.DropDownStyle = ComboBoxStyle.DropDownList;
ButtonAssignDropDown7.FormattingEnabled = true;
ButtonAssignDropDown7.Items.AddRange(new object[] { "(None)" });
ButtonAssignDropDown7.Location = new Point(0, 174);
ButtonAssignDropDown7.Name = "ButtonAssignDropDown7";
ButtonAssignDropDown7.Size = new Size(150, 23);
ButtonAssignDropDown7.TabIndex = 6;
//
// ButtonAssignDropDown8
//
ButtonAssignDropDown8.DropDownStyle = ComboBoxStyle.DropDownList;
ButtonAssignDropDown8.FormattingEnabled = true;
ButtonAssignDropDown8.Items.AddRange(new object[] { "(None)" });
ButtonAssignDropDown8.Location = new Point(0, 203);
ButtonAssignDropDown8.Name = "ButtonAssignDropDown8";
ButtonAssignDropDown8.Size = new Size(150, 23);
ButtonAssignDropDown8.TabIndex = 7;
//
// ButtonAssignDropDown9
//
ButtonAssignDropDown9.DropDownStyle = ComboBoxStyle.DropDownList;
ButtonAssignDropDown9.FormattingEnabled = true;
ButtonAssignDropDown9.Items.AddRange(new object[] { "(None)" });
ButtonAssignDropDown9.Location = new Point(0, 232);
ButtonAssignDropDown9.Name = "ButtonAssignDropDown9";
ButtonAssignDropDown9.Size = new Size(150, 23);
ButtonAssignDropDown9.TabIndex = 8;
//
// ButtonAssignDropDown10
//
ButtonAssignDropDown10.DropDownStyle = ComboBoxStyle.DropDownList;
ButtonAssignDropDown10.FormattingEnabled = true;
ButtonAssignDropDown10.Items.AddRange(new object[] { "(None)" });
ButtonAssignDropDown10.Location = new Point(0, 261);
ButtonAssignDropDown10.Name = "ButtonAssignDropDown10";
ButtonAssignDropDown10.Size = new Size(150, 23);
ButtonAssignDropDown10.TabIndex = 9;
//
// ButtonAssignDropDown11
//
ButtonAssignDropDown11.DropDownStyle = ComboBoxStyle.DropDownList;
ButtonAssignDropDown11.FormattingEnabled = true;
ButtonAssignDropDown11.Items.AddRange(new object[] { "(None)" });
ButtonAssignDropDown11.Location = new Point(0, 290);
ButtonAssignDropDown11.Name = "ButtonAssignDropDown11";
ButtonAssignDropDown11.Size = new Size(150, 23);
ButtonAssignDropDown11.TabIndex = 10;
//
// ButtonAssignDropDown12
//
ButtonAssignDropDown12.DropDownStyle = ComboBoxStyle.DropDownList;
ButtonAssignDropDown12.FormattingEnabled = true;
ButtonAssignDropDown12.Items.AddRange(new object[] { "(None)" });
ButtonAssignDropDown12.Location = new Point(0, 319);
ButtonAssignDropDown12.Name = "ButtonAssignDropDown12";
ButtonAssignDropDown12.Size = new Size(150, 23);
ButtonAssignDropDown12.TabIndex = 11;
//
// label14
//
label14.AutoSize = true;
label14.Location = new Point(6, 344);
label14.Name = "label14";
label14.Size = new Size(58, 15);
label14.TabIndex = 30;
label14.Text = "Button 12";
//
// label15
//
label15.AutoSize = true;
label15.Location = new Point(6, 315);
label15.Name = "label15";
label15.Size = new Size(58, 15);
label15.TabIndex = 28;
label15.Text = "Button 11";
//
// label16
//
label16.AutoSize = true;
label16.Location = new Point(6, 286);
label16.Name = "label16";
label16.Size = new Size(58, 15);
label16.TabIndex = 26;
label16.Text = "Button 10";
//
// label17
//
label17.AutoSize = true;
label17.Location = new Point(6, 257);
label17.Name = "label17";
label17.Size = new Size(52, 15);
label17.TabIndex = 24;
label17.Text = "Button 9";
//
// label10
//
label10.AutoSize = true;
label10.Location = new Point(6, 228);
label10.Name = "label10";
label10.Size = new Size(52, 15);
label10.TabIndex = 22;
label10.Text = "Button 8";
//
// label11
//
label11.AutoSize = true;
label11.Location = new Point(6, 199);
label11.Name = "label11";
label11.Size = new Size(52, 15);
label11.TabIndex = 20;
label11.Text = "Button 7";
//
// label12
//
label12.AutoSize = true;
label12.Location = new Point(6, 170);
label12.Name = "label12";
label12.Size = new Size(52, 15);
label12.TabIndex = 18;
label12.Text = "Button 6";
//
// label13
//
label13.AutoSize = true;
label13.Location = new Point(6, 141);
label13.Name = "label13";
label13.Size = new Size(52, 15);
label13.TabIndex = 16;
label13.Text = "Button 5";
//
// label8
//
label8.AutoSize = true;
label8.Location = new Point(6, 112);
label8.Name = "label8";
label8.Size = new Size(52, 15);
label8.TabIndex = 14;
label8.Text = "Button 4";
//
// label9
//
label9.AutoSize = true;
label9.Location = new Point(6, 83);
label9.Name = "label9";
label9.Size = new Size(52, 15);
label9.TabIndex = 12;
label9.Text = "Button 3";
//
// label7
//
label7.AutoSize = true;
label7.Location = new Point(6, 54);
label7.Name = "label7";
label7.Size = new Size(52, 15);
label7.TabIndex = 10;
label7.Text = "Button 2";
//
// label6
//
label6.AutoSize = true;
label6.Location = new Point(6, 25);
label6.Name = "label6";
label6.Size = new Size(52, 15);
label6.TabIndex = 8;
label6.Text = "Button 1";
//
// SkitListView
//
SkitListView.AutoArrange = false;
SkitListView.Columns.AddRange(new ColumnHeader[] { NameColumnHeader, LengthColumnHeader });
SkitListView.ContextMenuStrip = SkitContextMenu;
SkitListView.GridLines = true;
SkitListView.HeaderStyle = ColumnHeaderStyle.Nonclickable;
SkitListView.Location = new Point(12, 327);
SkitListView.MultiSelect = false;
SkitListView.Name = "SkitListView";
SkitListView.Size = new Size(350, 201);
SkitListView.TabIndex = 2;
SkitListView.UseCompatibleStateImageBehavior = false;
SkitListView.View = View.Details;
//
// NameColumnHeader
//
NameColumnHeader.Text = "Skit Name";
NameColumnHeader.Width = 260;
//
// LengthColumnHeader
//
LengthColumnHeader.Text = "Length";
//
// SkitContextMenu
//
SkitContextMenu.Items.AddRange(new ToolStripItem[] { RemoveButton });
SkitContextMenu.Name = "ShowContextMenu";
SkitContextMenu.Size = new Size(118, 26);
//
// RemoveButton
//
RemoveButton.Name = "RemoveButton";
RemoveButton.Size = new Size(117, 22);
RemoveButton.Text = "Remove";
RemoveButton.Click += RemoveButton_Click;
//
// SaveButton
//
SaveButton.DialogResult = DialogResult.OK;
SaveButton.Location = new Point(549, 503);
SaveButton.Name = "SaveButton";
SaveButton.Size = new Size(75, 25);
SaveButton.TabIndex = 10;
SaveButton.Text = "Save";
SaveButton.UseVisualStyleBackColor = true;
SaveButton.Click += SaveButton_Click;
//
// CancelButton
//
CancelButton.DialogResult = DialogResult.Cancel;
CancelButton.Location = new Point(468, 503);
CancelButton.Name = "CancelButton";
CancelButton.Size = new Size(75, 25);
CancelButton.TabIndex = 11;
CancelButton.Text = "Cancel";
CancelButton.UseVisualStyleBackColor = true;
//
// SelectShowFileDialog
//
SelectShowFileDialog.Filter = "UST Showtapes|*.ust";
SelectShowFileDialog.Multiselect = true;
//
// PlaybackGroupBox
//
PlaybackGroupBox.Controls.Add(label20);
PlaybackGroupBox.Controls.Add(label19);
PlaybackGroupBox.Controls.Add(label18);
PlaybackGroupBox.Controls.Add(ResyncTimeOption);
PlaybackGroupBox.Controls.Add(FrameShiftOption);
PlaybackGroupBox.Controls.Add(FrameSkipOption);
PlaybackGroupBox.Location = new Point(368, 388);
PlaybackGroupBox.Name = "PlaybackGroupBox";
PlaybackGroupBox.Size = new Size(256, 109);
PlaybackGroupBox.TabIndex = 4;
PlaybackGroupBox.TabStop = false;
PlaybackGroupBox.Text = "Tracking Adjustments";
//
// label20
//
label20.AutoSize = true;
label20.Location = new Point(6, 82);
label20.Name = "label20";
label20.Size = new Size(67, 15);
label20.TabIndex = 5;
label20.Text = "Frame Shift";
//
// label19
//
label19.AutoSize = true;
label19.Location = new Point(6, 53);
label19.Name = "label19";
label19.Size = new Size(73, 15);
label19.TabIndex = 4;
label19.Text = "Resync Time";
//
// label18
//
label18.AutoSize = true;
label18.Location = new Point(6, 24);
label18.Name = "label18";
label18.Size = new Size(65, 15);
label18.TabIndex = 3;
label18.Text = "Frame Skip";
//
// ResyncTimeOption
//
ResyncTimeOption.Location = new Point(200, 51);
ResyncTimeOption.Maximum = new decimal(new int[] { 60, 0, 0, 0 });
ResyncTimeOption.Minimum = new decimal(new int[] { 1, 0, 0, 0 });
ResyncTimeOption.Name = "ResyncTimeOption";
ResyncTimeOption.Size = new Size(50, 23);
ResyncTimeOption.TabIndex = 1;
ResyncTimeOption.Value = new decimal(new int[] { 1, 0, 0, 0 });
//
// FrameShiftOption
//
FrameShiftOption.Location = new Point(200, 80);
FrameShiftOption.Maximum = new decimal(new int[] { 60, 0, 0, 0 });
FrameShiftOption.Minimum = new decimal(new int[] { 60, 0, 0, int.MinValue });
FrameShiftOption.Name = "FrameShiftOption";
FrameShiftOption.Size = new Size(50, 23);
FrameShiftOption.TabIndex = 2;
//
// FrameSkipOption
//
FrameSkipOption.Location = new Point(200, 22);
FrameSkipOption.Maximum = new decimal(new int[] { 10, 0, 0, 0 });
FrameSkipOption.Minimum = new decimal(new int[] { 1, 0, 0, 0 });
FrameSkipOption.Name = "FrameSkipOption";
FrameSkipOption.Size = new Size(50, 23);
FrameSkipOption.TabIndex = 0;
FrameSkipOption.Value = new decimal(new int[] { 1, 0, 0, 0 });
//
// AdvancedSettingsForm
//
AutoScaleDimensions = new SizeF(7F, 15F);
AutoScaleMode = AutoScaleMode.Font;
ClientSize = new Size(636, 540);
Controls.Add(PlaybackGroupBox);
Controls.Add(CancelButton);
Controls.Add(SaveButton);
Controls.Add(SkitListView);
Controls.Add(ShowSelectorAssignmentGroupBox);
Controls.Add(ShowSelectorGroupBox);
Controls.Add(PlaylistPlaybackGroupBox);
FormBorderStyle = FormBorderStyle.FixedDialog;
MaximizeBox = false;
Name = "AdvancedSettingsForm";
Text = "Advanced Settings";
PlaylistPlaybackGroupBox.ResumeLayout(false);
PlaylistPlaybackGroupBox.PerformLayout();
((System.ComponentModel.ISupportInitialize)IntermissionTimeCounter).EndInit();
ShowSelectorGroupBox.ResumeLayout(false);
ShowSelectorGroupBox.PerformLayout();
((System.ComponentModel.ISupportInitialize)CooldownTimeCounter).EndInit();
ShowSelectorAssignmentGroupBox.ResumeLayout(false);
ShowSelectorAssignmentGroupBox.PerformLayout();
AssignmentPanel.ResumeLayout(false);
SkitContextMenu.ResumeLayout(false);
PlaybackGroupBox.ResumeLayout(false);
PlaybackGroupBox.PerformLayout();
((System.ComponentModel.ISupportInitialize)ResyncTimeOption).EndInit();
((System.ComponentModel.ISupportInitialize)FrameShiftOption).EndInit();
((System.ComponentModel.ISupportInitialize)FrameSkipOption).EndInit();
ResumeLayout(false);
}
#endregion
private GroupBox PlaylistPlaybackGroupBox;
private Label label1;
private ComboBox PlaylistStartedDropDown;
private ComboBox ShowEndedDropDown;
private ComboBox IntermissionUnitDropDown;
private NumericUpDown IntermissionTimeCounter;
private CheckBox IntermissionCheckBox;
private Label label2;
private GroupBox ShowSelectorGroupBox;
private ComboBox CooldownUnitDropDown;
private NumericUpDown CooldownTimeCounter;
private CheckBox CooldownCheckBox;
private Label label3;
private ComboBox SelectedShowEndDropDown;
private Label label4;
private ComboBox ButtonPressDropDown;
private Label label5;
private ComboBox AlreadyPlayingDropDown;
private CheckBox SkitCheckBox;
private Button AddSkitButton;
private GroupBox ShowSelectorAssignmentGroupBox;
private Label label14;
private ComboBox ButtonAssignDropDown12;
private Label label15;
private ComboBox ButtonAssignDropDown11;
private Label label16;
private ComboBox ButtonAssignDropDown10;
private Label label17;
private ComboBox ButtonAssignDropDown9;
private Label label10;
private ComboBox ButtonAssignDropDown8;
private Label label11;
private ComboBox ButtonAssignDropDown7;
private Label label12;
private ComboBox ButtonAssignDropDown6;
private Label label13;
private ComboBox ButtonAssignDropDown5;
private Label label8;
private ComboBox ButtonAssignDropDown4;
private Label label9;
private ComboBox ButtonAssignDropDown3;
private Label label7;
private ComboBox ButtonAssignDropDown2;
private Label label6;
private ComboBox ButtonAssignDropDown1;
private ListView SkitListView;
private ColumnHeader NameColumnHeader;
private ColumnHeader LengthColumnHeader;
private Button SaveButton;
private Button CancelButton;
private ContextMenuStrip SkitContextMenu;
private ToolStripMenuItem RemoveButton;
private OpenFileDialog SelectShowFileDialog;
private Panel AssignmentPanel;
private CheckBox LoopCheckBox;
private GroupBox PlaybackGroupBox;
private Label label18;
private NumericUpDown ResyncTimeOption;
private NumericUpDown FrameShiftOption;
private NumericUpDown FrameSkipOption;
private Label label20;
private Label label19;
}
}

View file

@ -0,0 +1,146 @@
namespace PC3Player
{
public partial class AdvancedSettingsForm : Form
{
public PlaylistConfig EditingObject { get; set; }
public AdvancedSettingsForm(PlaylistConfig playlist)
{
InitializeComponent();
EditingObject = playlist;
PlaylistStartedDropDown.SelectedIndex = EditingObject.PlaylistStartOption;
ShowEndedDropDown.SelectedIndex = EditingObject.PlaylistShowEndOption;
IntermissionCheckBox.Checked = EditingObject.PlaylistIntermissionOption;
IntermissionTimeCounter.Value = EditingObject.PlaylistIntermissionTimeOption;
IntermissionUnitDropDown.SelectedIndex = EditingObject.PlaylistIntermissionUnitOption;
LoopCheckBox.Checked = EditingObject.PlaylistLoopOption;
ButtonPressDropDown.SelectedIndex = EditingObject.SelectorButtonPressOption;
AlreadyPlayingDropDown.SelectedIndex = EditingObject.SelectorShowAlreadyPlayingOption;
SelectedShowEndDropDown.SelectedIndex = EditingObject.SelectorShowEndOption;
CooldownCheckBox.Checked = EditingObject.SelectorCooldownOption;
CooldownTimeCounter.Value = EditingObject.SelectorCooldownTimeOption;
CooldownUnitDropDown.SelectedIndex = EditingObject.SelectorCooldownUnitOption;
SkitCheckBox.Checked = EditingObject.SelectorPlaySkitOption;
FrameSkipOption.Value = EditingObject.FramesPerTick;
FrameShiftOption.Value = EditingObject.FrameShift;
ResyncTimeOption.Value = EditingObject.ResyncSeconds;
IntermissionTimeCounter.Enabled = IntermissionCheckBox.Checked;
IntermissionUnitDropDown.Enabled = IntermissionCheckBox.Checked;
CooldownTimeCounter.Enabled = CooldownCheckBox.Checked;
CooldownUnitDropDown.Enabled = CooldownCheckBox.Checked;
int i = 0;
foreach (ComboBox c in AssignmentPanel.Controls)
{
foreach (PlaylistShow s in EditingObject.Shows) c.Items.Add(s.Name);
if (EditingObject.SelectorAssignments[i] == null) c.SelectedIndex = 0;
else c.SelectedIndex = (int)EditingObject.SelectorAssignments[i] + 1;
i++;
}
UpdateListView();
}
private void UpdateListView()
{
SkitListView.Items.Clear();
foreach (PlaylistShow s in EditingObject.Skits) SkitListView.Items.Add(new ListViewItem(new[] { s.Name, s.Length }));
SkitCheckBox.Enabled = EditingObject.Skits.Count != 0;
if (EditingObject.Skits.Count == 0) SkitCheckBox.Checked = false;
}
private void IntermissionCheckBox_CheckedChanged(object sender, EventArgs e)
{
IntermissionTimeCounter.Enabled = IntermissionCheckBox.Checked;
IntermissionUnitDropDown.Enabled = IntermissionCheckBox.Checked;
}
private void CooldownCheckBox_CheckedChanged(object sender, EventArgs e)
{
CooldownTimeCounter.Enabled = CooldownCheckBox.Checked;
CooldownUnitDropDown.Enabled = CooldownCheckBox.Checked;
}
private void RemoveButton_Click(object sender, EventArgs e)
{
if (SkitListView.SelectedIndices.Count == 0) return;
EditingObject.Skits.RemoveAt(SkitListView.SelectedIndices[0]);
UpdateListView();
}
private void AddSkitButton_Click(object sender, EventArgs e)
{
if (!MainForm.ChannelMappingLoaded)
{
MessageBox.Show("You must load a channel mapping first.", "Information", MessageBoxButtons.OK, MessageBoxIcon.Information);
return;
}
if (SelectShowFileDialog.ShowDialog() == DialogResult.OK)
{
string tempUSTData = File.ReadAllText(SelectShowFileDialog.FileName);
if (!tempUSTData.StartsWith("UST,2,"))
{
MessageBox.Show("Selected showtape is not a UST version 2 showtape.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
return;
}
string[] headerData = tempUSTData.Split(';')[0].Split(',');
string[] stringyBits = tempUSTData.Split(';')[1].Split(',');
TimeSpan time = TimeSpan.FromSeconds(stringyBits.Length / 60);
string formattedLength = time.ToString(@"hh\:mm\:ss");
tempUSTData = null;
stringyBits = null;
if (headerData[3] != EditingObject.Mapping.Type)
{
MessageBox.Show(
$"Selected showtape type does not match the loaded Channel Map." +
$"\nLoaded Channel Map Type: {EditingObject.Mapping.Type}" +
$"\nShowtape Type: {headerData[3]}"
, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
return;
}
EditingObject.Skits.Add(new PlaylistShow(headerData[2], formattedLength, headerData[3], SelectShowFileDialog.FileName));
UpdateListView();
}
}
private void SaveButton_Click(object sender, EventArgs e)
{
EditingObject.PlaylistStartOption = PlaylistStartedDropDown.SelectedIndex;
EditingObject.PlaylistShowEndOption = ShowEndedDropDown.SelectedIndex;
EditingObject.PlaylistIntermissionOption = IntermissionCheckBox.Checked;
EditingObject.PlaylistIntermissionTimeOption = (int)IntermissionTimeCounter.Value;
EditingObject.PlaylistIntermissionUnitOption = IntermissionUnitDropDown.SelectedIndex;
EditingObject.PlaylistLoopOption = LoopCheckBox.Checked;
EditingObject.SelectorButtonPressOption = ButtonPressDropDown.SelectedIndex;
EditingObject.SelectorShowAlreadyPlayingOption = AlreadyPlayingDropDown.SelectedIndex;
EditingObject.SelectorShowEndOption = SelectedShowEndDropDown.SelectedIndex;
EditingObject.SelectorCooldownOption = CooldownCheckBox.Checked;
EditingObject.SelectorCooldownTimeOption = (int)CooldownTimeCounter.Value;
EditingObject.SelectorCooldownUnitOption = CooldownUnitDropDown.SelectedIndex;
EditingObject.SelectorPlaySkitOption = SkitCheckBox.Checked;
EditingObject.ResyncSeconds = (int)ResyncTimeOption.Value;
EditingObject.FrameShift = (int)FrameShiftOption.Value;
EditingObject.FramesPerTick = (int)FrameSkipOption.Value;
int i = 0;
foreach (ComboBox c in AssignmentPanel.Controls)
{
if (c.SelectedIndex == 0) EditingObject.SelectorAssignments[i] = null;
else EditingObject.SelectorAssignments[i] = c.SelectedIndex - 1;
i++;
}
}
}
}

View file

@ -0,0 +1,126 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<metadata name="SkitContextMenu.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>51, 28</value>
</metadata>
<metadata name="SelectShowFileDialog.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>215, 23</value>
</metadata>
</root>

View file

@ -0,0 +1 @@
PC3MAPPING,2,Beach Bear/Jasper,Rockafire Explosion/3-Stage;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;0

View file

@ -0,0 +1 @@
PC3MAPPING,2,Billy Bob,Rockafire Explosion/3-Stage;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;0

View file

@ -0,0 +1 @@
PC3MAPPING,2,Cyberamic Chuck E.,Cyberamics;1,2,3,4,5,6,7,8;0

View file

@ -0,0 +1 @@
PC3MAPPING,2,Cyberamic Helen,Cyberamics;9,10,11,12,13,14,15,16;0

View file

@ -0,0 +1 @@
PC3MAPPING,2,Cyberamic Jasper,Cyberamics;25,26,27,28,29,30,31,32;0

View file

@ -0,0 +1 @@
PC3MAPPING,2,Cyberamic Munch,Cyberamics;17,18,19,20,21,22,23,24;0

View file

@ -0,0 +1 @@
PC3MAPPING,2,Cyberamic Pasqually,Cyberamics;33,34,35,36,37,38,39,40;0

View file

@ -0,0 +1 @@
PC3MAPPING,2,Dook/Pasqually,Rockafire Explosion/3-Stage;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;0

View file

@ -0,0 +1 @@
PC3MAPPING,2,Fatz/Munch,Rockafire Explosion/3-Stage;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;0

View file

@ -0,0 +1 @@
PC3MAPPING,2,Mitzi/Helen,Rockafire Explosion/3-Stage;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;0

View file

@ -0,0 +1 @@
PC3MAPPING,2,Rolfe/Chuck,Rockafire Explosion/3-Stage;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;0

View file

@ -0,0 +1,73 @@
using System.Diagnostics.Eventing.Reader;
namespace PC3Player
{
public class PlaylistShow
{
public PlaylistShow(string name, string length, string type, string filePath)
{
Name = name;
Type = type;
Length = length;
FilePath = filePath;
}
public string Name { get; set; }
public string Type { get; set; }
public string Length { get; set; }
public string FilePath { get; set; }
}
public class ChannelMapping
{
public ChannelMapping(string name, string type, int[] bits, int[] invertedBits)
{
Name = name;
Type = type;
Bits = bits;
InvertedBits = invertedBits;
}
public string Name { get; set; }
public string Type { get; set; }
public int[] Bits { get; set; }
public int[] InvertedBits { get; set; }
}
public class PlaylistConfig
{
public int PlaylistStartOption { get; set; } = 0;
public int PlaylistShowEndOption { get; set; } = 0;
public bool PlaylistIntermissionOption { get; set; } = false;
public int PlaylistIntermissionTimeOption { get; set; } = 8;
public int PlaylistIntermissionUnitOption { get; set; } = 0;
public bool PlaylistLoopOption { get; set; } = true;
public int SelectorButtonPressOption { get; set; } = 0;
public int SelectorShowAlreadyPlayingOption { get; set; } = 0;
public int SelectorShowEndOption { get; set; } = 0;
public bool SelectorCooldownOption { get; set; } = false;
public int SelectorCooldownTimeOption { get; set; } = 30;
public int SelectorCooldownUnitOption { get; set; } = 1;
public bool SelectorPlaySkitOption { get; set; } = false;
public int?[] SelectorAssignments { get; set; } = new int?[12];
public int FramesPerTick { get; set; } = 6;
public int ResyncSeconds { get; set; } = 1;
public int FrameShift { get; set; } = 0;
public ChannelMapping Mapping { get; set; }
public List<PlaylistShow> Shows { get; set; } = new List<PlaylistShow>();
public List<PlaylistShow> Skits { get; set; } = new List<PlaylistShow>();
}
public enum StartMethod
{
PlaylistStart,
PlaylistShowEnd,
SelectorPress,
SelectorShowEnd
}
}

414
PC3Player/PC3Player/MainForm.Designer.cs generated Normal file
View file

@ -0,0 +1,414 @@
namespace PC3Player
{
partial class MainForm
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
components = new System.ComponentModel.Container();
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(MainForm));
ControllerGroupBox = new GroupBox();
ControllerSelectSerialPortButton = new Button();
ControllerAutoDetectButton = new Button();
PlaybackControlsGroupBox = new GroupBox();
TimeLabel = new Label();
StopButton = new Button();
SkipButton = new Button();
PauseButton = new Button();
StartButton = new Button();
ShowSelectorGroupBox = new GroupBox();
ShowSelectorSelectPortButton = new Button();
ShowSelectorAutoDetectButton = new Button();
PlaylistGroupBox = new GroupBox();
AdvancedSettingsButton = new Button();
AddShowButton = new Button();
LoadPlaylistButton = new Button();
SavePlaylistButton = new Button();
ChannelMappingGroupBox = new GroupBox();
LoadChannelMapButton = new Button();
PlaylistListView = new ListView();
NameColumnHeader = new ColumnHeader();
LengthColumnHeader = new ColumnHeader();
ShowContextMenu = new ContextMenuStrip(components);
MoveUpButton = new ToolStripMenuItem();
MoveDownButton = new ToolStripMenuItem();
RemoveButton = new ToolStripMenuItem();
SelectShowFileDialog = new OpenFileDialog();
SelectMappingFileDialog = new OpenFileDialog();
SavePlaylistFileDialog = new SaveFileDialog();
OpenPlaylistFileDialog = new OpenFileDialog();
NewPlaylistButton = new Button();
ControllerGroupBox.SuspendLayout();
PlaybackControlsGroupBox.SuspendLayout();
ShowSelectorGroupBox.SuspendLayout();
PlaylistGroupBox.SuspendLayout();
ChannelMappingGroupBox.SuspendLayout();
ShowContextMenu.SuspendLayout();
SuspendLayout();
//
// ControllerGroupBox
//
ControllerGroupBox.Controls.Add(ControllerSelectSerialPortButton);
ControllerGroupBox.Controls.Add(ControllerAutoDetectButton);
ControllerGroupBox.Location = new Point(12, 12);
ControllerGroupBox.Name = "ControllerGroupBox";
ControllerGroupBox.Size = new Size(256, 84);
ControllerGroupBox.TabIndex = 0;
ControllerGroupBox.TabStop = false;
ControllerGroupBox.Text = "Controller: Not Connected";
//
// ControllerSelectSerialPortButton
//
ControllerSelectSerialPortButton.Location = new Point(6, 53);
ControllerSelectSerialPortButton.Name = "ControllerSelectSerialPortButton";
ControllerSelectSerialPortButton.Size = new Size(244, 25);
ControllerSelectSerialPortButton.TabIndex = 1;
ControllerSelectSerialPortButton.Text = "Select Serial Port";
ControllerSelectSerialPortButton.UseVisualStyleBackColor = true;
ControllerSelectSerialPortButton.Click += ControllerSelectSerialPortButton_Click;
//
// ControllerAutoDetectButton
//
ControllerAutoDetectButton.Location = new Point(6, 22);
ControllerAutoDetectButton.Name = "ControllerAutoDetectButton";
ControllerAutoDetectButton.Size = new Size(244, 25);
ControllerAutoDetectButton.TabIndex = 0;
ControllerAutoDetectButton.Text = "Auto Detect";
ControllerAutoDetectButton.UseVisualStyleBackColor = true;
ControllerAutoDetectButton.Click += ControllerAutoDetectButton_Click;
//
// PlaybackControlsGroupBox
//
PlaybackControlsGroupBox.Controls.Add(TimeLabel);
PlaybackControlsGroupBox.Controls.Add(StopButton);
PlaybackControlsGroupBox.Controls.Add(SkipButton);
PlaybackControlsGroupBox.Controls.Add(PauseButton);
PlaybackControlsGroupBox.Controls.Add(StartButton);
PlaybackControlsGroupBox.Location = new Point(12, 376);
PlaybackControlsGroupBox.Name = "PlaybackControlsGroupBox";
PlaybackControlsGroupBox.Size = new Size(256, 99);
PlaybackControlsGroupBox.TabIndex = 4;
PlaybackControlsGroupBox.TabStop = false;
PlaybackControlsGroupBox.Text = "Controls: Not Playing";
//
// TimeLabel
//
TimeLabel.AutoSize = true;
TimeLabel.Location = new Point(6, 81);
TimeLabel.Name = "TimeLabel";
TimeLabel.Size = new Size(104, 15);
TimeLabel.TabIndex = 4;
TimeLabel.Text = "(00:00:00/00:00:00)";
//
// StopButton
//
StopButton.Enabled = false;
StopButton.Location = new Point(131, 53);
StopButton.Name = "StopButton";
StopButton.Size = new Size(119, 25);
StopButton.TabIndex = 3;
StopButton.Text = "Stop";
StopButton.UseVisualStyleBackColor = true;
StopButton.Click += StopButton_Click;
//
// SkipButton
//
SkipButton.Enabled = false;
SkipButton.Location = new Point(6, 53);
SkipButton.Name = "SkipButton";
SkipButton.Size = new Size(119, 25);
SkipButton.TabIndex = 2;
SkipButton.Text = "Skip";
SkipButton.UseVisualStyleBackColor = true;
SkipButton.Click += SkipButton_Click;
//
// PauseButton
//
PauseButton.Enabled = false;
PauseButton.Location = new Point(131, 22);
PauseButton.Name = "PauseButton";
PauseButton.Size = new Size(119, 25);
PauseButton.TabIndex = 1;
PauseButton.Text = "Pause";
PauseButton.UseVisualStyleBackColor = true;
PauseButton.Click += PauseButton_Click;
//
// StartButton
//
StartButton.Location = new Point(6, 22);
StartButton.Name = "StartButton";
StartButton.Size = new Size(119, 25);
StartButton.TabIndex = 0;
StartButton.Text = "Start Playlist";
StartButton.UseVisualStyleBackColor = true;
StartButton.Click += StartButton_Click;
//
// ShowSelectorGroupBox
//
ShowSelectorGroupBox.Controls.Add(ShowSelectorSelectPortButton);
ShowSelectorGroupBox.Controls.Add(ShowSelectorAutoDetectButton);
ShowSelectorGroupBox.Enabled = false;
ShowSelectorGroupBox.Location = new Point(12, 102);
ShowSelectorGroupBox.Name = "ShowSelectorGroupBox";
ShowSelectorGroupBox.Size = new Size(256, 84);
ShowSelectorGroupBox.TabIndex = 1;
ShowSelectorGroupBox.TabStop = false;
ShowSelectorGroupBox.Text = "Show Selector: Not Connected";
//
// ShowSelectorSelectPortButton
//
ShowSelectorSelectPortButton.Location = new Point(6, 53);
ShowSelectorSelectPortButton.Name = "ShowSelectorSelectPortButton";
ShowSelectorSelectPortButton.Size = new Size(244, 25);
ShowSelectorSelectPortButton.TabIndex = 1;
ShowSelectorSelectPortButton.Text = "Select Serial Port";
ShowSelectorSelectPortButton.UseVisualStyleBackColor = true;
ShowSelectorSelectPortButton.Click += ShowSelectorSelectPortButton_Click;
//
// ShowSelectorAutoDetectButton
//
ShowSelectorAutoDetectButton.Location = new Point(6, 22);
ShowSelectorAutoDetectButton.Name = "ShowSelectorAutoDetectButton";
ShowSelectorAutoDetectButton.Size = new Size(244, 25);
ShowSelectorAutoDetectButton.TabIndex = 0;
ShowSelectorAutoDetectButton.Text = "Auto Detect";
ShowSelectorAutoDetectButton.UseVisualStyleBackColor = true;
ShowSelectorAutoDetectButton.Click += ShowSelectorAutoDetectButton_Click;
//
// PlaylistGroupBox
//
PlaylistGroupBox.Controls.Add(NewPlaylistButton);
PlaylistGroupBox.Controls.Add(AdvancedSettingsButton);
PlaylistGroupBox.Controls.Add(AddShowButton);
PlaylistGroupBox.Controls.Add(LoadPlaylistButton);
PlaylistGroupBox.Controls.Add(SavePlaylistButton);
PlaylistGroupBox.Location = new Point(12, 254);
PlaylistGroupBox.Name = "PlaylistGroupBox";
PlaylistGroupBox.Size = new Size(256, 116);
PlaylistGroupBox.TabIndex = 3;
PlaylistGroupBox.TabStop = false;
PlaylistGroupBox.Text = "Playlist: Unsaved";
//
// AdvancedSettingsButton
//
AdvancedSettingsButton.Location = new Point(131, 22);
AdvancedSettingsButton.Name = "AdvancedSettingsButton";
AdvancedSettingsButton.Size = new Size(119, 25);
AdvancedSettingsButton.TabIndex = 1;
AdvancedSettingsButton.Text = "Advanced";
AdvancedSettingsButton.UseVisualStyleBackColor = true;
AdvancedSettingsButton.Click += AdvancedSettingsButton_Click;
//
// AddShowButton
//
AddShowButton.Location = new Point(6, 22);
AddShowButton.Name = "AddShowButton";
AddShowButton.Size = new Size(119, 25);
AddShowButton.TabIndex = 0;
AddShowButton.Text = "Add Show";
AddShowButton.UseVisualStyleBackColor = true;
AddShowButton.Click += AddShowButton_Click;
//
// LoadPlaylistButton
//
LoadPlaylistButton.Location = new Point(131, 53);
LoadPlaylistButton.Name = "LoadPlaylistButton";
LoadPlaylistButton.Size = new Size(119, 25);
LoadPlaylistButton.TabIndex = 3;
LoadPlaylistButton.Text = "Load Playlist";
LoadPlaylistButton.UseVisualStyleBackColor = true;
LoadPlaylistButton.Click += LoadPlaylistButton_Click;
//
// SavePlaylistButton
//
SavePlaylistButton.Location = new Point(6, 53);
SavePlaylistButton.Name = "SavePlaylistButton";
SavePlaylistButton.Size = new Size(119, 25);
SavePlaylistButton.TabIndex = 2;
SavePlaylistButton.Text = "Save Playlist";
SavePlaylistButton.UseVisualStyleBackColor = true;
SavePlaylistButton.Click += SavePlaylistButton_Click;
//
// ChannelMappingGroupBox
//
ChannelMappingGroupBox.Controls.Add(LoadChannelMapButton);
ChannelMappingGroupBox.Location = new Point(12, 192);
ChannelMappingGroupBox.Name = "ChannelMappingGroupBox";
ChannelMappingGroupBox.Size = new Size(256, 56);
ChannelMappingGroupBox.TabIndex = 2;
ChannelMappingGroupBox.TabStop = false;
ChannelMappingGroupBox.Text = "Channel Map: None Loaded";
//
// LoadChannelMapButton
//
LoadChannelMapButton.Location = new Point(6, 22);
LoadChannelMapButton.Name = "LoadChannelMapButton";
LoadChannelMapButton.Size = new Size(244, 25);
LoadChannelMapButton.TabIndex = 0;
LoadChannelMapButton.Text = "Load Channel Map";
LoadChannelMapButton.UseVisualStyleBackColor = true;
LoadChannelMapButton.Click += LoadChannelMapButton_Click;
//
// PlaylistListView
//
PlaylistListView.AutoArrange = false;
PlaylistListView.Columns.AddRange(new ColumnHeader[] { NameColumnHeader, LengthColumnHeader });
PlaylistListView.ContextMenuStrip = ShowContextMenu;
PlaylistListView.GridLines = true;
PlaylistListView.HeaderStyle = ColumnHeaderStyle.Nonclickable;
PlaylistListView.Location = new Point(274, 12);
PlaylistListView.MultiSelect = false;
PlaylistListView.Name = "PlaylistListView";
PlaylistListView.Size = new Size(400, 463);
PlaylistListView.TabIndex = 5;
PlaylistListView.UseCompatibleStateImageBehavior = false;
PlaylistListView.View = View.Details;
//
// NameColumnHeader
//
NameColumnHeader.Text = "Show Name";
NameColumnHeader.Width = 310;
//
// LengthColumnHeader
//
LengthColumnHeader.Text = "Length";
//
// ShowContextMenu
//
ShowContextMenu.Items.AddRange(new ToolStripItem[] { MoveUpButton, MoveDownButton, RemoveButton });
ShowContextMenu.Name = "ShowContextMenu";
ShowContextMenu.Size = new Size(139, 70);
//
// MoveUpButton
//
MoveUpButton.Name = "MoveUpButton";
MoveUpButton.Size = new Size(138, 22);
MoveUpButton.Text = "Move Up";
MoveUpButton.Click += MoveUpButton_Click;
//
// MoveDownButton
//
MoveDownButton.Name = "MoveDownButton";
MoveDownButton.Size = new Size(138, 22);
MoveDownButton.Text = "Move Down";
MoveDownButton.Click += MoveDownButton_Click;
//
// RemoveButton
//
RemoveButton.Name = "RemoveButton";
RemoveButton.Size = new Size(138, 22);
RemoveButton.Text = "Remove";
RemoveButton.Click += RemoveButton_Click;
//
// SelectShowFileDialog
//
SelectShowFileDialog.Filter = "UST Showtapes|*.ust";
SelectShowFileDialog.Multiselect = true;
//
// SelectMappingFileDialog
//
SelectMappingFileDialog.Filter = "PinkConnection Channel Map|*.pcm";
//
// SavePlaylistFileDialog
//
SavePlaylistFileDialog.Filter = "PC3Player Playlists (JSON Files)|*.json";
//
// OpenPlaylistFileDialog
//
OpenPlaylistFileDialog.Filter = "PC3Player Playlists (JSON Files)|*.json";
//
// NewPlaylistButton
//
NewPlaylistButton.Location = new Point(6, 84);
NewPlaylistButton.Name = "NewPlaylistButton";
NewPlaylistButton.Size = new Size(244, 25);
NewPlaylistButton.TabIndex = 4;
NewPlaylistButton.Text = "New Playlist";
NewPlaylistButton.UseVisualStyleBackColor = true;
NewPlaylistButton.Click += NewPlaylistButton_Click;
//
// MainForm
//
AutoScaleDimensions = new SizeF(7F, 15F);
AutoScaleMode = AutoScaleMode.Font;
ClientSize = new Size(686, 487);
Controls.Add(PlaylistListView);
Controls.Add(ChannelMappingGroupBox);
Controls.Add(PlaylistGroupBox);
Controls.Add(ShowSelectorGroupBox);
Controls.Add(PlaybackControlsGroupBox);
Controls.Add(ControllerGroupBox);
FormBorderStyle = FormBorderStyle.FixedSingle;
Icon = (Icon)resources.GetObject("$this.Icon");
MaximizeBox = false;
Name = "MainForm";
Text = "PinkConnection3 Player";
FormClosing += MainForm_FormClosing;
ControllerGroupBox.ResumeLayout(false);
PlaybackControlsGroupBox.ResumeLayout(false);
PlaybackControlsGroupBox.PerformLayout();
ShowSelectorGroupBox.ResumeLayout(false);
PlaylistGroupBox.ResumeLayout(false);
ChannelMappingGroupBox.ResumeLayout(false);
ShowContextMenu.ResumeLayout(false);
ResumeLayout(false);
}
#endregion
private GroupBox ControllerGroupBox;
private Button ControllerSelectSerialPortButton;
private Button ControllerAutoDetectButton;
private GroupBox PlaybackControlsGroupBox;
private Button SkipButton;
private Button PauseButton;
private Button StartButton;
private GroupBox ShowSelectorGroupBox;
private Button ShowSelectorSelectPortButton;
private Button ShowSelectorAutoDetectButton;
private GroupBox PlaylistGroupBox;
private Button AddShowButton;
private GroupBox ChannelMappingGroupBox;
private Button LoadChannelMapButton;
private ListView PlaylistListView;
private ColumnHeader NameColumnHeader;
private ColumnHeader LengthColumnHeader;
private Button StopButton;
private Button SavePlaylistButton;
private Button LoadPlaylistButton;
private OpenFileDialog SelectShowFileDialog;
private OpenFileDialog SelectMappingFileDialog;
private Button AdvancedSettingsButton;
private ContextMenuStrip ShowContextMenu;
private ToolStripMenuItem RemoveButton;
private ToolStripMenuItem MoveUpButton;
private ToolStripMenuItem MoveDownButton;
private SaveFileDialog SavePlaylistFileDialog;
private OpenFileDialog OpenPlaylistFileDialog;
private Label TimeLabel;
private Button NewPlaylistButton;
}
}

View file

@ -0,0 +1,900 @@
using SoundFlow.Backends.MiniAudio;
using SoundFlow.Components;
using SoundFlow.Enums;
using SoundFlow.Providers;
using System.Globalization;
using System.IO.Ports;
using System.Numerics;
using System.Text.Json;
using System.Timers;
namespace PC3Player
{
public partial class MainForm : Form
{
static PlaylistConfig Config = new();
static SerialPort ControllerPort;
static SerialPort ShowSelectorPort;
static Random SelectRandom = new Random();
System.Timers.Timer FrameTimer;
System.Timers.Timer ResyncTimer;
System.Timers.Timer GUIUpdateTimer;
SoundPlayer AudioPlayer;
StreamDataProvider dataProvider;
static int ShowtapeIndex = 0;
static int PlaylistIndex = 0;
static int IntermissionSecondsLeft = 0;
static int IntermissionTotalTime = 0;
static int ControllerBits;
static int SelectorButtons;
static bool ControllerConnected = false;
static bool ShowSelectorConnected = false;
public static bool ChannelMappingLoaded = false;
static bool Playing = false;
static bool Paused = false;
static bool InvalidateSave = false;
static bool Intermission;
static string[] ShowtapeFrames;
static PlaylistShow CurrentlyPlaying;
public MainForm()
{
InitializeComponent();
GUIUpdateTimer = new System.Timers.Timer(1000);
GUIUpdateTimer.Elapsed += GUIUpdateTick;
GUIUpdateTimer.AutoReset = true;
MiniAudioEngine audioEngine = new MiniAudioEngine(48000, Capability.Playback);
}
private void UpdateListView()
{
PlaylistListView.Items.Clear();
foreach (PlaylistShow s in Config.Shows) PlaylistListView.Items.Add(new ListViewItem(new[] { s.Name, s.Length }));
}
private void LoadChannelMapButton_Click(object sender, EventArgs e)
{
if (!ControllerConnected)
{
MessageBox.Show("You must connect a Controller first.", "Information", MessageBoxButtons.OK, MessageBoxIcon.Information);
return;
}
if (SelectMappingFileDialog.ShowDialog() == DialogResult.OK)
{
string tempMappingData = File.ReadAllText(SelectMappingFileDialog.FileName);
if (!tempMappingData.StartsWith("PC3MAPPING,2,"))
{
MessageBox.Show("Selected mapping file is not a Version 2 PinkConnection channel map.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
return;
}
string[] header = tempMappingData.Split(";")[0].Split(",");
List<int> targetBits = new List<int>();
foreach (string s in tempMappingData.Split(";")[1].Split(","))
{
targetBits.Add(int.Parse(s));
}
if (ChannelMappingLoaded)
{
if (header[3] != Config.Mapping.Type)
{
MessageBox.Show(
$"Selected Channel Map \"{header[2]}\"'s type does not match the old Channel Map's type." +
$"\nOld Channel Map Type: {Config.Mapping.Type}" +
$"\nNew Channel Map Type: {header[3]}"
, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
return;
}
}
if (targetBits.Count != ControllerBits)
{
MessageBox.Show("The mapped channel count is not equal to the connected controller's bit count.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
return;
}
if (targetBits.Count % 4 != 0)
{
MessageBox.Show("The mapped channel count is not divisible by 4.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
return;
}
List<int> invertedBits = new List<int>();
foreach (string s in tempMappingData.Split(";")[2].Split(","))
{
int ints = int.Parse(s);
if (ints == 0) continue;
invertedBits.Add(ints);
}
Config.Mapping = new ChannelMapping(header[2], header[3], targetBits.ToArray(), invertedBits.ToArray());
ChannelMappingLoaded = true;
ChannelMappingGroupBox.Text = $"Channel Map: {Config.Mapping.Name}";
InvalidateSave = true;
}
}
private void ControllerAutoDetectButton_Click(object sender, EventArgs e)
{
if (ControllerConnected)
{
MessageBox.Show("A Controller is already connected.", "Information", MessageBoxButtons.OK, MessageBoxIcon.Information);
return;
}
string successPortName = "";
foreach (string portName in SerialPort.GetPortNames())
{
if (ControllerConnected) break;
try
{
SerialPort tempPort = new SerialPort(portName, 9600, Parity.None, 8, StopBits.One);
tempPort.Open();
for (int i = 0; i < 10; i++)
{
tempPort.Write("! ");
Thread.Sleep(100);
string readAttempt = tempPort.ReadExisting();
if (readAttempt.Split(",")[0] == "PC3")
{
ControllerBits = int.Parse(readAttempt.Split(",")[1]);
ControllerConnected = true;
tempPort.Close();
ControllerPort = new SerialPort(portName, 9600, Parity.None, 8, StopBits.One);
ControllerPort.Open();
successPortName = portName;
break;
}
}
tempPort.Close();
}
catch (Exception) { continue; }
}
if (!ControllerConnected)
{
MessageBox.Show("Could not detect a PinkConnection3 controller on any of your serial ports.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
return;
}
ControllerGroupBox.Text = $"Controller: {ControllerBits} channel on {successPortName}";
ControllerAutoDetectButton.Enabled = false;
ControllerSelectSerialPortButton.Enabled = false;
}
private void ControllerSelectSerialPortButton_Click(object sender, EventArgs e)
{
if (ControllerConnected)
{
MessageBox.Show("A Controller is already connected.", "Information", MessageBoxButtons.OK, MessageBoxIcon.Information);
return;
}
SerialPortSelector portDialog = new SerialPortSelector();
if (portDialog.ShowDialog() != DialogResult.OK) return;
string successPortName = "";
try
{
SerialPort tempPort = new SerialPort(portDialog.PortName, 9600, Parity.None, 8, StopBits.One);
tempPort.Open();
for (int i = 0; i < 10; i++)
{
tempPort.Write("! ");
Thread.Sleep(100);
string readAttempt = tempPort.ReadExisting();
if (readAttempt.Split(",")[0] == "PC3")
{
ControllerBits = int.Parse(readAttempt.Split(",")[1]);
ControllerConnected = true;
tempPort.Close();
ControllerPort = new SerialPort(portDialog.PortName, 9600, Parity.None, 8, StopBits.One);
ControllerPort.Open();
successPortName = portDialog.PortName;
break;
}
}
tempPort.Close();
if (!ControllerConnected)
{
MessageBox.Show("Could not detect a PinkConnection3 controller on the specified serial port.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
return;
}
}
catch (Exception ex)
{
MessageBox.Show("Could not detect a PinkConnection3 controller on the specified serial port.\n" + ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
return;
}
ControllerGroupBox.Text = $"Controller: {ControllerBits} channel on {successPortName}";
ControllerAutoDetectButton.Enabled = false;
ControllerSelectSerialPortButton.Enabled = false;
}
private void AddShowButton_Click(object sender, EventArgs e)
{
if (!ChannelMappingLoaded)
{
MessageBox.Show("You must load a channel mapping first.", "Information", MessageBoxButtons.OK, MessageBoxIcon.Information);
return;
}
if (SelectShowFileDialog.ShowDialog() == DialogResult.OK)
{
foreach (string showFilePath in SelectShowFileDialog.FileNames)
{
string tempUSTData = File.ReadAllText(showFilePath);
if (!tempUSTData.StartsWith("UST,2,"))
{
MessageBox.Show($"Selected showtape \"{Path.GetFileNameWithoutExtension(showFilePath)}\" is not a UST version 2 showtape.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
return;
}
string[] headerData = tempUSTData.Split(';')[0].Split(',');
string[] stringyBits = tempUSTData.Split(';')[1].Split(',');
TimeSpan time = TimeSpan.FromSeconds(stringyBits.Length / 60);
string formattedLength = time.ToString(@"hh\:mm\:ss");
tempUSTData = null;
stringyBits = null;
if (headerData[3] != Config.Mapping.Type)
{
MessageBox.Show(
$"Selected Show \"{headerData[2]}\"'s type does not match the loaded Channel Map." +
$"\nLoaded Channel Map Type: {Config.Mapping.Type}" +
$"\nShow Type: {headerData[3]}"
, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
return;
}
Config.Shows.Add(new PlaylistShow(headerData[2], formattedLength, headerData[3], showFilePath));
}
UpdateListView();
InvalidateSave = true;
}
}
private void RemoveButton_Click(object sender, EventArgs e)
{
if (PlaylistListView.SelectedIndices.Count == 0) return;
Config = RemoveShowAt(PlaylistListView.SelectedIndices[0], Config);
UpdateListView();
InvalidateSave = true;
}
private void MoveUpButton_Click(object sender, EventArgs e)
{
if (PlaylistListView.SelectedIndices.Count == 0) return;
int selectedIndex = PlaylistListView.SelectedIndices[0];
if (selectedIndex == 0) return;
int assindex = 0;
foreach (int? assignment in Config.SelectorAssignments)
{
if (assignment == null) continue;
if (assignment == selectedIndex) Config.SelectorAssignments[assindex]--;
if (assignment == selectedIndex - 1) Config.SelectorAssignments[assindex]++;
assindex++;
}
PlaylistShow temp = Config.Shows[selectedIndex];
Config.Shows.RemoveAt(selectedIndex);
Config.Shows.Insert(selectedIndex - 1, temp);
UpdateListView();
InvalidateSave = true;
}
private void MoveDownButton_Click(object sender, EventArgs e)
{
if (PlaylistListView.SelectedIndices.Count == 0) return;
int selectedIndex = PlaylistListView.SelectedIndices[0];
if (selectedIndex >= PlaylistListView.Items.Count - 1) return;
int assindex = 0;
foreach (int? assignment in Config.SelectorAssignments)
{
if (assignment == null) continue;
if (assignment == selectedIndex) Config.SelectorAssignments[assindex]++;
if (assignment == selectedIndex + 1) Config.SelectorAssignments[assindex]--;
assindex++;
}
PlaylistShow temp = Config.Shows[selectedIndex];
Config.Shows.RemoveAt(selectedIndex);
Config.Shows.Insert(selectedIndex + 1, temp);
UpdateListView();
InvalidateSave = true;
}
private void AdvancedSettingsButton_Click(object sender, EventArgs e)
{
AdvancedSettingsForm advancedSettingsForm = new AdvancedSettingsForm(Config);
if (Config != advancedSettingsForm.EditingObject) InvalidateSave = true;
if (advancedSettingsForm.ShowDialog() == DialogResult.OK) Config = advancedSettingsForm.EditingObject;
}
private void ShowSelectorAutoDetectButton_Click(object sender, EventArgs e)
{
if (ShowSelectorConnected)
{
MessageBox.Show("A Show Selector is already connected.", "Information", MessageBoxButtons.OK, MessageBoxIcon.Information);
return;
}
string successPortName = "";
foreach (string portName in SerialPort.GetPortNames())
{
if (ShowSelectorConnected) break;
try
{
SerialPort tempPort = new SerialPort(portName, 9600, Parity.None, 8, StopBits.One);
tempPort.Open();
for (int i = 0; i < 10; i++)
{
tempPort.Write("\" ");
Thread.Sleep(100);
string readAttempt = tempPort.ReadExisting();
if (readAttempt.Split(",")[0] == "PCSELECTOR")
{
SelectorButtons = int.Parse(readAttempt.Split(",")[1]);
ShowSelectorConnected = true;
tempPort.Close();
ShowSelectorPort = new SerialPort(portName, 9600, Parity.None, 8, StopBits.One);
ShowSelectorPort.Open();
successPortName = portName;
break;
}
}
tempPort.Close();
}
catch (Exception) { continue; }
}
if (!ShowSelectorConnected)
{
MessageBox.Show("Could not detect a PinkConnection Show Selector on any of your serial ports.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
return;
}
ShowSelectorGroupBox.Text = $"{SelectorButtons} button on {successPortName}";
ShowSelectorAutoDetectButton.Enabled = false;
ShowSelectorSelectPortButton.Enabled = false;
}
private void ShowSelectorSelectPortButton_Click(object sender, EventArgs e)
{
if (ShowSelectorConnected)
{
MessageBox.Show("A Show Selector is already connected.", "Information", MessageBoxButtons.OK, MessageBoxIcon.Information);
return;
}
SerialPortSelector portDialog = new SerialPortSelector();
if (portDialog.ShowDialog() != DialogResult.OK) return;
string successPortName = "";
try
{
SerialPort tempPort = new SerialPort(portDialog.PortName, 9600, Parity.None, 8, StopBits.One);
tempPort.Open();
for (int i = 0; i < 10; i++)
{
tempPort.Write("\" ");
Thread.Sleep(100);
string readAttempt = tempPort.ReadExisting();
if (readAttempt.Split(",")[0] == "PCSELECTOR")
{
SelectorButtons = int.Parse(readAttempt.Split(",")[1]);
ShowSelectorConnected = true;
tempPort.Close();
ShowSelectorPort = new SerialPort(portDialog.PortName, 9600, Parity.None, 8, StopBits.One);
ShowSelectorPort.Open();
successPortName = portDialog.PortName;
break;
}
}
tempPort.Close();
if (!ShowSelectorConnected)
{
MessageBox.Show("Could not detect a PinkConnection Show Selector on the specified serial port.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
return;
}
}
catch (Exception ex)
{
MessageBox.Show("Could not detect a PinkConnection Show Selector on the specified serial port.\n" + ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
return;
}
ShowSelectorGroupBox.Text = $"Show Selector: {SelectorButtons} button on {successPortName}";
ShowSelectorAutoDetectButton.Enabled = false;
ShowSelectorSelectPortButton.Enabled = false;
}
private void MainForm_FormClosing(object sender, FormClosingEventArgs e)
{
if (Playing) Stop();
if (InvalidateSave)
if (MessageBox.Show(
"You have an unsaved Playlist!\nDo you still want to exit?",
"Unsaved Playlist",
MessageBoxButtons.YesNo,
MessageBoxIcon.Exclamation
) != DialogResult.Yes)
e.Cancel = true;
}
private void SavePlaylistButton_Click(object sender, EventArgs e)
{
if (SavePlaylistFileDialog.ShowDialog() == DialogResult.OK)
{
File.WriteAllText(SavePlaylistFileDialog.FileName, JsonSerializer.Serialize<PlaylistConfig>(Config));
InvalidateSave = false;
PlaylistGroupBox.Text = "Playlist: " + Path.GetFileNameWithoutExtension(SavePlaylistFileDialog.FileName);
}
}
private void LoadPlaylistButton_Click(object sender, EventArgs e)
{
if (Playing)
{
if (MessageBox.Show(
"A show is currently playing!\nPerforming this action will stop it.\nAre you sure?",
"Show Playing",
MessageBoxButtons.YesNo,
MessageBoxIcon.Exclamation
) != DialogResult.Yes)
return;
Stop();
}
if (!ControllerConnected)
{
MessageBox.Show("You must connect a Controller first.");
return;
}
if (InvalidateSave)
if (MessageBox.Show(
"You have an unsaved Playlist!\nDo you still want to load another?",
"Unsaved Playlist",
MessageBoxButtons.YesNo,
MessageBoxIcon.Exclamation
) != DialogResult.Yes)
return;
if (OpenPlaylistFileDialog.ShowDialog() == DialogResult.OK)
{
PlaylistConfig? tempConfig;
try
{
tempConfig = JsonSerializer.Deserialize<PlaylistConfig>(File.ReadAllText(OpenPlaylistFileDialog.FileName));
}
catch (Exception ex)
{
MessageBox.Show("Could not read the selected Playlist file.\n" + ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
return;
}
if (tempConfig == null)
{
MessageBox.Show("Could not read the selected Playlist file.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
return;
}
if (tempConfig.Mapping != null)
{
if (tempConfig.Mapping.Bits.Length % 4 != 0)
{
MessageBox.Show("The mapped channel count is not divisible by 4.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
return;
}
ChannelMappingGroupBox.Text = $"Channel Map: {tempConfig.Mapping.Name}";
ChannelMappingLoaded = true;
}
int showIndex = 0;
foreach (PlaylistShow show in tempConfig.Shows)
{
if (tempConfig.Mapping == null)
{
MessageBox.Show(
"The Playlist does not have a loaded Channel Map" +
"\nNo Shows or Skits will be loaded."
, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
break;
}
if (!File.Exists(show.FilePath))
{
if (MessageBox.Show(
$"Could not locate the file for the Show {show.Name}" +
$"\nWould you like to relocate it?",
"Could not find Show file",
MessageBoxButtons.YesNo,
MessageBoxIcon.Exclamation
) == DialogResult.Yes)
{
if (SelectShowFileDialog.ShowDialog() == DialogResult.OK)
{
tempConfig.Shows[showIndex].FilePath = SelectShowFileDialog.FileName;
}
else tempConfig = RemoveShowAt(showIndex, tempConfig);
}
else tempConfig = RemoveShowAt(showIndex, tempConfig);
}
if (show.Type != tempConfig.Mapping.Type)
{
MessageBox.Show(
$"Show \"{show.Name}\"'s type does not match the Playlist's Channel Map." +
$"\nIt will be removed from the playlist." +
$"\nLoaded Channel Map Type: {tempConfig.Mapping.Type}" +
$"\nShow Type: {show.Type}"
, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
tempConfig = RemoveShowAt(showIndex, tempConfig);
}
showIndex++;
}
int skitIndex = 0;
foreach (PlaylistShow skit in tempConfig.Skits)
{
if (tempConfig.Mapping == null) break;
if (!File.Exists(skit.FilePath))
{
if (MessageBox.Show(
$"Could not locate the file for the Skit {skit.Name}" +
$"\nWould you like to relocate it?",
"Could not find Skit file",
MessageBoxButtons.YesNo,
MessageBoxIcon.Exclamation
) == DialogResult.Yes)
{
if (SelectShowFileDialog.ShowDialog() == DialogResult.OK)
{
tempConfig.Skits[skitIndex].FilePath = SelectShowFileDialog.FileName;
}
else tempConfig.Skits.RemoveAt(skitIndex);
}
else tempConfig.Skits.RemoveAt(skitIndex);
}
if (skit.Type != tempConfig.Mapping.Type)
{
MessageBox.Show(
$"Skit \"{skit.Name}\"'s type does not match the Playlist's Channel Map." +
$"\nIt will be removed from the playlist." +
$"\nLoaded Channel Map Type: {tempConfig.Mapping.Type}" +
$"\nSkit Type: {skit.Type}"
, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
tempConfig.Skits.RemoveAt(skitIndex);
}
skitIndex++;
}
Config = tempConfig;
PlaylistGroupBox.Text = "Playlist: " + Path.GetFileNameWithoutExtension(OpenPlaylistFileDialog.FileName);
UpdateListView();
InvalidateSave = false;
}
}
private PlaylistConfig RemoveShowAt(int position, PlaylistConfig pcfg)
{
int assindex = 0;
foreach (int? assignment in pcfg.SelectorAssignments)
{
if (assignment == null) continue;
if (assignment == position) pcfg.SelectorAssignments[assindex] = null;
if (assignment > position) pcfg.SelectorAssignments[assindex]--;
assindex++;
}
pcfg.Shows.RemoveAt(position);
return pcfg;
}
private void LoadNextShowtape()
{
string tempUSTData = File.ReadAllText(CurrentlyPlaying.FilePath);
if (!tempUSTData.StartsWith("UST,2,"))
{
MessageBox.Show($"Selected showtape \"{Path.GetFileNameWithoutExtension(CurrentlyPlaying.FilePath)}\" is not a UST version 2 showtape.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
return;
}
string[] stringyBits = tempUSTData.Split(';')[1].Split(',');
if (File.Exists("pc3playertempaudio.tmp")) File.Delete("pc3playertempaudio.tmp");
File.WriteAllBytes("pc3playertempaudio.tmp", Convert.FromBase64String(tempUSTData.Split(';')[2]));
tempUSTData = null;
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 < Config.Mapping.Bits.Count() / 4; i++)
{
byte quartet = 64;
for (int j = 0; j < 4; j++)
{
if (Config.Mapping.Bits[selectBit] == 0) continue;
if (Config.Mapping.InvertedBits.Contains(Config.Mapping.Bits[selectBit])) { if (!((frame & BigInteger.Pow(2, Config.Mapping.Bits[selectBit] - 1)) == BigInteger.Pow(2, Config.Mapping.Bits[selectBit] - 1))) quartet += (byte)Math.Pow(2, j); }
else { if ((frame & BigInteger.Pow(2, Config.Mapping.Bits[selectBit] - 1)) == BigInteger.Pow(2, Config.Mapping.Bits[selectBit] - 1)) quartet += (byte)Math.Pow(2, j); }
selectBit++;
}
frameStringOut[i] = (char)quartet;
}
tempShowData.Add(new string(frameStringOut).Trim());
}
ShowtapeFrames = tempShowData.ToArray();
}
private void SelectNextShowtape(StartMethod method)
{
ShowtapeFrames = [];
ShowtapeIndex = 0;
if (Config.Shows.Count() == 0)
{
MessageBox.Show("There are no shows in the playlist.", "Information", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
return;
}
bool willStartShow = false;
bool bypassIntermission = false;
if (Intermission)
{
Intermission = false;
bypassIntermission = true;
GUIUpdateTimer.Stop();
}
switch (method)
{
case StartMethod.PlaylistStart:
switch (Config.PlaylistStartOption)
{
case 0:
PlaylistIndex = 0;
willStartShow = true;
break;
case 1:
PlaylistIndex = SelectRandom.Next(Config.Shows.Count());
willStartShow = true;
break;
}
break;
case StartMethod.PlaylistShowEnd:
if (Config.PlaylistIntermissionOption && (!bypassIntermission))
{
Intermission = true;
IntermissionTotalTime = IntermissionSecondsLeft = Config.PlaylistIntermissionTimeOption * ((Config.PlaylistIntermissionUnitOption == 1) ? 1 : 60);
SkipButton.Enabled = true;
StopButton.Enabled = true;
PauseButton.Enabled = true;
Invoke(delegate { PlaybackControlsGroupBox.Text = "Controls: Intermission"; });
GUIUpdateTimer.Start();
}
else
{
switch (Config.PlaylistShowEndOption)
{
case 0:
PlaylistIndex++;
if (PlaylistIndex >= Config.Shows.Count())
{
if (Config.PlaylistLoopOption)
{
PlaylistIndex = 0;
willStartShow = true;
}
}
else willStartShow = true;
break;
case 1:
PlaylistIndex = SelectRandom.Next(Config.Shows.Count());
willStartShow = true;
break;
case 2:
willStartShow = true;
break;
case 3:
break;
}
}
break;
}
if (willStartShow)
{
CurrentlyPlaying = Config.Shows[PlaylistIndex];
LoadNextShowtape();
FrameTimer = new System.Timers.Timer((1000d / 60d) * Config.FramesPerTick);
FrameTimer.Elapsed += PlayFrame;
FrameTimer.AutoReset = true;
ResyncTimer = new System.Timers.Timer(Config.ResyncSeconds * 1000);
ResyncTimer.Elapsed += Resync;
ResyncTimer.AutoReset = true;
dataProvider = new StreamDataProvider(File.OpenRead("pc3playertempaudio.tmp"));
AudioPlayer = new SoundPlayer(dataProvider);
Invoke(delegate { PlaybackControlsGroupBox.Text = $"Controls: Playing {CurrentlyPlaying.Name}"; });
Mixer.Master.AddComponent(AudioPlayer);
Playing = true;
AudioPlayer.Play();
FrameTimer.Start();
ResyncTimer.Start();
GUIUpdateTimer.Start();
PauseButton.Enabled = true;
StopButton.Enabled = true;
SkipButton.Enabled = true;
}
}
void GUIUpdateTick(object sender, ElapsedEventArgs e)
{
if (Playing)
{
Invoke(delegate { TimeLabel.Text = $"({TimeSpan.FromSeconds(AudioPlayer.Time).ToString(@"hh\:mm\:ss")}/{CurrentlyPlaying.Length})"; });
}
if (Intermission)
{
if (IntermissionSecondsLeft == 0) SelectNextShowtape(StartMethod.PlaylistShowEnd);
Invoke(delegate { TimeLabel.Text = $"({TimeSpan.FromSeconds(IntermissionTotalTime - IntermissionSecondsLeft).ToString(@"hh\:mm\:ss")}/{TimeSpan.FromSeconds(IntermissionTotalTime).ToString(@"hh\:mm\:ss")})"; });
if (!Paused) IntermissionSecondsLeft--;
}
}
void PlayFrame(object sender, ElapsedEventArgs e)
{
if (ShowtapeIndex + Config.FrameShift >= ShowtapeFrames.Length)
{
Stop();
SelectNextShowtape(StartMethod.PlaylistShowEnd);
return;
}
ControllerPort.Write(ShowtapeFrames[ShowtapeIndex + Config.FrameShift]);
ShowtapeIndex += Config.FramesPerTick;
}
void Resync(object sender, ElapsedEventArgs e)
{
ShowtapeIndex = (int)(AudioPlayer.Time * 60f);
}
private void PauseButton_Click(object sender, EventArgs e)
{
if (Paused)
{
Paused = false;
PauseButton.Text = "Pause";
if (Playing)
{
FrameTimer.Start();
ResyncTimer.Start();
AudioPlayer.Seek((float)(((float)ShowtapeIndex) / 60.0));
AudioPlayer.Play();
}
}
else
{
Paused = true;
PauseButton.Text = "Unpause";
if (Playing)
{
FrameTimer.Stop();
ResyncTimer.Stop();
AudioPlayer.Pause();
}
}
}
private void StopButton_Click(object sender, EventArgs e)
{
Stop();
}
private void SkipButton_Click(object sender, EventArgs e)
{
if (Playing) Stop();
SelectNextShowtape(StartMethod.PlaylistShowEnd);
}
private void StartButton_Click(object sender, EventArgs e)
{
if (Playing)
{
if (MessageBox.Show(
"A show is currently playing!\nPerforming this action will stop it.\nAre you sure?",
"Show Playing",
MessageBoxButtons.YesNo,
MessageBoxIcon.Exclamation
) != DialogResult.Yes)
return;
Stop();
}
SelectNextShowtape(StartMethod.PlaylistStart);
}
void Stop()
{
Playing = false;
AudioPlayer.Stop();
FrameTimer.Stop();
ResyncTimer.Stop();
GUIUpdateTimer.Stop();
ResyncTimer.Dispose();
FrameTimer.Dispose();
PauseButton.Enabled = false;
StopButton.Enabled = false;
SkipButton.Enabled = false;
if (Playing) Mixer.Master.RemoveComponent(AudioPlayer);
Paused = false;
Invoke(delegate
{
PlaybackControlsGroupBox.Text = "Controls: Not Playing";
PauseButton.Text = "Pause";
TimeLabel.Text = "(00:00:00/00:00:00)";
});
dataProvider.Dispose();
if (File.Exists("pc3playertempaudio.tmp")) File.Delete("pc3playertempaudio.tmp");
ShowtapeFrames = [];
ShowtapeIndex = 0;
}
private void NewPlaylistButton_Click(object sender, EventArgs e)
{
if (Playing)
{
if (MessageBox.Show(
"A show is currently playing!\nPerforming this action will stop it.\nAre you sure?",
"Show Playing",
MessageBoxButtons.YesNo,
MessageBoxIcon.Exclamation
) != DialogResult.Yes)
return;
Stop();
}
if (InvalidateSave)
if (MessageBox.Show(
"You have an unsaved Playlist!\nDo you still want to create a new one?",
"Unsaved Playlist",
MessageBoxButtons.YesNo,
MessageBoxIcon.Exclamation
) != DialogResult.Yes)
return;
Config = new PlaylistConfig();
ChannelMappingGroupBox.Text = "Channel Map: None Loaded";
PlaylistGroupBox.Text = "Playlist: Unsaved";
UpdateListView();
InvalidateSave = false;
}
}
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,21 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>net8.0-windows</TargetFramework>
<Nullable>enable</Nullable>
<UseWindowsForms>true</UseWindowsForms>
<ImplicitUsings>enable</ImplicitUsings>
<ApplicationIcon>icon.ico</ApplicationIcon>
</PropertyGroup>
<ItemGroup>
<Content Include="icon.ico" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="SoundFlow" Version="1.1.1" />
<PackageReference Include="System.IO.Ports" Version="9.0.6" />
</ItemGroup>
</Project>

View file

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<_LastSelectedProfileId>C:\Users\Persephone\source\repos\PC3Player\PC3Player\Properties\PublishProfiles\FolderProfile.pubxml</_LastSelectedProfileId>
</PropertyGroup>
<ItemGroup>
<Compile Update="AdvancedSettingsForm.cs">
<SubType>Form</SubType>
</Compile>
<Compile Update="MainForm.cs">
<SubType>Form</SubType>
</Compile>
<Compile Update="SerialPortSelector.cs">
<SubType>Form</SubType>
</Compile>
</ItemGroup>
</Project>

View file

@ -0,0 +1,17 @@
namespace PC3Player
{
internal static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
// To customize application configuration such as set high DPI settings or default font,
// see https://aka.ms/applicationconfiguration.
ApplicationConfiguration.Initialize();
Application.Run(new MainForm());
}
}
}

View file

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- https://go.microsoft.com/fwlink/?LinkID=208121. -->
<Project>
<PropertyGroup>
<Configuration>Release</Configuration>
<Platform>Any CPU</Platform>
<PublishDir>bin\Release\net8.0-windows\publish\</PublishDir>
<PublishProtocol>FileSystem</PublishProtocol>
<_TargetId>Folder</_TargetId>
<TargetFramework>net8.0-windows</TargetFramework>
<SelfContained>false</SelfContained>
</PropertyGroup>
</Project>

View file

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- https://go.microsoft.com/fwlink/?LinkID=208121. -->
<Project>
<PropertyGroup>
<History>True|2025-07-08T03:32:00.3108399Z||;True|2025-07-07T16:13:43.3420483-07:00||;</History>
<LastFailureDetails />
</PropertyGroup>
</Project>

View file

@ -0,0 +1,114 @@
namespace PC3Player
{
partial class SerialPortSelector
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
label1 = new Label();
PortDropDown = new ComboBox();
CancelButton = new Button();
OKButton = new Button();
panel1 = new Panel();
panel1.SuspendLayout();
SuspendLayout();
//
// label1
//
label1.AutoSize = true;
label1.Location = new Point(12, 15);
label1.Name = "label1";
label1.Size = new Size(29, 15);
label1.TabIndex = 0;
label1.Text = "Port";
//
// PortDropDown
//
PortDropDown.DropDownStyle = ComboBoxStyle.DropDownList;
PortDropDown.FormattingEnabled = true;
PortDropDown.Location = new Point(47, 12);
PortDropDown.Name = "PortDropDown";
PortDropDown.Size = new Size(191, 23);
PortDropDown.TabIndex = 1;
//
// CancelButton
//
CancelButton.DialogResult = DialogResult.Cancel;
CancelButton.Location = new Point(82, 13);
CancelButton.Name = "CancelButton";
CancelButton.Size = new Size(75, 25);
CancelButton.TabIndex = 2;
CancelButton.Text = "Cancel";
CancelButton.UseVisualStyleBackColor = true;
//
// OKButton
//
OKButton.DialogResult = DialogResult.OK;
OKButton.Location = new Point(163, 13);
OKButton.Name = "OKButton";
OKButton.Size = new Size(75, 25);
OKButton.TabIndex = 3;
OKButton.Text = "OK";
OKButton.UseVisualStyleBackColor = true;
OKButton.Click += OKButton_Click;
//
// panel1
//
panel1.BackColor = SystemColors.MenuBar;
panel1.Controls.Add(OKButton);
panel1.Controls.Add(CancelButton);
panel1.Location = new Point(0, 50);
panel1.Name = "panel1";
panel1.Size = new Size(250, 50);
panel1.TabIndex = 4;
//
// SerialPortSelector
//
AcceptButton = OKButton;
AutoScaleDimensions = new SizeF(7F, 15F);
AutoScaleMode = AutoScaleMode.Font;
ClientSize = new Size(250, 100);
Controls.Add(panel1);
Controls.Add(PortDropDown);
Controls.Add(label1);
FormBorderStyle = FormBorderStyle.FixedDialog;
Name = "SerialPortSelector";
Text = "Select a Serial Port";
Load += SerialPortSelector_Load;
panel1.ResumeLayout(false);
ResumeLayout(false);
PerformLayout();
}
#endregion
private Label label1;
private ComboBox PortDropDown;
private Button CancelButton;
private Button OKButton;
private Panel panel1;
}
}

View file

@ -0,0 +1,24 @@
using System.IO.Ports;
namespace PC3Player
{
public partial class SerialPortSelector : Form
{
public string PortName { get; set; }
public SerialPortSelector()
{
InitializeComponent();
}
private void SerialPortSelector_Load(object sender, EventArgs e)
{
PortDropDown.Items.Clear();
foreach (string port in SerialPort.GetPortNames()) PortDropDown.Items.Add(port);
}
private void OKButton_Click(object sender, EventArgs e)
{
PortName = (string)PortDropDown.SelectedItem;
}
}
}

View file

@ -0,0 +1,120 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>

Binary file not shown.

After

Width:  |  Height:  |  Size: 171 KiB

View file

@ -1,3 +1,3 @@
# PinkConnection2 # PinkConnection
Software for use with PinkConnection2 Animatronic Controllers Software for use with PinkConnection Animatronic Controllers

View file

@ -1,7 +1,7 @@
using System; using System;
using Eto.Forms; using Eto.Forms;
namespace PC2Converter.Gtk namespace USTConverter.Gtk
{ {
class Program class Program
{ {

View file

@ -7,7 +7,7 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\PC2Converter\PC2Converter.csproj" /> <ProjectReference Include="..\USTConverter\USTConverter.csproj" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

View file

@ -3,11 +3,11 @@
<plist version="1.0"> <plist version="1.0">
<dict> <dict>
<key>CFBundleName</key> <key>CFBundleName</key>
<string>PC2Converter</string> <string>USTConverter</string>
<key>CFBundleIdentifier</key> <key>CFBundleIdentifier</key>
<string>com.example.PC2Converter</string> <string>me.kawaiizenbo.USTConverter</string>
<key>CFBundleShortVersionString</key> <key>CFBundleShortVersionString</key>
<string>1.0</string> <string>1.3</string>
<key>LSMinimumSystemVersion</key> <key>LSMinimumSystemVersion</key>
<string>10.15</string> <string>10.15</string>
<key>CFBundleDevelopmentRegion</key> <key>CFBundleDevelopmentRegion</key>

View file

@ -1,7 +1,7 @@
using System; using System;
using Eto.Forms; using Eto.Forms;
namespace PC2Converter.Mac namespace USTConverter.Mac
{ {
class Program class Program
{ {

View file

@ -8,7 +8,7 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\PC2Converter\PC2Converter.csproj" /> <ProjectReference Include="..\USTConverter\USTConverter.csproj" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

View file

@ -1,7 +1,7 @@
using System; using System;
using Eto.Forms; using Eto.Forms;
namespace PC2Converter.Wpf namespace USTConverter.Wpf
{ {
class Program class Program
{ {

View file

@ -7,7 +7,7 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\PC2Converter\PC2Converter.csproj" /> <ProjectReference Include="..\USTConverter\USTConverter.csproj" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

View file

@ -0,0 +1,360 @@
using System.Collections;
using System.Diagnostics;
using System.IO;
using System.Numerics;
using Eto.Forms;
using Eto.Drawing;
namespace USTConverter
{
public partial class MainForm : Form
{
DropDown InputTypeSelector = new DropDown();
DropDown OutputTypeSelector = new DropDown();
TextBox FilePathTextBox = new TextBox();
Button BrowseFileButton = new Button { Text = "Browse", Width = 100 };
Button ConvertButton = new Button { Text = "Convert", Width = 100 };
CheckBox CompressAudioCheckBox = new CheckBox { Text = "Compress Audio" };
string[] InputTypes = {
"RSHW File (RR Engine)", "CSHW File (RR Engine)", "SSHW File (RR Engine)"/*,
"3ST File (APS)", "ROA/R12/C&R File (APS)"*/
};
string[] RAE3stOutputTypes = { "UST (Rock-afire Explosion/3-Stage)" , "UST (Cyberamics Rosetta)" };
string[] CyberOutputTypes = { "UST (Cyberamics)" };
string[] StudioCOutputTypes = { "UST (Studio C)" };
int[] CyberBitMap = {
1, 2, 3, 4, 8, 5, 6, 7,
65, 66, 67, 68, 72, 69, 70, 71,
49, 50, 51, 56, 53, 54, 55, 52,
17, 18, 19, 20, 24, 21, 22, 23,
33, 34, 35, 40, 37, 38, 39, 36,
9, 46, 62, 10, 74, 75, 76, 77, 78,
104, 102, 109, 107, 100, 123, 41,
27, 28, 29, 30, 25, 26, 57, 58,
120, 116, 127, 118, 117, 119,
114, 113, 115,
110, 108, 101, 106, 111,
103, 105, 125, 121, 126, 99, 124, 122, 97, 98
};
int[] CyberBitMapRosetta = {
1, 6, 7, 8, 4, 5, 2, 19,
185, 178, 179, 180, 183, 184, 181, 169,
45, 54, 55, 43, 44, 41, 58, 59,
166, 156, 157, 158, 156, 157, 151, 163,
30, 25, 21, 28, 29, 26, 31, 35,
0, 0, 0, 49, 0, 0, 0, 0, 0,
88, 86, 85, 82, 84, 81, 0,
93, 94, 91, 92, 91, 92, 0, 0,
229, 228, 226, 224, 223, 221,
235, 232, 234,
67, 68, 71, 72, 73,
220, 244, 245, 225, 77, 241, 240, 87, 222, 0
};
int[] RAE3stBitMap = {
1, 9, 10, 2, 3, 4, 5, 6, 7, 8, 11, 12, 13, 17, 18, 19, 14, 15, 16, 20, 36, 37,
185, 176, 177, 181, 182, 183, 184, 178, 179, 180, 173, 175, 174, 168, 170, 169, 186, 187, 188,
45, 41, 42, 43, 44, 54, 55, 51, 52, 53, 57, 59, 58, 60, 61, 62,
166, 151, 152, 153, 156, 157, 158, 161, 162, 163, 164, 154, 155, 159, 160, 165,
30, 23, 24, 26, 27, 28, 29, 25, 21, 22, 33, 35, 34, 31, 32, 63, 64,
196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 189, 190, 194, 211, 212, 213,
167, 191, 192, 193, 171, 172, 48,
39, 38, 47, 46, 49, 50,
88, 86, 85, 82, 242, 84, 83, 81, 238, 239, 240, 87,
93, 94, 91, 92, 89, 90,
229, 228, 227, 226, 224, 223, 221, 219, 218, 217, 216, 222,
235, 232, 231, 234, 236, 237, 233, 242, 243,
67, 68, 69, 66, 71, 72, 73,
78, 77, 76, 79, 80,
220, 244, 245, 225, 230, 241
};
int[] StudioCBitMap = {
21, 28, 25, 24, 26, 27, 29, 30, 31, 18, 19, 23, 22, 20, 6, 7, 11, 8, 9, 10, 1, 2, 17, 3, 4, 5, 12, 16, 15, 13, 14, 32,
33, 36, 34, 35, 40, 160, 161,
177, 178,
44, 45,
151, 154, 152, 153, 155, 157, 156, 181, 180, 182,
172, 174, 173, 171,
166, 165, 164,
159, 163, 167, 168, 176, 169, 170, 162, 179
};
int[] CyberRosettaInvertedBits = { 2, 181, 41, 59, 58, 151, 163, 26, 35, 31 };
int[] RAE3stAPSDescrambleTable = { 10, 11, 0, 1, 2, 3, 4, 12, 13, 5, 6, 7, 8, 9, 14, 15};
bool Rosetta = false;
const int USTVersion = 2;
public MainForm()
{
Title = "UST Showtape Converter";
Size = new Size(500, 300);
Maximizable = false;
Resizable = false;
BrowseFileButton.Command = new Command((sender, e) => { Event_BrowseFileButton(); });
ConvertButton.Command = new Command((sender, e) => { Event_ConvertFileButton(); });
InputTypeSelector.SelectedValueChanged += (sender, e) => Event_ChangeInputType();
foreach (string s in InputTypes)
{
InputTypeSelector.Items.Add(s);
}
Content = BuildLayout();
}
DynamicLayout BuildLayout()
{
DynamicLayout layout = new DynamicLayout { DefaultSpacing = new Size(10, 10), DefaultPadding = new Padding(5, 5, 5, 5) };
layout.BeginVertical();
layout.BeginHorizontal();
layout.Add(new Label { Text = "Input Format" });
layout.EndHorizontal();
layout.BeginHorizontal();
layout.Add(InputTypeSelector, true);
layout.EndHorizontal();
layout.BeginHorizontal();
layout.Add(new Label { Text = "Output Type" });
layout.EndHorizontal();
layout.BeginHorizontal();
layout.Add(OutputTypeSelector, true);
layout.EndHorizontal();
layout.EndVertical();
layout.BeginVertical();
layout.BeginHorizontal();
layout.Add(new Label { Text = "File to convert" });
layout.EndHorizontal();
layout.BeginHorizontal();
layout.Add(FilePathTextBox, true);
layout.Add(BrowseFileButton);
layout.EndHorizontal();
layout.EndVertical();
layout.BeginVertical();
layout.BeginHorizontal();
layout.Add(null, true);
layout.Add(CompressAudioCheckBox);
layout.Add(ConvertButton);
layout.EndHorizontal();
layout.EndVertical();
layout.BeginVertical();
layout.Add(null, true);
layout.EndVertical();
return layout;
}
string MakeHeader(string showName, string outputType)
{
string headerOut = $"UST,{USTVersion.ToString()},{showName.Replace(",", "_").Replace(";", "_")},";
switch (outputType)
{
case "UST (Rock-afire Explosion/3-Stage)":
headerOut += "Rockafire Explosion/3-Stage;";
break;
case "UST (Cyberamics Rosetta)":
headerOut += "Cyberamics;";
break;
case "UST (Cyberamics)":
headerOut += "Cyberamics;";
break;
case "UST (Studio C)":
headerOut += "Studio C;";
break;
}
return headerOut;
}
void Event_ChangeInputType()
{
switch(InputTypeSelector.SelectedIndex)
{
case 0:
OutputTypeSelector.Items.Clear();
foreach (string s in RAE3stOutputTypes)
{
OutputTypeSelector.Items.Add(s);
}
break;
case 1:
OutputTypeSelector.Items.Clear();
foreach (string s in CyberOutputTypes)
{
OutputTypeSelector.Items.Add(s);
}
break;
case 2:
OutputTypeSelector.Items.Clear();
foreach (string s in StudioCOutputTypes)
{
OutputTypeSelector.Items.Add(s);
}
break;
}
}
void Event_BrowseFileButton()
{
OpenFileDialog fileDialog = new OpenFileDialog();
string[] showFiles = { ".rshw", ".cshw", ".sshw" };
string[] allFiles = { ".*" };
fileDialog.Filters.Add(new FileFilter("Show Files (.rshw, .cshw, .sshw)", showFiles));
fileDialog.Filters.Add(new FileFilter("All Files", allFiles));
fileDialog.Title = "Select Show File.";
fileDialog.ShowDialog(this);
if (File.Exists(fileDialog.FileName)) FilePathTextBox.Text = fileDialog.FileName;
}
void Event_ConvertFileButton()
{
// safeties
if (InputTypeSelector.SelectedIndex == -1)
{
MessageBox.Show("Fatal: You must select an input type.");
return;
}
if (OutputTypeSelector.SelectedIndex == -1)
{
MessageBox.Show("Fatal: You must select an output type.");
return;
}
if (FilePathTextBox.Text.Trim() == "")
{
MessageBox.Show("Fatal: You must select an input file.");
return;
}
if (!File.Exists(FilePathTextBox.Text.Trim()))
{
MessageBox.Show("Fatal: Specified input file does not exist.");
return;
}
SaveFileDialog fileDialog = new SaveFileDialog();
fileDialog.Filters.Add(new FileFilter("UST Files (.ust)", new string[]{".ust"}));
fileDialog.Title = "Select Output File.";
fileDialog.ShowDialog(this);
if (fileDialog.FileName.Trim() == "") return;
string outFilePath = fileDialog.FileName;
// now its actually time to start doing some shit
string inputType = InputTypeSelector.SelectedKey;
string outputType = OutputTypeSelector.SelectedKey;
string filePath = FilePathTextBox.Text.Trim();
if (inputType == "RSHW File (RR Engine)" || inputType == "CSHW File (RR Engine)" || inputType == "SSHW File (RR Engine)")
{
// at some point there should be a warning displayed if the input type does not match the file extension but i dont feel like doing that right now
// rshw time
RSHWFile file = RSHWLoader.Load(filePath);
if (file.signalData == null)
{
MessageBox.Show("Fatal: This file contains no signal data.");
return;
}
if (file.audioData == null)
{
MessageBox.Show("Fatal: This file contains no audio data.");
return;
}
List<BitArray> rshwBits = new List<BitArray>();
int countlength = 0;
if (file.signalData[0] != 0)
{
countlength = 1;
BitArray bit = new BitArray(300);
rshwBits.Add(bit);
}
for (int i = 0; i < file.signalData.Length; i++)
{
if (file.signalData[i] == 0)
{
countlength += 1;
BitArray bit = new BitArray(300);
rshwBits.Add(bit);
}
else
{
rshwBits[countlength - 1].Set(file.signalData[i], true);
}
}
// pick which target bits to use and how many bytes the output should be
int[] targetBits = { 0 };
switch (outputType)
{
case "UST (Rock-afire Explosion/3-Stage)":
targetBits = RAE3stBitMap;
break;
case "UST (Cyberamics Rosetta)":
targetBits = CyberBitMapRosetta;
Rosetta = true;
break;
case "UST (Cyberamics)":
targetBits = CyberBitMap;
break;
case "UST (Studio C)":
targetBits = StudioCBitMap;
break;
}
List<string> writeOut = new List<string>();
foreach (BitArray bits in rshwBits)
{
BigInteger frameByte = 0;
for (int i = 0; i < targetBits.Length; i++)
{
if (Rosetta && CyberRosettaInvertedBits.Contains(targetBits[i]))
{
if (!bits.Get(targetBits[i])) frameByte += BigInteger.Pow(2, i);
}
else { if (bits.Get(targetBits[i])) frameByte += BigInteger.Pow(2, i); }
}
writeOut.Add(frameByte.ToString($"X{(64).ToString()}"));
}
writeOut[0] = (0).ToString($"X{(64).ToString()}");
byte[] audioOut = file.audioData;
if ((bool)CompressAudioCheckBox.Checked)
{
if (File.Exists("tmp.mp3")) File.Delete("tmp.mp3");
File.WriteAllBytes("tmp.wav", audioOut);
Process ffmpegProcess = new Process();
ffmpegProcess.StartInfo.FileName = "ffmpeg";
ffmpegProcess.StartInfo.Arguments = "-i tmp.wav -c:a mp3 -b:a 128k tmp.mp3";
ffmpegProcess.Start();
ffmpegProcess.WaitForExit();
audioOut = File.ReadAllBytes("tmp.mp3");
File.Delete("tmp.wav");
File.Delete("tmp.mp3");
}
File.WriteAllText(outFilePath, MakeHeader(Path.GetFileNameWithoutExtension(outFilePath), outputType)+String.Join(",", writeOut.ToArray())+";"+Convert.ToBase64String(audioOut));
}
MessageBox.Show("Conversion complete!");
}
int RRtoAPSBit(int rrBit) // aps lower drawer starts at 129 instead of 151
{
int outAPSBit = rrBit;
if (rrBit > 150) outAPSBit = rrBit - 22;
return outAPSBit;
}
}
}

View file

@ -1,4 +1,3 @@
using System.IO;
using System.Reflection; using System.Reflection;
using System.Runtime.Serialization.Formatters.Binary; using System.Runtime.Serialization.Formatters.Binary;