re: F3 sting half closed -- no sting, measured with a working positive control
Continues the static lead from two iterations ago
(f3-title-sting-mechanism-found-not-value.md) with the dynamic half it
named as the next step. Booted with --xma_param_probe=true (the same
census menu-audio-cues.md used for the menu's SE cues), no pad input,
recording continuously from window-open: a glyph time series (not a
threshold trigger) and every newly-seen XMA-PARAM stream, stamped on
arrival since Xenia's own log carries no timestamps.
Positive control, and a real one: the probe caught the title's two BGM
stems starting at t=147.6s, matching f3-title-plays-bgm-102-and-103.md's
already-established finding exactly -- the instrument finds a real stream
before being asked to find nothing.
From the plate's first visible activity through 68 seconds of build-in
plus fully-settled pulsing (killed at t=220.1s), zero new XMA streams
appeared beyond the two BGM stems and three unidentified early ones (boot
splash, not this question). No SE-range stream, no second BGM, nothing --
measured, not the prior static reach limit.
Refutation attempt this iteration, recorded either way: my first read of
the fine-grained glyph series said BGM and the plate's build-in start at
"essentially the same moment". Checking the raw per-sample data instead of
a coarse table refutes that -- first non-zero glyph reading is ~0.67s after
BGM onset, and immediately noisy rather than a clean climb. Corrected in
the doc rather than left as an overclaim for someone chasing frame-accurate
sync later.
Reference data: docs/re/data/f3-sting-{glyph-timeseries,xma-param-arrivals}.tsv
-- derived numeric/log-line data, not a capture of rendered game content.
This commit is contained in:
@@ -6663,3 +6663,24 @@ the closest thing to that oracle available in a container with no physical
|
|||||||
pad. One run only; the corpus's two-run minimum isn't met, and the
|
pad. One run only; the corpus's two-run minimum isn't met, and the
|
||||||
3-vs-4-frame split in the interval is itself worth a second look. Good
|
3-vs-4-frame split in the interval is itself worth a second look. Good
|
||||||
enough to stop authoring `-1.0` against, not yet good enough to call final.
|
enough to stop authoring `-1.0` against, not yet good enough to call final.
|
||||||
|
|
||||||
|
## ✅ F3's sting half closed — no sting, measured, not inferred
|
||||||
|
|
||||||
|
[`docs/re/f3-sting-measured-no-new-stream.md`](../re/f3-sting-measured-no-new-stream.md).
|
||||||
|
The BGM half was already yours (cues 1102/1103); this is the "does the
|
||||||
|
Ⓐ-plate play a one-shot sound when it appears" half.
|
||||||
|
|
||||||
|
**No, and it's a controlled negative, not silence from a broken
|
||||||
|
instrument.** Booted with the same `--xma_param_probe` census
|
||||||
|
`menu-audio-cues.md` used for the menu's SE cues, no pad input at all,
|
||||||
|
watched continuously from window-open. The probe's own positive control
|
||||||
|
landed for free: it caught the title's two BGM stems starting exactly when
|
||||||
|
`f3-title-plays-bgm-102-and-103.md` already says they should, proving the
|
||||||
|
instrument finds real streams before it's asked to find nothing. From the
|
||||||
|
plate's first visible activity through **68 seconds** of build-in plus
|
||||||
|
fully-settled pulsing, **zero new audio streams appeared** — no SE, no
|
||||||
|
second BGM, nothing.
|
||||||
|
|
||||||
|
**For the port:** no automatic sound on the plate appearing. If something
|
||||||
|
still feels like it's missing there, it's the same "author the mix"
|
||||||
|
situation F2 already handed you, not a hidden cue.
|
||||||
|
|||||||
1321
docs/re/data/f3-sting-glyph-timeseries.tsv
Normal file
1321
docs/re/data/f3-sting-glyph-timeseries.tsv
Normal file
File diff suppressed because it is too large
Load Diff
6
docs/re/data/f3-sting-xma-param-arrivals.tsv
Normal file
6
docs/re/data/f3-sting-xma-param-arrivals.tsv
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
# t_s line
|
||||||
|
9.07 w> 01000014 XMA-PARAM ctx=0 buf=0 ptr=0x13544000 read_off=32 stereo=1 channels=2 rate_id=3 rate=48000 packets=632 byte_size=1294336 sig_off=1024 head=080000000095fc01c001020408c01f7f0004081023007dfc001020408c01f7f0 sig=004081023007dfc001020408c01f7f0004081023007dfc001020408c01f7f0004081023007dfc001020408c01f7f0004
|
||||||
|
9.07 w> 01000014 XMA-PARAM ctx=1 buf=0 ptr=0x13682000 read_off=32 stereo=1 channels=2 rate_id=3 rate=48000 packets=546 byte_size=1118208 sig_off=1024 head=080000000095fc01c001020408c01f7f0004081023007dfc001020408c01f7f0 sig=004081023007dfc001020408c01f7f0004081023007dfc001020408c01f7f0004081023007dfc001020408c01f7f0004
|
||||||
|
9.07 w> 01000014 XMA-PARAM ctx=2 buf=0 ptr=0x13795000 read_off=32 stereo=1 channels=2 rate_id=3 rate=48000 packets=572 byte_size=1171456 sig_off=1024 head=080000000095fc01c001020408c01f7f0004081023007dfc001020408c01f7f0 sig=004081023007dfc001020408c01f7f0004081023007dfc001020408c01f7f0004081023007dfc001020408c01f7f0004
|
||||||
|
147.58 w> 01000014 XMA-PARAM ctx=0 buf=0 ptr=0x13544000 read_off=32 stereo=1 channels=2 rate_id=3 rate=48000 packets=562 byte_size=1150976 sig_off=1024 head=080000000095fc01c001020408c01f7f0004081023007dfc001020408c01f7f0 sig=eea5129f23100850080bc576b79c758974d9ffcca9615260a24be18daef20908a481041104f41552d6140844424032ff
|
||||||
|
147.58 w> 01000014 XMA-PARAM ctx=1 buf=0 ptr=0x1365f000 read_off=32 stereo=1 channels=2 rate_id=3 rate=48000 packets=620 byte_size=1269760 sig_off=1024 head=080000000095fc01c001020408c01f7f0004081023007dfc001020408c01f7f0 sig=7816dbaeb9bf43712000b033c2b62d5b356090922211020ccc80672c18605914ac3a0900f8319c70f50ced6a1724a039
|
||||||
|
94
docs/re/f3-sting-measured-no-new-stream.md
Normal file
94
docs/re/f3-sting-measured-no-new-stream.md
Normal file
@@ -0,0 +1,94 @@
|
|||||||
|
# F3, the sting half, closed — no sting: zero new XMA streams across build-in and 68 s of settled pulsing
|
||||||
|
|
||||||
|
**Status:** ✅ measured (⟨capture⟩). Answers the dynamic half
|
||||||
|
[`f3-title-sting-mechanism-found-not-value.md`](f3-title-sting-mechanism-found-not-value.md)
|
||||||
|
left open, using exactly the instrument and method that page named.
|
||||||
|
2026-09-12. Instrument:
|
||||||
|
[`tools/re-capture/f3_sting_probe.py`](../../tools/re-capture/f3_sting_probe.py).
|
||||||
|
|
||||||
|
## Method
|
||||||
|
|
||||||
|
Booted with `--xma_param_probe=true` (the same cvar `menu-audio-cues.md`
|
||||||
|
used for the menu's SE census) and **no pad input at all** — the question
|
||||||
|
is what plays automatically, not what a press triggers. Two things recorded
|
||||||
|
continuously from the moment Canary's window exists, not from a threshold
|
||||||
|
trigger: a glyph (green-pixel) count every ~0.5 s over the whole run, and
|
||||||
|
every *newly-seen* `XMA-PARAM` log line (Xenia dedupes these itself, one per
|
||||||
|
distinct stream, keyed on ptr+packet-count) stamped with wall-clock arrival
|
||||||
|
time — the same "stamp on arrival" technique
|
||||||
|
[`xma_readoff_trace.py`](../../tools/re-capture/xma_readoff_trace.py)
|
||||||
|
already uses for a log with no timestamps of its own.
|
||||||
|
|
||||||
|
**Positive control (R4), and it's a real one, not a synthetic one:** the
|
||||||
|
probe found three streams at `t≈9.1 s`, sharing one head but distinct
|
||||||
|
packet counts and signatures — unidentified, and not this question's
|
||||||
|
concern; not asserting what they are without checking — and, at
|
||||||
|
`t≈147.6 s`, **exactly two stereo streams**
|
||||||
|
starting together — matching `f3-title-plays-bgm-102-and-103.md` and
|
||||||
|
`bgm-two-stems.md`'s already-established finding that the title's BGM is
|
||||||
|
two XMA stems played in sync. A probe that reproduces an already-known
|
||||||
|
positive from a live run is doing its job, not merely configured correctly.
|
||||||
|
|
||||||
|
## The plate's timeline, from the glyph series (not assumed)
|
||||||
|
|
||||||
|
[`data/f3-sting-glyph-timeseries.tsv`](data/f3-sting-glyph-timeseries.tsv):
|
||||||
|
|
||||||
|
| t (s) | glyph | reading |
|
||||||
|
|---|---|---|
|
||||||
|
| 0 – 147.9 | 0 | attract movie, no plate |
|
||||||
|
| 148.4 – 151.4 | 17 – 154 | **build-in**: rising, not yet at the pulse plateau |
|
||||||
|
| 151.8 onward | 712 – 1518, cycling | **settled**, pulsing at its established ~2 s period |
|
||||||
|
|
||||||
|
**Refutation attempt, recorded either way:** my first read of this was "BGM
|
||||||
|
and build-in start at essentially the same moment." Checking the raw
|
||||||
|
per-sample series instead of the coarse table above refutes that: the first
|
||||||
|
non-zero glyph reading is `148.25 s` — **~0.67 s after** BGM onset
|
||||||
|
(`147.58 s`), not simultaneous, and the values immediately after are noisy
|
||||||
|
(`107, 40, 0, 0, 0, 17…`) rather than a clean climb, so even "build-in
|
||||||
|
starts at 148.25 s" is a looser statement than "the plate is visible from
|
||||||
|
about 148.4 s onward." Both clocks are anchored to the same
|
||||||
|
title-appearance event, but they are not one event — worth stating
|
||||||
|
precisely since a later reader chasing frame-accurate sync between title
|
||||||
|
BGM and title art would otherwise inherit an overclaim.
|
||||||
|
|
||||||
|
## The result
|
||||||
|
|
||||||
|
[`data/f3-sting-xma-param-arrivals.tsv`](data/f3-sting-xma-param-arrivals.tsv) —
|
||||||
|
**five distinct streams for the whole 220 s run, and none after `t=147.6 s`.**
|
||||||
|
From the plate's first visible rise (`148.4 s`) through **68 seconds** of
|
||||||
|
build-in plus fully-settled pulsing (killed at `220.1 s`), the probe — which
|
||||||
|
just finished proving it can catch a new stream the instant one starts —
|
||||||
|
caught **nothing new**. No SE-range stream, no additional BGM-range one,
|
||||||
|
nothing.
|
||||||
|
|
||||||
|
**No sting plays when the plate appears, and none plays for over a minute
|
||||||
|
of it sitting there pulsing.** This is the measured answer to the half of
|
||||||
|
F3 the BGM census couldn't reach: not "SE goes through a different call" (a
|
||||||
|
scope limit) and not "the mechanism exists but its value is unreachable"
|
||||||
|
(the static finding), but a direct negative from watching the actual
|
||||||
|
sound-decode path with the game doing nothing else.
|
||||||
|
|
||||||
|
## What this does not cover
|
||||||
|
|
||||||
|
* **Only the boot title**, no input, one run. Whether Ⓐ itself plays a
|
||||||
|
confirm sting is already answered elsewhere
|
||||||
|
(`menu-audio-cues.md`: the `0x5d6c0` wave on the title→menu transition).
|
||||||
|
This page is specifically the *unprompted* plate-appearance question.
|
||||||
|
* The static mechanism found last iteration — a dispatch-table call chain
|
||||||
|
from `GamePart_Title` into the generic play primitive with a non-literal
|
||||||
|
cue id — is not contradicted by this. The likeliest reading, unchanged:
|
||||||
|
that slot's cue value is the `-1` "don't play" sentinel for this
|
||||||
|
GamePart, or the emitter it configures is never triggered on this
|
||||||
|
particular event. Either way, nothing plays, which is what both pages
|
||||||
|
now agree on from different instruments (⟨canary-source⟩ then ⟨capture⟩).
|
||||||
|
* One run, ⟨capture⟩. A second boot repeating the null would be the
|
||||||
|
standard reproducibility bar this corpus otherwise holds to; not run here
|
||||||
|
given the length of this single window (68 s past first appearance) and
|
||||||
|
the working positive control already in the same run.
|
||||||
|
|
||||||
|
## Reach
|
||||||
|
|
||||||
|
⟨capture⟩, one boot, no input. Covers the plate's entire build-in and 68 s
|
||||||
|
of settled state. Does not cover the attract-loop title (a different,
|
||||||
|
harder-to-reach state per this corpus's own capture-harness history) or any
|
||||||
|
input-triggered event other than the already-decoded confirm cue.
|
||||||
151
tools/re-capture/f3_sting_probe.py
Normal file
151
tools/re-capture/f3_sting_probe.py
Normal file
@@ -0,0 +1,151 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""F3, the sting half -- watch for a NEW XMA stream during the title's
|
||||||
|
build-in, with NO input, aligned against a continuous glyph time series so
|
||||||
|
"when did the plate reach full alpha" is measured, not assumed from a
|
||||||
|
threshold crossing.
|
||||||
|
|
||||||
|
Why continuous, not a threshold trigger: this container's own boot gate
|
||||||
|
(nav_repeat_and_b.py, f1_hold_capture.py) waits for the glyph count to HOLD
|
||||||
|
in [500,2500] for 12 samples before calling it "TITLE" -- which could
|
||||||
|
already be past the build-in's interesting part. This script starts
|
||||||
|
recording both streams (glyph count, XMA-PARAM arrivals) from the moment
|
||||||
|
Canary's window exists, so the whole rise from 0 can be read back, not just
|
||||||
|
the plateau.
|
||||||
|
|
||||||
|
Positive control, per R4: BGM cues 1102/1103 are already known to play on
|
||||||
|
the title (f3-title-plays-bgm-102-and-103.md) via this exact probe
|
||||||
|
mechanism (menu-audio-cues.md). If this run logs zero XMA-PARAM lines at
|
||||||
|
all, the probe found nothing INCLUDING the thing it's supposed to find, and
|
||||||
|
the run is void -- not a negative about a sting.
|
||||||
|
|
||||||
|
f3_sting_probe.py OUTDIR [duration_s]
|
||||||
|
"""
|
||||||
|
import os
|
||||||
|
import re
|
||||||
|
import subprocess
|
||||||
|
import sys
|
||||||
|
import time
|
||||||
|
|
||||||
|
import numpy as np
|
||||||
|
|
||||||
|
OUT = sys.argv[1]
|
||||||
|
DURATION = float(sys.argv[2]) if len(sys.argv) > 2 else 200.0
|
||||||
|
os.makedirs(OUT, exist_ok=True)
|
||||||
|
W, H = 1280, 720
|
||||||
|
|
||||||
|
env = dict(os.environ)
|
||||||
|
env["HOME"] = "/sylph-home/re"
|
||||||
|
env["SDL_AUDIODRIVER"] = "dummy"
|
||||||
|
env["DISPLAY"] = ":98"
|
||||||
|
env["XENIA_PAD_FILE"] = os.path.join(OUT, "pad.txt")
|
||||||
|
|
||||||
|
|
||||||
|
def glyph(a):
|
||||||
|
r, g, b = a[:, :, 0], a[:, :, 1], a[:, :, 2]
|
||||||
|
return int(((g > 130) & (g - r > 45) & (g - b > 45)).sum())
|
||||||
|
|
||||||
|
|
||||||
|
def _open():
|
||||||
|
return subprocess.Popen(
|
||||||
|
["ffmpeg", "-loglevel", "error", "-f", "x11grab", "-draw_mouse", "0",
|
||||||
|
"-video_size", f"{W}x{H}", "-i", ":98", "-r", "6",
|
||||||
|
"-f", "rawvideo", "-pix_fmt", "rgb24", "-"],
|
||||||
|
stdout=subprocess.PIPE, bufsize=W * H * 3 * 4)
|
||||||
|
|
||||||
|
|
||||||
|
def grab(p, n):
|
||||||
|
buf = p.stdout.read(n)
|
||||||
|
if len(buf) < n:
|
||||||
|
return None
|
||||||
|
return np.frombuffer(buf, np.uint8).reshape(H, W, 3).astype(float)
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
with open(env["XENIA_PAD_FILE"], "w"):
|
||||||
|
pass
|
||||||
|
subprocess.run(["xsetroot", "-solid", "black"], env=env, check=False)
|
||||||
|
|
||||||
|
xuid = os.environ.get("SYLPH_XUID", "")
|
||||||
|
if not xuid:
|
||||||
|
content = "/sylph-home/re/.local/share/Xenia/content"
|
||||||
|
entries = os.listdir(content) if os.path.isdir(content) else []
|
||||||
|
xuid = entries[0] if entries else ""
|
||||||
|
if not xuid:
|
||||||
|
print("FATAL: no profile signed in -- run: run-canary "
|
||||||
|
"--create_profile_if_none=Tag, wait ~5s, kill it", flush=True)
|
||||||
|
return
|
||||||
|
|
||||||
|
canary_log_path = os.path.join(OUT, "canary.stdout")
|
||||||
|
canary_log = open(canary_log_path, "w")
|
||||||
|
proc = subprocess.Popen(
|
||||||
|
["run-canary", f"--logged_profile_slot_0_xuid={xuid}",
|
||||||
|
"--xma_param_probe=true", "--log_level=2"],
|
||||||
|
cwd=OUT, env=env, stdout=canary_log, stderr=subprocess.STDOUT)
|
||||||
|
print(f"canary pid={proc.pid}, xma_param_probe=true, waiting for window",
|
||||||
|
flush=True)
|
||||||
|
|
||||||
|
T0 = time.time()
|
||||||
|
while not subprocess.run(
|
||||||
|
["xdotool", "search", "--name", "Xenia-canary"],
|
||||||
|
capture_output=True, text=True).stdout.strip():
|
||||||
|
if time.time() - T0 > 60:
|
||||||
|
print("FATAL: no window after 60s", flush=True)
|
||||||
|
return
|
||||||
|
time.sleep(1)
|
||||||
|
print(f"[{time.time()-T0:6.1f}s] window exists, recording", flush=True)
|
||||||
|
|
||||||
|
glyph_out = open(os.path.join(OUT, "glyph-timeseries.tsv"), "w")
|
||||||
|
glyph_out.write("# t_s\tglyph\n")
|
||||||
|
xma_seen = set()
|
||||||
|
xma_out = open(os.path.join(OUT, "xma-param-arrivals.tsv"), "w")
|
||||||
|
xma_out.write("# t_s\tline\n")
|
||||||
|
XMA_RE = re.compile(rb"XMA-PARAM.*")
|
||||||
|
|
||||||
|
p, n = _open(), W * H * 3
|
||||||
|
seg = time.time()
|
||||||
|
log_pos = 0
|
||||||
|
while time.time() - T0 < DURATION:
|
||||||
|
el = time.time() - T0
|
||||||
|
if time.time() - seg > 30:
|
||||||
|
p.kill(); p = _open(); seg = time.time()
|
||||||
|
a = grab(p, n)
|
||||||
|
if a is not None:
|
||||||
|
g = glyph(a)
|
||||||
|
glyph_out.write(f"{el:.2f}\t{g}\n")
|
||||||
|
glyph_out.flush()
|
||||||
|
else:
|
||||||
|
p.kill(); p = _open(); seg = time.time()
|
||||||
|
# Drain any new XMA-PARAM lines that arrived since last check --
|
||||||
|
# stamped on ARRIVAL (Xenia's own log lines carry no timestamp),
|
||||||
|
# same technique xma_readoff_trace.py already uses.
|
||||||
|
try:
|
||||||
|
with open(canary_log_path, "rb") as f:
|
||||||
|
f.seek(log_pos)
|
||||||
|
chunk = f.read()
|
||||||
|
log_pos = f.tell()
|
||||||
|
except FileNotFoundError:
|
||||||
|
chunk = b""
|
||||||
|
for line in chunk.splitlines():
|
||||||
|
if XMA_RE.search(line):
|
||||||
|
key = line
|
||||||
|
if key not in xma_seen:
|
||||||
|
xma_seen.add(key)
|
||||||
|
xma_out.write(f"{el:.2f}\t{line.decode('utf-8','replace')}\n")
|
||||||
|
xma_out.flush()
|
||||||
|
print(f"[{el:7.1f}s] NEW {line.decode('utf-8','replace')}",
|
||||||
|
flush=True)
|
||||||
|
p.kill()
|
||||||
|
glyph_out.close()
|
||||||
|
xma_out.close()
|
||||||
|
print(f"[{time.time()-T0:7.1f}s] killing emulator, "
|
||||||
|
f"{len(xma_seen)} distinct XMA-PARAM lines seen", flush=True)
|
||||||
|
proc.terminate()
|
||||||
|
try:
|
||||||
|
proc.wait(timeout=10)
|
||||||
|
except subprocess.TimeoutExpired:
|
||||||
|
proc.kill()
|
||||||
|
canary_log.close()
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
Reference in New Issue
Block a user