rodio_xm/
lib.rs

1use std::fs;
2use std::path::PathBuf;
3use std::time::Duration;
4
5use libxm::*;
6use rodio::Source;
7
8pub const BUFFER_SIZE: usize = 2048;
9
10pub struct XMSource {
11    xm_context: XMContext,
12    buffer: [f32; BUFFER_SIZE],
13    buffer_index: usize,
14    sample_rate: u32,
15}
16
17impl XMSource {
18    pub fn new(xm_context: XMContext, sample_rate: u32) -> Self {
19        XMSource {
20            xm_context,
21            buffer: [0.0; BUFFER_SIZE],
22            buffer_index: 0,
23            sample_rate
24        }
25    }
26
27    pub fn from_bytes(bytes: &[u8], sample_rate: u32) -> Self {
28        let xm = libxm::XMContext::new(bytes, sample_rate)
29            .expect("failed to parse xm");
30
31        XMSource::new(xm, sample_rate)
32    }
33
34    pub fn from_file(path: PathBuf, sample_rate: u32) -> Self {
35        let file = fs::read(path).expect("couldn't read file");
36        let xm = libxm::XMContext::new(&file, sample_rate)
37            .expect("failed to parse xm");
38
39        XMSource::new(xm, sample_rate)
40    }
41}
42
43impl Source for XMSource {
44    fn current_frame_len(&self) -> Option<usize> {
45        Some(BUFFER_SIZE - self.buffer_index)
46    }
47
48    fn channels(&self) -> u16 { 2 }
49
50    fn sample_rate(&self) -> u32 { self.sample_rate }
51
52    fn total_duration(&self) -> Option<Duration> { None }
53}
54
55impl Iterator for XMSource {
56    type Item = f32;
57
58    fn next(&mut self) -> Option<Self::Item> {
59        self.buffer_index += 1;
60
61        if self.buffer_index >= BUFFER_SIZE {
62            self.xm_context.generate_samples(&mut self.buffer);
63            self.buffer_index = 0;
64        }
65
66        Some(self.buffer[self.buffer_index])
67    }
68}