mirror of
https://github.com/storytold/craft-libs.git
synced 2026-11-15 06:52:23 +00:00
EncodeFormat gains Aac and Alac (M4A through craft-media's MP4 muxer) and Mp3, Ac3 and Eac3 (raw streams), so one call writes any of them from WAV-order f32 audio and EncodeOptions. - EncodeOptions::rate_control (with_bitrate, with_quality): a bit rate is moved to the nearest one the stream can carry; quality is AAC's VBR. - Channels are mapped onto the codec's order by speaker, from EncodeOptions::layout. A layout the format has not is Unsupported instead of reaching the wrong speakers. - M4A: the edit list skips the AAC priming, and the last sample's duration is cut so the track ends at the last frame written. - encode_format_for, ENCODE_EXTENSIONS and EncodeFormat::ALL list the new formats; aac-encode and alac-encode now turn on craft-media's isobmff. Refs #1230
42 lines
2.2 KiB
Rust
42 lines
2.2 KiB
Rust
//! Write a tone as WAV, FLAC and AAC in M4A, whole and streamed, and as AAC packets.
|
|
//!
|
|
//! `cargo run -p craft-audio --example encode --features lossless-encode,aac-encode -- out`
|
|
|
|
use craft_audio::{AudioBuffer, BitDepth, ChannelLayout, EncodeFormat, EncodeOptions, FileEncoder, encode};
|
|
|
|
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|
let dir = std::path::PathBuf::from(std::env::args().nth(1).unwrap_or_else(|| ".".into()));
|
|
std::fs::create_dir_all(&dir)?;
|
|
let rate = 48_000;
|
|
let tone: Vec<f32> = (0..rate).map(|i| (i as f32 * 440.0 * std::f32::consts::TAU / rate as f32).sin() * 0.5).collect();
|
|
let stereo = AudioBuffer { sample_rate: rate as u32, channels: vec![tone.clone(), tone.clone()] };
|
|
|
|
// A whole buffer at once.
|
|
let wav = encode(&stereo, &EncodeOptions::new(EncodeFormat::Wav).with_bit_depth(BitDepth::Int24).with_dither(true))?;
|
|
std::fs::write(dir.join("tone.wav"), wav)?;
|
|
|
|
// A 5.1 file whose layout a channel count alone cannot name (side surrounds).
|
|
let surround = AudioBuffer { sample_rate: rate as u32, channels: vec![tone.clone(); 6] };
|
|
let wav = encode(&surround, &EncodeOptions::default().with_layout(ChannelLayout::SURROUND_5_1_SIDE))?;
|
|
std::fs::write(dir.join("tone-5.1.wav"), wav)?;
|
|
|
|
// Streamed: the bytes `encode` would give, block by block into a file.
|
|
let opts = EncodeOptions::new(EncodeFormat::Flac);
|
|
let mut enc = FileEncoder::new(std::fs::File::create(dir.join("tone.flac"))?, &opts, rate as u32, 2)?;
|
|
for chunk in tone.chunks(4096) {
|
|
enc.write(&[chunk, chunk], chunk.len())?;
|
|
}
|
|
enc.finish()?;
|
|
|
|
// AAC in M4A at 160 kbit/s: the same call, with a bit rate in place of a bit depth.
|
|
let m4a = encode(&stereo, &EncodeOptions::new(EncodeFormat::Aac).with_bitrate(160_000))?;
|
|
std::fs::write(dir.join("tone.m4a"), m4a)?;
|
|
|
|
// AAC packets for a muxer of your own, with the configuration its sample entry needs.
|
|
let mut aac = craft_audio::aac::Encoder::new(craft_audio::aac::EncoderConfig::cbr(rate as u32, 2, 128_000))?;
|
|
let mut units = aac.encode(&[&tone, &tone]);
|
|
units.extend(aac.flush());
|
|
println!("{} AAC access units, AudioSpecificConfig {:02x?}, priming {}", units.len(), aac.audio_specific_config(), aac.priming_samples());
|
|
Ok(())
|
|
}
|