extern crate hound;
extern crate cpal;
use std::env;
use std::thread;
fn main() {
let fname = env::args().nth(1).expect("no file given");
let mut reader = hound::WavReader::open(fname).unwrap();
let spec = reader.spec();
let endpoint = cpal::get_default_endpoint().unwrap();
let format = endpoint.get_supported_formats_list().unwrap()
.filter(|f| matches_format(f, &spec))
.next()
.expect("no supported playback format");
let mut voice = cpal::Voice::new(&endpoint, &format).unwrap();
let mut samples_left = reader.len() as usize;
let mut append_data = |voice: &mut cpal::Voice| {
match voice.append_data(samples_left) {
cpal::UnknownTypeBuffer::I16(mut wrapped_buf) => {
let buf: &mut [i16] = &mut *wrapped_buf;
for (dst, src) in buf.iter_mut().zip(reader.samples::<i16>()) {
*dst = src.unwrap();
}
samples_left -= buf.len();
}
cpal::UnknownTypeBuffer::F32(mut wrapped_buf) => {
let buf: &mut [f32] = &mut *wrapped_buf;
for (dst, src) in buf.iter_mut().zip(reader.samples::<f32>()) {
*dst = src.unwrap();
}
samples_left -= buf.len();
}
_ => unreachable!()
}
samples_left > 0
};
let mut has_more = append_data(&mut voice);
voice.play();
while has_more {
has_more = append_data(&mut voice);
}
while voice.underflowed() {
thread::yield_now();
}
}
fn matches_format(format: &cpal::Format, spec: &hound::WavSpec) -> bool {
let cpal::SamplesRate(sample_rate) = format.samples_rate;
if sample_rate != spec.sample_rate {
return false
}
if format.channels.len() != spec.channels as usize {
return false
}
let data_type = match (spec.bits_per_sample, spec.sample_format) {
(16, hound::SampleFormat::Int) => Some(cpal::SampleFormat::I16),
(32, hound::SampleFormat::Float) => Some(cpal::SampleFormat::F32),
_ => None
};
if Some(format.data_type) != data_type {
return false
}
true
}