# Native TFX music and sound archive

The [audio browser](index.html) 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](intro-renders.json) and in each browser player’s tooltip.

The [full render manifest](music-renders.json) 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:

```sh
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](index.html) 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](samples.json) 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](https://barryleitch.bandcamp.com/album/tfx-tactical-fighter-experiment) 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](../retained-cd-audio.md).

## Music selection and scene links

[scene-music.json](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](control-checks.json) 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](../unresolved/index.html). They are separate
from the 103 named sample descriptors. Their rate assumptions and use-site
investigation are documented in [unidentified data](../unidentified-data.md).
