Native TFX music and sound archive
The audio browser includes all 81 original OSL resources: 27 FM, 31 LAPC-I/MT-32 and 23 Sound Canvas arrangements or auxiliary banks. Each Sound Canvas resource has separate SCC-1A and SC-55 exports, giving 104 hardware auditions. Resources can contain the same composition or an effects bank; these counts do not mean 104 independent pieces of music. Byte-identical exports share one listening file, leaving 100 stored FLACs. No ZIP copies are created.
The browser groups matching selections by their original launcher slot,
with one compact table row per hardware version. For example, air superiority
pairs airsuper.adl, airsuper/clean.lap and xirsuper.scc; SCC-1A and SC-55
are two hardware renders of that last score. Filenames are retained beside
players. Slot membership establishes the same selection role, not necessarily
the same composition. Resources outside the launcher lists have their own
section, without guessed counterparts. Hardware filters retain the slot order
and explicitly show missing entries.
| Browser choice | Hardware emulation | ROM revision |
|---|---|---|
| Sound Blaster FM | TFX C++ DOSBox OPL backend | No ROM required |
| LAPC-I / CM-32L | Munt | CM-32L 1.02 |
| SCC-1A | Nuked Sound Canvas, CM-300 path | SCC-1A 1.30 |
| SC-55 | Nuked Sound Canvas, original SC-55 path | SC-55 1.21 |
All exports are 48 kHz, 24-bit stereo FLAC at compression level 12. FM is dual mono; the Roland paths can produce stereo. The two Sound Canvas choices use the same native SCC arrangement, with each model's actual firmware and wave ROMs. They are separate auditions because their instruments can sound noticeably different. The original SCC-1 ROM set remains unavailable.
Verified game playback
The refreshed exports use the actual game timer: PIT input 1,193,182 Hz,
divisor 21,845 (0x5555), approximately 54.62037 sequencer ticks/second.
The library's requested clock changes do not alter this shared IRQ. Playback
starts at song/order/row zero with the original general-play volume 75.
The previous auditions followed requested clocks, initially 50 Hz, at volume
127. For a 50 Hz resource the corrected playback is about 9.24% faster and
8.46% shorter. air.rld now continues beyond its zero-clock request instead
of being truncated there; the game continues calling the sequencer.
capture_osl_music.py executes the original shared IRQ and original device
driver through NativeOSL from the C++ project's independent comparison tools.
It verifies the PIT writes and IRQ counter and records the device bytes, row
and order boundaries and requested clock changes. TFX C++'s music_render
uses the production sequencer, music_clock, MIDI stream decoder and hardware
backends. Every render must match the original's complete 16-field playback
state trace and rationally scheduled sample boundary. The first IRQ occurs at
the first output sample on or after its deadline; fractional phase is retained.
Each audition ends at the first native backwards order/row jump or native stop, then uses the real device driver's stop operation and a two-second release tail. A backwards jump's first repeated notes are excluded. Reported loop starts mark the first observed target position, rather than guaranteeing a sample-perfect PCM splice with existing voices and reverb. Effects and engine banks are standalone order-zero auditions; interactive flight cue changes, throttle modulation and concurrent effects are not simulated in these files.
These are emulator exports, not physical-card recordings. Instruction-level serial transmission timing within an IRQ is not reconstructed. Device reset settling uses the same policy as the native C++ game. Complete MIDI and SysEx messages follow its decoder unchanged, including original invalid checksums; no replacement sound bank or Darker-specific percussion workaround is applied.
Intro comparison
The four intro-*.flac files are synthesised arrangements, separate from CD
track rips. Exact durations and repeat positions are in
intro-renders.json and in each browser player’s tooltip.
The full render manifest records source/ROM/renderer hashes, sample counts, native state verification, boundaries and export gain. Sound Canvas exports use fixed gain 0.25 (-12.04 dB); FM/LA use 1. Gain is reduced further only if required to avoid export clipping, and is recorded per file. This is fixed attenuation, without dynamic compression or loudness normalisation. Match listening levels when comparing hardware.
Every FLAC is decoded and compared against its floating-point render after
that gain, with differences bounded by 24-bit quantisation. SCC-1A and SC-55
share the same original-code event capture, but have separate ROM provenance
and audio hashes. The nested variants.sc55 entries retain the original
81-resource catalogue while exposing all 104 auditions.
Reproducing
Build the offline renderer from the sibling C++ project (C++26,
BUILD_TESTING=ON), then render or resume the archive:
cmake --build ../tfx-cpp/build-rel --target music_render -j
python3 tools/render_music_archive.py --jobs 4
python3 tools/map_music_scenes.py
python3 tools/check_analysis.py
The capture requires unicorn==2.1.4; the batch also uses NumPy, FFmpeg and
FFprobe. ROMs default to ~/.local/share/tfx, respecting an absolute
XDG_DATA_HOME. --roms, --renderer and --implementation override custom
locations. --name intro limits an audition pass; full runs retain all resources.
tools/build_osl_renderer.sh TFX_CPP_DIRECTORY OUTPUT_BINARY [BUILD_DIRECTORY]
can copy a built renderer to another location.
Only completed files with matching source, capture, renderer and ROM fingerprints are reused. Each new FLAC is validated before replacing its previous version, and intermediate PCM files are removed. The actual game resources and ROMs remain external to the source tools.
Complete audio catalogue and sampled effects
The audio browser brings together both retained CD audio masters, all 104 hardware auditions of the 81 OSL resources and 103 sampled effects/speech clips. The latter are unsigned 8-bit mono PCM WAVs, preserving the resource bytes rather than normalising or filtering them.
Their rates come from the 26-byte native effect descriptors around executable file offsets 0xf7304–0xf7e00. Sample filenames are resolved by the archive's original hash, using the descriptor's actual name. The loader at 0xc5214 constructs samples/<name>.sam; the playback preparation at 0xdd22c reads the rate at descriptor offset 4 and forwards the complete resource buffer and length. It does not skip an assumed sample header.
Most descriptors specify 7,500 Hz; some use 6,500, 8,363 or 9,000 Hz. The exports use that nominal rate. They do not emulate Sound Blaster clock quantisation, the driver/effect pointer, attenuation, cooldown logic or spatial processing. Sample metadata records the descriptor file offset, configured rate, cooldown, source resource, sample count and source hash. All 103 named descriptors resolve to PCM resources. The x10 buffer was initially excluded by a text-classification heuristic; resolving every native descriptor directly identifies it as resource 5f59fe09 (3,524 unsigned PCM bytes at the configured 6,500 Hz). Other sample-name candidates remain in the resource catalogue without an invented playback rate.
Regenerate these exports with python3 tools/decode_samples.py. The four-byte prefix shown by a hex viewer is audio data, not an inferred header.
Composer Barry Leitch's 2026 TFX soundtrack release describes the MT-32 arrangement as the superior version. That supports using it as the preferred synthesised reference, while keeping the FM, SCC and CD arrangements as independent evidence. It does not establish which hardware the original tracks were composed on. The release's modern remake should also not be confused with the original CD mastering variants documented in the disc audio comparison.
Music selection and scene links
scene-music.json exposes literal filename lists from START.EXE: 18 LAPC entries, 22 FM entries and 21 SCC entries. These are indexed runtime lists, not the entire archive. Full nested names such as tunes/airsuper/clean.lap recover aliases that a basename-only scan missed.
Two original-list inconsistencies are visible: tunes/intercep/clean.lap resolves to an FM OSL resource despite occupying the LAPC list; tunes/antiarm.adl has no archive match. These are preserved rather than silently substituted. Filename hashes alone remain supporting evidence, so all list entries also retain their actual OSL device header.
The parser's audio statement at 0xb2214 selects synth for mode 0 and CD for mode 1. The previously labelled synthesised routine 0xb4000 is actually CD playback: it builds an MSCDEX 0x1510 request with command 0x84, using physical CD track index + 1. 0xb40c8 stops the CD. Native checks verify the dispatch, request bytes and track/sector indexing.
For synthesis, 0xa5d68 loads/allocates a resident OSL resource. An initial index 10 or above is retained as a preselection; the next play request consumes that retained index. The capture verifies indices 0–15, including this two-request behaviour. 0xa5b64 starts the allocated slot at order zero with game-volume argument 75; the refreshed auditions use the same volume 75.
The mapping records 269 audio statements and resolves local sequential music for 98 of 116 presentation groups. For example, the CD opening presentation explicitly starts synthesised intro, the training introduction uses enrol, death uses death, and regional intros select their local composition. The presentation page links directly to each available device audition. The remaining 18 groups have no local proven start; inherited music, branches and flight-session state are not guessed. Mission scripts contain no explicit music/tune/CD commands in the recovered corpus. The scene viewer does not autoplay audio on an approximate visual schedule.
Additional breathing recordings and numeric speech candidates have auditions in the remaining-resource viewer. They are separate from the 103 named sample descriptors. Their rate assumptions and use-site investigation are documented in unidentified data.