1extern crate tsf_sys;
2
3use tsf_sys::*;
4use std::ffi::{CString, c_void};
5use std::os::raw::c_int;
6
7pub struct Tsf {
33 tsf_ptr: *mut tsf_sys::tsf,
35 output_mode: Option<OutputMode>
38}
39
40unsafe impl Send for Tsf {}
41unsafe impl Sync for Tsf {}
42
43impl Drop for Tsf {
44 fn drop(&mut self) {
45 unsafe { tsf_close(self.tsf_ptr) };
46 }
47}
48
49impl Tsf {
50 fn new(tsf_ptr: *mut tsf) -> Self {
51 Tsf {
52 tsf_ptr,
53 output_mode : None
54 }
55 }
56
57 pub fn load_filename<T: Into<Vec<u8>>>(filename: T) -> Option<Tsf> {
61 let filename_cstring = CString::new(filename).expect("filename wasn't a valid C string - did it have an internal 0 byte?");
62 let tsf_ptr: *mut tsf = unsafe { tsf_load_filename(filename_cstring.as_ptr()) };
63 if tsf_ptr.is_null() { None } else { Some(Tsf::new(tsf_ptr)) }
64 }
65
66 pub fn load_memory<T: Into<Vec<u8>>>(buffer: T) -> Option<Tsf> {
68 let vec = buffer.into();
69 let tsf_ptr: *mut tsf = unsafe {
70 tsf_load_memory(vec.as_ptr() as *const c_void, vec.len() as c_int)
71 };
72 if tsf_ptr.is_null() { None } else { Some(Tsf::new(tsf_ptr)) }
73 }
74
75 pub fn close(self) {
77 }
80
81 pub fn set_output(&mut self, mode: OutputMode, sample_rate: u16, global_gain_db: f32) {
86 let converted_mode = match mode {
87 OutputMode::StereoInterleaved => TSFOutputMode_TSF_STEREO_INTERLEAVED,
88 OutputMode::StereoUnweaved => TSFOutputMode_TSF_STEREO_UNWEAVED,
89 OutputMode::Mono => TSFOutputMode_TSF_MONO,
90 };
91 unsafe { tsf_set_output(self.tsf_ptr, converted_mode, sample_rate as c_int, global_gain_db) };
92
93 self.output_mode = Some(mode);
95 }
96
97 pub fn render_float(&mut self, samples: usize) -> Vec<f32> {
104 let output_channels = match self.output_mode.as_ref().expect("set_output not yet called") {
105 OutputMode::StereoInterleaved => 2,
106 OutputMode::StereoUnweaved => 2,
107 OutputMode::Mono => 1,
108 };
109
110 let mut dst: Vec<f32> = Vec::with_capacity(samples * output_channels);
111 let dst_ptr: *mut f32 = dst.as_mut_ptr();
112 unsafe {
113 tsf_render_float(self.tsf_ptr, dst_ptr, samples as c_int, 0);
114 dst.set_len(samples*output_channels);
115 }
116 dst
117 }
118
119 pub fn channel_note_on(&mut self, channel: u16, key: u8, vel: f32) {
120 assert!(key <= 127u8, "key must be between 0 and 127");
121 assert!(vel >= 0f32 && vel <= 1f32, "vel must be between 0.0 and 1.0");
122 unsafe { tsf_channel_note_on(self.tsf_ptr, channel as c_int, key as c_int, vel) };
123 }
124
125 pub fn channel_note_off(&mut self, channel: u16, key: u8) {
126 assert!(key <= 127u8, "key must be between 0 and 127");
127 unsafe { tsf_channel_note_off(self.tsf_ptr, channel as c_int, key as c_int) };
128 }
129
130 pub fn channel_note_off_all(&mut self, channel: u16) {
131 unsafe { tsf_channel_note_off_all(self.tsf_ptr, channel as c_int) };
132 }
133
134 pub fn note_off_all(&mut self) {
135 unsafe { tsf_note_off_all(self.tsf_ptr) };
136 }
137
138 pub fn channel_set_preset_number(&mut self, channel: u16, preset_number: u16, mididrums: bool) {
139 unsafe { tsf_channel_set_presetnumber(self.tsf_ptr, channel as c_int, preset_number as c_int, if mididrums { 1 } else { 0 }) };
140 }
141
142 pub fn get_preset_count(&mut self) -> u16 {
143 unsafe { tsf_get_presetcount(self.tsf_ptr) as u16 }
144 }
145}
146
147pub enum OutputMode {
148 StereoInterleaved,
149 StereoUnweaved,
150 Mono
151}
152
153#[cfg(test)]
154mod tests {
155 use super::*;
156
157 #[test]
158 fn load_filename_and_render_c3() {
159 let mut tsf = Tsf::load_filename("test_resources/sinewave.sf2").unwrap();
160
161 assert_eq!(1, tsf.get_preset_count());
162
163 let sample_rate = 48000;
164 let samples = (sample_rate / 10) as usize; tsf.set_output(OutputMode::Mono, sample_rate, 0f32);
167
168 let silence_samples = tsf.render_float(samples);
170 assert!(silence_samples.into_iter().all(|x| x==0f32), "Didn't get silence");
171
172 tsf.channel_set_preset_number(0, 0, false);
174 tsf.channel_note_on(0, 48, 1f32);
175
176 let note_on_samples = tsf.render_float(4800);
177 assert!(note_on_samples.into_iter().any(|x| x!=0f32), "Got silence");
178
179 tsf.channel_note_off(0, 48);
181 let note_off_samples = tsf.render_float(4800);
182 assert!(note_off_samples.into_iter().any(|x| x!=0f32), "Got silence");
183
184 for _ in 0..100 {
187 tsf.render_float(samples);
188 }
189
190 let silence_after_samples = tsf.render_float(samples);
192 assert!(silence_after_samples.into_iter().all(|x| x==0f32), "Didn't get silence");
193
194 }
197}