use std::sync::Arc;
use bevy_seedling::prelude::ChannelCount;
use firewheel::{
channel_config::ChannelConfig,
event::ProcEvents,
node::{
AudioNode, AudioNodeInfo, AudioNodeProcessor, ConstructProcessorContext, EmptyConfig,
ProcBuffers, ProcExtra, ProcInfo, ProcessStatus,
},
};
use midix::prelude::ChannelVoiceMessage;
use midix_synth::prelude::{SoundFont, Synthesizer, SynthesizerSettings};
use trotcast::{Channel, Receiver};
use crate::{
input::FromMidiInputData,
synth::node::{MidiSynthNode, MidiSynthProcessor},
};
impl<D: FromMidiInputData> MidiSynthNode<Channel<D>> {
pub(crate) fn new_with_channel(
soundfont: Arc<SoundFont>,
enable_reverb_and_chorus: bool,
channel: Channel<D>,
) -> Self {
Self {
soundfont,
enable_reverb_and_chorus,
channel,
}
}
}
impl<D: FromMidiInputData> AudioNode for MidiSynthNode<Channel<D>> {
type Configuration = EmptyConfig;
fn info(&self, _config: &Self::Configuration) -> AudioNodeInfo {
AudioNodeInfo::new()
.debug_name("MIDI Synthesizer")
.channel_config(ChannelConfig {
num_inputs: ChannelCount::ZERO,
num_outputs: ChannelCount::STEREO,
})
}
fn construct_processor(
&self,
_config: &Self::Configuration,
cx: ConstructProcessorContext,
) -> impl AudioNodeProcessor {
MidiSynthProcessor::new_with_channel(self, cx)
}
}
impl<D: FromMidiInputData> MidiSynthProcessor<Receiver<D>> {
pub fn new_with_channel(
config: &MidiSynthNode<Channel<D>>,
cx: ConstructProcessorContext,
) -> Self {
let mut settings = SynthesizerSettings::new(cx.stream_info.sample_rate.get() as i32);
settings.enable_reverb_and_chorus = config.enable_reverb_and_chorus;
let synthesizer = Synthesizer::new(config.soundfont.clone(), &settings)
.expect("Failed to create synthesizer");
Self {
synthesizer,
channel: config.channel.spawn_rx(),
}
}
}
impl<D: FromMidiInputData> AudioNodeProcessor for MidiSynthProcessor<Receiver<D>> {
fn process(
&mut self,
info: &ProcInfo,
ProcBuffers { outputs, .. }: ProcBuffers,
events: &mut ProcEvents,
_extra: &mut ProcExtra,
) -> ProcessStatus {
for event in events.drain() {
if let Some(message) = event.downcast_ref::<ChannelVoiceMessage>() {
self.process_message(*message);
}
}
while let Ok(data) = self.channel.try_recv() {
if let Some(cvm) = data.to_channel_voice_message() {
self.process_message(cvm);
}
}
let frames = info.frames;
let (left, right) = outputs.split_at_mut(1);
self.synthesizer
.render(&mut left[0][..frames], &mut right[0][..frames]);
ProcessStatus::outputs_not_silent()
}
}