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
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
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};
#[derive(Debug)]
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
}
}
}
#[derive(Debug)]
pub struct SndFile {
ptr: *mut 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 {
Ok(SndFile {
ptr: sndfile_ptr,
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()
}
}
}