#![doc = r#"
Synthesizer resources, setup and plugins
"#]
use crate::prelude::SoundFont;
use bevy::prelude::*;
use crossbeam_channel::Sender;
use midix::prelude::ChannelVoiceMessage;
use std::sync::Mutex;
use tinyaudio::{OutputDevice, OutputDeviceParameters};
mod plugin;
pub use plugin::*;
struct SynthCommand {
event: ChannelVoiceMessage,
}
impl SynthCommand {
pub fn new(event: ChannelVoiceMessage) -> Self {
Self { event }
}
}
enum SynthState {
NotLoaded,
LoadHandle { sound_font: Handle<SoundFont> },
Loaded(Sender<SynthCommand>),
}
#[derive(Resource)]
pub struct Synth {
params: OutputDeviceParameters,
synthesizer: SynthState,
_device: Option<Mutex<OutputDevice>>,
}
impl Synth {
pub fn new(params: SynthParams) -> Self {
Self {
params: OutputDeviceParameters {
channels_count: params.channel_count,
sample_rate: params.sample_rate,
channel_sample_count: params.channel_sample_count,
},
..Default::default()
}
}
pub fn handle_event(&self, event: ChannelVoiceMessage) {
let SynthState::Loaded(channel) = &self.synthesizer else {
error!("An event was passed to the synth, but the soundfont has not been loaded!");
return;
};
channel.send(SynthCommand::new(event)).unwrap();
}
pub fn is_ready(&self) -> bool {
matches!(self.synthesizer, SynthState::Loaded(_))
}
pub fn use_soundfont(&mut self, sound_font: Handle<SoundFont>) {
self.synthesizer = SynthState::LoadHandle { sound_font };
self._device = None;
}
}
impl Default for Synth {
fn default() -> Self {
let params = OutputDeviceParameters {
channels_count: 2,
sample_rate: 44100,
channel_sample_count: 441,
};
Self {
params,
synthesizer: SynthState::NotLoaded,
_device: None,
}
}
}