Commit Graph
5 Commits
Author SHA1 Message Date
arcattackandClaude Opus 4.8 37d4554440 Audio: implement NOTE->PITCH + control pitch -- the AL_PITCH was never applied (task #50)
The whole pitch system existed but was discarded: NoteAudioHandler captured the
MIDI note, ExecuteModel computed relativePitch from the control-chain cents --
and NOTHING ever called alSourcef(AL_PITCH).  Every sample played at root.

Consequences fixed:
- The load-time 'chirping' ambience: an authored looped sequence (div=120
  tempo=160, note 51 events on bank1:83) plays a rhythmic tick pitched ~9
  semitones DOWN; at root it was a high click ('chirp').  Identified live via
  the new BT_AUDIO_DUMP playing-source tape + user ear-match at cadence.
- Engine now revs: EngineMotor pitch rides the throttle (measured 1.0 -> 1.12).
- All sequence-authored patterns (alarms/klaxons/ambience) regain their pitch.

Implementation: BTNotePitchFactor(note) = 2^((note-60)/12); applied at all 3
patch-source StartImplementations (fresh attach) and all 3 ExecuteModels
(combined with the control-chain relativePitch, clamped 0.5..2.0 as before).
Uses the existing AudioSource::GetCurrentNoteValue().

Also: [seqcfg] sequence-config dump, g_bufferNames + BT_AUDIO_DUMP live tape
(1/s: every playing AL source with sample name/gain/pitch/loop),
tools/soundboard.py updated mapping.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-16 08:20:42 -05:00
arcattackandClaude Opus 4.8 5ba541ed56 Audio: subsystem STATE sounds -- GaugeAlarm54 IS a StateIndicator; register Generator/Condenser/Reservoir state (task #50)
The audio subsystem binds AudioStateWatchers (class 28) to per-subsystem state
attrs (GeneratorState/CondenserState/ReservoirState) BY NAME.  Recovered the
watcher TYPE per attribute via a MakeObjectImplementation ClassID trace.

Root cause of the subsystem-state crash: the binary's 0x54-byte subsystem alarm
(FUN_0041b9ec, reconstructed as GaugeAlarm54) IS a StateIndicator -- its "three
sub-indicators" @0x18/0x2c/0x40 are the audio/video/gauge watcher SChains, and
level@0x14 is currentState.  The reconstruction had modeled that tail as an opaque
`_tail`, so the sockets were never constructed -> AddAudioWatcher AV'd on 0xCDCDCDCD.

- GaugeAlarm54: give it the three REAL, constructed SChainOf<Component*> sockets +
  AddAudioWatcher/Video/Gauge; SetLevel now fires the watchers on a level CHANGE
  (empty sockets = no-op, so the ~all other alarms are unaffected).  levelB (weapon
  LevelCountB "reset source") is left untouched -- weapons unchanged.  sizeof stays
  0x54 (static_assert holds -> SChainOf<Component*> is 0x14, layout exact).
- Register the state attrs -> the subsystem's own alarm (own AttributePointers[]
  chained to the parent): Generator.GeneratorState->stateAlarm, Condenser.
  CondenserState->condenserAlarm, Reservoir.ReservoirState->reservoirAlarm.  Those
  alarms are already SetLevel'd by the sim, so the state audio fires on transition.
- AudioStateWatcher guard now validates the +0x18 SOCKET (what AddAudioWatcher
  touches), not the +0 vtable -- GaugeAlarm54 is non-polymorphic at +0 (raw header)
  but has a real socket at +0x18.

audiostate skips 85 -> 10 (only AmmoBin AmmoState/SimulationState left).  The
Logical/Scalar/Enum subsystem attrs (ReportLeak/GeneratorOn/ConfigureActivePress/
MotionState/SpeedOfTorsoHorizontal/TargetRangeExponent) stay inert (read 0, silent,
non-crashing) -- they need backing members in size-locked layouts (a polish wave).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-15 21:38:15 -05:00
arcattackandClaude Opus 4.8 5b46655b82 Audio: ENABLE sound -- real OpenAL + in-tree WAV loader; both backend DLLs were no-op STUBS (task #50)
Root cause of "no sound, ever": the two audio backend DLLs shipped in the repo
are fakes. libsndfile-1.dll exports 15 funcs BY ORDINAL ONLY (no names) and
sf_open() always returns NULL; OpenAL32.dll (72KB) imports only KERNEL32 -- no
dsound/wasapi/winmm -- so it is a pure no-op that returns fake handles
(ctx=0x00000001, alGenSources->0) and never touches the hardware. The whole
render->device->buffer->source->play chain ran clean and silent.

Fixes:
- OpenAL32.dll: replace the stub with the real OpenAL Soft 1.25.2 Win32 build
  (imports AVRT/ole32/WINMM, real WASAPI backend). The exe imports the 25 AL
  funcs by NAME so it is a drop-in; alGenSources now yields a live source and
  alSourcePlay reaches AL_PLAYING.
- libsndfile: DROPPED entirely. It is replaced by LoadWavPCM() in L4AUDRES --
  a tiny RIFF/WAVE fmt+data reader that loads our soundbank WAVs (16-bit PCM)
  straight into the AL buffer. Removed the .lib/.dll from the link + copy and
  git-rm'd the stub. (This also kills the "ordinal 50 could not be located in
  libsndfile-1.dll" load-failure popup: adding an sf_strerror import bound to
  an ordinal the 2..16-only stub could not satisfy.)
- Soundbank: 241 samples cracked from AUDIO1/2.RES (SF2 v1.0) by
  tools/sf2extract.py into content/AUDIO/*.wav + the allPresets[2][128] table
  (audiopresets.cpp), replacing the zero-init btstubs stub. All 241 now load
  (alErr=0). BT_AUDIO_TEST plays buffer0 as proof-of-life; BT_AUDIO_LOG traces
  the chain.

Remaining: in-game triggering (AudioEntities on fire/step/engine/explosion)
so PlayNote fires during play -- next audio wave.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-15 18:55:33 -05:00
arcattackandClaude Opus 4.8 52440e13b0 Audio: ENABLE the engine (relax dead AWE-card gate) + diagnose the real silence (task #50)
User reported never hearing any audio. Root-caused: the KB "Audio: DONE" was wrong.
The OpenAL playback chain IS fully implemented (device/buffers/sources; PlayNote
really calls alSourcePlay), but three gaps kept it silent:

1. GATED OFF (the "no sound" root cause): BTL4Application::MakeAudioRenderer returned
   NULL unless the pod's AWE_FRONT/AWE_REAR AWE32-card env vars were set -- authentic
   1995 pod behavior, dead on modern hardware, so the renderer was NEVER created.
   FIXED: default audio ON (BT_NO_AUDIO=1 restores silence; AWE vars still force-on).
   Verified: the OpenAL device now opens with no env vars ([audio] device OPENED).
2. Soundbank STUB: allPresets[2][100] (btstubs.cpp) is zero-init -> PRESET_isImplemented
   false -> 0 buffers load. Sample data exists (AUDIO1/2.RES: EnginePower/LaserAFire/...)
   but the event->sample map is gone (not in the decomp). STILL OPEN.
3. No triggering: the reconstructed game never creates AudioEntities on events. STILL OPEN.

So the device opens but nothing loads/plays yet -- enabling real sound needs the
soundbank reconstructed + the game triggers wired (a proper audio wave). Added a
BT_AUDIO_LOG trace harness across L4AUDRND/L4AUDRES/L4AUDLVL. KB corrected.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-15 18:02:31 -05:00
arcattackandClaude Opus 4.8 7b7d465e5e Initial commit: bt411 -- standalone Windows BattleTech (Tesla 4.10 port)
Clean, self-contained extraction of the BattleTech-specific work from the
reverse-engineering workspace -- engine + game + content + build, with nothing
from Red Planet or the raw archive dumps. Builds green (Win32) and runs the
single-player drive->animate->target->fire->damage->destroy loop out of the box.

Layout:
  engine/   MUNGA + MUNGA_L4 shared 2007 engine, carrying our BT render/loader
            work (bgfload/L4D3D/L4VIDEO: BSL bit-slice decode, LOD/ground/shadow
            models) + image codec; the minimal rp/ headers the audio HAL needs
  game/     reconstructed BT logic + surviving-original BT source + fwd shims
            + WinMain launcher
  content/  full runtime tree (BTL4.RES, VIDEO/, GAUGE/, AUDIO/, eggs, BTDPL.INI)
  docs/     format specs + reconstruction ledgers
  reference/ raw Ghidra pseudocode (recon source-of-truth) + decomp exporter
  tools/    MP console emulator + map/resource scanners

One top-level CMake builds munga_engine lib + bt410_l4 game lib + btl4.exe.
All paths relativized (186 fwd shims + ~437 CMake abs paths -> repo-relative);
DXSDK is the one external, overridable via -DDXSDK. Verified: builds to a
byte-identical 2.27MB exe and runs combat (TARGET DESTROYED, 0 crashes) against
the bundled content.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-05 21:03:40 -05:00