1#![allow(dead_code)]
17
18use alloc::{string::String, vec::Vec};
19use core::sync::atomic::{AtomicBool, AtomicU32, Ordering};
20
21use crate::error::KernelError;
22
23pub type FixedPoint = i32;
29
30const FP_SHIFT: i32 = 16;
32
33const FP_ONE: FixedPoint = 1 << FP_SHIFT;
35
36const FP_MAX: FixedPoint = i32::MAX;
38
39const FP_MIN: FixedPoint = i32::MIN;
41
42#[inline]
47pub fn fp_from_i16(sample: i16) -> FixedPoint {
48 (sample as i32) << FP_SHIFT
49}
50
51#[inline]
55pub fn fp_to_i16(fp: FixedPoint) -> i16 {
56 let shifted = fp >> FP_SHIFT;
57 if shifted > i16::MAX as i32 {
58 i16::MAX
59 } else if shifted < i16::MIN as i32 {
60 i16::MIN
61 } else {
62 shifted as i16
63 }
64}
65
66#[inline]
70pub fn fp_mul(a: FixedPoint, b: FixedPoint) -> FixedPoint {
71 let result = (a as i64 * b as i64) >> FP_SHIFT;
72 if result > FP_MAX as i64 {
73 FP_MAX
74 } else if result < FP_MIN as i64 {
75 FP_MIN
76 } else {
77 result as i32
78 }
79}
80
81#[inline]
85pub fn fp_from_volume(volume: u16) -> FixedPoint {
86 volume as i32
87}
88
89#[inline]
91fn fp_add_saturate(a: FixedPoint, b: FixedPoint) -> FixedPoint {
92 let result = (a as i64) + (b as i64);
93 if result > FP_MAX as i64 {
94 FP_MAX
95 } else if result < FP_MIN as i64 {
96 FP_MIN
97 } else {
98 result as i32
99 }
100}
101
102pub struct MixerChannel {
108 pub id: u16,
110 volume: AtomicU32,
112 muted: AtomicBool,
114 buffer_index: u32,
116 pub name: String,
118 samples: Vec<i16>,
120}
121
122impl MixerChannel {
123 fn new(id: u16, name: String) -> Self {
125 Self {
126 id,
127 volume: AtomicU32::new(65535), muted: AtomicBool::new(false),
129 buffer_index: 0,
130 name,
131 samples: Vec::new(),
132 }
133 }
134
135 pub fn get_volume(&self) -> u16 {
137 self.volume.load(Ordering::Relaxed) as u16
138 }
139
140 pub fn set_volume(&self, vol: u16) {
142 self.volume.store(vol as u32, Ordering::Relaxed);
143 }
144
145 pub fn is_muted(&self) -> bool {
147 self.muted.load(Ordering::Relaxed)
148 }
149
150 pub fn set_muted(&self, muted: bool) {
152 self.muted.store(muted, Ordering::Relaxed);
153 }
154
155 pub fn write_samples(&mut self, data: &[i16]) {
157 self.samples.clear();
158 self.samples.extend_from_slice(data);
159 self.buffer_index = 0;
160 }
161
162 fn read_samples(&mut self, count: usize) -> &[i16] {
164 let start = self.buffer_index as usize;
165 let available = self.samples.len().saturating_sub(start);
166 let to_read = count.min(available);
167 let end = start + to_read;
168 self.buffer_index = end as u32;
169 &self.samples[start..end]
170 }
171
172 fn available_samples(&self) -> usize {
174 self.samples
175 .len()
176 .saturating_sub(self.buffer_index as usize)
177 }
178}
179
180pub struct AudioMixer {
186 channels: Vec<MixerChannel>,
188 master_volume: AtomicU32,
190 output_buffer: Vec<i16>,
192 sample_rate: u32,
194 output_channels: u8,
196 next_channel_id: u16,
198}
199
200impl AudioMixer {
201 pub fn new(sample_rate: u32, channels: u8) -> Self {
207 Self {
208 channels: Vec::new(),
209 master_volume: AtomicU32::new(65535),
210 output_buffer: Vec::new(),
211 sample_rate,
212 output_channels: channels,
213 next_channel_id: 1,
214 }
215 }
216
217 pub fn add_channel(&mut self, name: &str) -> u16 {
219 let id = self.next_channel_id;
220 self.next_channel_id = self.next_channel_id.wrapping_add(1);
221 let channel = MixerChannel::new(id, String::from(name));
222 self.channels.push(channel);
223 println!("[AUDIO] Mixer: added channel {} (id={})", name, id);
224 id
225 }
226
227 pub fn remove_channel(&mut self, id: u16) {
229 if let Some(pos) = self.channels.iter().position(|c| c.id == id) {
230 let name = self.channels[pos].name.clone();
231 self.channels.remove(pos);
232 println!("[AUDIO] Mixer: removed channel {} (id={})", name, id);
233 }
234 }
235
236 pub fn set_volume(&self, channel_id: u16, volume: u16) {
238 if let Some(ch) = self.channels.iter().find(|c| c.id == channel_id) {
239 ch.set_volume(volume);
240 }
241 }
242
243 pub fn set_master_volume(&self, volume: u16) {
245 self.master_volume.store(volume as u32, Ordering::Relaxed);
246 }
247
248 pub fn get_master_volume(&self) -> u16 {
250 self.master_volume.load(Ordering::Relaxed) as u16
251 }
252
253 pub fn mix_to_output(&mut self, output: &mut [i16]) {
259 let master_vol = fp_from_volume(self.get_master_volume());
260 let num_samples = output.len();
261
262 for sample in output.iter_mut() {
264 *sample = 0;
265 }
266
267 if self.channels.is_empty() || master_vol == 0 {
269 return;
270 }
271
272 for channel in self.channels.iter_mut() {
274 if channel.is_muted() {
275 continue;
276 }
277
278 let ch_vol = fp_from_volume(channel.get_volume());
279 if ch_vol == 0 {
280 continue;
281 }
282
283 let samples = channel.read_samples(num_samples);
284 for (i, &sample) in samples.iter().enumerate() {
285 if i >= num_samples {
286 break;
287 }
288
289 let fp_sample = fp_from_i16(sample);
291
292 let scaled = fp_mul(fp_sample, ch_vol);
294
295 let mastered = fp_mul(scaled, master_vol);
297
298 let existing = fp_from_i16(output[i]);
300 let mixed = fp_add_saturate(existing, mastered);
301 output[i] = fp_to_i16(mixed);
302 }
303 }
304 }
305
306 pub fn channel_count(&self) -> usize {
308 self.channels.len()
309 }
310
311 pub fn get_channel_mut(&mut self, id: u16) -> Option<&mut MixerChannel> {
313 self.channels.iter_mut().find(|c| c.id == id)
314 }
315
316 pub fn write_channel_samples(&mut self, channel_id: u16, samples: &[i16]) {
318 if let Some(ch) = self.channels.iter_mut().find(|c| c.id == channel_id) {
319 ch.write_samples(samples);
320 }
321 }
322}
323
324static MIXER: spin::Mutex<Option<AudioMixer>> = spin::Mutex::new(None);
329
330pub fn init(sample_rate: u32) -> Result<(), KernelError> {
332 let mut mixer = MIXER.lock();
333 if mixer.is_some() {
334 return Err(KernelError::InvalidState {
335 expected: "uninitialized",
336 actual: "already initialized",
337 });
338 }
339
340 *mixer = Some(AudioMixer::new(sample_rate, 2));
341 println!("[AUDIO] Mixer initialized at {} Hz, stereo", sample_rate);
342 Ok(())
343}
344
345pub fn with_mixer<R, F: FnOnce(&mut AudioMixer) -> R>(f: F) -> Result<R, KernelError> {
347 let mut guard = MIXER.lock();
348 match guard.as_mut() {
349 Some(mixer) => Ok(f(mixer)),
350 None => Err(KernelError::NotInitialized {
351 subsystem: "audio mixer",
352 }),
353 }
354}
355
356#[cfg(test)]
361mod tests {
362 use super::*;
363
364 #[test]
365 fn test_fp_from_i16() {
366 assert_eq!(fp_from_i16(0), 0);
367 assert_eq!(fp_from_i16(1), FP_ONE);
368 assert_eq!(fp_from_i16(-1), -FP_ONE);
369 assert_eq!(fp_from_i16(i16::MAX), (i16::MAX as i32) << FP_SHIFT);
370 }
371
372 #[test]
373 fn test_fp_to_i16_roundtrip() {
374 for val in [0i16, 1, -1, 100, -100, i16::MAX, i16::MIN] {
375 assert_eq!(fp_to_i16(fp_from_i16(val)), val);
376 }
377 }
378
379 #[test]
380 fn test_fp_to_i16_saturation() {
381 assert_eq!(fp_to_i16(i32::MAX), i16::MAX);
383 assert_eq!(fp_to_i16(i32::MIN), i16::MIN);
385 }
386
387 #[test]
388 fn test_fp_mul_basic() {
389 assert_eq!(fp_mul(FP_ONE, FP_ONE), FP_ONE);
391 assert_eq!(fp_mul(FP_ONE, 0), 0);
393 let two = 2 << FP_SHIFT;
395 let half = FP_ONE / 2;
396 assert_eq!(fp_mul(two, half), FP_ONE);
397 }
398
399 #[test]
400 fn test_fp_mul_saturation() {
401 let large = i32::MAX;
403 let result = fp_mul(large, large);
404 assert_eq!(result, FP_MAX);
405 }
406
407 #[test]
408 fn test_fp_from_volume() {
409 assert_eq!(fp_from_volume(0), 0);
410 assert_eq!(fp_from_volume(65535), 65535);
411 assert_eq!(fp_from_volume(32768), 32768);
412 }
413
414 #[test]
415 fn test_mixer_add_remove_channel() {
416 let mut mixer = AudioMixer::new(48000, 2);
417 assert_eq!(mixer.channel_count(), 0);
418
419 let id1 = mixer.add_channel("test1");
420 assert_eq!(mixer.channel_count(), 1);
421
422 let id2 = mixer.add_channel("test2");
423 assert_eq!(mixer.channel_count(), 2);
424
425 mixer.remove_channel(id1);
426 assert_eq!(mixer.channel_count(), 1);
427
428 mixer.remove_channel(id2);
429 assert_eq!(mixer.channel_count(), 0);
430 }
431
432 #[test]
433 fn test_mixer_volume_scaling() {
434 let mut mixer = AudioMixer::new(48000, 1);
435 let ch_id = mixer.add_channel("test");
436
437 let input = [16384i16; 4]; mixer.write_channel_samples(ch_id, &input);
440
441 let mut output = [0i16; 4];
443 mixer.mix_to_output(&mut output);
444
445 for &sample in &output {
448 assert!(
449 sample > 16000 && sample < 16500,
450 "Expected ~16384, got {}",
451 sample
452 );
453 }
454 }
455
456 #[test]
457 fn test_mixer_two_channels() {
458 let mut mixer = AudioMixer::new(48000, 1);
459 let ch1 = mixer.add_channel("ch1");
460 let ch2 = mixer.add_channel("ch2");
461
462 let samples1 = [8000i16; 4];
464 let samples2 = [8000i16; 4];
465 mixer.write_channel_samples(ch1, &samples1);
466 mixer.write_channel_samples(ch2, &samples2);
467
468 let mut output = [0i16; 4];
469 mixer.mix_to_output(&mut output);
470
471 for &sample in &output {
473 assert!(sample > 14000, "Expected combined ~16000, got {}", sample);
474 }
475 }
476
477 #[test]
478 fn test_mixer_muted_channel() {
479 let mut mixer = AudioMixer::new(48000, 1);
480 let ch_id = mixer.add_channel("muted");
481
482 let input = [16384i16; 4];
483 mixer.write_channel_samples(ch_id, &input);
484
485 if let Some(ch) = mixer.get_channel_mut(ch_id) {
487 ch.set_muted(true);
488 }
489
490 let mut output = [0i16; 4];
491 mixer.mix_to_output(&mut output);
492
493 for &sample in &output {
495 assert_eq!(sample, 0);
496 }
497 }
498
499 #[test]
500 fn test_mixer_saturation() {
501 let mut mixer = AudioMixer::new(48000, 1);
502 let ch1 = mixer.add_channel("ch1");
503 let ch2 = mixer.add_channel("ch2");
504
505 let max_samples = [i16::MAX; 4];
507 mixer.write_channel_samples(ch1, &max_samples);
508 mixer.write_channel_samples(ch2, &max_samples);
509
510 let mut output = [0i16; 4];
511 mixer.mix_to_output(&mut output);
512
513 for &sample in &output {
515 assert!(sample > 0, "Saturation failed: got {}", sample);
516 }
517 }
518}