# 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=` -> **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.