#![feature(unique)]
extern crate libc;
mod bindgen;
use bindgen::{SF_INFO, SNDFILE, sf_count_t, sf_open, sf_readf_float, sf_close, sf_error, sf_error_number, sf_strerror, OpenMode, SfError};
use std::ffi::{CString, NulError, CStr};
use libc::{c_int, c_float};
use std::ptr::Unique;
#[derive(Debug, Clone, Copy)]
pub struct SndFileInfo {
pub frames: sf_count_t,
pub samplerate: c_int,
pub channels: c_int,
format: c_int,
sections: c_int,
seekable: c_int
}
impl From<SF_INFO> for SndFileInfo {
fn from(info: SF_INFO) -> Self {
SndFileInfo {
frames: info.frames,
samplerate: info.samplerate,
channels: info.channels,
format: info.format,
sections: info.sections,
seekable: info.seekable
}
}
}
pub struct SndFile {
ptr: Unique<SNDFILE>,
pub info: SndFileInfo
}
impl Drop for SndFile {
fn drop(&mut self) {
unsafe { sf_close(*self.ptr) };
}
}
impl SndFile {
pub fn open(path: &str) -> Result<Self, SndError> {
let cstr = try!(CString::new(path));
let mut sfi = SF_INFO {
frames: 0,
samplerate: 0,
channels: 0,
format: 0,
sections: 0,
seekable: 0
};
let sndfile_ptr: *mut SNDFILE;
unsafe {
sndfile_ptr = sf_open(cstr.as_ptr(), OpenMode::SFM_READ as c_int, &mut sfi);
}
if sndfile_ptr.is_null() {
Err(Self::get_error(sndfile_ptr))
}
else {
let unique: Unique<SNDFILE>;
unsafe {
unique = Unique::new(sndfile_ptr);
}
Ok(SndFile {
ptr: unique,
info: SndFileInfo::from(sfi)
})
}
}
fn get_error(sf: *mut SNDFILE) -> SndError {
let strptr: &CStr;
let mut errno: c_int;
unsafe {
errno = sf_error(sf);
if errno >= SfError::SF_ERR_UNLISTED as c_int {
strptr = CStr::from_ptr(sf_error_number(errno));
errno = SfError::SF_ERR_UNLISTED as c_int;
}
else {
strptr = CStr::from_ptr(sf_strerror(sf));
}
}
let expl = strptr.to_string_lossy().into_owned();
SndError {
err: errno,
expl: expl
}
}
pub fn into_slice_float(&mut self, buf: &mut [c_float], frames: usize) -> Result<usize, SndError> {
let units_reqd = self.info.channels as usize * frames;
if buf.len() < units_reqd {
return Err(SndError {
err: SfError::SF_ERR_UNLISTED as c_int,
expl: "Binding: Buffer provided not big enough".to_string()
});
}
let mut written: sf_count_t = 0;
let ptr = buf.as_mut_ptr();
unsafe {
written = sf_readf_float(*self.ptr, ptr, frames as i64);
}
assert!(written >= 0);
assert!((written as usize) < ::std::usize::MAX);
Ok(written as usize)
}
}
#[derive(Debug)]
pub struct SndError {
err: c_int,
pub expl: String
}
impl From<NulError> for SndError {
fn from(_: NulError) -> SndError {
SndError {
err: SfError::SF_ERR_UNLISTED as c_int,
expl: "Binding: Encountered a NUL byte in path argument".to_string()
}
}
}