chore(audio): Campaign A slice A6 — delete what retail does not have

Retail EoR has no music system: the linked winmm MIDI player has zero
callers, 'music' appears zero times in the 65 MB decomp, SoundType has no
music member, InitPrefs registers no music key, and the install ships no
music files. So PlayMusic/StopMusic/MusicVolume and the AudioSettings
Music knob are deleted rather than left as an API modelling dead code —
the string-keyed signature was the tell, since every other entry point is
DID-keyed. Old settings.json files carrying a 'music' key still load; the
reader ignores unknown keys and the next save drops it.

The Ambient slider is now surfaced, because slice A5 gave it something to
drive, and its default returns to retail's 1.0 from an invented 0.8 —
InitPrefs defaults every sound preference to unity. The panel rule is
unchanged: no slider that does nothing.

r05-audio-sound.md gets a SUPERSEDED banner naming its five wrong
sections (falloff, pan, voice pool, selection, music, ambient) so a
future reader reaches the lane notes instead of the Ghidra-era reads that
this campaign spent its first two slices undoing.

TS-9 re-scoped from 'any MP3 cue' to the measured blast radius: exactly 1
MP3 among 786 shipped waves, a ~2 s mono clip. Its original framing
assumed a music system that does not exist. The ADPCM count remains
unmeasured and is named as the open question.

Deferred deliberately: #321's sound-cache decode-dedup race. It is a
pre-existing concurrency flake rather than audio-parity behaviour, and
shipping a speculative fix to a race I have not reproduced is exactly the
shortcut this project's no-workarounds rule exists to prevent.

Campaign A is code-complete; the plan carries the closeout.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Erik 2026-08-08 22:58:49 +02:00
parent 7c4dd1ade7
commit dd2cb92b99
13 changed files with 152 additions and 65 deletions

View file

@ -52,10 +52,17 @@ public sealed class WaveData
/// </summary>
public interface IAudioEngine : IDisposable
{
/// <summary>Set master volume [0..1].</summary>
/// <summary>
/// acdream's own master, on top of retail's two live knobs. Retail has
/// three preferences — effect, ambient, and an interface one it registers
/// and never reads — and NO master and no music knob. See AP-174.
/// </summary>
float MasterVolume { get; set; }
/// <summary>Retail's <c>effect_sound_volume</c>.</summary>
float SfxVolume { get; set; }
float MusicVolume { get; set; }
/// <summary>Retail's <c>ambient_sound_volume</c> (applied twice — TS-65).</summary>
float AmbientVolume{ get; set; }
/// <summary>
@ -86,7 +93,17 @@ public interface IAudioEngine : IDisposable
// up a source that was never created. `AmbientSoundController` +
// `AmbientSoundScheduler` carry the real model.
/// <summary>Start music (fades out previous if any).</summary>
void PlayMusic(string resourceName, bool loop);
void StopMusic();
// A `PlayMusic(resourceName, loop)` / `StopMusic()` pair and a `MusicVolume`
// knob lived here until 2026-08-08 (Campaign A slice A6). They modelled a
// subsystem retail does not have. The EoR client links a complete winmm
// midiStream player and never feeds it: `midiPlay` @ 0x00553390 has zero
// callers (its only textual occurrences in the 65 MB decomp are its own
// definition and its own queue drainer), both MIDI callbacks are statically
// null, the string "music" appears zero times, `SoundType` has no music
// member, `SoundManager::InitPrefs` registers no music preference, and the
// retail install ships no .mid/.mp3/.wav at all. The string-keyed signature
// was itself the tell — every other entry point in this interface is
// DID-keyed. What players remember as music is the AdminEnvirons UI stinger
// family (see `EnvironSoundCueMap`) and the intro AVI's audio track.
// Evidence: docs/research/2026-08-08-audio-retail-music-absence.md.
}