• src/doors/syncretro/test_

    From Rob Swindell (on Debian L@VERT to Git commit to main/sbbs/m on Fri Jul 17 02:57:00 2026
    https://gitlab.synchro.net/main/sbbs/-/commit/dde9d0eafe36516ef8e77e7f
    Added Files:
    src/doors/syncretro/test_audio_bytes.c test_audio_bytes.golden src/doors/termgfx/audio_stream.c audio_stream.h chunk.c src/doors/termgfx/test/CMakeLists.txt test_audio_stream.c
    Modified Files:
    docs/superpowers/plans/2026-07-16-syncscumm-m4.md src/doors/syncretro/CMakeLists.txt syncretro_audio.c syncretro_audio.h src/doors/termgfx/CMakeLists.txt
    Removed Files:
    src/doors/syncretro/syncretro_chunk.c syncretro_chunk.h test_chunk.c Log Message:
    termgfx: share the PCM streaming module between doors

    syncretro's audio module turned out to have no libretro in it at all: it
    never includes libretro.h, never touches a core, and reaches its door only through three output calls and five config values. It is a general answer
    to "I have one continuous mixed PCM stream and a SyncTERM channel FIFO" --
    and ScummVM's mixer asks the same question. This is the second consumer,
    which is the point at which extraction pays.

    Moves the state machine, cushion, two-strike backlog policy, silence cache, blob path and telemetry into libtermgfx behind an injected config struct
    and a put/flush/backlog vtable. The chunk accumulator moves too, into its
    own translation unit so the tests can compile it directly and link no
    library -- audio_stream.c reaches libsndfile, and the accumulator is the
    pure pointer arithmetic most worth testing. Its encoder channel count is
    now configuration rather than a hardcoded 1, so a genuinely stereo source works; syncretro keeps its mono downmix, which is lossless for cores that
    emit the same sample to both sides.

    syncretro keeps its sr_audio_* surface and becomes a ~140-line adapter: no
    call site changed.

    The guard came first, deliberately. The module had NO automated coverage -- M4_AUDIO.md described a fakecore/fakterm harness that was never built --
    and a port that quietly dropped an Update re-arm or rotated a cache name differently would sound fine on a short listen and fail on a long one. So test_audio_bytes drives a scripted session (prime, run, cached silence, an injected underrun, a sustained backlog, shutdown) and pins every emitted
    APC against a committed transcript. It is normalized per-APC rather than
    raw bytes because libsndfile stamps a random serial into every Ogg stream,
    so identical PCM never encodes identically twice. That transcript passed unchanged across the move, which is the only reason to believe this diff.

    ---
    þ Synchronet þ Vertrauen þ Home of Synchronet þ [vert/cvs/bbs].synchro.net
  • From Rob Swindell (on Debian L@VERT to Git commit to main/sbbs/m on Wed Jul 22 20:38:00 2026
    https://gitlab.synchro.net/main/sbbs/-/commit/7d5cbf75f9b80b4d7fad57ad
    Modified Files:
    src/doors/syncretro/test_dirty.c
    Log Message:
    syncretro: test the dirty-rect stranding fallback

    sr_dirty_find()'s band_align pre-pass returns 0 (full-frame fallback)
    when a bottom-clamped rect can't cover its own changed rows, but that
    path had no test -- only the height-roundup path was covered. Add a
    case that forces it: a single tall, narrow dirty column in a frame
    whose height isn't a multiple of LCM(ch,6), so the vstep-aligned rect
    falls short of the column's own changed-rows bottom.

    Assert the same geometry with band_align=0 does NOT return 0, so the
    test proves stranding is a band_align-specific behavior and not just
    an always-empty result.

    Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

    ---
    þ Synchronet þ Vertrauen þ Home of Synchronet þ [vert/cvs/bbs].synchro.net
  • From Rob Swindell (on Debian L@VERT to Git commit to main/sbbs/m on Fri Jul 24 11:06:00 2026
    https://gitlab.synchro.net/main/sbbs/-/commit/da866ee25b900b7b41615540
    Added Files:
    src/doors/syncretro/test_axis.c
    Modified Files:
    src/doors/syncretro/CMakeLists.txt syncretro_binds.c syncretro_binds.h syncretro_input.c test_binds.c
    Log Message:
    syncretro: reach a twin-stick cabinet's second stick from the keyboard

    MAME 2003-Plus binds a cabinet's second stick -- Battlezone's right tread, Robotron's aim -- to the RetroPad's RIGHT analog stick and nowhere else. Not a button, not the d-pad, and no core option moves it: mame_remapping, input_interface and digital_joy_centering were each measured against it and changed nothing. The arcade profile had no key that produced an analog value, so half of Battlezone's control panel was unreachable -- the tank pivoted on its one live tread and could never drive straight or reverse.

    Add SR_ACT_AXIS: a bind row whose id is a state slot ABOVE the last RetroPad button id, so it rides the pad's existing press / release / auto-release-dwell machinery rather than duplicating it, and sr_pad_get() answers it only as an analog deflection. I and K deflect the right stick, on the arcade profile alone.

    Deliberately NOT by turning sr_profile_analog() on for the arcade: that flag means "this console's stick IS the Intellivision disc and keypad", and setting it here would hand the right stick to sr_keypad_analog() and let a disc sweep suppress the d-pad.

    Three guards keep the blast radius contained. A negative-array-size typedef fails the BUILD if an axis slot ever collides with a button id -- a collision no test can catch, because the compiler has already resolved it. test_axis drives the REAL input path end to end (bytes in through sr_input_pump(), value out through sr_pad_get(), only the platform read seam stubbed) and asserts
    that a gamepad profile still reads a centred stick from I and K, so the two cartridge consoles sharing this binary are unaffected. The audio_bytes golden-byte capture still passes.

    Measured with probe_core against the real romset: W alone swings the heading 115px, the old one-tread pivot; W and I together rotate not at all while the scene still moves -- straight ahead, which the door could not do before.

    ---
    þ Synchronet þ Vertrauen þ Home of Synchronet þ [vert/cvs/bbs].synchro.net
  • From Rob Swindell (on Debian L@VERT to Git commit to main/sbbs/m on Fri Jul 24 11:06:00 2026
    https://gitlab.synchro.net/main/sbbs/-/commit/b77dab307bc17fc5957ed79e
    Modified Files:
    src/doors/syncretro/test_binds.c test_games.c
    Log Message:
    syncretro: give test_binds/test_games their own fixture dirs

    Both tests wrote, read and removed a games.ini fixture in the
    process cwd. Neither add_test() set a WORKING_DIRECTORY, so under
    serial ctest they never collided, but ctest -j (or any future
    parallel runner) would race one test's fopen(..., "w")/remove()
    against the other's read.

    Give each test its own fixture directory instead of sharing the
    cwd: test_games.c now writes to gamesfx/games.ini, test_binds.c to bindsfx/games.ini, both created with xpdev's mkpath() so this stays
    portable to MSVC. The nonexistent-directory assertions in
    test_games.c are left untouched, since they still exercise a path
    that does not exist.

    ---
    þ Synchronet þ Vertrauen þ Home of Synchronet þ [vert/cvs/bbs].synchro.net
  • From Rob Swindell (on Debian L@VERT to Git commit to main/sbbs/m on Tue Jul 28 17:19:00 2026
    https://gitlab.synchro.net/main/sbbs/-/commit/7727f08ccde7c5c36645e226
    Added Files:
    src/doors/syncretro/test_warmup.c
    Modified Files:
    src/doors/syncretro/CMakeLists.txt GAMES_INI.md main.c retro_bridge.c syncretro.h syncretro_games.c syncretro_games.h test_games.c xtrn/syncarcade/README.md games.ini
    Log Message:
    syncretro: run a cabinet's power-on self-test at full speed

    An arcade driver spends its first seconds checking RAM and ROMs behind a test pattern, and the door paced all of it to the emulated 60 fps -- so the player watched fifteen seconds of something no coin-op will let them act on, since nothing responds until a credit is in.

    games.ini gains boot_frames: run the first N frames unpaced, with the core's video and audio discarded at the bridge, then arm the pacer and start drawing. Written before any section it is the install-wide default, and a section may override it; unlike the button labels it needs no per-romset measurement, because warming up past a short boot only lands the player further into the attract loop. Values are clamped to 18000 frames -- this is real CPU spent on every node with the player looking at a static screen. The arcade install
    ships 900.

    The emulation is not altered. The same instructions run on the same emulated cycle counts, self-tests and NVRAM load included; MAME's timing is in cycles, not host time, so the driver cannot tell. Only the waiting is gone. Measured
    on MAME 2003-Plus: 68-149x realtime standalone, ~47x inside the door, so 900 frames costs 0.11-0.29 s depending on romset.

    Not a save state, though the core supports one -- seven romsets round-trip byte-identically at 32-324 KB, declaring no serialization quirks. A state cannot speed up loading the ROM at all (retro_unserialize needs a loaded game, so the zip decode and ROM decrypt happen either way), the blob carries no version stamp so its cache must be keyed on core, romset and resolved options, save-state support in this lineage is per-driver across some 5000 drivers, and the core's NVRAM write at unload means a boot snapshot restored on every
    launch can roll back high scores.

    Input is suspended for the duration -- a key struck against a screen the
    player cannot see is not the game's -- while the pump keeps running
    underneath, so the terminal's probe replies still land. The loop polls for
    exit every frame, so a session limit or a dropped carrier still ends the door mid-warm-up.

    test_warmup.c pins the output gate by capturing the callbacks the bridge installs: nothing reaches termgfx or the audio stream while it is set, a suppressed batch still reports its frames consumed, and the pump is untouched. GAMES_INI.md sec 13 documents the key, the measurements and the rejected alternative.

    Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

    ---
    þ Synchronet þ Vertrauen þ Home of Synchronet þ [vert/cvs/bbs].synchro.net