1 // Hound -- A wav encoding and decoding library in Rust
2 // Copyright (C) 2015 Ruud van Asseldonk
3 //
4 // Licensed under the Apache License, Version 2.0 (the "License");
5 // you may not use this file except in compliance with the License.
6 // A copy of the License has been included in the root of the repository.
7 // Unless required by applicable law or agreed to in writing, software
8 // distributed under the License is distributed on an "AS IS" BASIS,
9 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10 // See the License for the specific language governing permissions and
11 // limitations under the License.
12
13 // This example shows how to play a wav file using the cpal crate.
14
15 extern crate hound;
16 extern crate cpal;
17
18 use std::env;
19 use std::thread;
20
main()21 fn main() {
22 // Make a WavReader that reads the file provided as program argument.
23 let fname = env::args().nth(1).expect("no file given");
24 let mut reader = hound::WavReader::open(fname).unwrap();
25 let spec = reader.spec();
26
27 let endpoint = cpal::get_default_endpoint().unwrap();
28
29 // Pick a playback format supported by the endpoint, which matches the spec
30 // of the wav file.
31 let format = endpoint.get_supported_formats_list().unwrap()
32 .filter(|f| matches_format(f, &spec))
33 .next()
34 .expect("no supported playback format");
35
36 // A voice in cpal is used for playback.
37 let mut voice = cpal::Voice::new(&endpoint, &format).unwrap();
38
39 let mut samples_left = reader.len() as usize;
40
41 let mut append_data = |voice: &mut cpal::Voice| {
42 match voice.append_data(samples_left) {
43 cpal::UnknownTypeBuffer::I16(mut wrapped_buf) => {
44 // We cannot rely on Rust's autoderef here, because we want to
45 // call .len() on the buffer, which would cause a deref() of the
46 // buffer, not a deref_mut(), and cpal's deref() implementation
47 // is to panic.
48 let buf: &mut [i16] = &mut *wrapped_buf;
49 for (dst, src) in buf.iter_mut().zip(reader.samples::<i16>()) {
50 *dst = src.unwrap();
51 }
52 samples_left -= buf.len();
53 }
54 cpal::UnknownTypeBuffer::F32(mut wrapped_buf) => {
55 let buf: &mut [f32] = &mut *wrapped_buf;
56 for (dst, src) in buf.iter_mut().zip(reader.samples::<f32>()) {
57 *dst = src.unwrap();
58 }
59 samples_left -= buf.len();
60 }
61 _ => unreachable!()
62 }
63
64 // Loop again if there are samples left.
65 samples_left > 0
66 };
67
68 // The voice must have some data before playing for the first time.
69 let mut has_more = append_data(&mut voice);
70 voice.play();
71
72 // Then we keep providing new data until the end of the audio.
73 while has_more {
74 has_more = append_data(&mut voice);
75 }
76
77 // Wait for playback to complete.
78 while voice.underflowed() {
79 thread::yield_now();
80 }
81 }
82
matches_format(format: &cpal::Format, spec: &hound::WavSpec) -> bool83 fn matches_format(format: &cpal::Format, spec: &hound::WavSpec) -> bool {
84 let cpal::SamplesRate(sample_rate) = format.samples_rate;
85 if sample_rate != spec.sample_rate {
86 return false
87 }
88
89 if format.channels.len() != spec.channels as usize {
90 return false
91 }
92
93 let data_type = match (spec.bits_per_sample, spec.sample_format) {
94 (16, hound::SampleFormat::Int) => Some(cpal::SampleFormat::I16),
95 (32, hound::SampleFormat::Float) => Some(cpal::SampleFormat::F32),
96 _ => None
97 };
98
99 if Some(format.data_type) != data_type {
100 return false
101 }
102
103 // If the sample rate, channel count, and sample format match, then we can
104 // play back the file in this format.
105 true
106 }
107