Files
CydandClaude Fable 5 a0a4260fd4 Sound: dual-AWE32 EMU8000 emulation -- the pod has audio
Vendored 86Box EMU8000 core (GPL-2, emu8k.cpp/.h + shim) plus vweawe.cpp:
two cards at the production addresses (0x620/0x640 register triplets),
rear-card DSP/mixer stub at 0x240, synthesis on an autonomous render
thread with direct winmm output so sustained voices ride through
emulation-thread stalls (RIO staging retries) like the real silicon did.
WC sample-counter interpolation between render chunks keeps HMI SOS
busy-waits fast. VWE_AWE32/VWE_AWE_ROM/VWE_AWE_RAM_KB/VWE_AWE_SHIFT/
VWE_AWE_LEAD_MS/VWE_AWE_DUMP/VWE_AWE_LOG env knobs.

emulator/roms: the AWE32 1MGM GM ROM dumped from our own pod card (SF2)
plus the reconstructed raw image the emulated EMU8000 loads. The HMI
driver refuses the AUDIO*.RES SoundFont upload without it (banks declare
irom=1MGM) -- that was the root cause of the first silent runs; full
debug chain in SOUND-NOTES.md. Repo serves the pod-owner community only.

.gitignore: drop the ROM excludes and un-ignore ALPHA_1/ and sda4/
(committed separately).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-04 19:40:15 -05:00

