1#![allow(dead_code)]
4
5#[cfg(target_os = "windows")]
13mod dsound;
14
15#[cfg(target_os = "linux")]
16mod alsa;
17
18#[cfg(target_os = "macos")]
19mod coreaudio;
20
21#[cfg(not(any(
23 target_os = "windows",
24 target_os = "linux",
25 target_os = "macos",
26 target_arch = "wasm32"
27)))]
28mod dummy;
29
30#[cfg(target_arch = "wasm32")]
31mod web;
32
33#[repr(C)]
34#[derive(Debug, Copy, Clone, Default)]
35pub struct NativeSample {
36 pub left: i16,
37 pub right: i16,
38}
39
40pub type FeedCallback = dyn FnMut(&mut [(f32, f32)]) + Send;
41
42pub struct MixContext<'a> {
43 mix_buffer: &'a mut [(f32, f32)],
44 out_data: &'a mut [NativeSample],
45 callback: &'a mut FeedCallback,
46}
47
48trait Device {
49 fn get_mix_context(&mut self) -> Option<MixContext>;
50
51 fn run(&mut self);
52
53 fn mix(&mut self) {
54 if let Some(context) = self.get_mix_context() {
55 for (left, right) in context.mix_buffer.iter_mut() {
57 *left = 0.0;
58 *right = 0.0;
59 }
60
61 (context.callback)(context.mix_buffer);
63
64 assert_eq!(context.mix_buffer.len(), context.out_data.len());
66 for ((left, right), ref mut out_sample) in
67 context.mix_buffer.iter().zip(context.out_data)
68 {
69 fn sample_to_i16(sample: f32) -> i16 {
70 const SCALE: f32 = i16::MAX as f32;
71 let clamped = if sample > 1.0 {
72 1.0
73 } else if sample < -1.0 {
74 -1.0
75 } else {
76 sample
77 };
78 (clamped * SCALE) as i16
79 }
80
81 out_sample.left = sample_to_i16(*left);
82 out_sample.right = sample_to_i16(*right);
83 }
84 }
85 }
86}
87
88pub(in crate) fn run_device<F: FnMut(&mut [(f32, f32)]) + Send + 'static>(
91 #[allow(unused_variables)] buffer_len_bytes: u32,
92 #[allow(unused_variables)] callback: F,
93) {
94 #[cfg(not(target_arch = "wasm32"))]
95 {
96 std::thread::spawn(move || {
97 #[cfg(target_os = "windows")]
98 let mut device = dsound::DirectSoundDevice::new(buffer_len_bytes, callback).unwrap();
99 #[cfg(target_os = "linux")]
100 let mut device = alsa::AlsaSoundDevice::new(buffer_len_bytes, callback).unwrap();
101 #[cfg(target_os = "macos")]
102 let mut device =
103 coreaudio::CoreaudioSoundDevice::new(buffer_len_bytes, callback).unwrap();
104 #[cfg(not(any(target_os = "windows", target_os = "linux", target_os = "macos")))]
105 let mut device = dummy::DummySoundDevice::new(buffer_len_bytes, callback).unwrap();
106 device.run()
107 });
108 }
109
110 #[cfg(target_arch = "wasm32")]
111 {
112 let mut device = web::WebAudioDevice::new(buffer_len_bytes, callback);
113 device.run();
114 std::mem::forget(device);
115 }
116}