Skip to content

fix(audio): audioFramesForTick counts frames at the realm's declared rate - #275

Draft
NathanWalker wants to merge 1 commit into
pocket-stack:mainfrom
NathanWalker:fix/audio-frames-per-realm-rate
Draft

fix(audio): audioFramesForTick counts frames at the realm's declared rate#275
NathanWalker wants to merge 1 commit into
pocket-stack:mainfrom
NathanWalker:fix/audio-frames-per-realm-rate

Conversation

@NathanWalker

Copy link
Copy Markdown
Contributor

The audio deferral from #257, closed before any audio-capable host grows a declared rate: audioFramesForTick divided by a literal 60, so a 120 realm would consume PCM at 2x and the zero-drift statement went false.

What changed

  • contracts/spec/audio.ts: audioFramesForTick(rate, tick, ticksPerSecond = 60). The default keeps every existing callsite byte-identical — the 60-window tests now pin the default path. The doc states the generalized property (sum over any ticksPerSecond consecutive ticks is exactly rate) and the reachability argument: the pairing invariant refuses a mismatched mount, so formula and realm can only disagree through a host bug, never through a bundle.
  • hosts/sim/audio.ts: createSimAudioSink(ticksPerSecond = 60) — a runner driving a non-60 realm constructs the sink at that rate, keeping one-tick-one-sink.tick() pairing intact.
  • contracts/spec/gen-rust.ts + regenerated engine/core/src/spec.rs: the pin now also asserts the formula at a declared 120 (22050 -> 183, 184), and the emitted doc states the rate-parameterized form.

Tests

  • Zero drift at declared 90/120/240 for every AUDIO_RATES entry, window starts 0/1/59/600, plus the ±1-frame bound.
  • Sink x WavPlayer at a declared 120: the same 1 s track consumes exactly 22050 frames in 120 ticks with zero underruns, and the consumed byte-stream hash equals the 60-sink run — the declared rate changes per-tick chunking, never the bytes.

Verification

bun run test 11/11 stages green (38.5 s); bunx tsc --noEmit clean; bun tests/contract.ts green against the regenerated spec.rs; cargo check -p pocketjs-core clean (the spec.rs delta is doc text).

Deliberately not here: nothing calls this with a non-60 rate yet — the sim can't reach a non-60 realm until engine/wasm exports ui_set_tick_rate (next PR in this follow-up series).

🤖 Generated with Claude Code

…rate

The Bresenham floor difference takes the realm's ticks-per-second (default
60, so every existing callsite and tape is byte-identical); the sim sink is
constructed at the runner's declared rate. The zero-drift property is now
stated and tested over any ticksPerSecond window, and gen-rust pins the
formula at a declared 120 alongside the 60 pins.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant