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