Ver código fonte

Track sample/voice mappings with sampler::mode::Mode note_on and note_off.

mitchmindtree 8 anos atrás
pai
commit
76fe5dbefe
1 arquivos alterados com 158 adições e 0 exclusões
  1. 158 0
      src/mode.rs

+ 158 - 0
src/mode.rs

@@ -0,0 +1,158 @@
+pub use instrument::mode::{Mono, MonoKind, Poly, Dynamic};
+use map::Map;
+use pitch;
+use sample::Frame;
+use sampler::PlayingSample;
+use Velocity;
+
+/// The "mode" with which the Sampler will handle notes.
+pub trait Mode {
+
+    /// Handle a `note_on` event.
+    ///
+    /// Is called immediately following `instrument::Mode::note_on`.
+    fn note_on<F>(&mut self,
+                  note_hz: pitch::Hz,
+                  note_velocity: Velocity,
+                  map: &Map<F>,
+                  voices: &mut [Option<PlayingSample<F>>])
+        where F: Frame;
+
+    /// Handle a `note_off` event.
+    fn note_off<F>(&self,
+                   note_hz: pitch::Hz,
+                   map: &Map<F>,
+                   voices: &mut [Option<PlayingSample<F>>])
+        where F: Frame;
+
+    /// Handle a `stop` event.
+    fn stop(&mut self) {}
+}
+
+
+// Helper function for constructing a `PlayingSample`.
+fn play_sample<F>(hz: pitch::Hz, vel: Velocity, map: &Map<F>) -> Option<PlayingSample<F>>
+    where F: Frame,
+{
+    play_sample_from_playhead_idx(0, hz, vel, map)
+}
+
+// Helper function for constructing a `PlayingSample` with a given playhead index.
+fn play_sample_from_playhead_idx<F>(idx: usize,
+                                    hz: pitch::Hz,
+                                    vel: Velocity,
+                                    map: &Map<F>) -> Option<PlayingSample<F>>
+    where F: Frame,
+{
+    map.sample(hz, vel).map(|sample| PlayingSample::from_playhead_idx(idx, hz, vel, sample))
+}
+
+
+impl Mode for Mono {
+
+    fn note_on<F>(&mut self,
+                  note_hz: pitch::Hz,
+                  note_vel: Velocity,
+                  map: &Map<F>,
+                  voices: &mut [Option<PlayingSample<F>>])
+        where F: Frame,
+    {
+        let sample = match play_sample(note_hz, note_vel, map) {
+            Some(sample) => sample,
+            None => return,
+        };
+        for voice in voices {
+            *voice = Some(sample.clone());
+        }
+    }
+
+    fn note_off<F>(&self,
+                   note_hz: pitch::Hz,
+                   map: &Map<F>,
+                   voices: &mut [Option<PlayingSample<F>>])
+        where F: Frame,
+    {
+        let Mono(kind, ref note_stack) = *self;
+
+        let should_reset = voices.iter().next()
+            .and_then(|v| v.as_ref().map(|v| v.note_on_hz == note_hz))
+            .unwrap_or(false);
+
+        if should_reset {
+            let maybe_fallback_note_hz = note_stack.iter().last();
+            for voice in voices {
+                // If there's some fallback note in the note stack, play it.
+                if let Some(ref mut playing_sample) = *voice {
+                    if let Some(&hz) = maybe_fallback_note_hz {
+                        let hz = pitch::Hz(hz.into());
+                        let idx = match kind {
+                            MonoKind::Legato => playing_sample.rate_converter.source().idx,
+                            MonoKind::Retrigger => 0,
+                        };
+                        let vel = playing_sample.note_on_vel;
+                        if let Some(sample) = play_sample_from_playhead_idx(idx, hz, vel, map) {
+                            *playing_sample = sample;
+                            continue;
+                        }
+                    }
+                }
+                // Otherwise, set the voices to `None`.
+                *voice = None;
+            }
+        }
+    }
+
+}
+
+impl Mode for Poly {
+
+    fn note_on<F>(&mut self,
+                  note_hz: pitch::Hz,
+                  note_vel: Velocity,
+                  map: &Map<F>,
+                  voices: &mut [Option<PlayingSample<F>>])
+        where F: Frame,
+    {
+        let sample = match play_sample(note_hz, note_vel, map) {
+            Some(sample) => sample,
+            None => return,
+        };
+
+        // Find the right voice to play the note.
+        let mut oldest = None;
+        let mut max_sample_count = 0;
+        for voice in voices.iter_mut() {
+            match *voice {
+                None => {
+                    *voice = Some(sample);
+                    return;
+                },
+                Some(ref mut playing_sample) => {
+                    let playhead = playing_sample.rate_converter.source().idx;
+                    if playhead >= max_sample_count {
+                        max_sample_count = playhead;
+                        oldest = Some(playing_sample);
+                    }
+                },
+            }
+        }
+        if let Some(voice) = oldest {
+            *voice = sample;
+        }
+    }
+
+    fn note_off<F>(&self,
+                   note_hz: pitch::Hz,
+                   _map: &Map<F>,
+                   voices: &mut [Option<PlayingSample<F>>])
+        where F: Frame,
+    {
+        for voice in voices {
+            let should_reset = voice.as_ref().map(|v| v.note_on_hz == note_hz).unwrap_or(false);
+            if should_reset {
+                *voice = None;
+            }
+        }
+    }
+
+}