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
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
use asprim::AsPrim;
use dsp::pan;
use note::*;
use num_traits::Float;
use voice::{Renderable, Voice, VoiceState};
use vst::api::Events;
use vst::buffer::AudioBuffer;
use vst::event::Event;
/// The base structure for handling voices, sounds, and processing
///
/// * `T` - a struct we create that implements the `Renderable` trait,
/// and contains all of our DSP code.
pub struct Synth<T>
where
    T: Renderable,
{
    /// A vector containing multiple objects implementing the `Voice` trait
    pub voices: Vec<Voice<T>>,
    /// A vector that keeps track of currently playing voices
    /// Each u8 refers to the note being played, and each 32b integer in the vector
    /// corresponds to an index in `voices`.  Note that this data is duplicate of data
    /// in the `Voice` structure itself, so it shouldn't be relied upon for anything external,
    /// and must be manually updated when notes change.
    voices_used: Vec<(u8, usize)>,
    /// The sample rate the Synthesizer and voices should use
    sample_rate: f64,
    /// What method the synth should use to steal voices (if any)
    pub steal_mode: StealMode,
    /// The balance of the instrument represented as a float between -1 and 1,
    /// where 0 is center and 1 is to the right.
    pan: f32,
    /// The raw amp values for panning
    /// This can be used in tandem with a state object to set the global
    /// panning values every block render, without having to perform
    /// an expensive panning formula every time.  For instance, we can
    /// calculate `constant_power_pan` in a callback every time the pan knob is moved
    /// and assign that value to a tuple.
    /// Then, before calling the `render_next` method on our synth, we can set the
    /// `pan_raw` field to our aforementioned tuple.
    /// Note that although the framework supports any number of outputs,
    /// panning is currently only supported with stereo.
    pub pan_raw: (f32, f32),
    /// The number of samples passed since the plugin started.  Can represent 24372 centuries of
    /// samples at 48kHz, so wrapping shouldn't be a problem.
    pub sample_counter: f64,
}

/// Get default values
/// This is only really useful with our internal builder methods.
/// If we try something like `let s = { sample_rate: 48_000, .. Synthesizer::default() };`
/// the compiler will complain that some fields are private.
impl<T> Default for Synth<T>
where
    T: Renderable,
{
    fn default() -> Self {
        Synth {
            voices: vec![],
            sample_rate: 48_000f64,
            steal_mode: StealMode::First,
            pan: 0f32,
            pan_raw: (0f32, 0f32),
            voices_used: vec![],
            sample_counter: 0f64,
        }
    }
}

