The sound effects play at the pitch they were written at
Red Planet's original AWE32 soundbanks are back in the tree, and the game's sound effects are now generated from them instead of from an incomplete one-off extraction. AUDIO1.RES and AUDIO2.RES come from the 1996 release in the TeslaRel410 archive, hash-identical. AUDIO.INI has named them all along - they were simply never carried into the port. tools/rp_sf2extract.py reads them and regenerates both the WAV set and RP_L4/WTPresets.cpp, so the assets are reproducible from the banks rather than hand-maintained. Two things were wrong with the old set: Pitch. Every shipped WAV was flat 44100 Hz with the banks' tuning discarded, so 202 of the 219 zones played at the wrong speed - the worst by nine semitones. The EMU8000's per-zone root key and tuning are now baked into each file's declared sample rate, which is exact and needs no engine change. Layers that were meant to be deep now are: a collision sub-thud that lasted 18 milliseconds at the wrong rate is a 0.66 second one at 1228 Hz. Missing layers. 93 presets were short of zones and 176 were missing outright, 219 of 395. Nothing was lost recovering them - the 46 preset slots that disappeared were all empty placeholders. The old files were also over-read, running past the end of their sample into whatever PCM came next; WellheadDrill02a was six seconds where the bank says eight hundred milliseconds. Every one of the 395 files now matches its bank record exactly. Also baked in: per-zone layer attenuation, and the static resonant low-pass the EMU8000 applied in hardware. Measured while doing it, and worth knowing: RP's banks contain no key-splits at all - every multi-zone preset is a pure layer stack - and no preset has more than four zones, which is what the engine's own "AWE appears to only play 1st 4 voices" warning has been asserting since 1995. Still to do: loop regions and the release fades, which 349 zones ask for and which need new SAMPLEINFO fields. And voice demand per sound has gone from about one zone to about two and a half, so the per-event alGenSources and alDeleteSources churn roughly doubles - the BT tree measured pooling as the fix for that, and a CPU win besides. Builds clean. The extreme baked rates, 1228 Hz up to 88200, were checked through the real path - libsndfile, alBufferData, alSourcePlay - and all load. Not yet listened to on the pod. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
+67
-24
@@ -334,11 +334,16 @@ gains and four ITD pitch offsets. Every consumer of those values is commented ou
|
||||
|
||||
## 8. Where the original assets actually are
|
||||
|
||||
RP412 ships 223 loose `.wav` files loaded through libsndfile, a hand-maintained
|
||||
preset table in `MUNGA_L4/L4AUDLVL.cpp` + `WTPresets.cpp`, and a **1-byte stub**
|
||||
> **Update (2026-08-05):** both banks now live in `assets/RP411/AUDIO/`, and the
|
||||
> WAV set and preset table are generated from them by `tools/rp_sf2extract.py`.
|
||||
> The history below is kept because it is what made that possible, and because
|
||||
> the `.SCP` sources are still only in TeslaRel410.
|
||||
|
||||
RP412 used to ship 223 loose `.wav` files loaded through libsndfile, a
|
||||
hand-maintained preset table in `RP_L4/WTPresets.cpp`, and a **1-byte stub**
|
||||
`AUDIO.RES`. The `front_audio_resource`/`rear_audio_resource` lines in AUDIO.INI
|
||||
are not stale leftovers — they are the original authored configuration, and the
|
||||
banks they name exist. They were simply not carried into `dist/`.
|
||||
were never stale leftovers — they are the original authored configuration, and
|
||||
the banks they name existed all along, simply never carried into the port.
|
||||
|
||||
Everything below is verified present in `../TeslaRel410/`:
|
||||
|
||||
@@ -420,27 +425,61 @@ points resolve, so F9/F11 are live rather than silently inert. The driver grants
|
||||
explicitly via context attributes. RP412 still accepts the default; worth
|
||||
revisiting if voice starvation shows up in a busy match.
|
||||
|
||||
### Asset-side — unlocked by §8, blocked until the banks are wired in
|
||||
### Asset-side — measured against RP's own banks
|
||||
|
||||
These are all bank-derived, so they cannot even be assessed against RP412's flat
|
||||
WAV set. Prevalences are BT's; RP's own numbers need measuring once its banks are
|
||||
parsed.
|
||||
RP's banks turned out to differ from BT's in ways that matter, so BT's
|
||||
prevalences do not transfer. Measured directly (`tools/rp_sf2extract.py --stats`):
|
||||
|
||||
| # | Gap | What is lost |
|
||||
| | RP total |
|
||||
|---|---|
|
||||
| Presets | 154 (67 in bank 1, 87 in bank 2) |
|
||||
| Instrument zones | **395** |
|
||||
| Multi-zone presets | 130 / 154 (84%) |
|
||||
| **Key-splits** | **zero** |
|
||||
| Max zones in any preset | **4** |
|
||||
| Looping zones | 129 |
|
||||
| Zones with an authored low-pass | 154 |
|
||||
| Zones with layer attenuation | 97 |
|
||||
| Zones with `releaseVolEnv` | 349 |
|
||||
|
||||
**Two RP-specific findings that change the work:**
|
||||
|
||||
1. **RP's banks contain no key-splits at all.** Every multi-zone preset is a pure
|
||||
*layer* stack whose zones share one key range, all covering note 60. Combined
|
||||
with RP's content never authoring a note (§9 above), key ranges are
|
||||
unreachable here — so zone selection is a non-issue and every zone is simply a
|
||||
simultaneous voice. BT's F1, which is largely about key-splits, mostly does
|
||||
not apply; what applies is the plain zone count.
|
||||
2. **Max 4 zones per preset**, which fits `PRESETINFO.samples[5]` as it stands.
|
||||
No structural change was needed — and the engine's long-standing
|
||||
`Warn(GetVoiceCount() > 4)` ("AWE appears to only play 1st 4 voices",
|
||||
`L4AUDLVL.cpp:29`) matches the bank data exactly.
|
||||
|
||||
| # | Gap | RP status |
|
||||
|---|---|---|
|
||||
| F1 | Multi-zone preset collapse | The extractor keeps only the first sample-bearing zone: key-splits, layers and stereo pairs dropped. In BT, 68/115 and 94/126 presets are multi-zone |
|
||||
| F2 | Root-key and tuning metadata dropped | Everything plays as if rooted at MIDI 60. In BT, ~83% of presets land ≥1 semitone off, worst −36 st. Fix is algebraically exact: bake tuning into each WAV's declared sample rate |
|
||||
| F13 | Loop regions and release envelopes | Whole-buffer looping instead of authored sub-regions; instant cuts where 1.1–3.9 s releases were authored |
|
||||
| F14 | Per-zone generators | `initialAttenuation` (**inverted scale in SBK**: 127 = full volume), `initialFilterFc`/`Q`, volume envelopes — `SAMPLEINFO` has no fields for any of it |
|
||||
| F1 | Zones dropped | **fixed** — 93 presets were short; 176 zones recovered, 219 → 395 |
|
||||
| F2 | Root key / tuning dropped | **fixed** — every shipped WAV was flat 44100 Hz; 202 of 219 checked zones were off, worst ~9 semitones. Tuning is now baked into each WAV's declared rate |
|
||||
| F14 | Per-zone generators | **partly fixed** — `initialAttenuation` (SBK inverted scale) and the authored `initialFilterFc`/`Q` resonant low-pass are baked into the PCM. Volume envelopes still dropped |
|
||||
| F13 | Loop regions and release envelopes | **open** — needs `SAMPLEINFO` fields plus engine work (see below) |
|
||||
|
||||
**Ordering hazard, inherited from BT's F13:** loop-region support must ship *with
|
||||
or before* multi-zone extraction. Some layer zones carry loop regions covering as
|
||||
little as 1.5% of the sample; whole-buffer looping over those would replay an
|
||||
entire explosion on every cycle.
|
||||
**F13 remains the outstanding asset-side item.** It needs `loopStart`/`loopEnd`
|
||||
and `releaseSec` on `SAMPLEINFO`, `AL_SOFT_loop_points` at buffer setup, and a
|
||||
gain ramp on the stop path. 349 of 395 zones carry an authored release envelope
|
||||
that is currently an instant cut.
|
||||
|
||||
Tooling already exists — `../BT411/tools/sf2extract.py` — but note it is the
|
||||
source of F1 and F2 in its current form. It needs the multi-zone and tuning fixes
|
||||
before being pointed at RP's banks.
|
||||
The **ordering hazard** BT flagged — loop regions must land with or before
|
||||
multi-zone extraction, or whole-buffer looping over a short loop region replays
|
||||
an entire sample every cycle — is worth re-checking for RP now that zone counts
|
||||
have gone up. RP's 129 looping zones should be measured for loop-region coverage
|
||||
before F13 lands.
|
||||
|
||||
**A churn risk this work introduces.** Voice demand per sound has gone from ~1.1
|
||||
to ~2.6 zones. `RequestAudioChannels` calls `alGenSources` per sound event and
|
||||
`ReleaseSourceSet` calls `alDeleteSources` on release, so the allocation churn
|
||||
roughly doubles. BT411 hit exactly this and its measured conclusion was that
|
||||
raising the source budget was *not* the fix — **pooling** the sources was, and it
|
||||
was a net CPU win (8.67 ms → 7.79 ms per frame). RP412 has the same churn
|
||||
pattern and no pooling. Worth doing before any complaint arrives, not after.
|
||||
|
||||
## 10. A recovery path, in order
|
||||
|
||||
@@ -450,10 +489,14 @@ before being pointed at RP's banks.
|
||||
against vRIO on COM1 with `RP412STEAM=0` — reaches gameplay and holds a
|
||||
steady frame loop. **Not yet listened to on the pod**, which is the real
|
||||
acceptance test: F4 in particular changes the level of everything.
|
||||
2. **Wire RP's banks in.** Copy `AUDIO1.RES`/`AUDIO2.RES` from
|
||||
`ALPHA_1/REL410/RP/AUDIO/` into `dist/AUDIO/` — the AUDIO.INI already names
|
||||
them. Fix `sf2extract.py` for multi-zone (F1), tuning (F2) and loop regions
|
||||
(F13) *before* regenerating, then rebuild the preset table.
|
||||
2. ~~**Wire RP's banks in.**~~ **Done (2026-08-05).** Both banks are now in
|
||||
`assets/RP411/AUDIO/`, hash-identical to the 1996 originals.
|
||||
`tools/rp_sf2extract.py` extracts all 395 zones with tuning, layer
|
||||
attenuation and the authored low-pass baked in, and regenerates
|
||||
`RP_L4/WTPresets.cpp`. Verified: 176 zones recovered with none lost (the 46
|
||||
preset slots that disappeared were all empty placeholders); every extreme
|
||||
baked rate (1228 Hz – 88200 Hz) accepted by libsndfile → `alBufferData` →
|
||||
`alSourcePlay` on the real runtime path. **Still open here: F13.**
|
||||
3. **Recover the `.SCP` sources** from `sda4/RPLIVE/AUDIO/` into the asset
|
||||
pipeline, so authored audio becomes editable again rather than frozen in
|
||||
`RPL4.RES`.
|
||||
|
||||
Reference in New Issue
Block a user