Combined audio for effect recipes
Effect browser · Audio manifest
All 21 visual recipe entry points now have combined sound auditions. They share
15 distinct sound sequences, rendered once each and mapped through
recipe_to_clip. WAV, Ogg and sample-indexed register traces live together in
analysis/audio/recipes/. Identical sound layers do not create duplicate files.
Each layer retains its decoded FM patch, pitch parameter, level and duration.
The original 39A9, 1121 and 10F4 paths program a separate voice on one
emulated OPL chip. This lets the chip combine the voices, rather than adding
independently normalised WAVs. There are 39 native voice checks across the
15 sequences, covering patch registers, pitch, carrier attenuation, key-on and
independent key-off times.
Controlled audition conditions
- The clock is assumed to run at 500 Hz: each timer tick is 96 output samples at 48 kHz. All layers are scheduled at recipe onset; their individual duration fields determine key-off, not the visual emitters' delayed starts.
- Voices are assigned fixed channels in recipe record order. Live allocation, distance admission, stereo placement, Doppler, music and voice stealing are absent. The temporary voice flags select the original nonspatial path with key-on/retrigger state; exported source flags remain preserved in metadata.
- Rendering uses the same pinned, vendored Nuked OPL3 core as the earlier sound auditions, in OPL2-compatible mode, with waveform selection enabled.
- Each shared clip extends through its longest member recipe, followed by two seconds of release padding. Long visual effects may therefore have substantial silence after their early sounds; later emitter starts do not imply another sound trigger.
- No loudness normalisation, gain correction or DC blocker is applied to PCM. FM waveforms can be asymmetric while sounding. Per-channel means and half-second means are retained for inspection; this is not the earlier MIDI-rendering path.
Audio verification
All rendered WAVs contain nonzero PCM and no samples at either signed 16-bit limit. Peaks, clipped-sample counts, uncompressed PCM hashes, channel means and half-second means are saved beside each register trace. The Ogg files are also decoded and checked for gross mean offsets, with decoded peaks recorded. These checks do not claim sample identity between lossy Ogg and WAV, nor analog output filtering identical to a physical Sound Blaster card.
Browser playback
The existing Play/Pause, timeline and Reset controls now operate sound and the
composite visual together. With sound enabled, the visual timeline follows
HTMLAudioElement.currentTime, avoiding accumulation of an independent browser
animation clock. Seeking changes both. Disabling sound returns to the inspection
clock. Changing recipe or resetting pauses the previous audio; related recipes
reuse the same clip. Audio is optional, starts only on user interaction, and has
a listening-volume control plus direct Ogg/WAV/trace links.
The timeline includes the clip's release padding. This is extra audition time, not a change to the original emitter lifetimes. The per-layer patch links in the table remain baseline reference tones, distinct from the combined audition. Browser checks verify audio progression, time alignment, pause, seek and reset, alongside the existing recipe, phase and projection checks.
PYTHONPATH=/tmp/darker-python python3 tools/render_recipe_audio.py
PYTHONPATH=/tmp/darker-python python3 tools/extract_effect_recipes.py
NODE_PATH=/tmp/riotfire-browser/node_modules node tools/verify_effect_recipes.js
The first command requires the previously exported recipes.json; the second
embeds the new audio manifest into the browser. Original DOS files are unchanged.