impl<T> Synth<T>
where
    T: Renderable,
{
    /// Constructor for the Synthesizer utilizing a builder pattern
    pub fn new() -> Self {
        Synth::default()
    }

    /// Set voices using the builder
    ///
    /// * `voices` - A vector containing any number of `Voice` structures.
    /// If our instrument is polyphonic, the number of voices will determine the maximum amount
    /// of notes it can play at once.
    pub fn voices(mut self, voices: Vec<Voice<T>>) -> Self {
        self.voices = voices;
        self
    }

    /// Set the sample rate using the builder.  This is also useful after the `Synth` is finalized
    /// if the host sample rate is changed, or a voice is added during execution with `default` filling
    /// in the sample rate.
    ///
    /// * `sample_rate` - set the sample rate of our instrument
    pub fn sample_rate(mut self, sample_rate: f64) -> Self {
        self.sample_rate = sample_rate;
        for voice in &self.voices {
            voice.sample_rate.set(sample_rate);
        }
        self
    }

    /// Set the note steal mode using the builder
    ///
    /// * `steal_mode` - this determines how "voice stealing" will be implemented, if at all.
    pub fn steal_mode(mut self, steal_mode: StealMode) -> Self {
        self.steal_mode = steal_mode;
        self
    }

    /// Finalize the builder and return an immutable `Synth`
    #[allow(unused_variables)]
    pub fn finalize(self) -> Self {
        let (pan_left_amp, pan_right_amp) = pan::constant_power(self.pan);
        Synth {
            pan: self.pan,
            voices: self.voices,
            sample_rate: self.sample_rate,
            steal_mode: self.steal_mode,
            pan_raw: self.pan_raw,
            voices_used: vec![],
            sample_counter: 0f64,
        }
    }

    /// Set the panning for the entire instrument
    /// This is done via a function instead of directly setting the field
    /// as the formula is potentially costly and should only be calculated
    /// when needed.  For instance, do not use this function in a loop for
    /// every sample.  Instead, update the value only when parameters change.
    /// If you need to set the panning every block render, consider accessing
    /// the `pan_raw` field directly.
    ///
    /// * `amount` - a float value between -1 and 1 where 0 is center and 1 is to the right.
    /// Values not within this range will be
    pub fn set_pan(&mut self, amount: f32) {
        self.pan = amount;
        let (pan_left_amp, pan_right_amp) = pan::constant_power(self.pan);
        self.pan_raw = (pan_left_amp, pan_right_amp);
    }

    /// Modify an audio buffer with rendered audio from the voice
    ///
    /// * `buffer` - the audio buffer to modify
    #[allow(unused_variables)]
    pub fn render_next<'a, F: Float + AsPrim>(&mut self, buffer: &mut AudioBuffer<'a, F>) {
        // split the buffer
        let (mut inputs, mut outputs) = buffer.split();
        for voice in &mut self.voices {
            voice.render_next::<F>(&mut inputs, &mut outputs);
        }
    }

    /// Process events from the plugin host.  This is useful if you are
    /// responding to MIDI notes and data.
    ///
    /// * `events` - a reference to an `Events` structure from the `vst::api::Events`
    /// module.
    pub fn process_events(&mut self, events: &Events) {
        // loop through all events
        for e in events.events() {
            // check if the event is a midi signal
            match e {
                Event::Midi(ev) => self.process_midi(NoteData::data(ev.data)),
                _ => return,
            }
        }
    }

    /// Take in note data and turn a note on/off depending on the state
    fn process_midi(&mut self, note_data: NoteData) {
        match note_data.state {
            NoteState::On => self.trigger_note_on(note_data),
            NoteState::Off => self.trigger_note_off(note_data),
            _ => return,
        }
    }

    /// Used to find a voice to start playing.
    /// If voice stealing is enabled, it will take place here.
    fn trigger_note_on(&mut self, note_data: NoteData) {
        // TODO: Voice stealing
        // for now, just find the first available voice
        // to keep mutability in our voice, use a simple mutable var i and increment in the loop
        // Here, `i` refers to the index of our `voices` vector.
        let mut i: usize = 0;

        for voice in &mut self.voices {
            if voice.state == VoiceState::Off {
                // Success.  Push our data to the vector containing "on" voices
                self.voices_used.push((note_data.note, i));
                // set our note data
                voice.note_data = note_data;
                voice.state = VoiceState::On;
                // exit early
                break;
            }
            // increment our iterator
            i += 1;
        }
    }

    /// Finds a voice playing the same note as `note_data.note` and triggers that
    /// voice to begin releasing
    fn trigger_note_off(&mut self, note_data: NoteData) {
        // index for `voices_used`
        // HACK
        let mut remove_from_voices_used = false;
        let mut i = 0;

        // find the index of our voice in our `voices_used` array by the note number
        for &(note, voice_index) in &self.voices_used {
            if note == note_data.note {
                // Also assign the value `note_data`
                self.voices[voice_index].note_data = note_data;
                remove_from_voices_used = true;
                break;
            }

            i += 1;
        }

        // remove index from the `voices_used` array and free it up for use again.
        if remove_from_voices_used {
            self.voices_used.remove(i);
        }
    }
}

/// The way new notes will play if all voices are being currently utilized
/// This will change
pub enum StealMode {
    /// new notes will simply not be played if all voices are busy
    Off,
    /// stop playing the first voice to start playing in this frame
    First,
    /// stop playing the last voice to start playing in this frame
    Last,
}