mod font;
mod midi;
mod params;
mod write;
use crate::chorus::Chorus;
use crate::core::font_bank::FontBank;
pub use crate::core::soundfont::generator::GeneratorType;
use crate::error::OxiError;
use crate::reverb::Reverb;
use crate::{MidiEvent, SettingsError, SynthDescriptor};
pub use crate::{Tuning, TuningManager};
#[derive(Default)]
pub struct Synth {
core: crate::core::Synth,
}
impl Synth {
pub fn new(desc: SynthDescriptor) -> Result<Self, SettingsError> {
Ok(Synth {
core: crate::core::Synth::new(desc)?,
})
}
pub fn set_sample_rate(&mut self, sample_rate: f32) {
self.core.settings.sample_rate = sample_rate;
self.core.voices.set_sample_rate(sample_rate);
self.core.chorus = Chorus::new(sample_rate, self.core.chorus.active());
}
pub fn send_event(&mut self, event: MidiEvent) -> Result<(), OxiError> {
self.core.send_event(event)
}
pub fn font_bank(&self) -> &FontBank {
&self.core.font_bank
}
pub fn font_bank_mut(&mut self) -> &mut FontBank {
&mut self.core.font_bank
}
}
impl Synth {
pub fn get_reverb(&self) -> &Reverb {
&self.core.reverb
}
pub fn get_reverb_mut(&mut self) -> &mut Reverb {
&mut self.core.reverb
}
}
impl Synth {
pub fn chorus(&self) -> &Chorus {
&self.core.chorus
}
pub fn chorus_mut(&mut self) -> &mut Chorus {
&mut self.core.chorus
}
}
impl Synth {
pub fn count_midi_channels(&self) -> usize {
self.core.channels.len()
}
pub fn count_effects_channels(&self) -> u8 {
2
}
}
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))
}
}
impl Synth {
pub fn channel_set_tuning(&mut self, chan: u8, tuning: Tuning) -> Result<(), OxiError> {
let channel = self.core.channels.get_mut(chan as usize)?;
channel.set_tuning(Some(tuning));
Ok(())
}
pub fn channel_reset_tuning(&mut self, chan: u8) -> Result<(), OxiError> {
let channel = self.core.channels.get_mut(chan as usize)?;
channel.set_tuning(None);
Ok(())
}
}
#[cfg(test)]
mod test {
use crate::{MidiEvent, SoundFont, Synth, SynthDescriptor};
use std::{fs::File, io::Write, slice::from_raw_parts};
#[test]
fn synth_sf2() {
let mut pcm = File::create("Boomwhacker.sf2.pcm").unwrap();
let mut synth = Synth::new(SynthDescriptor::default()).unwrap();
let mut file = std::fs::File::open("./testdata/Boomwhacker.sf2").unwrap();
let font = SoundFont::load(&mut file).unwrap();
synth.add_font(font, true);
let mut samples = [0f32; 44100 * 2];
synth
.send_event(MidiEvent::NoteOn {
channel: 0,
key: 60,
vel: 127,
})
.unwrap();
synth.write(samples.as_mut());
pcm.write_all(unsafe {
from_raw_parts(samples.as_ptr() as _, std::mem::size_of_val(&samples))
})
.unwrap();
synth
.send_event(MidiEvent::NoteOff {
channel: 0,
key: 60,
})
.unwrap();
synth.write(samples.as_mut());
pcm.write_all(unsafe {
from_raw_parts(samples.as_ptr() as _, std::mem::size_of_val(&samples))
})
.unwrap();
drop(synth);
}
}