1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
extern crate openmpt_sys;
extern crate sfml;

use crate::string::OpenMptString;
use openmpt_sys::*;
use sfml::audio::SoundStream;
use sfml::system::Time;
use std::fs::File;
use std::io;
use std::io::prelude::*;
use std::path::Path;
use std::ptr;

mod string;

pub struct ModStream {
    module: *mut openmpt_module,
    buffer: [i16; 2048],
}

impl ModStream {
    pub fn from_file<P: AsRef<Path>>(path: P) -> Result<Self, io::Error> {
        let mut file = File::open(path)?;
        let mut buf = Vec::new();
        file.read_to_end(&mut buf)?;
        Ok(Self::from_memory(&buf))
    }
    pub fn from_memory(data: &[u8]) -> Self {
        unsafe {
            let module = openmpt_module_create_from_memory(
                data.as_ptr() as *const _,
                data.len(),
                None,
                ptr::null_mut(),
                ptr::null(),
            );
            if module.is_null() {
                panic!("Failed load module");
            }
            Self {
                module,
                buffer: [0; 2048],
            }
        }
    }
    pub fn get_duration_seconds(&self) -> f64 {
        unsafe { openmpt_module_get_duration_seconds(self.module) }
    }
    pub fn metadata<'a, K: Key<'a>>(&self, key: K) -> Option<OpenMptString> {
        let key = std::ffi::CString::new(key.into_str()).unwrap();
        let ret = unsafe { openmpt_module_get_metadata(self.module, key.as_ptr()) };
        OpenMptString::new(ret)
    }
}

pub trait Key<'a> {
    fn into_str(self) -> &'a str;
}

impl<'a> Key<'a> for &'a str {
    fn into_str(self) -> &'a str {
        self
    }
}

pub enum Metadata {
    Tracker,
    Artist,
    Title,
    Date,
    Message,
}

impl Key<'static> for Metadata {
    fn into_str(self) -> &'static str {
        match self {
            Self::Tracker => "tracker",
            Self::Artist => "artist",
            Self::Title => "title",
            Self::Date => "date",
            Self::Message => "message",
        }
    }
}

impl SoundStream for ModStream {
    fn get_data(&mut self) -> (&mut [i16], bool) {
        unsafe {
            let keep_playing = openmpt_module_read_interleaved_stereo(
                self.module,
                44_100,
                1024,
                self.buffer.as_mut_ptr(),
            ) != 0;
            (&mut self.buffer[..], keep_playing)
        }
    }
    fn seek(&mut self, offset: Time) {
        unsafe {
            openmpt_module_set_position_seconds(self.module, f64::from(offset.as_seconds()));
        }
    }
    fn sample_rate(&self) -> u32 {
        44_100
    }
    fn channel_count(&self) -> u32 {
        2
    }
}

impl Drop for ModStream {
    fn drop(&mut self) {
        unsafe {
            openmpt_module_destroy(self.module);
        }
    }
}