A simple library to read and write audio files on your disk.
The library can read many formats and can write only to wav files.
Read a file into interleaved f32 (or f64) samples, full scale at ±1.0:
let audio = audio_file::read::<f32>("test_data/test_1ch.wav", audio_file::ReadConfig::default())?;
let samples = &audio.samples_interleaved;
let sample_rate = audio.sample_rate;
let num_channels = audio.num_channels;Write interleaved samples back out as a wav file:
let samples = [0.0, 1.0, 0.0, 1.0, 0.0, 1.0]; // interleaved
let num_channels = 2;
let sample_rate = 48_000;
audio_file::write(
"output.wav",
&samples,
num_channels,
sample_rate,
audio_file::WriteConfig::default(),
)?;That covers most uses. Everything below is optional.
With no default features, this crate reads and writes wav through a built-in decoder, with almost no dependencies. Everything else is additive on top of that.
| Feature | Default | What it adds |
|---|---|---|
all-codecs |
yes | Read every common codec: MP3, FLAC, AAC, ALAC, Vorbis, and the MP4, Ogg, Matroska, AIFF and CAF containers |
resample |
yes | Resample while reading, via rubato |
simd |
yes | Symphonia's SIMD optimizations. Only does something alongside a codec feature |
audio-blocks |
no | Read and write any channel layout, via audio-blocks |
Turning a feature off removes the API it brings rather than making it fail at runtime.
Without resample, ReadConfig has no sample_rate field at all, so asking for a rate
nothing would resample to does not compile.
ReadConfig selects what to read. Only the selected frames are stored, though the reader
may decode and discard earlier packets for accurate seeking and codec warm-up.
Positions are given as a Position, in frames or in time. start is inclusive and stop
is exclusive, so frame 300 to 400 yields 100 frames. Frame 0 is the first playable frame:
encoder delay and padding, as used by formats like MP3, are not part of the timeline.
// the first half second
let audio = audio_file::read::<f32>(
"test_data/test_1ch.wav",
audio_file::ReadConfig {
stop: audio_file::Position::Time(Duration::from_secs_f32(0.5)),
..Default::default()
},
)?;
// frame 300 up to frame 400
let audio = audio_file::read::<f32>(
"test_data/test_1ch.wav",
audio_file::ReadConfig {
start: audio_file::Position::Frame(300),
stop: audio_file::Position::Frame(400),
..Default::default()
},
)?;Channels are selected the same way, with start_channel and num_channels:
// the first two channels
let audio = audio_file::read::<f32>(
"test_data/test_4ch.wav",
audio_file::ReadConfig {
num_channels: Some(2),
..Default::default()
},
)?;
// channel 2 and 3, skipping the first
let audio = audio_file::read::<f32>(
"test_data/test_4ch.wav",
audio_file::ReadConfig {
start_channel: Some(1),
num_channels: Some(2),
..Default::default()
},
)?;With the resample feature, a sample_rate makes the reader hand back audio at that rate
whatever the file holds:
let audio = audio_file::read::<f32>(
"test_data/test_1ch.wav",
audio_file::ReadConfig {
sample_rate: Some(22_050),
..Default::default()
},
)?;A file is either read in full or not at all: a packet the decoder rejects fails the whole read rather than being skipped over or filled in.
Output is always wav. WriteConfig picks the sample format:
SampleFormat |
Description |
|---|---|
Int8 |
8-bit integer |
Int16 |
16-bit integer (default, for the broadest compatibility) |
Int32 |
32-bit integer |
Float32 |
32-bit float |
audio_file::write(
"output_float32.wav",
&samples_interleaved,
num_channels,
sample_rate,
audio_file::WriteConfig {
sample_format: audio_file::SampleFormat::Float32,
},
)?;Interleaved is the only layout read and write speak. With the audio-blocks feature you
get read_block and write_block, which work in AudioBlocks and so handle any layout, plus
channel-wise access to what was read:
let (block, sample_rate) =
audio_file::read_block::<f32>("test_data/test_4ch.wav", ReadConfig::default())?;
let left: Vec<f32> = block.channel_iter(0).copied().collect();
let block = Sequential::from_slice(&[0.0, 0.0, 0.0, 1.0, 1.0, 1.0], 2);
audio_file::write_block("output_layout.wav", block, 48_000, WriteConfig::default())?;all-codecs is a convenience for "read anything". To keep the dependency tree small, name
only the formats you need instead:
| Format | Feature flags |
|---|---|
| WAV, integer PCM and IEEE float | none, built in |
| WAV, A-law, mu-law and ADPCM | wav-compressed |
| FLAC | flac |
| MP1, MP2, MP3 | mp1, mp2, mp3 |
| AAC (raw ADTS) | aac |
| MP4, M4A | isomp4 plus aac or alac |
| Ogg | ogg plus vorbis or flac |
| Matroska (MKA, MKV) | mkv plus the codec inside: pcm, flac, vorbis, aac, alac |
| AIFF | aiff plus pcm |
| CAF | caf plus pcm or alac |
A container and the codec inside it are separate flags, so a format that can hold several
codecs needs one of each. Enabling only the container reads no file at all. A file no decoder
in the build can read fails with ReadError::UnsupportedFormat.
Some formats have channel ceilings below what the format itself allows, see the
reader module docs.