mixr/
system.rs

1use std::collections::HashMap;
2use std::collections::VecDeque;
3use crate::{AudioFormat, ChannelProperties};
4
5#[derive(Debug)]
6pub enum AudioErrorType {
7    InvalidBuffer,
8    InvalidChannel,
9    NoChannels
10}
11
12#[derive(Debug)]
13pub struct AudioError<'a> {
14    pub error_type: AudioErrorType,
15    pub description: &'a str
16}
17
18impl<'a> AudioError<'a> {
19    pub fn new(error_type: AudioErrorType) -> Self {
20        let description = match error_type {
21            AudioErrorType::InvalidBuffer => "An invalid buffer was provided.",
22            AudioErrorType::InvalidChannel => "An invalid channel was provided.",
23            AudioErrorType::NoChannels => "No available channels.",
24        };
25
26        Self {
27            error_type,
28            description
29        }
30    }
31}
32
33struct Buffer {
34    has_data: bool,
35
36    data: Vec<u8>,
37    format: AudioFormat,
38}
39
40struct Channel {
41    buffer: i32,
42    playing: bool,
43    chunk: u64,
44    position: f64,
45    sample_rate: i32,
46    speed: f64,
47
48    properties: ChannelProperties,
49    queued: VecDeque<i32>
50}
51
52pub struct AudioSystem {
53    pub format: AudioFormat,
54    
55    buffers: HashMap<i32, Buffer>,
56    channels: Vec<Channel>,
57    current_handle: i32,
58    current_sample: u8,
59
60    callback: Option<fn(u16, i32)>
61}
62
63impl AudioSystem {
64    pub fn new(format: Option<AudioFormat>, channels: u16) -> AudioSystem {
65        let i_fmt = if format.is_none() {
66            AudioFormat {
67                channels: 2,
68                sample_rate: 48000,
69                bits_per_sample: 16
70            }
71        } else { format.unwrap() };
72
73        let mut v_channels = Vec::with_capacity(channels as usize);
74        for _ in 0..channels {
75            v_channels.push(Channel {
76                buffer: -1,
77                playing: false,
78                chunk: 0,
79                position: 0.0,
80                sample_rate: 0,
81                speed: 0.0,
82                properties: ChannelProperties::default(),
83                queued: VecDeque::new()
84            });
85        }
86
87        AudioSystem { format: i_fmt, buffers: HashMap::new(), channels: v_channels, current_handle: 0, current_sample: 0, callback: None }
88    }
89
90    pub fn create_buffer(&mut self) -> i32 {
91        let buffer = Buffer { has_data: false, data: Vec::new(), format: AudioFormat { channels: 0, sample_rate: 0, bits_per_sample: 0 } };
92        self.buffers.insert(self.current_handle, buffer);
93        
94        let p_buffer = self.current_handle;
95        self.current_handle += 1;
96
97        p_buffer
98    }
99
100    pub fn delete_buffer(&mut self, buffer: i32) -> Result<(), AudioError> {
101        for channel in self.channels.iter_mut() {
102            if channel.buffer == buffer {
103                channel.playing = false;
104            }
105        }
106
107        self.buffers.remove(&buffer).ok_or(AudioError::new(AudioErrorType::InvalidBuffer))?;
108
109        Ok(())
110    }
111
112    pub fn update_buffer(&mut self, buffer: i32, data: &[u8], format: AudioFormat) -> Result<(), AudioError> {
113
114        let mut i_buffer = self.buffers.get_mut(&buffer).ok_or(AudioError::new(AudioErrorType::InvalidBuffer))?;
115
116        i_buffer.data = data.to_vec();
117        i_buffer.format = format;
118        i_buffer.has_data = true;
119
120        Ok(())
121    }
122
123    pub fn play_buffer(&mut self, buffer: i32, channel: u16, properties: ChannelProperties) -> Result<(), AudioError> {
124        let i_buffer = self.buffers.get(&buffer).ok_or(AudioError::new(AudioErrorType::InvalidBuffer))?;
125        let i_channel = self.channels.get_mut(channel as usize).ok_or(AudioError::new(AudioErrorType::InvalidChannel))?;
126
127        i_channel.queued.clear();
128
129        i_channel.chunk = 0;
130        i_channel.position = 0.0;
131        i_channel.properties = properties;
132        i_channel.sample_rate = i_buffer.format.sample_rate;
133        i_channel.speed = i_buffer.format.sample_rate as f64 / self.format.sample_rate as f64;
134        i_channel.speed *= i_channel.properties.speed;
135        i_channel.buffer = buffer;
136        i_channel.playing = true;
137
138        Ok(())
139    }
140
141    pub fn set_channel_properties(&mut self, channel: u16, properties: ChannelProperties) -> Result<(), AudioError> {
142        let mut channel = &mut self.channels.get_mut(channel as usize).ok_or(AudioError::new(AudioErrorType::InvalidChannel))?;
143        channel.properties = properties;
144        channel.speed = self.buffers.get(&channel.buffer).ok_or(AudioError::new(AudioErrorType::InvalidBuffer))?.format.sample_rate as f64 / self.format.sample_rate as f64;
145        channel.speed *= channel.properties.speed;
146
147        Ok(())
148    }
149
150    pub fn play(&mut self, channel: u16) -> Result<(), AudioError> {
151        let mut channel = &mut self.channels.get_mut(channel as usize).ok_or(AudioError::new(AudioErrorType::InvalidChannel))?;
152        channel.playing = true;
153
154        Ok(())
155    }
156
157    pub fn pause(&mut self, channel: u16) -> Result<(), AudioError> {
158        let mut channel = &mut self.channels.get_mut(channel as usize).ok_or(AudioError::new(AudioErrorType::InvalidChannel))?;
159        channel.playing = false;
160
161        Ok(())
162    }
163
164    pub fn stop(&mut self, channel: u16) -> Result<(), AudioError> {
165        let mut channel = &mut self.channels.get_mut(channel as usize).ok_or(AudioError::new(AudioErrorType::InvalidChannel))?;
166        channel.playing = false;
167        channel.position = 0.0;
168        channel.chunk = 0;
169        channel.queued.clear();
170
171        Ok(())
172    }
173
174    pub fn set_buffer_finished_callback(&mut self, callback: fn(u16, i32)) {
175        self.callback = Some(callback);
176    }
177
178    pub fn queue_buffer(&mut self, buffer: i32, channel: u16) -> Result<(), AudioError> {
179        let channel = &mut self.channels.get_mut(channel as usize).ok_or(AudioError::new(AudioErrorType::InvalidChannel))?;
180        if !self.buffers.contains_key(&buffer) { 
181            return Err(AudioError::new(AudioErrorType::InvalidBuffer));
182        }
183        channel.queued.push_back(buffer);
184
185        Ok(())
186    }
187
188    pub fn advance(&mut self) -> i16 {
189        let mut result: i32 = 0;
190
191        let mut current_channel = 0;
192        for channel in self.channels.iter_mut() {
193            if !channel.playing {
194                continue;
195            }
196
197            const CHUNK_SIZE: f64 = 48000.0;
198
199            let mut buffer = &self.buffers[&channel.buffer];
200            let format = &buffer.format;
201            let properties = &channel.properties;
202            let fmt_channels = format.channels;
203            let fmt_bps = format.bits_per_sample;
204            let mut data = &buffer.data;
205
206            let alignment = (fmt_bps / 8) as usize;
207
208            let pos_f64 = channel.position + channel.chunk as f64 * CHUNK_SIZE as f64;
209            let pos = pos_f64 as usize;
210
211            let mut get_pos = pos * alignment * fmt_channels as usize;
212            get_pos += self.current_sample as usize * alignment * (fmt_channels - 1) as usize;
213            get_pos -= get_pos % alignment;
214            
215            let next_pos = if channel.speed < 1.0 { pos + channel.properties.interpolation_type as usize } else { pos };
216
217            let mut get_next_pos = next_pos * alignment * fmt_channels as usize;
218            get_next_pos += self.current_sample as usize * alignment * (fmt_channels - 1) as usize;
219            get_next_pos -= get_next_pos % alignment;
220
221            if get_next_pos >= data.len() {
222                if properties.looping {
223                    channel.chunk = 0;
224                    let amount = channel.position - CHUNK_SIZE;
225                    channel.position = if amount > 0.0 { amount } else { 0.0 };
226                    if get_pos == get_next_pos {
227                        get_pos = 0;
228                    }
229
230                    get_next_pos = 0;
231
232                } else if channel.queued.len() > 0 {
233                    if let Some(cb) = self.callback {
234                        cb(current_channel, channel.buffer)
235                    };
236
237                    channel.buffer = channel.queued.pop_front().unwrap();
238                    buffer = &self.buffers[&channel.buffer];
239                    data = &buffer.data;
240
241                    channel.chunk = 0;
242                    let amount = channel.position - CHUNK_SIZE;
243                    channel.position = if amount > 0.0 { amount } else { 0.0 };
244
245                    if get_pos == get_next_pos {
246                        get_pos = 0;
247                    }
248
249                    get_next_pos = 0;
250                } else {
251                    if let Some(cb) = self.callback {
252                        cb(current_channel, channel.buffer)
253                    };
254                    channel.playing = false;
255                    channel.chunk = 0;
256                    channel.position = 0.0;
257                    continue;
258                }
259            }
260
261            if data.len() == 0 {
262                continue;
263            }
264
265            let pan = f64::clamp(if self.current_sample == 0 { (1.0 - channel.properties.panning) * 2.0 } else { 1.0 - ((0.5 - channel.properties.panning)) * 2.0 }, 0.0, 1.0);
266            
267            let mut value = Self::get_sample(data, get_pos, fmt_bps);
268            let value_next = Self::get_sample(data, get_next_pos, fmt_bps);
269
270            value = Self::lerp(value, value_next, pos_f64 - pos as f64);
271            value *= channel.properties.volume * pan;
272
273            result += value as i32;
274
275            if self.current_sample == 0 {
276                channel.position += channel.speed;   
277            }
278
279            if channel.position >= CHUNK_SIZE {
280                channel.chunk += 1;
281                channel.position = channel.position - CHUNK_SIZE;
282            }
283
284            current_channel += 1;
285        }
286
287        self.current_sample += 1;
288        self.current_sample = self.current_sample % 2;
289
290        let result = i32::clamp(result, i16::MIN as i32, i16::MAX as i32) as i16;
291
292        result
293    }
294
295    pub fn num_channels(&self) -> u16 {
296        self.channels.len() as u16
297    }
298
299    pub fn is_playing(&self, channel: u16) -> bool {
300        if let Some(channel) = self.channels.get(channel as usize) {
301            channel.playing
302        } else {
303            false
304        }
305    }
306
307    pub fn get_available_channel(&self) -> Result<u16, AudioError> {
308        for (i, channel) in self.channels.iter().enumerate() {
309            if !channel.playing {
310                return Ok(i as u16);
311            }
312        }
313
314        Err(AudioError::new(AudioErrorType::NoChannels))
315    }
316
317    #[inline(always)]
318    fn get_sample(data: &[u8], pos: usize, fmt_bps: u8) -> f64 {
319        match fmt_bps {
320            16 => (data[pos] as i16 | ((data[pos + 1] as i16) << 8) as i16) as f64,
321            8 => ((((data[pos] as i32) << 8) as i32) - i16::MAX as i32) as f64,
322            _ => panic!("Invalid bits per sample.")
323        }
324    }
325
326    #[inline(always)]
327    fn lerp(value: f64, next: f64, amount: f64) -> f64 {
328        amount * (next - value) + value
329    }
330}