1use crate::{ffi, option_from_ptr, Chan, Error, FontId, FontRef, PresetRef, Result, Status, Synth};
2use std::{ffi::CString, marker::PhantomData, path::Path};
3
4impl Synth {
8 pub fn sfload<P: AsRef<Path>>(&self, filename: P, reset_presets: bool) -> Result<FontId> {
16 let filename = filename.as_ref().to_str().ok_or(Error::Path)?;
17 let filename = CString::new(filename).map_err(|_| Error::Path)?;
18
19 self.neg_err(unsafe {
20 ffi::fluid_synth_sfload(self.handle, filename.as_ptr(), reset_presets as _)
21 })
22 .map(|id| id as _)
23 }
24
25 pub fn sfreload(&self, id: FontId) -> Result<FontId> {
30 self.neg_err(unsafe { ffi::fluid_synth_sfreload(self.handle, id as _) })
31 .map(|id| id as _)
32 }
33
34 pub fn sfunload(&self, id: FontId, reset_presets: bool) -> Status {
38 self.zero_ok(unsafe { ffi::fluid_synth_sfunload(self.handle, id, reset_presets as _) })
39 }
40
41 pub fn sfcount(&self) -> u32 {
45 unsafe { ffi::fluid_synth_sfcount(self.handle) as _ }
46 }
47
48 pub fn get_sfont(&self, num: u32) -> Option<FontRef<'_>> {
55 option_from_ptr(unsafe { ffi::fluid_synth_get_sfont(self.handle, num) })
56 .map(FontRef::from_ptr)
57 }
58
59 pub fn sfont_iter(&self) -> FontIter<'_> {
63 FontIter::from_ptr(self.handle)
64 }
65
66 pub fn get_sfont_by_id(&self, id: FontId) -> Option<FontRef<'_>> {
70 option_from_ptr(unsafe { ffi::fluid_synth_get_sfont_by_id(self.handle, id) })
71 .map(FontRef::from_ptr)
72 }
73
74 pub fn remove_sfont(&self, sfont: FontRef<'_>) {
80 unsafe {
81 ffi::fluid_synth_remove_sfont(self.handle, sfont.as_ptr());
82 }
83 }
84
85 pub fn get_channel_preset(&self, chan: Chan) -> Option<PresetRef<'_>> {
99 option_from_ptr(unsafe { ffi::fluid_synth_get_channel_preset(self.handle, chan as _) })
100 .map(PresetRef::from_ptr)
101 }
102
103 pub fn set_bank_offset(&self, sfont_id: FontId, offset: u32) -> Status {
108 self.zero_ok(unsafe {
109 ffi::fluid_synth_set_bank_offset(self.handle, sfont_id as _, offset as _)
110 })
111 }
112
113 pub fn get_bank_offset(&self, sfont_id: FontId) -> Result<u32> {
117 self.neg_err(unsafe { ffi::fluid_synth_get_bank_offset(self.handle, sfont_id as _) })
118 .map(|val| val as _)
119 }
120}
121
122#[cfg(test)]
123mod test {
124 use crate::{IsFont, IsPreset, Settings, Synth};
125
126 #[test]
127 fn font_and_preset() {
128 let synth = Synth::new(Settings::new().unwrap()).unwrap();
129
130 assert_eq!(synth.sfcount(), 0);
131
132 synth.sfload("sf_/Boomwhacker.sf2", true).unwrap();
133
134 assert_eq!(synth.sfcount(), 1);
135
136 let font = synth.get_sfont(0).unwrap();
137
138 assert_eq!(font.get_id(), 1);
139 assert_eq!(font.get_name().unwrap(), "sf_/Boomwhacker.sf2");
140
141 let preset = font.get_preset(0, 0).unwrap();
142
143 assert_eq!(preset.get_name().unwrap(), "Boomwhacker");
144 assert_eq!(preset.get_banknum().unwrap(), 0);
145 assert_eq!(preset.get_num().unwrap(), 0);
146 }
147}
148
149pub struct FontIter<'a> {
153 handle: *mut ffi::fluid_synth_t,
154 phantom: PhantomData<&'a ()>,
155 font_no: u32,
156}
157
158impl<'a> FontIter<'a> {
159 fn from_ptr(handle: *mut ffi::fluid_synth_t) -> Self {
160 Self {
161 handle,
162 phantom: PhantomData,
163 font_no: 0,
164 }
165 }
166}
167
168impl<'a> Iterator for FontIter<'a> {
169 type Item = FontRef<'a>;
170
171 fn next(&mut self) -> Option<Self::Item> {
172 let font =
173 option_from_ptr(unsafe { ffi::fluid_synth_get_sfont(self.handle, self.font_no) })
174 .map(FontRef::from_ptr);
175 if font.is_some() {
176 self.font_no += 1;
177 }
178 font
179 }
180}