فهرست منبع

Update example with thumbpiano sampler demo. Loads one sample and plays it across three notes repetitively

mitchmindtree 10 سال پیش
والد
کامیت
a468b7519f
1فایلهای تغییر یافته به همراه39 افزوده شده و 20 حذف شده
  1. 39 20
      examples/wav.rs

+ 39 - 20
examples/wav.rs

@@ -1,6 +1,16 @@
-extern crate find_folder;
-extern crate hound;
-extern crate portaudio as pa;
+extern crate find_folder; // For easily finding the assets folder.
+extern crate portaudio as pa; // For audio I/O
+extern crate pitch_calc as pitch; // To work with musical notes.
+extern crate sample; // To convert portaudio sample buffers to frames.
+extern crate sampler;
+
+use sampler::Sampler;
+
+const CHANNELS: i32 = 2;
+const SAMPLE_RATE: f64 = 44_100.0;
+const FRAMES_PER_BUFFER: u32 = 64;
+const THUMB_PIANO: &'static str = "thumbpiano A#3.wav";
+
 
 fn main() {
     run().unwrap();
@@ -8,27 +18,34 @@ fn main() {
 
 fn run() -> Result<(), pa::Error> {
 
-    let mut samples = {
-        let assets = find_folder::Search::ParentsThenKids(5, 5).for_folder("assets").unwrap();
-        let sample_file = assets.join("amen_brother.wav");
-        let mut reader = hound::WavReader::open(&sample_file).unwrap();
-        reader.samples().collect::<Result<Vec<i16>, _>>().unwrap().into_iter()
-    };
+    // We'll create a sample map that maps a single sample to the entire note range.
+    let assets = find_folder::Search::ParentsThenKids(5, 5).for_folder("assets").unwrap();
+    let sample = sampler::Sample::from_wav_file(assets.join(THUMB_PIANO), SAMPLE_RATE).unwrap();
+    let sample_map = sampler::Map::from_single_sample(sample);
 
-    let pa = try!(pa::PortAudio::new());
+    // Create a polyphonic sampler.
+    let mut sampler = Sampler::poly((), sample_map).num_voices(4);
 
-    const CHANNELS: i32 = 1;
-    const SAMPLE_RATE: f64 = 44_100.0;
-    const FRAMES_PER_BUFFER: u32 = 64;
+    // Initialise PortAudio and create an output stream.
+    let pa = try!(pa::PortAudio::new());
+    let settings = 
+        try!(pa.default_output_stream_settings::<i16>(CHANNELS, SAMPLE_RATE, FRAMES_PER_BUFFER));
 
-    let settings = try!(pa.default_output_stream_settings(CHANNELS, SAMPLE_RATE, FRAMES_PER_BUFFER));
     let callback = move |pa::OutputStreamCallbackArgs { buffer, .. }| {
-        for sample in buffer.iter_mut() {
-            *sample = match samples.next() {
-                Some(s) => s,
-                None => return pa::Complete,
-            };
+        let buffer: &mut [[i16; CHANNELS as usize]] =
+            sample::slice::to_frame_slice_mut(buffer).unwrap();
+        sample::slice::equilibrium(buffer);
+
+        // If the sampler is not currently active, play a note.
+        if !sampler.is_active() {
+            let vel = 0.3;
+            sampler.note_on(pitch::LetterOctave(pitch::Letter::Ash, 3).to_hz(), vel);
+            sampler.note_on(pitch::LetterOctave(pitch::Letter::Dsh, 3).to_hz(), vel);
+            sampler.note_on(pitch::LetterOctave(pitch::Letter::Gsh, 1).to_hz(), vel);
         }
+
+        sampler.fill_slice(buffer, SAMPLE_RATE);
+
         pa::Continue
     };
 
@@ -36,7 +53,9 @@ fn run() -> Result<(), pa::Error> {
 
     try!(stream.start());
 
-    while let Ok(true) = stream.is_active() {}
+    while let Ok(true) = stream.is_active() {
+        std::thread::sleep(std::time::Duration::from_millis(16));
+    }
 
     try!(stream.stop());
     try!(stream.close());