1use std;
2use std::sync::mpsc::{channel, Receiver, Sender};
3
4use super::{SoundError, SoundGenerator};
5use cpal::traits::{DeviceTrait, HostTrait, StreamTrait};
6use cpal::{self, Device, Sample, SampleFormat, Stream};
7use uni_app::App;
8
9pub struct SoundDriver<T: Send + 'static> {
11 config: Option<cpal::StreamConfig>,
12 tx: Option<Sender<T>>,
13 generator: Option<Box<dyn SoundGenerator<T>>>,
14 device: Option<Device>,
15 format: Option<SampleFormat>,
16 stream: Option<Stream>,
17 err: SoundError,
18 event_buffer: Vec<T>,
20}
21
22impl<T: Send + 'static> SoundDriver<T> {
23 pub fn get_error(&self) -> SoundError {
25 self.err
26 }
27
28 pub fn new(generator: Box<dyn SoundGenerator<T>>) -> Self {
30 let host = cpal::default_host();
31 let mut stream_config = None;
32 let mut err = SoundError::NoError;
33 let mut device = None;
34 let mut format = None;
35 if let Some(dev) = host.default_output_device() {
36 match dev.default_output_config() {
37 Ok(config) => {
38 App::print(format!(
39 "sound device : {} {:?}\n",
40 dev.name().unwrap_or_else(|_| "?".to_owned()),
41 config
42 ));
43 format = Some(config.sample_format());
44 stream_config = Some(config.into());
45 device = Some(dev);
46 }
47 Err(e) => {
48 err = SoundError::UnknownStreamFormat;
49 App::print(format!(
50 "error : uni-snd - could not get default output configuration : {:?}\n",
51 e
52 ));
53 }
54 }
55 } else {
56 err = SoundError::NoDevice;
57 App::print("warning : no sound device detected\n");
58 }
59 Self {
60 config: stream_config,
61 tx: None,
62 device,
63 format,
64 stream: None,
65 generator: Some(generator),
66 err,
67 event_buffer: Vec::new(),
68 }
69 }
70 pub fn send_event(&mut self, event: T) {
72 if let Some(ref mut tx) = self.tx {
73 tx.send(event).unwrap();
74 } else {
75 self.event_buffer.push(event);
76 }
77 }
78 fn get_sample_rate(&self) -> f32 {
79 if let Some(ref config) = self.config {
80 config.sample_rate.0 as f32
81 } else {
82 1.0
83 }
84 }
85 pub fn start(&mut self) {
88 if self.config.is_none() || self.device.is_none() || self.generator.is_none() {
89 App::print("no sound");
90 return;
91 }
92 let (tx, rx) = channel();
93 self.tx = Some(tx);
94 let sample_rate = self.get_sample_rate();
95 let config = self.config.take().unwrap();
96 let device = self.device.take().unwrap();
97 let mut generator = self.generator.take().unwrap();
98 generator.init(sample_rate);
99
100 for event in self.event_buffer.drain(0..) {
102 generator.handle_event(event);
103 }
104
105 let stream_res = match self.format {
106 Some(SampleFormat::F32) => build_stream::<f32, T>(&device, &config, generator, rx),
107 Some(SampleFormat::I16) => build_stream::<i16, T>(&device, &config, generator, rx),
108 Some(SampleFormat::U16) => build_stream::<u16, T>(&device, &config, generator, rx),
109 None => Err(String::new()),
110 };
111 match stream_res {
112 Ok(str) => {
113 App::print("starting audio loop\n");
114 str.play().unwrap_or_else(|e| {
115 App::print(format!("error : uni-snd - could not start play {}", e));
116 });
117 self.stream = Some(str);
118 }
119 Err(e) => {
120 self.err = SoundError::OutputStream;
121 App::print(format!(
122 "error : uni-snd - could not build output stream : {}\n",
123 e
124 ))
125 }
126 }
127 }
128}
129
130fn build_stream<S, T: Send + 'static>(
131 device: &cpal::Device,
132 config: &cpal::StreamConfig,
133 mut generator: Box<dyn SoundGenerator<T>>,
134 rx: Receiver<T>,
135) -> Result<Stream, String>
136where
137 S: cpal::Sample,
138{
139 let channels = config.channels as usize;
140 let err_fn = |err| {
141 App::print(&format!(
142 "error : uni-snd - an error occurred on stream: {}",
143 err
144 ))
145 };
146 device
147 .build_output_stream(
148 config,
149 move |data: &mut [S], _: &cpal::OutputCallbackInfo| {
150 for event in rx.try_iter() {
151 generator.handle_event(event);
152 }
153 write_data(data, channels, &mut generator);
154 },
155 err_fn,
156 )
157 .map_err(|e| format!("error : uni-snd - could not build output stream {}", e))
158}
159
160fn write_data<S, T: Send + 'static>(
161 output: &mut [S],
162 channels: usize,
163 generator: &mut Box<dyn SoundGenerator<T>>,
164) where
165 S: Sample,
166{
167 for frame in output.chunks_mut(channels) {
168 for sample in frame.iter_mut() {
169 let val = generator.next_value();
170 *sample = Sample::from::<f32>(&val);
171 }
172 }
173}