Skip to main content

rustedbytes_bytepusher/
audio.rs

1use crate::memory::Memory;
2use crate::vm::{AUDIO_BUFFER_SIZE, AUDIO_SAMPLES_PER_SECOND};
3
4use rodio::{Sink, cpal::Sample, source::Source};
5use std::cell::RefCell;
6use std::rc::Rc;
7use std::time::Duration;
8
9/// Configurazione per l'audio
10#[derive(Clone)]
11pub struct AudioConfig {
12    pub sample_rate: u32,
13    pub channels: u16,
14}
15
16impl Default for AudioConfig {
17    fn default() -> Self {
18        Self {
19            sample_rate: AUDIO_SAMPLES_PER_SECOND, // 256 * 60
20            channels: 1,
21        }
22    }
23}
24
25pub struct AudioHandler {
26    config: AudioConfig,
27    memory_register_addr: usize,
28    memory: Rc<RefCell<Memory>>,
29    sink: Rc<RefCell<Sink>>,
30}
31
32impl AudioHandler {
33    pub fn new(
34        memory_register_addr: usize,
35        memory: Rc<RefCell<Memory>>,
36        sink: Rc<RefCell<Sink>>,
37    ) -> Self {
38        Self {
39            config: AudioConfig::default(),
40            memory,
41            memory_register_addr,
42            sink,
43        }
44    }
45
46    /// Recupera il buffer dalla memoria e lo aggiunge al sink se contiene dati non-zero
47    pub fn append_samples(&self) {
48        let buffer = self.get_sample_buffer();
49        if buffer.iter().any(|&sample| sample != 0) {
50            let source = SampleBufferSource::new(buffer, self.config.clone());
51            self.sink.borrow_mut().append(source);
52        }
53    }
54
55    pub fn get_sample_buffer(&self) -> [u8; AUDIO_BUFFER_SIZE] {
56        let mem = self.memory.borrow();
57        let audio_addr = (mem.read_16_bits(self.memory_register_addr) as usize) << 8;
58        let sample_buffer = &mem[audio_addr..audio_addr + AUDIO_BUFFER_SIZE];
59        let mut arr = [0u8; AUDIO_BUFFER_SIZE];
60        arr.copy_from_slice(sample_buffer);
61        arr
62    }
63}
64
65/// Sorgente audio per buffer a dimensione fissa
66pub struct SampleBufferSource<const N: usize> {
67    buffer: [u8; N],
68    index: usize,
69    config: AudioConfig,
70}
71
72impl<const N: usize> SampleBufferSource<N> {
73    pub fn new(buffer: [u8; N], config: AudioConfig) -> Self {
74        Self {
75            buffer,
76            index: 0,
77            config,
78        }
79    }
80
81    /// Converte un sample da u8 a i16 passando per i8
82    fn convert_sample(sample: u8) -> i16 {
83        (sample as i8).to_sample::<i16>()
84    }
85}
86
87impl<const N: usize> Source for SampleBufferSource<N> {
88    fn current_frame_len(&self) -> Option<usize> {
89        let remaining = self.buffer.len().saturating_sub(self.index);
90        if remaining == 0 {
91            None
92        } else {
93            Some(remaining)
94        }
95    }
96
97    fn channels(&self) -> u16 {
98        self.config.channels
99    }
100
101    fn sample_rate(&self) -> u32 {
102        self.config.sample_rate
103    }
104
105    fn total_duration(&self) -> Option<Duration> {
106        let samples = self.buffer.len() as u64;
107        let duration_nanos = (samples * 1_000_000_000) / (self.config.sample_rate as u64);
108        Some(Duration::from_nanos(duration_nanos))
109    }
110}
111
112impl<const N: usize> Iterator for SampleBufferSource<N> {
113    type Item = i16;
114
115    fn next(&mut self) -> Option<Self::Item> {
116        self.buffer.get(self.index).map(|&sample| {
117            self.index += 1;
118            Self::convert_sample(sample)
119        })
120    }
121}