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

9.7 KiB
Raw Permalink Blame History

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 ns. 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. Intercomclosed, 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.