Keep the fraction of a frame the ocarina recorder's clock was losing above 60 fps, in a new patch set orecord.

The ocarina manager counts the length of each note and rest in whole 60 Hz frames and adds the time manager's frames
per update to that clock at four sites (main+0x32926c8, main+0x3293410, main+0x3296b08, main+0x3296da4) through
fcvtzu, which cuts the step toward zero. Above 60 fps the step is under one frame, so the clock never moved: a
recording kept its notes without their lengths (the recorder leaves a length of 0 out), the 360 and 120 frame limits
never came, and a recording ended after a fixed 60 frames of its timer instead of following the clock; at the 40 and
45 fps limits it counted one a frame. The set replaces each fcvtzu with nine words that add the fraction carried on
the patch page's +264, store what is left after the cut (NaN and negatives as 0) and convert the sum. Steps of one
and two frames give the game's count with the fraction left at 0, so 30 and 60 fps are unchanged. The words call
nothing and take no lock (one of the functions returns through an unsaved x30), and use only v16-v18, which the three
functions never name. The set is appended so that no existing set's index moves; ocarina_timing = 0 gives the game's
words.

Not reproduced before the change (read from the code). The generator's check of the original words passed against
the 1.1.1 main, the new tests/ocarina_timing_check.py passed (.venv, Unicorn), as did frame_step_check,
text_speed_check, sprint_check, movie_timeline_check, cfg_parse_check, launcher_test and cfg_rows_check.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
chrg6
2026-11-13 18:57:56 -05:00
parent a40afdd86d
commit 5f9374e1d9
5 changed files with 393 additions and 1 deletions

View File

@@ -35,6 +35,7 @@ static int save_ok = 1; // the last cfg_save_to wrote (o
// logged as unknown. A new variable goes here too, or its ini key logs a harmless "unknown key" line.
static const char *const known[] = {
"CORES", "TM_DISPATCH", "NVN2_CS_TABLE", "SKIP_SHADERS", "MOVIE_DEBAND", "MOVIE_FPS", "MOVIE_SKIP", "MOVIE_OVERLAY", "MOVIES", "NPLN", "NVN2_PROGRAMS", "NVN_TRAP", "OCARINA_REALTIME", "ONESHOT_BUDGET", "ONESHOT_WAIT_MS", "OCARINA_STEP", "PHYSICS_STEPS", "PHYSICS_STEPS_FULL", "PICKUP_COUNT", "WATER_STEPS", "SOUND_STEPS", "FLOOR_PROBE", "FLOOR_SCAN", "FLOOR_WATCH", "FLOOR_CARRY", "MOVIE_PTS", "STEP_STEADY", "VI_HZ", "VI_VRR", "TIME_DUMP", "SHADER_DUMP", "SHOT_AFTER", "SHOT_DIR", "SHOT_EVERY", // Switch 2 port: movie skip (romfs.c), NVN2 proc traps (nvn_procs.c)
"OCARINA_TIMING",
"AA", "AA_LOG", "AB", "AMIIBO_DIR", "ANISO", "APP_POOL", "ASPECT", "ASPECT_PATCH", "ASSUME_FOCUS", "ASTC", "ASTC_BC", "ASTC_TIME", "ASYNC_PREEMPT", "AUDIO", "AUDIO_CATCHUP", "AUDIO_CHANNELS", "AUDIO_DEVICE", "AUDIO_GAME_PRIO", "AUDIO_OFF", "AUDIO_PREFILL_MS", "AUDIO_RAMP", "AUDIO_STATS",
"AUDIO_STRICT",
"BARRIER_GAME", "MESH_AHEAD", "MESH_FALLBACK", "MESH_FALLBACK_MB", "MESH_FALLBACK_WORKERS", "PROBE_MESHFB_DIR",
@@ -119,7 +120,7 @@ static const struct { const char *key, *section; } sections[] = {
{"FPS_LIMIT", "frame rate"}, {"FPS60", "frame rate"}, {"RTSS", "frame rate"},
{"REALTIME", "frame rate"}, {"CLOTH_REALTIME", "frame rate"}, {"HIGHFPS_FIX", "frame rate"},
{"PHYSICS_STEPS", "frame rate"}, {"PICKUP_COUNT", "frame rate"}, {"WATER_STEPS", "frame rate"},
{"SOUND_STEPS", "frame rate"}, {"FLOOR_CARRY", "frame rate"},
{"SOUND_STEPS", "frame rate"}, {"FLOOR_CARRY", "frame rate"}, {"OCARINA_TIMING", "frame rate"},
{"MOVIE_PTS", "frame rate"}, {"STEP_STEADY", "frame rate"},
{"FULLSCREEN", "display"}, {"WINDOW_SIZE", "display"}, {"PERF_OVERLAY", "display"}, {"VK_PRESENT", "display"},
{"GPU_INDEX", "display"}, {"MONITOR", "display"}, {"OUTPUT_RES", "display"}, {"GAME_ASPECT", "display"}, {"GAME_RES", "display"}, {"RENDER_SCALE", "display"}, {"UPSCALER", "display"},
@@ -279,6 +280,8 @@ static const CfgMeta metas[] = {
// the set ofollow of patches-v111.txt (frame_rate.c floor_carry_store): a moving floor carries a character above
// 100 fps as at 60
{"FLOOR_CARRY", "1", "0|1", RESTART},
// the set orecord of patches-v111.txt: the ocarina recorder's clock keeps each frame's fraction above 60 fps
{"OCARINA_TIMING", "1", "0|1", RESTART},
// frame_rate.c floor_probe: lines about Link on a moving floor (0 off, 1 = 4000 lines, or a count)
{"FLOOR_PROBE", "0", NULL, RESTART},
// frame_rate.c floor_scan: finds the moving floor under Link in guest memory (0 off, 1 = 20000 lines, or a count)