83 lines
2.8 KiB
Rust
83 lines
2.8 KiB
Rust
// Claxon -- A FLAC decoding library in Rust
|
|
// Copyright 2015 Ruud van Asseldonk
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// A copy of the License has been included in the root of the repository.
|
|
|
|
// This file implements a decoder, like the reference `flac -d`. It is fast, but
|
|
// being fast requires dealing with a few details of the FLAC format. There is
|
|
// also a simpler example, `decode_simple`, which is less verbose.
|
|
|
|
extern crate claxon;
|
|
extern crate hound;
|
|
|
|
use claxon::{Block, FlacReader};
|
|
use hound::{WavSpec, WavWriter};
|
|
use std::env;
|
|
use std::path::Path;
|
|
|
|
fn decode_file(fname: &Path) {
|
|
let mut reader = FlacReader::open(fname).expect("failed to open FLAC stream");
|
|
|
|
// TODO: Write fallback for other sample widths and channel numbers.
|
|
assert!(reader.streaminfo().bits_per_sample == 16);
|
|
assert!(reader.streaminfo().channels == 2);
|
|
|
|
let spec = WavSpec {
|
|
channels: reader.streaminfo().channels as u16,
|
|
sample_rate: reader.streaminfo().sample_rate,
|
|
bits_per_sample: reader.streaminfo().bits_per_sample as u16,
|
|
sample_format: hound::SampleFormat::Int,
|
|
};
|
|
|
|
let fname_wav = fname.with_extension("wav");
|
|
let mut wav_writer = WavWriter::create(fname_wav, spec).expect("failed to create wav file");
|
|
|
|
let mut frame_reader = reader.blocks();
|
|
let mut block = Block::empty();
|
|
loop {
|
|
// Read a single frame. Recycle the buffer from the previous frame to
|
|
// avoid allocations as much as possible.
|
|
match frame_reader.read_next_or_eof(block.into_buffer()) {
|
|
Ok(Some(next_block)) => block = next_block,
|
|
Ok(None) => break, // EOF.
|
|
Err(error) => panic!("{}", error),
|
|
}
|
|
|
|
let mut sample_writer = wav_writer.get_i16_writer(block.duration() * 2);
|
|
|
|
// Write the samples in the block to the wav file, channels interleaved.
|
|
for (left, right) in block.stereo_samples() {
|
|
// The `stereo_samples()` iterator does not yield more samples
|
|
// than the duration of the block, so we never write more
|
|
// samples to the writer than requested, hence using the
|
|
// unchecked functions is safe here.
|
|
unsafe {
|
|
sample_writer.write_sample_unchecked(left);
|
|
sample_writer.write_sample_unchecked(right);
|
|
}
|
|
}
|
|
|
|
sample_writer.flush().expect("failed to write samples to wav file");
|
|
}
|
|
|
|
wav_writer.finalize().expect("failed to finalize wav file");
|
|
}
|
|
|
|
fn main() {
|
|
let mut no_args = true;
|
|
|
|
for fname in env::args().skip(1) {
|
|
no_args = false;
|
|
|
|
print!("{}", fname);
|
|
decode_file(&Path::new(&fname));
|
|
println!(": done");
|
|
}
|
|
|
|
if no_args {
|
|
println!("no files to decode");
|
|
}
|
|
}
|