1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
use std::sync::{Arc, Mutex};
use cpal::traits::{DeviceTrait, HostTrait, StreamTrait};
use super::{Mixer, Sound, SoundSource};
use crate::converter::{ChannelConverter, SampleRateConverter};
pub struct AudioEngine {
mixer: Arc<Mutex<Mixer>>,
channels: u16,
sample_rate: u32,
_stream: cpal::platform::Stream,
}
impl AudioEngine {
pub fn new() -> Result<Self, &'static str> {
let host = cpal::default_host();
let device = host
.default_output_device()
.ok_or("no output device available")?;
let mut supported_configs_range = device
.supported_output_configs()
.map_err(|_| "error while querying formats")?;
let config = supported_configs_range
.next()
.ok_or("no supported format?!")?
.with_max_sample_rate()
.config();
let mixer = Arc::new(Mutex::new(Mixer::new(
config.channels,
super::SampleRate(config.sample_rate.0),
)));
let stream = {
let mixer = mixer.clone();
device
.build_output_stream(
&config,
move |buffer, _| {
let mut buf = vec![0; buffer.len()];
mixer.lock().unwrap().write_samples(&mut buf);
for i in 0..buffer.len() {
buffer[i] = buf[i] as f32 / i16::max_value() as f32;
}
},
move |err| match err {
cpal::StreamError::DeviceNotAvailable => {
todo!("handle device disconnection")
}
cpal::StreamError::BackendSpecific { err } => panic!("{}", err),
},
)
.unwrap()
};
stream.play().unwrap();
let m = mixer.lock().unwrap();
let channels = m.channels;
let sample_rate = m.sample_rate;
drop(m);
Ok(Self {
mixer,
channels,
sample_rate,
_stream: stream,
})
}
pub fn sample_rate(&self) -> u32 {
self.sample_rate
}
pub fn new_sound<T: SoundSource + Send + 'static>(
&self,
source: T,
) -> Result<Sound, &'static str> {
let sound: Box<dyn SoundSource + Send> = if source.sample_rate() != self.sample_rate {
if source.channels() == self.channels {
Box::new(SampleRateConverter::new(source, self.sample_rate))
} else if source.channels() == 1 {
Box::new(ChannelConverter::new(
SampleRateConverter::new(source, self.sample_rate),
self.channels,
))
} else {
return Err("Number of channels do not match the output, and is not 1");
}
} else if source.channels() == self.channels {
Box::new(source)
} else if source.channels() == 1 {
Box::new(ChannelConverter::new(source, self.channels))
} else {
return Err("Number of channels do not match the output, and is not 1");
};
let id = self.mixer.lock().unwrap().add_sound(sound);
Ok(Sound {
mixer: self.mixer.clone(),
id,
})
}
}