use audio_processor_traits::parameters::AudioProcessorHandleRef;
use audio_processor_traits::{AudioProcessor, MidiEventHandler, MidiMessageLike};
pub trait StandaloneProcessor: Send + 'static {
type Processor: AudioProcessor<SampleType = f32>;
type Midi: MidiEventHandler;
fn processor(&mut self) -> &mut Self::Processor;
fn midi(&mut self) -> Option<&mut Self::Midi> {
None
}
fn supports_midi(&mut self) -> bool {
self.midi().is_some()
}
fn options(&self) -> &StandaloneOptions;
fn handle(&self) -> Option<AudioProcessorHandleRef> {
None
}
}
#[derive(Clone)]
pub struct StandaloneOptions {
pub accepts_input: bool,
pub input_device: Option<String>,
pub output_device: Option<String>,
pub handle: Option<AudioProcessorHandleRef>,
}
impl Default for StandaloneOptions {
fn default() -> Self {
StandaloneOptions {
accepts_input: true,
input_device: None,
output_device: None,
handle: None,
}
}
}
pub struct NoMidiEventHandler {}
impl MidiEventHandler for NoMidiEventHandler {
fn process_midi_events<Message: MidiMessageLike>(&mut self, _midi_messages: &[Message]) {}
}
pub struct StandaloneAudioOnlyProcessor<P> {
processor: P,
options: StandaloneOptions,
}
impl<P: AudioProcessor> From<P> for StandaloneAudioOnlyProcessor<P> {
fn from(processor: P) -> Self {
Self {
processor,
options: Default::default(),
}
}
}
impl<P> StandaloneAudioOnlyProcessor<P> {
pub fn new(processor: P, options: StandaloneOptions) -> Self {
StandaloneAudioOnlyProcessor { processor, options }
}
}
impl<P> StandaloneProcessor for StandaloneAudioOnlyProcessor<P>
where
P: AudioProcessor<SampleType = f32> + Send + 'static,
{
type Processor = P;
type Midi = NoMidiEventHandler;
fn processor(&mut self) -> &mut Self::Processor {
&mut self.processor
}
fn midi(&mut self) -> Option<&mut Self::Midi> {
None
}
fn options(&self) -> &StandaloneOptions {
&self.options
}
fn handle(&self) -> Option<AudioProcessorHandleRef> {
self.options.handle.clone()
}
}
pub struct StandaloneProcessorImpl<P> {
processor: P,
options: StandaloneOptions,
}
impl<P> StandaloneProcessorImpl<P> {
pub fn new(processor: P) -> Self {
StandaloneProcessorImpl {
processor,
options: StandaloneOptions::default(),
}
}
pub fn new_with(processor: P, options: StandaloneOptions) -> Self {
StandaloneProcessorImpl { processor, options }
}
}
impl<P> StandaloneProcessor for StandaloneProcessorImpl<P>
where
P: AudioProcessor<SampleType = f32> + Send + 'static,
P: MidiEventHandler,
{
type Processor = P;
type Midi = P;
fn processor(&mut self) -> &mut Self::Processor {
&mut self.processor
}
fn midi(&mut self) -> Option<&mut Self::Midi> {
Some(&mut self.processor)
}
fn options(&self) -> &StandaloneOptions {
&self.options
}
fn handle(&self) -> Option<AudioProcessorHandleRef> {
self.options.handle.clone()
}
}
#[cfg(test)]
mod test {
use audio_processor_standalone_midi::host::MidiMessageEntry;
use audio_processor_traits::simple_processor::{MonoAudioProcessor, MonoCopyProcessor};
use audio_processor_traits::NoopAudioProcessor;
use super::*;
#[test]
fn test_midi_event_handler() {
let mut handler = NoMidiEventHandler {};
let midi_messages: Vec<MidiMessageEntry> = vec![];
handler.process_midi_events(&midi_messages);
}
#[test]
fn test_create_standalone_audio_processor() {
let processor = NoopAudioProcessor::new();
let mut standalone_audio_processor =
StandaloneAudioOnlyProcessor::new(processor, Default::default());
assert!(!standalone_audio_processor.supports_midi());
assert!(standalone_audio_processor.midi().is_none());
let _processor = standalone_audio_processor.processor();
}
#[test]
fn test_create_standalone_audio_midi_processor() {
struct MockProcessor {}
impl MonoAudioProcessor for MockProcessor {
type SampleType = f32;
}
impl MidiEventHandler for MockProcessor {
fn process_midi_events<Message: MidiMessageLike>(
&mut self,
_midi_messages: &[Message],
) {
}
}
let processor = MonoCopyProcessor::new(MockProcessor {});
let mut standalone_audio_processor = StandaloneProcessorImpl::new(processor);
assert!(standalone_audio_processor.supports_midi());
assert!(standalone_audio_processor.midi().is_some());
let _processor = standalone_audio_processor.processor();
}
}