A demo recorder: --record-pad writes what --pad reads
One byte a frame, in exactly the format the player takes, so a recording needs no conversion and there is no second format to keep in step. That symmetry is the feature, and it makes the strongest form of the claim testable: a recording is made OF a playback, and the bytes coming out have to be the bytes that went in. It exists because some inputs cannot sensibly be written by hand. Flying a lander from one base to another is a few hundred frames of steering that has to arrive somewhere eight cells wide, and several attempts at authoring one got within two columns and no closer. That is a piloting exercise rather than a test. Playing it once and keeping what happened is the answer. A BYTE FOR EVERY FRAME, written inside the loop that advances the recordings rather than after it, so a machine that jumped several frames at once still writes one for each. A recording is a timeline: one that skipped the frames nobody looked at would play back faster than it was flown. What is recorded is what the DEVICE WOULD REPORT, not the live state - a recording of a playback that wrote the live state would be a file of noughts. And it is flushed as it goes, because a recording is usually stopped by whoever is playing rather than by the program ending, and a demo lost to a buffer is a demo flown twice. Tests/replay.sh is where this and whatever follows it are checked. Twelve scripts now. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01E2JrLzFvuFX9fgi1LDRjrW
This commit is contained in:
co-authored by
Claude Opus 5
parent
caf5e1f99d
commit
a163c670d0
@@ -38,6 +38,10 @@ void printHelp(const char *programName) {
|
||||
printf(" again for the next pad. A byte is the buttons held:\n");
|
||||
printf(" 1 right, 2 left, 4 down, 8 up, 16 A, 32 B, 64 start,\n");
|
||||
printf(" 128 select.\n");
|
||||
printf(" -Y, --record-pad FILE\n");
|
||||
printf(" Write what a controller held, one byte a frame, in the\n");
|
||||
printf(" format --pad reads. Given again for the next pad. Play a\n");
|
||||
printf(" thing once and keep what happened.\n");
|
||||
printf(" -N, --sound FILE Save every sample the machine made, as raw signed 16 bit\n");
|
||||
printf(" at 48kHz. What --screen is for a picture: the only way to\n");
|
||||
printf(" check a sound on a machine with no speaker.\n");
|
||||
@@ -57,6 +61,7 @@ uint8_t parseOptions(int argc, char *argv[], EmulatorOptions *options) {
|
||||
{"keyboard", required_argument, 0, 'K'},
|
||||
{"sound", required_argument, 0, 'N'},
|
||||
{"pad", required_argument, 0, 'P'},
|
||||
{"record-pad", required_argument, 0, 'Y'},
|
||||
{"help", no_argument, 0, 'h'},
|
||||
{0, 0, 0, 0 }
|
||||
};
|
||||
@@ -76,7 +81,7 @@ uint8_t parseOptions(int argc, char *argv[], EmulatorOptions *options) {
|
||||
*options = (EmulatorOptions){0};
|
||||
|
||||
// Parse options
|
||||
while ((opt = getopt_long(argc, argv, "dc:fhD:WL:S:K:N:R:P:", long_options, &option_index)) != -1) {
|
||||
while ((opt = getopt_long(argc, argv, "dc:fhD:WL:S:K:N:R:P:Y:", long_options, &option_index)) != -1) {
|
||||
switch (opt) {
|
||||
case 'd':
|
||||
options->debug = 1;
|
||||
@@ -136,6 +141,11 @@ uint8_t parseOptions(int argc, char *argv[], EmulatorOptions *options) {
|
||||
case 'N':
|
||||
options->sound = optarg;
|
||||
break;
|
||||
case 'Y':
|
||||
if (options->padRecordCount < PAD_DRIVE_COUNT) {
|
||||
options->padRecord[options->padRecordCount++] = optarg;
|
||||
}
|
||||
break;
|
||||
case 'P':
|
||||
// Fills the pads in turn, the same way --disk fills the drives, so the first
|
||||
// one named is pad nought and the machine has as many as were asked for.
|
||||
|
||||
Reference in New Issue
Block a user