devalang_core/core/audio/
player.rs

1use rodio::{Decoder, OutputStream, OutputStreamHandle, Sink, Source};
2use std::{fs::File, io::BufReader};
3
4pub struct AudioPlayer {
5    _stream: OutputStream,
6    handle: OutputStreamHandle,
7    sink: Sink,
8    last_path: Option<String>,
9}
10
11impl Default for AudioPlayer {
12    fn default() -> Self {
13        Self::new()
14    }
15}
16
17impl AudioPlayer {
18    pub fn new() -> Self {
19        let (stream, handle) = OutputStream::try_default().unwrap();
20        let sink = Sink::try_new(&handle).unwrap();
21
22        Self {
23            _stream: stream,
24            handle,
25            sink,
26            last_path: None,
27        }
28    }
29
30    fn load_source(&self, path: &str) -> Option<impl Source<Item = f32> + Send + 'static> {
31        if let Ok(file) = File::open(path) {
32            let reader = BufReader::new(file);
33            match Decoder::new(reader) {
34                Ok(decoder) => Some(decoder.convert_samples()),
35                Err(e) => {
36                    eprintln!("❌ Failed to decode audio file '{}': {}", path, e);
37                    None
38                }
39            }
40        } else {
41            eprintln!("❌ Could not open audio file: {}", path);
42            None
43        }
44    }
45
46    pub fn play_file_once(&mut self, path: &str) {
47        self.sink.stop();
48        self.sink = Sink::try_new(&self.handle).unwrap();
49        self.sink.set_volume(1.0);
50
51        if let Some(source) = self.load_source(path) {
52            self.sink.append(source);
53            self.last_path = Some(path.to_string());
54        } else {
55            eprintln!("⚠️ Skipping playback: failed to load '{}'", path);
56        }
57    }
58
59    pub fn replay_last(&mut self) {
60        if let Some(path) = self.last_path.clone() {
61            self.play_file_once(&path);
62        } else {
63            eprintln!("⚠️ No previous audio to replay.");
64        }
65    }
66
67    pub fn wait_until_end(&self) {
68        self.sink.sleep_until_end();
69    }
70}