Skip to content

11K — Raw PCM Audio (.11K / .5K / .8K)

FA audio files are raw, headerless, signed 8-bit mono PCM. The sample rate is encoded in the file extension:

Extension Sample rate Notes
.5K 5512 Hz
.8K 8000 Hz Confirmed via TOOLKIT LIBPTR cache
.11K 11025 Hz Most common
.22K 22050 Hz Supported by TOOLKIT; not observed in FA LIBs (may be ATF/USNF only)

Tools

fx

fx audio info   <file.11K|.5K|.8K>              # sample rate, sample count, duration
fx audio unpack <file.11K|.5K|.8K> [-o out.wav] # raw PCM → WAV
fx audio pack   <in.wav> -o <out.11K|.5K|.8K>   # WAV → raw PCM
                            [-r 11025]            # override sample rate (default from ext)

The output extension determines the stored sample rate when packing. Input WAV must be mono, 8-bit; fx rejects stereo or 16-bit input.

Other Tools

Audacity can also import the raw PCM file directly without the fx step (File → Import → Raw Data: signed 8-bit, mono, sample rate from extension).

  • Audacity — free, cross-platform; raw import, noise reduction, pitch/tempo tools
  • Adobe Audition $ — paid; professional mastering and spectral repair

File Layout

Single-byte samples; no multi-byte integers.

  • Signed 8-bit (int8_t), range −128..127
  • Mono (1 channel)
  • No header, no footer — the file is raw samples from byte 0

Filename Prefix Conventions

The filename prefix (before any letters) is an engine convention, not a format difference:

Prefix Meaning Example
& Looping ambient / cockpit sound &AFTB2.11K
^ Voice / radio callout (one-shot) ^ENGAGE.11K, ^MLTRY-A.11K

fx lib unpack maps & and ^ to _ on extraction because Windows rejects those characters in filenames. The original names are preserved in memory for patching.

WAV Conversion

WAV stores 8-bit audio as unsigned (0..255), not signed. Apply ^ 0x80 on both directions:

// FA raw → WAV sample
wav_byte = (uint8_t)((int8_t)fa_byte + 128);   // equivalently: fa_byte ^ 0x80

// WAV sample → FA raw
fa_byte = (int8_t)(wav_byte - 128);

WAV header (mono, 8-bit, sample rate R):

RIFF chunk:  "RIFF" + (file_size - 8) u32LE + "WAVE"
fmt  chunk:  "fmt " + 16 u32LE + 1 u16LE (PCM) + 1 u16LE (channels)
             + R u32LE (sample rate) + R u32LE (byte rate)
             + 1 u16LE (block align) + 8 u16LE (bits per sample)
data chunk:  "data" + sample_count u32LE + [samples]

To create a .5K variant of a sound: pack at 11025 Hz after doubling playback speed 2×, then rename the extension to .5K. The engine plays it at half rate, yielding the correct pitch with reduced quality.

Engine Notes

AIL Runtime Integration (the game executable)

The game executable calls the Miles Audio Interface Library (AIL) API directly. The following API calls and globals were confirmed via Ghidra analysis of the The game executable main binary:

Initialization sequence:

_AIL_startup_0();
_AIL_set_preference_8(4, 0x78);                              // MIDI preference
_AIL_midiOutOpen_12(&_musicDriverHandle, 0, 0xFFFFFFFF);     // open MIDI driver
_AIL_lock_0();
_AIL_set_XMIDI_master_volume_8(...);
_AIL_unlock_0();
_AIL_register_timer_4(&_PollMod__YGXK_Z) → _timerHandle;    // register poll callback
_AIL_set_timer_frequency_8(_timerHandle, 0x1e);              // 30 Hz
_AIL_start_timer_4(_timerHandle);

_AIL_set_preference_8(0xf, 0);
_AIL_set_preference_8(0xe, 0x4000);
_AIL_set_preference_8(0,   0x10);
_AIL_set_preference_8(2,   0x28f);
_AIL_waveOutOpen_16(&_soundDriverHandle, 0, 0, &fmt);        // 22050 Hz, stereo, 16-bit

// Allocate mix channels (loop):
_AIL_allocate_sample_handle_4(_soundDriverHandle) → _mixChanHandle[i]

Runtime globals:

Global Type Role
_musicDriverHandle__3PAU_MDI_DRIVER__A MDI_DRIVER* MIDI driver handle
_soundDriverHandle__3PAU_DIG_DRIVER__A DIG_DRIVER* Digital audio driver handle (22050 Hz stereo 16-bit)
_timerHandle__3JA HTIMER 30 Hz poll timer for _PollMod
_mixChanHandle__3PAPAU_SAMPLE__A HSAMPLE[] Per-channel digital audio handles
_ailActive__3DA bool AIL system active flag

Channel teardown: _AIL_end_sample_4(channel) — called per channel on shutdown.

The WAIL32.DLL and msapi.dll are the AIL wrapper DLLs loaded at runtime. Their import surface has not been traced (no Ghidra output available for the secondary project). IP.EXE audio path is also uncharted.

Round-Trip Notes

The format is raw samples with no derived fields, so WAV → PCM → WAV round trips are byte-identical; tests/test_audio.cpp asserts the PCM round-trip. The ^ 0x80 signedness flip is exactly self-inverse.

An earlier draft of this page described .MUS files as named pointers to .11K audio; the confirmed decode shows .MUS playlists drive .XMI MIDI tracks instead — see MUS.md for the corrected music-slot table and modding workflow.

Formats: LIB — container archives (and the &/^ extraction mapping); MUS — the music playlist DLLs (MIDI, not PCM); CB8 — FMV clips pair with a .11K of the same stem; VDO — briefing videos share one .11K narration per 3-character group prefix (AAC.11K for AACAAACE), not per full stem.