#![cfg_attr(feature = "midi", doc ="\
# Example of using polyphony
The following example illustrates a plugin (or application) that has multiple voices that
correspond to different tones.
_Remark_ the example assumes the `polyphony` crate is compiled with the `midi` feature.
```
use polyphony::{Voice, EventDispatchClassifier, VoiceAssigner};
use polyphony::midi::{ToneIdentifier, RawMidiEventToneIdentifierDispatchClassifier};
use polyphony::simple_event_dispatching::SimpleVoiceState;
use polyphony::simple_event_dispatching::SimpleEventDispatcher;
struct MyVoice {
// ...
}
impl MyVoice {
fn handle_raw_midi_event(&mut self, event: &[u8; 3]) {
// Here you typically change the state of the voice.
unimplemented!();
}
fn render_buffer(&mut self, audio_buffer: &mut[f32]) {
unimplemented!();
}
}
impl Voice<SimpleVoiceState<ToneIdentifier>> for MyVoice {
fn state(&self) -> SimpleVoiceState<ToneIdentifier> {
// Let the event dispatcher know what state this voice is in.
unimplemented!();
}
}
struct MyPlugin {
voices: Vec<MyVoice>,
// ...
}
impl MyPlugin
{
fn handle_event(&mut self, raw_midi_event: &[u8;3]) {
let mut classifier = RawMidiEventToneIdentifierDispatchClassifier;
let classification = classifier.classify(raw_midi_event);
let mut dispatcher = SimpleEventDispatcher;
let assignment = dispatcher.assign(classification, &mut self.voices);
assignment.dispatch(raw_midi_event, &mut self.voices, MyVoice::handle_raw_midi_event);
}
fn render_buffer(&mut self, buffer: &mut [f32]) {
for voice in self.voices.iter_mut() {
voice.render_buffer(buffer);
}
}
}
```
")]
#[cfg(feature = "midi")]
extern crate midi_consts;
#[cfg(feature = "midi")]
pub mod midi;
pub mod simple_event_dispatching;
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub enum EventDispatchClass<Identifier> {
Broadcast,
AssignNewVoice(Identifier),
VoiceSpecific(Identifier),
}
pub trait EventDispatchClassifier<Event> {
type VoiceIdentifier: Eq + Copy;
fn classify(&self, event: &Event) -> EventDispatchClass<Self::VoiceIdentifier>;
}
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub enum VoiceAssignment {
None,
All,
Some { index: usize },
}
impl VoiceAssignment {
pub fn dispatch<E, F, V>(self, event: E, voices: &mut [V], mut action: F)
where
E: Copy,
F: FnMut(&mut V, E),
{
match self {
VoiceAssignment::None => {}
VoiceAssignment::Some { index } => {
action(&mut voices[index], event);
}
VoiceAssignment::All => {
for voice in voices.iter_mut() {
action(voice, event);
}
}
}
}
}
pub trait VoiceAssigner<Voice, Identifier> {
fn assign(
&mut self,
classifier: EventDispatchClass<Identifier>,
voices: &mut [Voice],
) -> VoiceAssignment;
}
pub trait VoiceAssignerHelper<Voice, Identifier> {
fn find_active_voice(&mut self, identifier: Identifier, voices: &mut [Voice]) -> Option<usize>;
fn find_new_voice(&mut self, identifier: Identifier, voices: &mut [Voice]) -> usize;
}
impl<Voice, Identifier, T> VoiceAssigner<Voice, Identifier> for T
where
T: VoiceAssignerHelper<Voice, Identifier>,
{
fn assign(
&mut self,
classifier: EventDispatchClass<Identifier>,
voices: &mut [Voice],
) -> VoiceAssignment {
match classifier {
EventDispatchClass::Broadcast => VoiceAssignment::All,
EventDispatchClass::VoiceSpecific(identifier) => {
match self.find_active_voice(identifier, voices) {
Some(index) => VoiceAssignment::Some { index },
None => VoiceAssignment::None,
}
}
EventDispatchClass::AssignNewVoice(identifier) => VoiceAssignment::Some {
index: self.find_new_voice(identifier, voices),
},
}
}
}
pub trait Voice<State> {
fn state(&self) -> State;
}