use std::sync::Arc;
use crate::{GeneratorType, OxiError, Preset, SoundFont, SoundFontId, Synth};
impl Synth {
pub fn add_font(&mut self, font: SoundFont, reset_presets: bool) -> SoundFontId {
let id = self.core.font_bank.add_font(font);
if reset_presets {
self.reset_program();
}
id
}
fn update_presets(&mut self) {
for id in 0..self.core.channels.len() {
let sfontnum = self.core.channels[id].sfontnum();
if let Some(sfontnum) = sfontnum {
let banknum = self.core.channels[id].banknum();
let prognum = self.core.channels[id].prognum();
let preset = self.core.font_bank.preset(sfontnum, banknum, prognum);
self.core.channels[id].set_preset(preset);
}
}
}
pub fn remove_font(&mut self, id: SoundFontId, reset_presets: bool) -> Option<SoundFont> {
let sfont = self.core.font_bank.remove_font(id);
if let Some(font) = sfont {
if reset_presets {
self.reset_program();
} else {
self.update_presets();
}
Some(font)
} else {
log::error!("No SoundFont with id = {:?}", id);
None
}
}
pub fn select_sound_font(
&mut self,
channel: u8,
sfont_id: SoundFontId,
) -> Result<(), OxiError> {
self.core
.channels
.get_mut(channel as usize)?
.set_sfontnum(Some(sfont_id));
Ok(())
}
pub fn sound_font_count(&self) -> usize {
self.core.font_bank.count()
}
pub fn nth_sound_font(&self, num: usize) -> Option<&SoundFont> {
self.core.font_bank.nth_font(num)
}
pub fn sound_font(&self, id: SoundFontId) -> Option<&SoundFont> {
self.core.font_bank.font(id)
}
pub fn set_bank_offset(&mut self, sfont_id: SoundFontId, offset: u32) {
self.core.font_bank.bank_offsets.set(sfont_id, offset)
}
pub fn bank_offset(&self, sfont_id: SoundFontId) -> Option<u32> {
self.core
.font_bank
.bank_offsets
.get(sfont_id)
.map(|o| o.offset)
}
pub fn channel_preset(&self, channel: u8) -> Option<Arc<Preset>> {
if let Ok(channel) = self.core.channels.get(channel as usize) {
channel.preset().cloned()
} else {
log::warn!("Channel out of range");
None
}
}
}
impl Synth {
pub fn set_gen(
&mut self,
chan: usize,
param: GeneratorType,
value: f32,
) -> Result<(), OxiError> {
let channel = self.core.channels.get_mut(chan)?;
crate::core::midi::set_gen(channel, &mut self.core.voices, param, value);
Ok(())
}
pub fn gen(&self, chan: u8, param: GeneratorType) -> Result<f32, OxiError> {
let channel = self.core.channels.get(chan as usize)?;
Ok(channel.gen(param))
}
}
#[cfg(test)]
mod test {
use crate::{SoundFont, Synth, SynthDescriptor};
#[test]
fn font_and_preset() {
let mut synth = Synth::new(SynthDescriptor::default()).unwrap();
assert_eq!(synth.sound_font_count(), 0);
let sin = {
let mut file = std::fs::File::open("../testdata/sin.sf2").unwrap();
let font = SoundFont::load(&mut file).unwrap();
let id = synth.add_font(font, true);
assert_eq!(synth.sound_font_count(), 1);
let font = synth.sound_font(id).unwrap();
let preset = font.preset(0, 0).unwrap();
assert_eq!(preset.name(), "Sine Wave");
assert_eq!(preset.banknum(), 0);
assert_eq!(preset.num(), 0);
id
};
let boom = {
let mut file = std::fs::File::open("../testdata/Boomwhacker.sf2").unwrap();
let font = SoundFont::load(&mut file).unwrap();
let id = synth.add_font(font, true);
assert_eq!(synth.sound_font_count(), 2);
let font = synth.sound_font(id).unwrap();
let preset = font.preset(0, 0).unwrap();
assert_eq!(preset.name(), "Boomwhacker");
assert_eq!(preset.banknum(), 0);
assert_eq!(preset.num(), 0);
id
};
{
}
{
let font = synth.sound_font(sin).unwrap();
let preset = font.preset(0, 0).unwrap();
assert_eq!(preset.name(), "Sine Wave");
assert_eq!(preset.banknum(), 0);
assert_eq!(preset.num(), 0);
}
{
let font = synth.sound_font(boom).unwrap();
let preset = font.preset(0, 0).unwrap();
assert_eq!(preset.name(), "Boomwhacker");
assert_eq!(preset.banknum(), 0);
assert_eq!(preset.num(), 0);
}
}
}