4.3 KiB
Mod mission music
Package music uses namespaced MusicDef entries and a mission's optional
music_track. It plays through the existing Rust MUS/GENMIDI FM synthesizer,
with the ordinary Music volume and fade controls. Sound effects keep their
separate digital bus. Original numeric mission tracks, menus and classic
cinematics keep their existing music paths.
Tracks use package-relative .mus files. The registry checks references,
duplicate IDs, namespaces and explicit overrides. Activation decodes the
winning owner's file and rejects missing, escaping, malformed or oversized
scores. The package's existing SHA-256 hash includes the score file, so pilot
mod compatibility covers music changes. Applying mods clears the bounded
decoded-score cache and returns an active mod track to main-menu music.
Limits apply to mod music without changing the legacy decoder: 128 KiB per
file, 16,384 events, at most 256 events at any service tick, positive duration,
and at most 126,000 score ticks (30 minutes at 70 Hz). Header ranges, supported
event types, primary channel count, velocities, controllers and the final end
event are checked by MusScore::decode. Cache allocation is bounded separately
from digital effects. Only MUS is supported; external MIDI and SoundFonts
remain deferred.
The host retains a namespaced desired-track ID and its loop flag. A mission preview can select its music before SDL audio is initialized; attaching the device applies that pending score. Re-selecting the same active ID/loop preserves playback position. Selecting original menu or cinematic music clears the mod identity. A failed score load leaves the pilot and menu state intact.
Synthetic checks cover registration and missing references, conflicting legacy/custom choices, explicit overrides and owner resolution, hash changes, cache invalidation, path and symlink containment, unsupported formats, file size, event density, duration and channel limits. FM output checks exercise the definition's actual loop flag and show that Music volume mutes the mod score while digital effects remain audible. A one-play score's ending tail has less than one twentieth the energy of the looping score in the tested fixture.
cargo test --locked --no-default-features \
--manifest-path RustRaptor/Cargo.toml --test music
Portable host checks verify pending identity, original-menu transitions and rollback when music cannot load. The paused SDL test attaches a real device object and compares consecutive FM PCM blocks against uninterrupted reference playback, proving that selecting the same track does not restart it:
LD_LIBRARY_PATH="$HOME/.local/lib" cargo test --locked \
--manifest-path RustRaptor/Cargo.toml --lib mission_mod_music
LD_LIBRARY_PATH="$HOME/.local/lib" cargo test --locked \
--manifest-path RustRaptor/Cargo.toml --lib failed_mission_music_load
LD_LIBRARY_PATH="$HOME/.local/lib" SDL_AUDIODRIVER=dummy cargo test --locked \
--manifest-path RustRaptor/Cargo.toml --lib pending_mod_music_resumes -- --ignored
These checks validate the engine path using synthetic scores. Composition, listening review and original-data in-game soundtrack captures are separate release checks for each music package.
Black Tide soundtrack
mods/iron_coast_stage2_music contains three original compositions: Rivetline
Assault (D minor, 144 BPM, 93.33 seconds), Undertow Pursuit (F-sharp minor,
168 BPM, 91.43 seconds), and Black Tide Rising (C minor, 126 BPM, 106.67 seconds).
Five FM channels and percussion use the bundled original GENMIDI instruments.
They introduce no original-score copies or replacements. Mission definitions
choose their namespaced IDs and the usual Music setting controls playback.
The package's real decoder and FM renderer checks cover every second, peak
levels at normal/full volume, exact mute, voice counts, looping boundaries and
one-play release tails. Recomposition and all six full/boundary PCM renders
reproduce byte-for-byte. validate_music.py resolves the exact active Cargo
library artifacts instead of guessing from modification time, so separate
desktop and headless builds cannot select incompatible Serde dependencies.
The package README documents the composition and reproduction commands.
These are automated score/PCM checks; physical speaker listening is separate.