170 lines
9.7 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Sound subsystem — recon & plan
Goal: bring the pod's audio up in the DOSBox-X fork, faithful to the
production hardware: **two AWE32 ISA cards driving four cockpit speakers**
(front pair + rear pair).
## What the production system actually was (recon 2026-07-04)
- **Cards** (`REL410/BT/SETENV.BAT:158`, `VGL_LABS/PARAMETR.BAT:172`):
- `AWE_FRONT = A220 I5 D1 H5 P330 T6`
- `AWE_REAR = A240 I7 D3 H6 P300 T6`
Sound is enabled by SETENV **arg 3 = `s`** (`n` = NOSOUND — our current
emulator confs run `call setenv.bat r s n g`, i.e. sound explicitly OFF).
Mixer preset via `c:\sb16\sb16set` + `audio\ctmix.cfg` (not in the ALPHA_1
image — lived on the pod's local C:); `icom.cfg` variant opens **line-in
on the front card** when `L4INTERCOM=ON` (analog intercom mix).
`AWE_MASTER_VOLUME` / `c:\setvol.bat` = per-pod volume.
- **The game does NOT stream PCM through the SB16 DSP.** The audio engine
(`CODE/RP/MUNGA_L4/L4AUD*.CPP|HPP`, shared MUNGA "Audio Manager" brick,
1995) is **MIDI-only wavetable synthesis**:
- HMI **Sound Operating System** MIDI layer (`sosm.h`,
`sosMIDISendMIDIData`), `_MIDI_DRIVER_TYPE _MIDI_AWE32`, driver **linked
into BTL4OPT.EXE** (`sosMIDIInitDriver` string present; no external
.MDI).
- Each `AudioCard` parses its BLASTER-style env var (`AWE_FRONT` /
`AWE_REAR` -> srcAddx/irq/dma/**mpuAddx**/**emuAddx**) and drives the
card's **EMU8000** sampler: note on/off, program change, pitch bend,
and the AWE NRPNs (pitch 16, filter cutoff 21, vol attack 11). 32
voices, 16 channels per card. `LoadSBK()` uploads SoundFont banks into
card sample DRAM.
- `AudioHardware` = `frontCard` + `rearCard`.
- **All sound content is SoundFont banks**: `REL410/BT/AUDIO/AUDIO1.RES`
(3.7MB) and `AUDIO2.RES` (3.4MB) are RIFF `sfbk` (SBK/SF1, `isng` =
EMU8000) — renamed SoundFonts. `AUDIO.INI [AudioResources]` loads BOTH
into EACH card. Both banks per card ⇒ >7MB samples ⇒ **the pod AWE32s
had DRAM upgrades** (stock is 512KB); emulate with 8MB.
- **3D audio is computed in software** by the game's AudioRenderer
(`AUDIO.INI [AudioRenderer]`): amplitude + HF rolloff with knees, doppler
(speed_of_sound 250), **ITD 1.5ms**, source compression, reverb scale —
rendered by steering wavetable voices per ear across the front/rear
cards. Quad positional audio, 1995.
- **HARDWARE CONFIRMED (Cyd, 2026-07-04)**: pulled a card from a cockpit —
they are indeed **AWE32s, each with 2× 30-pin memory SIMMs** fitted (the
predicted DRAM upgrade; both banks per card ⇒ likely 2×4MB SIMMs = 8MB).
Also confirmed: **the intercom hardware was removed from the cockpits**
at some point — the intercom path (line-in mix, `icom.cfg`,
`L4INTERCOM`) is documented here for the record but will NOT be
restored; plan item 8 is closed as won't-do (mic/comms, if ever wanted,
would be a new host-side feature, not a restoration).
- **Period test suite exists**: `VWETEST/VGLTEST/` — TEST.BAT, SETENV1-9,
and diagnostic SBKs (PINKNOIS pink noise, SPKPLACE/SPKBASE placement,
QCHNTSTF/QCHNTSTB quad front/back, phase tests) + PINKNOIS.TXT
procedure. This is VWE's own speaker validation battery — use it to
validate the emulation before the game.
## The gap
DOSBox-X emulates one SB16 (DSP/mixer/OPL) and an MPU-401 — but **no
EMU8000**, and no second card. The game's entire audio path is EMU8000
register programming at `base+0x400/+0x800/+0xC00` (0x620/0xA20/0xE20 and
0x640/0xA40/0xE40). Nothing will sound until the EMU8000 exists.
## Plan
1. **EMU8000 core in the fork** (the big rock). Port the emu8k core from
86Box (GPL-2, same license as DOSBox-X; mature implementation incl.
sample-RAM read/write via SMALR/SMALW, 32 voices, filters, envelopes,
chorus/reverb). Two instances (front/rear), I/O hooks at both cards'
EMU8000 port triplets, 8MB sample DRAM each, each mixed into its own
DOSBox mixer channel (`AWEFRONT`, `AWEREAR`) at 44.1kHz. Config via env
or conf section, following the vpxlog device pattern.
2. **Second-card detection plumbing.** Keep DOSBox-X's native SB16 as the
front card — conf `[sblaster] sbtype=sb16 irq=5 dma=1 hdma=5` to match
`I5`. Add a minimal stub at 0x240 (DSP reset/version 4.xx + mixer
register file) so probes/sb16set succeed for the rear card. No DMA
audio needed anywhere (MIDI-only engine; SB IRQ/DMA unused — I5/I7
conflicts are a non-issue in emulation).
3. **Source verification pass** (before/while coding): read
`L4AUDIO.CPP`/`L4AUDRND.CPP`/`L4AUDRES.CPP` for the SOS init sequence
(timer rate, card detection order, failure modes), the exact SBK load
path, and what `InitMIDIReceive`/`GetMIDIByte` (MPU input!) is used for
in pod mode — open question.
4. **Enable sound**: gauge confs arg3 `n``s`. sb16set calls will error
harmlessly (not in image) — emulated mixer defaults stand in; optionally
add period SB16 utils to a `SB16/` dir later for authenticity. Do NOT
flip the flag before step 1 lands (unknown hang risk probing absent
EMU8000 — or do one throwaway run first to record the failure mode).
5. **Validate with VGLTEST** in the emulator: pink noise per speaker, quad
front/back tests — the way VWE techs did it.
6. **In-mission validation**: arena1 — engine pitch vs throttle (NRPN),
weapons, front/rear pan while turning past sources. Archive captures via
DOSBox-X mixer WAV record.
7. **Quad host output (cockpit build)**: start with front+rear summed to
stereo; then map to a 4.0 SDL output or send the rear card's channel to
a second host audio device for the physical rear pair.
8. ~~Intercom~~**closed, won't-do**: the intercom hardware was removed
from the cockpits (confirmed 2026-07-04). Remaining deferred items:
MPU MIDI-receive consumer, AUDIOMR.INI (mission-review audio profile)
differences.
## STATUS 2026-07-04: FIRST SOUND ACHIEVED (steps 1-4 done)
Implemented in the fork: vendored 86Box EMU8000 core (`emu8k.cpp/.h`, GPL-2)
+ `vweawe.cpp` glue (two cards at 0x620/0x640 triplets, per-card mixer
channels AWE32F/AWE32R, 0x240 DSP/mixer stub, `VWEAWE_Init` from sdlmain,
env: VWE_AWE32=1, VWE_AWE_RAM_KB, VWE_AWE_ROM, VWE_AWE_SHIFT, VWE_AWE_DUMP
(s16 stream dump), VWE_AWE_LOG=1 (port trace + 10s activity reports incl.
smldW upload counter + active voices + peak)).
Debug chain that got to sound, for the record:
1. Game run: SOS driver alive, EMU8000 detected, DRAM probe PASSES
(FFFF/AAAA/5555 bank scan verified in the SM trace), notes played
(voices>0) but **smldW=99** -- SoundFont upload never ran, voices played
zeroed DRAM = silence.
2. AWEUTIL /S (production boot runs it per card, PARAMETR.BAT:181-186)
hung polling WC: first lead. WC itself verified good after adding
block-interpolation (emu8k_shim_wc_extra; killed the 268M-poll storm).
3. Root cause: the banks declare `irom=1MGM` and the HMI AWE32 driver (and
AWEUTIL) verify the GM ROM before accepting SBKs. Emulated cards had a
zeroed ROM -> silent rejection.
4. Fix: reconstructed a 1MB ROM image from a user-supplied 1MGM.SF2 (smpl
chunk 1,047,588 B end-aligned into 1MB + ID words 0x314D/0x474D at word
offsets 2/3) -> `VWE_AWE_ROM=<path>` -> **both cards uploaded 3,513,581
sample words (full 7MB) and the mission plays real audio on both
channels** (front peak 11.8k, rear hit full-scale 32768).
**Architecture rev 2 (same day): autonomous synth thread.** User feedback:
sound great, but RIO stalls (staging-phase drops pre-date sound; the game
can't service the board while loading — button-press resync is the player
ritual) made audio chop, because DOSBox's mixer renders on the emulation
thread. Fix: synthesis moved to a dedicated render thread with its OWN
winmm output (10ms slots, VWE_AWE_LEAD_MS queue, default 80ms), EMU8000
state guarded by one critical section against guest port I/O. Like the
real silicon, sustained voices keep sounding through emulation-thread
stalls. Both cards sum to one stereo stream for now (user runs a headset);
per-card devices for the 4-speaker cockpit later. Note: our audio no
longer routes through the DOSBox mixer (its volume controls don't affect
it). Also: first render-path rev needlessly memset 64KB/card/ms — fixed
(clear only consumed region) before the thread move; both changes reduce
emulation-thread load vs the first-sound build.
Follow-ups:
- ROM provenance settled: `emulator/roms/1mgm.sf2` was dumped from one of
OUR OWN pod AWE32 cards; the repo serves the pod-owner community only,
so it is committed along with the reconstructed `emulator/roms/awe32.raw`
(recipe: SF2 smpl chunk end-aligned into 1MB + ID words 314D/474D at
word offsets 2-3). Point `VWE_AWE_ROM` at `emulator\roms\awe32.raw`.
The reconstruction may misalign ROM-resident GM presets (VWE banks are
RAM samples, unaffected) -- a raw linear re-dump of the ROM chips would
perfect it if GM playback ever matters.
- Rear card hit peak 32768 = clipping; consider VWE_AWE_SHIFT=1 or mixer
channel trim once real gameplay levels are assessed.
- Upload pacing is ~32K words/s (driver polls between words) -> adds ~2min
per card to boot. Optimization candidate later.
- Re-enable `aweutil /s` in the boot sequence now that a ROM exists
(currently skipped in the scratch conf) -- production authenticity.
- Promote the scratch gauge_sound.conf changes into the repo gauge confs
once validated: [sblaster] irq=5, production DIAGNOSE(+AWEUTIL) init
block, setenv arg3 `s`.
## Risks / notes
- emu8k port: integration surface is small (ISA I/O + mixer callback), but
verify the driver's DRAM size probe and chip ID/revision reads pass.
- HMI SOS hooks the PIT for MIDI timing — routine under DOSBox.
- Ran fine under 32RTM/DPMI on real pods, so no new protected-mode risk.
- RP (Red Planet) uses the same MUNGA audio brick and its own AUDIO*.RES —
everything here carries over.