Skip to content

Audio and Timing

Nick Hamze edited this page Jul 17, 2026 · 2 revisions

Audio and Timing

Audio comes after the visual language is coherent enough to support a real story. It should strengthen scene rhythm, not become a reason to rebuild a known-good ROM pipeline.

Legacy tracker envelope

  • 32 steps per cue
  • 16th-note grid
  • BPM from 30 through 300
  • up to four channels
  • square, triangle, sawtooth, and sine wave tables

The editor may label a channel noise, but the current converter maps it to a square wave. Do not compose a part that depends on true hardware noise.

Correct WonderSwan timing

The default WonderSwan frame is 40,704 clocks at 3.072 MHz, about 75.472 Hz. A 60 Hz assumption makes tracker and PCM timing wrong. Story Forge carries the runtime correction in:

runtime-patches/visual-novel-creator-story-forge-runtime.patch

The patch also prevents PCM text ticks from repeatedly stealing the authored score’s channel-two voice.

Compose for narrative pivots

Reuse a short motif across:

  1. title;
  2. investigation or travel;
  3. discovery;
  4. quiet aftermath;
  5. materially different endings.

Use musicAction: "keep" between pivots. A small VN rarely needs a new cue at every node.

Desktop audition

python3 scripts/render_wscvn_music_preview.py \
  --project games/<slug>/projects/<slug>.wscvn.json \
  --out-dir games/<slug>/audio \
  --report games/<slug>/reports/soundtrack-preview-report.json

Listen through two loops. Check the actual seam, clipping, silence, DC offset, and exposed semitone collisions.

Compiled-ROM proof

The primary release gate reads SwanSong's normalized native audio stream while each route executes. It rejects non-finite samples, unexpected silence, and a clipped-sample share above 0.1%, then writes a short route WAV and binds it to the exact ROM and engine hashes.

This validates player-native output and runs automatically under:

python3 scripts/ship_wscvn_game.py <slug>

Keep the Mednafen recording below as independent timing evidence when a public release requires it; it does not replace SwanSong-native audio validation.

Record at least one cue from the compiled ROM and bind it to the editable project and ROM hash:

python3 scripts/check_wscvn_audio_proof.py \
  --wav games/<slug>/audio/title-emulator-proof.wav \
  --project games/<slug>/projects/<slug>.wscvn.json \
  --rom games/<slug>/runtime-local/<slug>.wsc \
  --track <title-track-id> \
  --loops 2 \
  --report games/<slug>/reports/emulator-audio-proof-report.json

A hand-trimmed clip with the expected duration is not timing proof. The measured repeat period must agree with the editable BPM.

For the top-level Signal reference slice, ship_signal_before_dawn_slice.py rerenders the desktop soundtrack auditions and revalidates the compiled-ROM proof against the post-reproducibility project and ROM before packaging. A visually changed ROM may preserve identical music data, but its proof report must still bind the current ROM hash; an older green report is stale evidence.

The runtime Options screen provides separate Mute, 25%, 50%, 75%, and 100% music and SFX levels. The restart-persistence test changes both through the real UI and verifies that they survive a fresh engine.

Clone this wiki locally