audio_processor_standalone/
standalone_processor.rs

1// Augmented Audio: Audio libraries and applications
2// Copyright (c) 2022 Pedro Tacla Yamada
3//
4// The MIT License (MIT)
5//
6// Permission is hereby granted, free of charge, to any person obtaining a copy
7// of this software and associated documentation files (the "Software"), to deal
8// in the Software without restriction, including without limitation the rights
9// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10// copies of the Software, and to permit persons to whom the Software is
11// furnished to do so, subject to the following conditions:
12//
13// The above copyright notice and this permission notice shall be included in
14// all copies or substantial portions of the Software.
15//
16// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22// THE SOFTWARE.
23use audio_processor_traits::parameters::AudioProcessorHandleRef;
24use audio_processor_traits::{AudioProcessor, MidiEventHandler, MidiMessageLike};
25
26/// Abstract standalone processor with runtime optional MIDI handling.
27pub trait StandaloneProcessor: Send + 'static {
28    type Processor: AudioProcessor<SampleType = f32>;
29    type Midi: MidiEventHandler;
30
31    fn processor(&mut self) -> &mut Self::Processor;
32
33    fn midi(&mut self) -> Option<&mut Self::Midi> {
34        None
35    }
36
37    fn supports_midi(&mut self) -> bool {
38        self.midi().is_some()
39    }
40
41    fn options(&self) -> &StandaloneOptions;
42
43    fn handle(&self) -> Option<AudioProcessorHandleRef> {
44        None
45    }
46}
47
48/// Options for `audio-processor-standalone`, this is provided by the `StandaloneProcessor` trait
49/// implementation at the moment, which is less than ideal.
50#[derive(Clone)]
51pub struct StandaloneOptions {
52    /// If true a callback will be created for an input device
53    pub accepts_input: bool,
54    /// If set starting this processor will attempt to find this device and use it
55    pub input_device: Option<String>,
56    /// If set starting this processor will attempt to find this device and use it
57    pub output_device: Option<String>,
58    /// If set and running in a VST and the VST uses the generated GUI, this will be used
59    /// to build a generic GUI over the generic audio processor handle.
60    ///
61    /// TODO - Move this somewhere else
62    pub handle: Option<AudioProcessorHandleRef>,
63}
64
65impl Default for StandaloneOptions {
66    fn default() -> Self {
67        StandaloneOptions {
68            accepts_input: true,
69            input_device: None,
70            output_device: None,
71            handle: None,
72        }
73    }
74}
75
76/// Noop MIDI event handler.
77pub struct NoMidiEventHandler {}
78impl MidiEventHandler for NoMidiEventHandler {
79    fn process_midi_events<Message: MidiMessageLike>(&mut self, _midi_messages: &[Message]) {}
80}
81
82/// A standalone processor impl that will only process audio
83pub struct StandaloneAudioOnlyProcessor<P> {
84    processor: P,
85    options: StandaloneOptions,
86}
87
88impl<P: AudioProcessor> From<P> for StandaloneAudioOnlyProcessor<P> {
89    fn from(processor: P) -> Self {
90        Self {
91            processor,
92            options: Default::default(),
93        }
94    }
95}
96
97impl<P> StandaloneAudioOnlyProcessor<P> {
98    pub fn new(processor: P, options: StandaloneOptions) -> Self {
99        StandaloneAudioOnlyProcessor { processor, options }
100    }
101}
102
103impl<P> StandaloneProcessor for StandaloneAudioOnlyProcessor<P>
104where
105    P: AudioProcessor<SampleType = f32> + Send + 'static,
106{
107    type Processor = P;
108    type Midi = NoMidiEventHandler;
109
110    fn processor(&mut self) -> &mut Self::Processor {
111        &mut self.processor
112    }
113
114    fn midi(&mut self) -> Option<&mut Self::Midi> {
115        None
116    }
117
118    fn options(&self) -> &StandaloneOptions {
119        &self.options
120    }
121
122    fn handle(&self) -> Option<AudioProcessorHandleRef> {
123        self.options.handle.clone()
124    }
125}
126
127/// A standalone processor impl that will process audio and MIDI
128pub struct StandaloneProcessorImpl<P> {
129    processor: P,
130    options: StandaloneOptions,
131}
132
133impl<P> StandaloneProcessorImpl<P> {
134    pub fn new(processor: P) -> Self {
135        StandaloneProcessorImpl {
136            processor,
137            options: StandaloneOptions::default(),
138        }
139    }
140
141    pub fn new_with(processor: P, options: StandaloneOptions) -> Self {
142        StandaloneProcessorImpl { processor, options }
143    }
144}
145
146impl<P> StandaloneProcessor for StandaloneProcessorImpl<P>
147where
148    P: AudioProcessor<SampleType = f32> + Send + 'static,
149    P: MidiEventHandler,
150{
151    type Processor = P;
152    type Midi = P;
153
154    fn processor(&mut self) -> &mut Self::Processor {
155        &mut self.processor
156    }
157
158    fn midi(&mut self) -> Option<&mut Self::Midi> {
159        Some(&mut self.processor)
160    }
161
162    fn options(&self) -> &StandaloneOptions {
163        &self.options
164    }
165
166    fn handle(&self) -> Option<AudioProcessorHandleRef> {
167        self.options.handle.clone()
168    }
169}
170
171#[cfg(test)]
172mod test {
173    use audio_processor_standalone_midi::host::MidiMessageEntry;
174    use audio_processor_traits::simple_processor::{MonoAudioProcessor, MonoCopyProcessor};
175    use audio_processor_traits::NoopAudioProcessor;
176
177    use super::*;
178
179    #[test]
180    fn test_midi_event_handler() {
181        let mut handler = NoMidiEventHandler {};
182        let midi_messages: Vec<MidiMessageEntry> = vec![];
183        handler.process_midi_events(&midi_messages);
184    }
185
186    #[test]
187    fn test_create_standalone_audio_processor() {
188        let processor = NoopAudioProcessor::new();
189        let mut standalone_audio_processor =
190            StandaloneAudioOnlyProcessor::new(processor, Default::default());
191        assert!(!standalone_audio_processor.supports_midi());
192        assert!(standalone_audio_processor.midi().is_none());
193        let _processor = standalone_audio_processor.processor();
194    }
195
196    #[test]
197    fn test_create_standalone_audio_midi_processor() {
198        struct MockProcessor {}
199        impl MonoAudioProcessor for MockProcessor {
200            type SampleType = f32;
201        }
202        impl MidiEventHandler for MockProcessor {
203            fn process_midi_events<Message: MidiMessageLike>(
204                &mut self,
205                _midi_messages: &[Message],
206            ) {
207            }
208        }
209
210        let processor = MonoCopyProcessor::new(MockProcessor {});
211        let mut standalone_audio_processor = StandaloneProcessorImpl::new(processor);
212        assert!(standalone_audio_processor.supports_midi());
213        assert!(standalone_audio_processor.midi().is_some());
214        let _processor = standalone_audio_processor.processor();
215    }
216}