ACIDCAT . FILE FORMAT REFERENCE

NCW Anatomy

NI Compressed Wave.ncw . Kontakt libraries
rev 2026.07
magic 01 A8 9E D6
endian little
codec lossless blocks
sample 2ch 24-bit 48k

NCW is the sample format inside Kontakt instruments: PCM audio, losslessly compressed. The file is a fixed little-endian header, a block table, and a run of delta/bit-packed audio blocks that reconstruct the original samples exactly. No ASCII magic here; the file opens with the 4-byte sentinel 01 A8 9E D6 (a newer writer variant uses 01 A8 9E D7). Everything below is field-verified against a real Kontakt library .ncw. Hover any field to light its exact bytes and read the decode; click a field with a + to open its table. Color marks kind (see the key).

file regions

Top to bottom, what a reader walks. The audio parameters a producer wants sit in the first 32 bytes; acidcat inspect decodes them and derives the duration without touching the compressed body.

fixed header0x00 . 120 bytes . drawn below

All integers little-endian. The first 32 bytes carry the magic, the audio parameters, and three offsets that lay out the rest of the file; the remainder of the 120-byte header is zero in the files examined. The worked example is the corpus file: 2 channels, 24-bit, 48000 Hz, 439295 samples.

magic01 A8 9E D6 at offset 0; 01 A8 9E D7 on newer writers
audio paramschannels u16 @ 0x08 . bits u16 @ 0x0A . sample_rate u32 @ 0x0C . num_samples u32 @ 0x10
layout offsetsblock table @ the u32 at 0x14, audio data @ the u32 at 0x18, body size in the u32 at 0x1C
cross-checkdata_offset + data_size = file size; 3556 + 1909184 = 1912740 on the corpus file
block table0x78 . u32 offsets

Between the header and the audio sits an index: one u32 offset per compressed block, relative to the start of the audio body, plus a final entry marking its end. Random access falls out for free; a player seeks the table, not the stream.

entryu32 little-endian, offset from data_offset
corpus file859 entries at 0x78: 858 blocks plus the end sentinel, ascending from 0 to 1909184
block spaneach block covers 512 sample frames; 858 x 512 = 439296, one frame past num_samples, so the last block runs short
sizingentry deltas give each block's compressed byte size; they vary block to block with the material
compressed audio bodydata_offset . opaque to acidcat

The samples themselves, packed block by block. Each block is delta/bit-packed: store the differences between neighbouring samples, then keep only as many bits per delta as the block actually needs. Quiet or smooth material packs tight; noise barely shrinks. Decoding reconstructs the original PCM exactly; this is lossless, not perceptual.

unitfixed blocks of 512 samples, each independently decodable via the table
packingper-block delta coding with a per-block bit width
guaranteebit-exact PCM out; the WAV that went in comes back whole
acidcatleft opaque; deep audio decode is out of scope, the header already answers the catalog questions
what acidcat reads

The header is enough. Four fields in, one division out, and a corrupt file gets rejected instead of cataloged with a nonsense duration.

header decode + validationinspect . index
readchannels, bit depth, sample rate, sample count from the fixed header
deriveduration = num_samples / sample_rate; 439295 / 48000 = 9.152 s on the corpus file
validatechannels 1-32 . bits in {8, 16, 24, 32} . sample_rate 8000-384000 . num_samples 1 to 2e9
on failurethe file is rejected as corrupt rather than shown with an absurd duration