flacx
High-performance WAV/FLAC conversion and FLAC recompression for Rust.
flacx is the publishable library crate in this workspace. It exposes the
reusable encode/decode pipeline used by Rust callers and by the sibling
flacx-cli crate.
Warning: this crate is still experimental. The current
fxmdlayout is the canonicalv1format, and historicalfxmdpayload variants are not supported.
Add to your project
[]
= "0.8.2"
If you want live progress reporting from library code, enable the optional
progress feature:
[]
= { = "0.8.2", = ["progress"] }
Public API at a glance
| Area | Main items |
|---|---|
| Encoder configuration | EncoderConfig, EncoderBuilder, Encoder::builder() |
| Decoder configuration | DecodeConfig, DecodeBuilder, Decoder::builder() |
| Recompression configuration | RecompressConfig, RecompressBuilder, Recompressor::builder() |
| Encoding | Encoder, EncodeSummary, encode_file, encode_bytes |
| Decoding | Decoder, DecodeSummary, decode_file, decode_bytes |
| Recompression | Recompressor, recompress_file, recompress_bytes |
| Inspection helpers | inspect_wav_total_samples, inspect_flac_total_samples |
| Compression levels | level::Level, level::LevelProfile |
| Optional progress | ProgressSnapshot, EncodeProgress, DecodeProgress, progress-enabled methods |
Quick start: encode, decode, and recompress files
The file-based API is the simplest entry point when you already have paths on disk.
use ;
let encoder = new;
let encode_summary = encoder.encode_file.unwrap;
assert!;
let decoder = default;
let decode_summary = decoder.decode_file.unwrap;
assert_eq!;
Recompress an existing FLAC with a different output profile:
use ;
let config = builder
.mode
.level
.threads
.build;
let summary = new
.recompress_file
.unwrap;
assert!;
Both EncodeSummary and DecodeSummary report the frame count, total samples,
block-size information, sample rate, channel count, and bits per sample for the
processed stream. That makes them useful for assertions in tests and for quick
sanity checks after a run.
If you prefer the convenience constructors, Encoder::builder() and
Decoder::builder() return the same builders as the config types.
use ;
let encoder_config = builder
.level
.threads
.strict_fxmd_validation
.build;
let decoder_config = builder
.threads
.emit_fxmd
.strict_channel_mask_provenance
.build;
let _encoder = new;
let _decoder = new;
Configuration
EncoderConfig controls how FLAC encoding is planned and executed:
levelselects a compression preset fromlevel::Levelthreadssets the worker countblock_sizesets a fixed block sizeblock_scheduleenables a custom block-size schedule for advanced usecapture_fxmdcontrols whether encode-side WAV ingestion imports the privatefxmdchunkstrict_fxmd_validationcontrols whether malformed or duplicatefxmdchunks are rejected during encode-side ingestion
EncoderConfig::default() uses Level::Level8 and a thread count derived from
the current machine’s available parallelism.
DecodeConfig controls FLAC-to-WAV decoding:
threadssets the worker countemit_fxmdcontrols whether decode output writes the privatefxmdpreservation chunkstrict_channel_mask_provenancerequires explicit provenance before the decoder restores non-ordinary channel masksstrict_seektable_validationturns malformedSEEKTABLEmetadata from a tolerated parse-time warning into a decode error
The config types also expose fluent with_* methods if you prefer direct
mutation over the builders.
use ;
let encoder_config = default
.with_level
.with_threads
.with_block_size
.with_strict_fxmd_validation;
let decoder_config = default
.with_threads
.with_emit_fxmd
.with_strict_channel_mask_provenance
.with_strict_seektable_validation;
assert_eq!;
assert_eq!;
RecompressConfig controls FLAC-to-FLAC recompression:
modeselectsloose,default, orstrictrecompress-side metadata handlinglevelselects the output compression presetthreadssets the worker count shared by decode and encode phasesblock_sizeoptionally overrides the encode-side FLAC block size
use ;
let recompress_config = default
.with_mode
.with_level
.with_threads
.with_block_size;
assert_eq!;
assert_eq!;
assert_eq!;
assert_eq!;
Notes:
with_threads(0)clamps to at least one thread.with_level(...)resets the explicit block-size override so the selected level controls the default block size again.with_block_size(...)installs a fixed encode-side block-size override for recompress output.
Byte helpers
Use the byte helpers when you already have the whole WAV or FLAC payload in memory.
use ;
let wav_bytes = read.unwrap;
let flac_bytes = encode_bytes.unwrap;
let roundtrip_wav_bytes = decode_bytes.unwrap;
assert!;
assert!;
These helpers are useful when you are:
- testing encode/decode behavior in memory
- piping data through a higher-level application buffer
- avoiding temporary output files in a prototype
The recompression helpers work the same way for FLAC input:
use recompress_bytes;
let flac_bytes = read.unwrap;
let recompressed = recompress_bytes.unwrap;
assert!;
Metadata round-trip behavior
When Decoder writes WAV output, flacx preserves otherwise-non-roundtrippable
FLAC metadata in a private canonical WAV chunk so a later WAV -> FLAC encode can
reconstruct the original FLAC metadata ordering and payloads. Where WAV has
native compatibility surfaces, flacx also emits derived mirrors such as
LIST/INFO and cue .
This means decoded WAV output may contain extra metadata chunks compared with a minimal PCM-only WAV, even when the audio samples are unchanged.
Compatibility note:
- the current crate recognizes only the unified private
fxmdpreservation chunk at runtime, and exact metadata-preserving workflows require the current canonicalfxmd v1format - historical
fxmdpayload variants are intentionally unsupported - older split private chunks such as
fxvc/fxcsare intentionally no longer imported and are treated like unknown WAV chunks
Sample inspection helpers
inspect_wav_total_samples and inspect_flac_total_samples are lightweight
metadata probes. They are useful when you want to confirm the total sample count
before committing to a longer encode or decode.
use ;
use File;
let wav_total_samples = inspect_wav_total_samples.unwrap;
let flac_total_samples = inspect_flac_total_samples.unwrap;
assert!;
assert!;
These helpers do not perform a full transcode; they only inspect the container metadata needed to report sample counts.
Compression levels
The level module exposes the compression presets used by the encoder.
Level::Level0throughLevel::Level8Level::profile()returns the correspondingLevelProfileLevelProfilestores the block size and encoder search limits used by that preset
use Level;
let level = Level8;
let profile = level.profile;
assert_eq!;
assert_eq!;
If you need to map from a numeric CLI-style level into the Rust enum, use
Level::try_from(u8).
Optional progress feature
Progress support is behind the optional progress feature and is disabled by
default.
use ;
use Cursor;
let encoder = new;
let input = new;
let mut output = new;
let _summary = encoder
.encode_with_progress
.unwrap;
let mut recompress_output = new;
let _summary = new
.recompress_with_progress
.unwrap;
When enabled, the progress surface includes:
ProgressSnapshotRecompressProgressEncodeProgressDecodeProgressEncoder::encode_with_progressEncoder::encode_file_with_progressDecoder::decode_with_progressDecoder::decode_file_with_progressRecompressor::recompress_with_progressRecompressor::recompress_file_with_progress
The CLI crate enables this feature and uses it to render its live terminal progress UI.
Supported scope
- WAV -> FLAC encoding
- FLAC -> WAV decoding
- FLAC -> FLAC recompression with policy-driven metadata handling
flacx is focused on the current WAV ↔ FLAC workflow:
- WAV-to-FLAC encoding
- FLAC-to-WAV decoding
- file-based input/output
- in-memory byte helpers
- sample-count inspection
- optional progress reporting
Limitations
The library intentionally stays narrow. It does not aim to be a general audio toolkit.
Out of scope for the current crate:
- metadata editing
- non-seekable streaming APIs
- broader transcoding beyond WAV ↔ FLAC
- broader format support beyond the current engine envelope
Workspace note
flacx-cli lives in the same workspace but remains a separate crate. It is a
thin command-line front end over the same encode/decode pipeline documented
here.
Practical guidance
- Use the builder types when you want a one-shot configuration setup.
- Use the fluent
with_*methods when you want to derive a config from an existing value. - Use the file helpers for a simple path-to-path workflow.
- Use the byte helpers or inspection helpers when you need in-memory control or preflight metadata checks.
- Use the progress feature only when you need callback-driven progress from Rust code.
Stability note
The package layout and documentation may evolve independently from the encode engine. This README tracks the current public library surface without relying on internal milestone labels.