Pure Rust decoder for Monkey's Audio (APE) lossless audio files. Zero dependencies.
- Decodes APE v3.99+ (format version 3990) files to PCM samples
- All compression levels: Fast (1000), Normal (2000), High (3000), Extra High (4000), Insane (5000)
- Mono and stereo
- 8-bit, 16-bit, and 24-bit sample depths
- Bit-exact output (verified against FFmpeg across millions of samples)
- No unsafe code
- No dependencies beyond
std
Add to your Cargo.toml:
[dependencies]
ape-rs = { git = "https://github.com/lexicone42/ape-rs" }Decode an APE file:
use ape_rs::ApeReader;
let mut reader = ApeReader::open("track.ape").unwrap();
let info = reader.info();
println!("{}ch, {}Hz, {}bit", info.channels, info.sample_rate, info.bits_per_sample);
// Iterate over interleaved i32 PCM samples
for sample in reader.samples() {
let sample: i32 = sample.unwrap();
// For stereo files, samples alternate: [L0, R0, L1, R1, ...]
// Normalize to f32 with: sample as f32 / 2^(bits_per_sample - 1)
}Or collect all samples at once:
use ape_rs::ApeReader;
let mut reader = ApeReader::open("track.ape").unwrap();
let samples: Vec<i32> = reader.samples().collect::<Result<_, _>>().unwrap();| Method | Description |
|---|---|
ApeReader::open(path) |
Open an APE file by path |
ApeReader::new(reader) |
Create from any Read + Seek source |
.info() |
Returns &ApeInfo with metadata |
.samples() |
Returns an iterator over Result<i32, ApeError> |
| Field | Type | Description |
|---|---|---|
sample_rate |
u32 |
Sample rate in Hz (e.g. 44100) |
channels |
u16 |
1 (mono) or 2 (stereo) |
bits_per_sample |
u16 |
8, 16, or 24 |
total_samples |
u64 |
Total interleaved samples (blocks x channels) |
compression_level |
u16 |
1000-5000 |
format_version |
u16 |
e.g. 3990 |
src/
lib.rs Public API (ApeReader, ApeInfo, ApeSamples iterator)
header.rs APE descriptor, header, and seek table parsing
range_coder.rs Arithmetic entropy decoder
nnfilter.rs Adaptive FIR filter (sign-LMS, 0-3 stages by level)
predictor.rs Linear predictor + stereo channel decorrelation
decode.rs Frame decoding pipeline
buffer.rs Sample buffering and interleaving
error.rs Error types
Per-frame decode pipeline:
- Seek to frame offset, read and byte-swap compressed data
- Skip frame header (alignment, CRC, optional flags)
- Range-decode entropy-coded residuals
- NNFilter inverse (adaptive FIR, restores short-term correlation)
- Predictor inverse (linear prediction, restores long-term correlation)
- Channel decorrelation inverse (mid/side to L/R for stereo)
The test suite verifies bit-exact decoding across all 10 configurations (mono/stereo x 5 compression levels). To run tests, generate test data with the MAC encoder and place files in tests/data/:
# Create test WAV files, then encode at each level:
mac input.wav tests/data/test_mono_c2000.ape -c2000
# Run tests
cargo test --release- Only APE v3.99+ (format version >= 3990). Older versions (v3.93-v3.97) use a different header layout.
- No APEv2 tag parsing (metadata tags at EOF are ignored).
- No encoding, decode only.
This is an original Rust implementation. The Monkey's Audio format has limited public documentation; behavior was derived from the format header specification and empirical testing against FFmpeg's decoder output. Output is verified bit-exact against FFmpeg across millions of samples.
MIT
Monkey's Audio is by Matthew T. Ashland. FFmpeg (LGPL) was used as a reference for verification.