pub mod ffi;
use std::mem;
#[derive(Copy, Clone, Debug)]
pub enum XMError {
Unknown(ffi::c_int),
ModuleDataNotSane,
MemoryAllocationFailed
}
#[derive(Copy, Clone)]
pub struct PlayingSpeed {
pub bpm: u16,
pub tempo: u16
}
#[derive(Copy, Clone)]
pub struct Position {
pub pattern_index: u8,
pub pattern: u8,
pub row: u8,
pub samples: u64
}
pub struct XMContext {
raw: *mut ffi::xm_context_t
}
unsafe impl Send for XMContext {}
unsafe impl Sync for XMContext {}
impl XMContext {
pub fn new(mod_data: &[u8], rate: u32) -> Result<XMContext, XMError> {
unsafe {
let mut raw: *mut ffi::xm_context = std::ptr::null_mut();
let mod_data_ptr = mem::transmute(mod_data.as_ptr());
let mod_data_len = mod_data.len() as ffi::size_t;
let result = ffi::xm_create_context_safe(&mut raw, mod_data_ptr, mod_data_len, rate);
match result {
0 => Ok(XMContext {
raw: raw
}),
1 => Err(XMError::ModuleDataNotSane),
2 => Err(XMError::MemoryAllocationFailed),
_ => Err(XMError::Unknown(result))
}
}
}
#[inline]
pub fn generate_samples(&mut self, output: &mut [f32]) {
unsafe {
assert!(output.len() % 2 == 0);
let output_len = (output.len() / 2) as ffi::size_t;
ffi::xm_generate_samples(self.raw, output.as_mut_ptr(), output_len);
}
}
#[inline]
pub fn set_max_loop_count(&mut self, loopcnt: u8) {
unsafe { ffi::xm_set_max_loop_count(self.raw, loopcnt); }
}
#[inline]
pub fn loop_count(&self) -> u8 {
unsafe { ffi::xm_get_loop_count(self.raw) }
}
#[inline]
pub fn module_name(&self) -> Option<&[u8]> {
unsafe {
let name = ffi::xm_get_module_name(self.raw);
if name.is_null() {
None
} else {
Some(std::ffi::CStr::from_ptr(name).to_bytes())
}
}
}
#[inline]
pub fn tracker_name(&self) -> Option<&[u8]> {
unsafe {
let name = ffi::xm_get_tracker_name(self.raw);
if name.is_null() {
None
} else {
Some(std::ffi::CStr::from_ptr(name).to_bytes())
}
}
}
#[inline]
pub fn number_of_channels(&self) -> u16 {
unsafe { ffi::xm_get_number_of_channels(self.raw) }
}
#[inline]
pub fn module_length(&self) -> u16 {
unsafe { ffi::xm_get_module_length(self.raw) }
}
#[inline]
pub fn number_of_patterns(&self) -> u16 {
unsafe { ffi::xm_get_number_of_patterns(self.raw) }
}
#[inline]
pub fn number_of_rows(&self, pattern: u16) -> u16 {
assert!(pattern < self.number_of_patterns());
unsafe { ffi::xm_get_number_of_rows(self.raw, pattern) }
}
#[inline]
pub fn number_of_instruments(&self) -> u16 {
unsafe { ffi::xm_get_number_of_instruments(self.raw) }
}
#[inline]
pub fn number_of_samples(&self, instrument: u16) -> u16 {
assert!(instrument >= 1);
assert!(instrument <= self.number_of_instruments());
unsafe { ffi::xm_get_number_of_samples(self.raw, instrument) }
}
#[inline]
pub fn playing_speed(&self) -> PlayingSpeed {
let (mut bpm, mut tempo) = (0, 0);
unsafe { ffi::xm_get_playing_speed(self.raw, &mut bpm, &mut tempo) };
PlayingSpeed {
bpm: bpm,
tempo: tempo
}
}
#[inline]
pub fn position(&self) -> Position {
let (mut pattern_index, mut pattern, mut row) = (0, 0, 0);
let mut samples = 0;
unsafe { ffi::xm_get_position(self.raw, &mut pattern_index, &mut pattern, &mut row, &mut samples) };
Position {
pattern_index: pattern_index,
pattern: pattern,
row: row,
samples: samples
}
}
#[inline]
pub fn latest_trigger_of_instrument(&self, instrument: u16) -> u64 {
assert!(instrument >= 1);
assert!(instrument <= self.number_of_instruments());
unsafe { ffi::xm_get_latest_trigger_of_instrument(self.raw, instrument) }
}
#[inline]
pub fn latest_trigger_of_sample(&self, instrument: u16, sample: u16) -> u64 {
assert!(instrument >= 1);
assert!(instrument <= self.number_of_instruments());
assert!(sample < self.number_of_samples(instrument));
unsafe { ffi::xm_get_latest_trigger_of_sample(self.raw, instrument, sample) }
}
#[inline]
pub fn latest_trigger_of_channel(&self, channel: u16) -> u64 {
assert!(channel >= 1);
assert!(channel <= self.number_of_channels());
unsafe { ffi::xm_get_latest_trigger_of_channel(self.raw, channel) }
}
}
impl Drop for XMContext {
fn drop(&mut self) {
unsafe {
ffi::xm_free_context(self.raw);
}
}
}