1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
//! Library to facilitate generating different sounds at the same time (polyphony).
//!
//! Polyphony consists of different steps:
//!
//! 1. Classify how the event should be dispatched.
//!    How exactly it should be classified, is defined by the [`EventDispatchClass`] enum.
//!    The dispatching itself is done by a type that implements the [`EventDispatchClassifier`] trait.
//! 2. Next, using the classification, voices are assigned to the event.
//!    The assigned voice(s) are described by the [`VoiceAssignment`] enum.
//!    The [`VoiceAssigner`] trait defines this action.
//! 3. Then, the event can be dispatched by calling the [`dispatch`] method on the [`VoiceAssignment`].
#![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);
        }
    }
}

```
")]
//! [`EventDispatchClass`]: ./enum.EventDispatchClass.html
//! [`EventDispatchClassifier`]: ./trait.EventDispatchClassifier.html
//! [`VoiceAssignment`]: ./enum.VoiceAssignment.html
//! [`VoiceAssigner`]: ./trait.VoiceAssigner.html
//! [`dispatch`]: enum.VoiceAssignment.html#method.dispatch

#[cfg(feature = "midi")]
extern crate midi_consts;
#[cfg(feature = "midi")]
pub mod midi;

pub mod simple_event_dispatching;

/// Describe how an event should be dispatched.
///
/// # Example.
/// Suppose events are dispatched based on the tone that is played.
/// Then `EventDispatchClass::VoiceSpecific(ToneIdentifier(60))` means that this event
/// should be dispatched to whatever voice is currently playing the tone with midi number 60
/// (central C on the piano).
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub enum EventDispatchClass<Identifier> {
    /// The event should be dispatched to all voices
    Broadcast,
    /// The event should be dispatched to a newly created voice with the given identifier
    AssignNewVoice(Identifier),
    /// The event should be dispatched to an already existing voice with the given identifier
    VoiceSpecific(Identifier),
}

/// Determine to what voices the event should be dispatched.
pub trait EventDispatchClassifier<Event> {
    /// The identifier used to identify a specific voice.
    type VoiceIdentifier: Eq + Copy;

    /// Classify how the event should be dispatched.
    fn classify(&self, event: &Event) -> EventDispatchClass<Self::VoiceIdentifier>;
}

/// Describe to what particular voice an event should be assigned.
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub enum VoiceAssignment {
    /// This event should be assigned to no particular voice (i.e.: it should simply be dropped).
    None,
    /// This event should be assigned to all voices.
    All,
    /// This event should be assigned to the voice with the given index
    Some { index: usize },
}

impl VoiceAssignment {
    /// Dispatch an action to the assigned voices.
    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);
                }
            }
        }
    }
}

/// Define to which particular voice(s) the event should be assigned, based on the [`EventDispatchClass`].
///
/// This does the "voice stealing".
///
/// [`EventDispatchClass`]: ./enum.EventDispatchClass.html
pub trait VoiceAssigner<Voice, Identifier> {
    /// Define to which particular voice(s) the event should be assigned, based on the [`EventDispatchClass`].
    /// The implementation of this method may assume that for subsequent calls to it, always the
    /// same slice of voices is used.
    ///
    /// [`EventDispatchClass`]: ./enum.EventDispatchClass.html
    fn assign(
        &mut self,
        classifier: EventDispatchClass<Identifier>,
        voices: &mut [Voice],
    ) -> VoiceAssignment;
}

/// Trait used to facilitate implementing a [`VoiceAssigner`].
///
/// [`VoiceAssigner`]: ./trait.VoiceAssigner.html
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),
            },
        }
    }
}

/// A trait used by some dispatchers.
pub trait Voice<State> {
    fn state(&self) -> State;
}