Johann Woelper 4 years ago
parent
commit
cb1e536366
18 changed files with 498 additions and 2549 deletions
  1. 2 24
      .gitignore
  2. 0 15
      .travis.yml
  3. 473 0
      Cargo.lock
  4. 6 34
      Cargo.toml
  5. 0 13
      LICENSE-APACHE
  6. 0 21
      LICENSE-MIT
  7. 0 1
      README.md
  8. BIN
      assets/thumbpiano A#3.wav
  9. BIN
      beep.wav
  10. 0 64
      examples/wav.rs
  11. 0 255
      src/audio.rs
  12. 0 40
      src/dynamic.rs
  13. 0 27
      src/lib.rs
  14. 17 0
      src/main.rs
  15. 0 237
      src/map.rs
  16. 0 199
      src/mode.rs
  17. 0 400
      src/sampler.rs
  18. 0 1219
      src/serde.rs

+ 2 - 24
.gitignore

@@ -1,24 +1,2 @@
-.DS_Store
-*~
-*#
-*.o
-*.so
-*.swp
-*.dylib
-*.dSYM
-*.dll
-*.rlib
-*.dummy
-*.exe
-*-test
-/bin/main
-/bin/test-internal
-/bin/test-external
-/doc/
-/target/
-/build/
-/.rust/
-rusti.sh
-/examples/**/target
-
-Cargo.lock
+/target
+.history

+ 0 - 15
.travis.yml

@@ -1,15 +0,0 @@
-language: rust
-
-rust:
-    - stable
-    - nightly
-
-os:
-    - linux
-
-script:
-    - cargo build --verbose
-    - cargo build --no-default-features
-    - cargo test --verbose
-    - cargo test --features="serde_serialization" --verbose
-    - cargo doc --verbose

+ 473 - 0
Cargo.lock

@@ -0,0 +1,473 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+[[package]]
+name = "aho-corasick"
+version = "0.7.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "743ad5a418686aad3b87fd14c43badd828cf26e214a00f92a384291cf22e1811"
+dependencies = [
+ "memchr",
+]
+
+[[package]]
+name = "alsa-sys"
+version = "0.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b0edcbbf9ef68f15ae1b620f722180b82a98b6f0628d30baa6b8d2a5abc87d58"
+dependencies = [
+ "libc",
+ "pkg-config",
+]
+
+[[package]]
+name = "autocfg"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f8aac770f1885fd7e387acedd76065302551364496e46b3dd00860b2f8359b9d"
+
+[[package]]
+name = "backtrace"
+version = "0.3.44"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e4036b9bf40f3cf16aba72a3d65e8a520fc4bafcdc7079aea8f848c58c5b5536"
+dependencies = [
+ "backtrace-sys",
+ "cfg-if",
+ "libc",
+ "rustc-demangle",
+]
+
+[[package]]
+name = "backtrace-sys"
+version = "0.1.32"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5d6575f128516de27e3ce99689419835fce9643a9b215a14d2b5b685be018491"
+dependencies = [
+ "cc",
+ "libc",
+]
+
+[[package]]
+name = "bindgen"
+version = "0.51.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ebd71393f1ec0509b553aa012b9b58e81dadbdff7130bd3b8cba576e69b32f75"
+dependencies = [
+ "bitflags",
+ "cexpr",
+ "cfg-if",
+ "clang-sys",
+ "lazy_static",
+ "peeking_take_while",
+ "proc-macro2",
+ "quote",
+ "regex",
+ "rustc-hash",
+ "shlex",
+]
+
+[[package]]
+name = "bitflags"
+version = "1.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
+
+[[package]]
+name = "byteorder"
+version = "1.3.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de"
+
+[[package]]
+name = "cc"
+version = "1.0.50"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "95e28fa049fda1c330bcf9d723be7663a899c4679724b34c81e9f5a326aab8cd"
+
+[[package]]
+name = "cexpr"
+version = "0.3.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fce5b5fb86b0c57c20c834c1b412fd09c77c8a59b9473f86272709e78874cd1d"
+dependencies = [
+ "nom",
+]
+
+[[package]]
+name = "cfg-if"
+version = "0.1.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
+
+[[package]]
+name = "clang-sys"
+version = "0.28.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "81de550971c976f176130da4b2978d3b524eaa0fd9ac31f3ceb5ae1231fb4853"
+dependencies = [
+ "glob",
+ "libc",
+ "libloading",
+]
+
+[[package]]
+name = "claxon"
+version = "0.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f86c952727a495bda7abaf09bafdee1a939194dd793d9a8e26281df55ac43b00"
+
+[[package]]
+name = "core-foundation-sys"
+version = "0.6.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e7ca8a5221364ef15ce201e8ed2f609fc312682a8f4e0e3d4aa5879764e0fa3b"
+
+[[package]]
+name = "coreaudio-rs"
+version = "0.9.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f229761965dad3e9b11081668a6ea00f1def7aa46062321b5ec245b834f6e491"
+dependencies = [
+ "bitflags",
+ "coreaudio-sys",
+]
+
+[[package]]
+name = "coreaudio-sys"
+version = "0.2.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7e8f5954c1c7ccb55340443e8b29fca24013545a5e7d72c1ca7db4fc02b982ce"
+dependencies = [
+ "bindgen",
+]
+
+[[package]]
+name = "cpal"
+version = "0.10.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3ded070249be850b5b59e1e3a44a70b8ae395e0e5c65b487131d8909a8208120"
+dependencies = [
+ "alsa-sys",
+ "core-foundation-sys",
+ "coreaudio-rs",
+ "failure",
+ "lazy_static",
+ "libc",
+ "num-traits",
+ "stdweb",
+ "winapi",
+]
+
+[[package]]
+name = "failure"
+version = "0.1.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f8273f13c977665c5db7eb2b99ae520952fe5ac831ae4cd09d80c4c7042b5ed9"
+dependencies = [
+ "backtrace",
+ "failure_derive",
+]
+
+[[package]]
+name = "failure_derive"
+version = "0.1.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0bc225b78e0391e4b8683440bf2e63c2deeeb2ce5189eab46e2b68c6d3725d08"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+ "synstructure",
+]
+
+[[package]]
+name = "glob"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574"
+
+[[package]]
+name = "hound"
+version = "3.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8a164bb2ceaeff4f42542bdb847c41517c78a60f5649671b2a07312b6e117549"
+
+[[package]]
+name = "lazy_static"
+version = "1.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
+
+[[package]]
+name = "lewton"
+version = "0.9.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8d542c1a317036c45c2aa1cf10cc9d403ca91eb2d333ef1a4917e5cb10628bd0"
+dependencies = [
+ "byteorder",
+ "ogg",
+ "smallvec",
+]
+
+[[package]]
+name = "libc"
+version = "0.2.66"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d515b1f41455adea1313a4a2ac8a8a477634fbae63cc6100e3aebb207ce61558"
+
+[[package]]
+name = "libloading"
+version = "0.5.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f2b111a074963af1d37a139918ac6d49ad1d0d5e47f72fd55388619691a7d753"
+dependencies = [
+ "cc",
+ "winapi",
+]
+
+[[package]]
+name = "mach"
+version = "0.2.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "86dd2487cdfea56def77b88438a2c915fb45113c5319bfe7e14306ca4cd0b0e1"
+dependencies = [
+ "libc",
+]
+
+[[package]]
+name = "maybe-uninit"
+version = "2.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "60302e4db3a61da70c0cb7991976248362f30319e88850c487b9b95bbf059e00"
+
+[[package]]
+name = "memchr"
+version = "2.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "53445de381a1f436797497c61d851644d0e8e88e6140f22872ad33a704933978"
+
+[[package]]
+name = "minimp3"
+version = "0.3.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9943faa16a9729ff85d28857d9e4a4e8ac4f47f82a738184cd28d32a50c2bc38"
+dependencies = [
+ "minimp3-sys",
+ "slice-deque",
+]
+
+[[package]]
+name = "minimp3-sys"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c109ae05c00ad6e3a53fab101e2f234545bdd010f0fffd399355efaf70817817"
+dependencies = [
+ "cc",
+]
+
+[[package]]
+name = "nom"
+version = "4.2.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2ad2a91a8e869eeb30b9cb3119ae87773a8f4ae617f41b1eb9c154b2905f7bd6"
+dependencies = [
+ "memchr",
+ "version_check",
+]
+
+[[package]]
+name = "num-traits"
+version = "0.2.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c62be47e61d1842b9170f0fdeec8eba98e60e90e5446449a0545e5152acd7096"
+dependencies = [
+ "autocfg",
+]
+
+[[package]]
+name = "ogg"
+version = "0.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d79f1db9148be9d0e174bb3ac890f6030fcb1ed947267c5a91ee4c91b5a91e15"
+dependencies = [
+ "byteorder",
+]
+
+[[package]]
+name = "peeking_take_while"
+version = "0.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099"
+
+[[package]]
+name = "pkg-config"
+version = "0.3.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "05da548ad6865900e60eaba7f589cc0783590a92e940c26953ff81ddbab2d677"
+
+[[package]]
+name = "proc-macro2"
+version = "1.0.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3acb317c6ff86a4e579dfa00fc5e6cca91ecbb4e7eb2df0468805b674eb88548"
+dependencies = [
+ "unicode-xid",
+]
+
+[[package]]
+name = "quote"
+version = "1.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "053a8c8bcc71fcce321828dc897a98ab9760bef03a4fc36693c231e5b3216cfe"
+dependencies = [
+ "proc-macro2",
+]
+
+[[package]]
+name = "regex"
+version = "1.3.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "322cf97724bea3ee221b78fe25ac9c46114ebb51747ad5babd51a2fc6a8235a8"
+dependencies = [
+ "aho-corasick",
+ "memchr",
+ "regex-syntax",
+ "thread_local",
+]
+
+[[package]]
+name = "regex-syntax"
+version = "0.6.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b28dfe3fe9badec5dbf0a79a9cccad2cfc2ab5484bdb3e44cbd1ae8b3ba2be06"
+
+[[package]]
+name = "rodio"
+version = "0.10.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1e0e0dfa7c8b17c6428f6e992a22ea595922cc86f946191b6b59e7ce96b77262"
+dependencies = [
+ "claxon",
+ "cpal",
+ "hound",
+ "lazy_static",
+ "lewton",
+ "minimp3",
+]
+
+[[package]]
+name = "rustc-demangle"
+version = "0.1.16"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4c691c0e608126e00913e33f0ccf3727d5fc84573623b8d65b2df340b5201783"
+
+[[package]]
+name = "rustc-hash"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
+
+[[package]]
+name = "sampler"
+version = "0.1.0"
+dependencies = [
+ "rodio",
+]
+
+[[package]]
+name = "shlex"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7fdf1b9db47230893d76faad238fd6097fd6d6a9245cd7a4d90dbd639536bbd2"
+
+[[package]]
+name = "slice-deque"
+version = "0.2.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ffddf594f5f597f63533d897427a570dbaa9feabaaa06595b74b71b7014507d7"
+dependencies = [
+ "libc",
+ "mach",
+ "winapi",
+]
+
+[[package]]
+name = "smallvec"
+version = "0.6.13"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f7b0758c52e15a8b5e3691eae6cc559f08eee9406e548a4477ba4e67770a82b6"
+dependencies = [
+ "maybe-uninit",
+]
+
+[[package]]
+name = "stdweb"
+version = "0.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ef5430c8e36b713e13b48a9f709cc21e046723fe44ce34587b73a830203b533e"
+
+[[package]]
+name = "syn"
+version = "1.0.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "af6f3550d8dff9ef7dc34d384ac6f107e5d31c8f57d9f28e0081503f547ac8f5"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "unicode-xid",
+]
+
+[[package]]
+name = "synstructure"
+version = "0.12.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "67656ea1dc1b41b1451851562ea232ec2e5a80242139f7e679ceccfb5d61f545"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+ "unicode-xid",
+]
+
+[[package]]
+name = "thread_local"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d40c6d1b69745a6ec6fb1ca717914848da4b44ae29d9b3080cbee91d72a69b14"
+dependencies = [
+ "lazy_static",
+]
+
+[[package]]
+name = "unicode-xid"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c"
+
+[[package]]
+name = "version_check"
+version = "0.1.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "914b1a6776c4c929a602fafd8bc742e06365d4bcbe48c30f9cca5824f70dc9dd"
+
+[[package]]
+name = "winapi"
+version = "0.3.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6"
+dependencies = [
+ "winapi-i686-pc-windows-gnu",
+ "winapi-x86_64-pc-windows-gnu",
+]
+
+[[package]]
+name = "winapi-i686-pc-windows-gnu"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
+
+[[package]]
+name = "winapi-x86_64-pc-windows-gnu"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"

+ 6 - 34
Cargo.toml

@@ -1,38 +1,10 @@
 [package]
 name = "sampler"
-version = "0.2.0"
-authors = ["mitchmindtree <mitchell.nordine@gmail.com>"]
-description = "A polyphonic audio sampler instrument that supports unique sample mappings across both frequency and velocity ranges."
-readme = "README.md"
-keywords = ["sample", "dsp", "audio", "music", "instrument"]
-license = "MIT OR Apache-2.0"
-repository = "https://github.com/RustAudio/sampler.git"
-homepage = "https://github.com/RustAudio/sampler"
+version = "0.1.0"
+authors = ["Johann Woelper <woelper@gmail.com>"]
+edition = "2018"
 
-[dependencies]
-instrument = "0.2.0"
-pitch_calc = "0.11.0"
-time_calc = "0.11.0"
-sample = "0.6.0"
-
-# optional dependencies
-hound = { optional = true, version = "2.0.0" }
-serde = { optional = true, version = "0.7.0" }
-serde_json = { optional = true, version = "0.7.0" }
-find_folder = { optional = true, version = "0.3.0" }
+# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
 
-[features]
-default = ["wav"]
-wav = ["hound"]
-serde_serialization = [
-    "serde",
-    "serde_json",
-    "time_calc/serde_serialization",
-    "pitch_calc/serde_serialization",
-    "instrument/serde_serialization",
-    "find_folder",
-]
-
-[dev-dependencies]
-find_folder = "0.3.0"
-portaudio = "0.6.4"
+[dependencies]
+rodio = "*"

+ 0 - 13
LICENSE-APACHE

@@ -1,13 +0,0 @@
-Copyright 2016 Mitchell Nordine
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
-    http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.

+ 0 - 21
LICENSE-MIT

@@ -1,21 +0,0 @@
-The MIT License (MIT)
-
-Copyright (c) 2016 Mitchell Nordine
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.

+ 0 - 1
README.md

@@ -1 +0,0 @@
-# sampler [![Build Status](https://travis-ci.org/RustAudio/sampler.svg?branch=master)](https://travis-ci.org/RustAudio/sampler) [![Crates.io](https://img.shields.io/crates/v/sampler.svg)](https://crates.io/crates/sampler) [![Crates.io](https://img.shields.io/crates/l/sampler.svg)](https://github.com/RustAudio/sampler/blob/master/LICENSE)

BIN
assets/thumbpiano A#3.wav


BIN
beep.wav


+ 0 - 64
examples/wav.rs

@@ -1,64 +0,0 @@
-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();
-}
-
-fn run() -> Result<(), pa::Error> {
-
-    // 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);
-
-    // Create a polyphonic sampler.
-    let mut sampler = Sampler::poly((), sample_map).num_voices(4);
-
-    // Initialise PortAudio and create an output stream.
-    let pa = try!(pa::PortAudio::new());
-    let settings = 
-        try!(pa.default_output_stream_settings::<f32>(CHANNELS, SAMPLE_RATE, FRAMES_PER_BUFFER));
-
-    let callback = move |pa::OutputStreamCallbackArgs { buffer, .. }| {
-        let buffer: &mut [[f32; 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
-    };
-
-    let mut stream = try!(pa.open_non_blocking_stream(settings, callback));
-
-    try!(stream.start());
-
-    while let Ok(true) = stream.is_active() {
-        std::thread::sleep(std::time::Duration::from_millis(16));
-    }
-
-    try!(stream.stop());
-    try!(stream.close());
-
-    Ok(())
-}

+ 0 - 255
src/audio.rs

@@ -1,255 +0,0 @@
-use sample;
-use std;
-
-
-/// The audio data that provides the slice of frames that are to be rendered.
-///
-/// By making this a trait instead of a hard type, we can allow users to use their own `Audio`
-/// types which might require other data (i.e. file paths, names, etc) for unique serialization
-/// implementations.
-pub trait Audio: Clone {
-    /// The type of `Frame` data associated with the audio.
-    type Frame: sample::Frame;
-    /// A reference to the slice of frames used to play the audio.
-    fn data(&self) -> &[Self::Frame];
-}
-
-/// A wrapper around `sampler::map::Audio` types that slices a specific range of frames.
-#[derive(Clone, Debug, PartialEq)]
-pub struct Range<A> {
-    /// The start index of the range.
-    pub start: usize,
-    /// The end index of the range.
-    pub end: usize,
-    /// Some audio type that implements `Audio` and can yield a slice of frames.
-    pub audio: A,
-}
-
-
-impl<A> Range<A> {
-    /// Construct a new `Range` with a max playback range.
-    pub fn new(audio: A) -> Self
-        where A: Audio,
-    {
-        Range {
-            start: 0,
-            end: audio.data().len(),
-            audio: audio,
-        }
-    }
-}
-
-impl<A> Audio for std::sync::Arc<A>
-    where A: Audio,
-{
-    type Frame = A::Frame;
-    #[inline]
-    fn data(&self) -> &[Self::Frame] {
-        A::data(self)
-    }
-}
-
-impl<A> Audio for Range<A>
-    where A: Audio,
-{
-    type Frame = A::Frame;
-    #[inline]
-    fn data(&self) -> &[Self::Frame] {
-        let slice = self.audio.data();
-        let len = slice.len();
-        if self.start < len && self.end <= len {
-            &slice[self.start..self.end]
-        } else {
-            &[]
-        }
-    }
-}
-
-
-#[cfg(feature="wav")]
-pub mod wav {
-    use hound;
-    use sample;
-    use std;
-
-
-    /// WAV data loaded into memory as a single contiguous slice of PCM frames.
-    #[derive(Clone, Debug, PartialEq)]
-    pub struct Audio<F> {
-        pub path: std::path::PathBuf,
-        pub data: Box<[F]>,
-        pub sample_hz: f64,
-    }
-
-    /// Errors that may occur during `WAV` loading
-    #[derive(Debug)]
-    pub enum Error {
-        /// Some error returned from the `hound` crate during sample loading.
-        Hound(hound::Error),
-        /// The bit depth of the given WAV file is unsupported.
-        UnsupportedBitsPerSample(u16),
-        /// There is no obvious way to map the given channels described in the WAV spec to the
-        /// number of channels in the `Frame` type.
-        ///
-        /// Contains the source number of channels and the target number of channels.
-        UnsupportedChannelMapping(u16, u16),
-    }
-
-
-    impl<F> super::Audio for Audio<F>
-        where F: sample::Frame,
-    {
-        type Frame = F;
-        fn data(&self) -> &[Self::Frame] {
-            &self.data[..]
-        }
-    }
-
-    impl<F> Audio<F>
-        where F: sample::Frame,
-              F::Sample: sample::Duplex<f64> + sample::Duplex<i32>,
-              Box<[F::Sample]>: sample::ToBoxedFrameSlice<F>,
-    {
-
-        /// Loads a `Sample` from the `.wav` file at the given `path`.
-        ///
-        /// The PCM data retrieved from the file will be:
-        /// - re-sized from its source bit rate to that of the target and
-        /// - re-sampled upon loading (rather than at playback) to the given target sample rate for
-        /// efficiency.
-        pub fn from_file<P>(path: P, target_sample_hz: f64) -> Result<Self, Error>
-            where P: AsRef<std::path::Path>,
-        {
-            use sample::{Frame, Sample, Signal};
-
-            let path = path.as_ref();
-            let mut wav_reader = try!(hound::WavReader::open(path));
-
-            let spec = wav_reader.spec();
-
-            // Collect the samples in a loop so that we may handle any errors if necessary.
-            let mut samples: Vec<F::Sample> = Vec::new();
-
-            // Reads the samples to their correct format type, and then converts them to the target
-            // `F::Sample` type.
-            type WavReader = hound::WavReader<std::io::BufReader<std::fs::File>>;
-            fn fill_samples<S, H>(samples: &mut Vec<S>, mut wav_reader: WavReader)
-                    -> Result<(), hound::Error>
-                where S: sample::FromSample<i32>,
-                      H: sample::Sample + sample::ToSample<i32> + hound::Sample,
-            {
-                for sample in wav_reader.samples() {
-                    let read_sample: H = try!(sample);
-                    let i32_sample: i32 = sample::Sample::to_sample(read_sample);
-                    samples.push(sample::Sample::to_sample(i32_sample));
-                }
-                Ok(())
-            }
-
-            match spec.sample_format {
-                hound::SampleFormat::Float => match spec.bits_per_sample {
-                    32 => try!(fill_samples::<_, f32>(&mut samples, wav_reader)),
-                    n => return Err(Error::UnsupportedBitsPerSample(n)),
-                },
-                hound::SampleFormat::Int => match spec.bits_per_sample {
-                    8 => try!(fill_samples::<_, i8>(&mut samples, wav_reader)),
-                    16 => try!(fill_samples::<_, i16>(&mut samples, wav_reader)),
-                    32 => try!(fill_samples::<_, i32>(&mut samples, wav_reader)),
-                    // The sample crate uses a specific type for 24 bit samples, so this 24-bit sample
-                    // conversion requires this special case.
-                    24 => {
-                        for sample in wav_reader.samples() {
-                            let read_sample: i32 = try!(sample);
-                            let i24_sample = try!(sample::I24::new(read_sample)
-                                .ok_or(hound::Error::FormatError("Incorrectly formatted 24-bit sample \
-                                                            received from hound::read::WavSamples")));
-                            let i32_sample: i32 = sample::Sample::to_sample(i24_sample);
-                            samples.push(sample::Sample::to_sample(i32_sample));
-                        }
-                    },
-                    n => return Err(Error::UnsupportedBitsPerSample(n)),
-                },
-            }
-
-            let boxed_samples = samples.into_boxed_slice();
-            let boxed_frames: Box<[F]> = match (spec.channels, F::n_channels() as u16) {
-
-                // In the case that the `spec` has a different number of channels to the actual
-                // slice, just collect as many valid frames as we can and discard the final
-                // mismatching frame.
-                (source, target) if source == target => {
-                    let samples = boxed_samples.iter().cloned();
-                    let vec: Vec<F> = sample::signal::from_interleaved_samples(samples)
-                        .collect();
-                    vec.into_boxed_slice()
-                },
-
-                // Sum the left and right channels together when mapping to a mono signal.
-                (2, 1) => {
-                    let samples = boxed_samples.iter().cloned();
-                    let vec: Vec<F> = 
-                        sample::signal::from_interleaved_samples::<_, [F::Sample; 2]>(samples)
-                            .filter_map(|f| {
-                                let mut channels = f.channels();
-                                channels.next()
-                                    .and_then(|l| channels.next().map(|r| (l, r)))
-                                    .map(|(l, r)| {
-                                        let sum = l.add_amp(r.to_signed_sample());
-                                        F::from_fn(|_| sum)
-                                    })
-                            })
-                            .collect();
-                    vec.into_boxed_slice()
-                },
-
-                // Simply copy the single mono channel to both channels in the output stereo
-                // signal.
-                (1, 2) => {
-                    let samples = boxed_samples.iter().cloned();
-                    let vec: Vec<F> = samples.map(|s| F::from_fn(|_| s)).collect();
-                    vec.into_boxed_slice()
-                },
-
-                (source, target) => {
-                    return Err(Error::UnsupportedChannelMapping(source, target))
-                },
-                
-            };
-
-            // Convert the sample rate to our target sample rate.
-            let frames: Vec<F> = boxed_frames.iter().cloned()
-                .from_hz_to_hz(spec.sample_rate as f64, target_sample_hz)
-                .collect();
-
-            Ok(Audio {
-                path: path.to_path_buf(),
-                sample_hz: target_sample_hz,
-                data: frames.into_boxed_slice(),
-            })
-        }
-
-    }
-
-    impl From<hound::Error> for Error {
-        fn from(err: hound::Error) -> Self {
-            Error::Hound(err)
-        }
-    }
-
-    impl std::error::Error for Error {
-        fn description(&self) -> &str {
-            match *self {
-                Error::Hound(ref hound) => std::error::Error::description(hound),
-                Error::UnsupportedBitsPerSample(_n_bits) => "unsupported bits per sample",
-                Error::UnsupportedChannelMapping(_source, _target) => "unsupported channel mapping",
-            }
-        }
-    }
-
-    impl std::fmt::Display for Error {
-        fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
-            std::fmt::Debug::fmt(self, f)
-        }
-    }
-
-}

+ 0 - 40
src/dynamic.rs

@@ -1,40 +0,0 @@
-use audio;
-use instrument;
-use map;
-use sampler;
-
-/// An alias for a dynamic `Mode` type.
-pub type Mode = instrument::mode::Dynamic;
-
-/// An alias for a dynamic `NoteFreqGenerator` type.
-pub type NoteFreqGenerator = instrument::note_freq::DynamicGenerator;
-
-/// An alias for a `Sampler` type that uses a dynamic instrument and note frequency mode.
-pub type Sampler<A> = sampler::Sampler<Mode, NoteFreqGenerator, A>;
-
-impl<A> Sampler<A>
-    where A: audio::Audio,
-{
-
-    /// Construct a dynamic `Sampler`.
-    pub fn dynamic(mode: instrument::mode::Dynamic, map: map::Map<A>) -> Self {
-        let nfg = instrument::note_freq::DynamicGenerator::Constant;
-        Self::new(mode, nfg, map)
-    }
-
-    /// Construct a dynamic `Sampler` initialised with a `Mono::Legato` playback mode.
-    pub fn dynamic_legato(map: map::Map<A>) -> Self {
-        Self::dynamic(instrument::mode::Dynamic::legato(), map)
-    }
-
-    /// Construct a dynamic `Sampler` initialised with a `Mono::Retrigger` playback mode.
-    pub fn dynamic_retrigger(map: map::Map<A>) -> Self {
-        Self::dynamic(instrument::mode::Dynamic::retrigger(), map)
-    }
-
-    /// Construct a dynamic `Sampler` initialised with a `Poly` playback mode.
-    pub fn dynamic_poly(map: map::Map<A>) -> Self {
-        Self::dynamic(instrument::mode::Dynamic::poly(), map)
-    }
-
-}

+ 0 - 27
src/lib.rs

@@ -1,27 +0,0 @@
-#[cfg(feature="wav")] extern crate hound;
-pub extern crate instrument;
-pub extern crate sample;
-extern crate pitch_calc as pitch;
-extern crate time_calc as time;
-
-pub use audio::Audio;
-pub use map::{Map, Sample};
-pub use mode::Mode;
-pub use sampler::{Frames, Sampler};
-
-pub mod audio;
-pub mod dynamic;
-pub mod map;
-mod mode;
-mod sampler;
-
-#[cfg(feature="serde_serialization")]
-mod serde;
-
-/// `pitch::Step` represented in discretes intervals, useful for range mapping.
-pub type Step = i16;
-/// The force with which a note was pressed on a keyboard.
-pub type Velocity = f32;
-
-pub const MIN_STEP: Step = 0;
-pub const MAX_STEP: Step = 127;

+ 17 - 0
src/main.rs

@@ -0,0 +1,17 @@
+extern crate rodio;
+
+use std::io::BufReader;
+use std::thread;
+use std::time::Duration;
+
+fn main() {
+    let device = rodio::default_output_device().unwrap();
+
+    let file = std::fs::File::open("beep.wav").unwrap();
+    let beep1 = rodio::play_once(&device, BufReader::new(file)).unwrap();
+    beep1.set_volume(0.2);
+    println!("Started beep1");
+
+    thread::sleep(Duration::from_millis(1500));
+
+}

+ 0 - 237
src/map.rs

@@ -1,237 +0,0 @@
-use {Step, Velocity, MIN_STEP, MAX_STEP};
-use audio::Audio;
-use pitch;
-
-
-/// A type that maps frequncy and velocity ranges to audio samples.
-#[derive(Clone, Debug, PartialEq)]
-pub struct Map<A> {
-    pub pairs: Vec<SampleOverRange<A>>,
-}
-
-/// A performable `Sample` with some base playback Hz and Velocity.
-#[derive(Clone, Debug, PartialEq)]
-pub struct Sample<A> {
-    pub base_hz: pitch::Hz,
-    pub base_vel: Velocity,
-    pub audio: A,
-}
-
-/// A 2-dimensional space, represented as a frequency range and a velocity range.
-#[derive(Clone, Debug, PartialEq, PartialOrd)]
-pub struct StepVelRange {
-    pub step: Range<Step>,
-    pub vel: Range<Velocity>,
-}
-
-/// A range paired with a specific sample.
-#[derive(Clone, Debug, PartialEq)]
-pub struct SampleOverRange<A> {
-    pub range: StepVelRange,
-    pub sample: Sample<A>,
-}
-
-/// A continuous range of `T` from the `min` to the `max`.
-#[derive(Clone, Debug, PartialEq, PartialOrd)]
-pub struct Range<T> {
-    pub min: T,
-    pub max: T,
-}
-
-
-impl Range<Step> {
-    /// Is the given step greater than or equal to the `min` and smaller than the `max`.
-    pub fn is_over(&self, step: Step) -> bool {
-        self.min <= step && step <= self.max
-    }
-}
-
-impl Range<Velocity> {
-    /// Is the given velocity greater than or equal to the `min` and smaller than the `max`.
-    pub fn is_over(&self, vel: Velocity) -> bool {
-        self.min <= vel && vel <= self.max
-    }
-}
-
-impl<A> Sample<A> {
-
-    /// Constructor for a new `Sample` with the given base Hz and Velocity.
-    pub fn new(base_hz: pitch::Hz, base_vel: Velocity, audio: A) -> Self {
-        Sample {
-            base_hz: base_hz,
-            base_vel: base_vel,
-            audio: audio,
-        }
-    }
-
-    /// Maps the `Sample` with some `Audio` type `A` to a `Sample` with some `Audio` type `B`.
-    pub fn map_audio<F, B>(self, map: F) -> Sample<B>
-        where F: FnOnce(A) -> B,
-    {
-        let Sample { base_hz, base_vel, audio } = self;
-        Sample {
-            base_hz: base_hz,
-            base_vel: base_vel,
-            audio: map(audio),
-        }
-    }
-
-}
-
-impl<A> Map<A>
-    where A: Audio,
-{
-
-    /// Construct an empty `Map`.
-    pub fn empty() -> Self {
-        Map { pairs: vec![] }
-    }
-
-    /// Construct a `Map` from a series of mappings, starting from (-C2, 1.0).
-    pub fn from_sequential_steps<I>(mappings: I) -> Self
-        where I: IntoIterator<Item=(Step, Velocity, Sample<A>)>,
-    {
-        let (mut last_step, mut last_vel) = (0, 1.0);
-        let pairs = mappings.into_iter().map(|(step, vel, sample)| {
-            let range = StepVelRange {
-                step: Range { min: last_step, max: step },
-                vel: Range { min: last_vel, max: vel },
-            };
-            last_step = step;
-            last_vel = vel;
-            SampleOverRange { range: range, sample: sample }
-        }).collect();
-        Map { pairs: pairs }
-    }
-
-    /// Creates a `Map` with a single sample mapped to the entire Step and Velocity range.
-    pub fn from_single_sample(sample: Sample<A>) -> Self {
-        let range = StepVelRange {
-            step: Range { min: MIN_STEP, max: MAX_STEP },
-            vel: Range { min: 0.0, max: 1.0 },
-        };
-        let pairs = vec![SampleOverRange { range: range, sample: sample }];
-        Map { pairs: pairs }
-    }
-
-    /// Inserts a range -> audio mapping into the Map.
-    pub fn insert(&mut self, range: StepVelRange, sample: Sample<A>) {
-        for i in 0..self.pairs.len() {
-            if self.pairs[i].range > range {
-                self.pairs.insert(i, SampleOverRange { range: range, sample: sample });
-                return;
-            }
-        }
-        self.pairs.push(SampleOverRange { range: range, sample: sample });
-    }
-
-    /// Returns the `Audio` associated with the range within which the given hz and velocity exist.
-    ///
-    /// TODO: This would probably be quicker with some sort of specialised RangeMap.
-    pub fn sample(&self, hz: pitch::Hz, vel: Velocity) -> Option<Sample<A>> {
-        let step = hz.step().round() as Step;
-        for &SampleOverRange { ref range, ref sample } in &self.pairs {
-            if range.step.is_over(step) && range.vel.is_over(vel) {
-                return Some(sample.clone());
-            }
-        }
-        None
-    }
-
-}
-
-
-#[cfg(feature="wav")]
-pub mod wav {
-    use audio;
-    use map;
-    use pitch;
-    use sample;
-    use std;
-
-
-    /// An alias for the `wav` `Sample` type.
-    pub type Sample<F> = super::Sample<std::sync::Arc<audio::wav::Audio<F>>>;
-
-
-    impl<F> Sample<F>
-        where F: sample::Frame,
-              F::Sample: sample::Duplex<f64> + sample::Duplex<i32>,
-              Box<[F::Sample]>: sample::ToBoxedFrameSlice<F>,
-    {
-
-        /// Loads a `Sample` from the `.wav` file at the given `path`.
-        ///
-        /// If the `.wav` file has a musical note in the file name, that note's playback frequency in
-        /// `hz` will be used as the `base_hz`.
-        ///
-        /// If a musical note cannot be determined automatically, a default `C1` will be used.
-        ///
-        /// The PCM data retrieved from the file will be re-sampled upon loading (rather than at
-        /// playback) to the given target sample rate for efficiency.
-        pub fn from_wav_file<P>(path: P, target_sample_hz: f64) -> Result<Self, audio::wav::Error>
-            where P: AsRef<std::path::Path>,
-        {
-            let path = path.as_ref();
-
-            const DEFAULT_LETTER_OCTAVE: pitch::LetterOctave = pitch::LetterOctave(pitch::Letter::C, 1);
-            let base_letter_octave = read_base_letter_octave(path).unwrap_or(DEFAULT_LETTER_OCTAVE);
-            let base_hz = base_letter_octave.to_hz();
-            let base_vel = 1.0;
-
-            let audio = std::sync::Arc::new(try!(audio::wav::Audio::from_file(path, target_sample_hz)));
-
-            Ok(map::Sample::new(base_hz, base_vel, audio))
-        }
-    }
-
-
-    /// Scans the given path for an indication of its pitch.
-    fn read_base_letter_octave(path: &std::path::Path) -> Option<pitch::LetterOctave> {
-        use pitch::Letter::*;
-        use std::ascii::AsciiExt;
-
-        let s = path.to_str().map_or("".into(), |s| s.to_ascii_lowercase());
-
-        // Check to see if the path contains a note for the given `letter` for any octave
-        // between -8 and 24. If so, return the `LetterOctave`.
-        let contains_letter = |letter: &str| -> Option<pitch::LetterOctave> {
-            for i in -8i8..24 {
-                let pattern = format!("{}{}", letter, i);
-                if s.contains(&pattern) {
-                    let letter = match letter {
-                        "c" => C,
-                        "c#" | "csh" => Csh,
-                        "d" => D,
-                        "d#" | "dsh" => Dsh,
-                        "e" => E,
-                        "f" => F,
-                        "f#" | "fsh" => Fsh,
-                        "g" => G,
-                        "g#" | "gsh" => Gsh,
-                        "a" => A,
-                        "a#" | "ash" => Ash,
-                        "b" => B,
-                        _ => unreachable!(),
-                    };
-                    return Some(pitch::LetterOctave(letter, i as pitch::Octave));
-                }
-            }
-            None
-        };
-
-        let list = [
-            "c", "c#", "csh", "d", "d#", "dsh", "e", "f", "f#", "fsh", "g", "g#", "gsh",
-            "a", "a#", "ash", "b",
-        ];
-
-        for letter in &list[..] {
-            if let Some(letter_octave) = contains_letter(letter) {
-                return Some(letter_octave);
-            }
-        }
-
-        None
-    }
-
-}

+ 0 - 199
src/mode.rs

@@ -1,199 +0,0 @@
-use audio::Audio;
-use instrument;
-use map::Map;
-use pitch;
-use sampler::PlayingSample;
-use std;
-use Velocity;
-
-pub use instrument::mode::{Mono, MonoKind, Poly, Dynamic};
-
-/// 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<A>(&self,
-                  note_hz: pitch::Hz,
-                  note_velocity: Velocity,
-                  map: &Map<A>,
-                  voices: &mut [Option<PlayingSample<A>>])
-        where A: Audio;
-
-    /// Handle a `note_off` event.
-    fn note_off<A>(&self,
-                   note_hz: pitch::Hz,
-                   map: &Map<A>,
-                   voices: &mut [Option<PlayingSample<A>>])
-        where A: Audio;
-}
-
-
-// Helper function for constructing a `PlayingSample`.
-fn play_sample<A>(hz: pitch::Hz, vel: Velocity, map: &Map<A>) -> Option<PlayingSample<A>>
-    where A: Audio,
-{
-    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<A>(idx: usize,
-                                    hz: pitch::Hz,
-                                    vel: Velocity,
-                                    map: &Map<A>) -> Option<PlayingSample<A>>
-    where A: Audio,
-{
-    map.sample(hz, vel).map(|sample| PlayingSample::from_playhead_idx(idx, hz, vel, sample))
-}
-
-
-impl Mode for Mono {
-
-    fn note_on<A>(&self,
-                  note_hz: pitch::Hz,
-                  note_vel: Velocity,
-                  map: &Map<A>,
-                  voices: &mut [Option<PlayingSample<A>>])
-        where A: Audio,
-    {
-        let Mono(ref kind, ref note_stack) = *self;
-
-        // If we're in `Legato` mode, begin the note from the same index as the previous note's
-        // current state if there is one.
-        let sample = if let instrument::mode::MonoKind::Legato = *kind {
-            note_stack.last()
-                .and_then(|&last_hz| {
-                    voices.iter()
-                        .filter_map(|v| v.as_ref())
-                        .find(|sample| instrument::mode::does_hz_match(sample.note_on_hz.hz(), last_hz))
-                        .and_then(|sample| {
-                            let idx = sample.rate_converter.source().idx;
-                            play_sample_from_playhead_idx(idx, note_hz, note_vel, map)
-                        })
-                })
-                .or_else(|| play_sample(note_hz, note_vel, map))
-        // Otherwise, we're in `Retrigger` mode, so start from the beginning of the sample.
-        } else {
-            play_sample(note_hz, note_vel, map)
-        };
-
-        if let Some(sample) = sample {
-            for voice in voices {
-                *voice = Some(sample.clone());
-            }
-        }
-    }
-
-    fn note_off<A>(&self,
-                   note_hz: pitch::Hz,
-                   map: &Map<A>,
-                   voices: &mut [Option<PlayingSample<A>>])
-        where A: Audio,
-    {
-        let Mono(kind, ref note_stack) = *self;
-
-        let should_reset = voices.iter()
-            .filter_map(|v| v.as_ref())
-            .any(|v| instrument::mode::does_hz_match(v.note_on_hz.hz(), note_hz.hz()));
-
-        if !should_reset {
-            return;
-        }
-
-        // If there is some note to fall back to, do so.
-        if let Some(&fallback_note_hz) = note_stack.last() {
-            let hz = fallback_note_hz.into();
-            for voice in voices {
-                if let Some(ref mut playing_sample) = *voice {
-                    let idx = match kind {
-                        MonoKind::Retrigger => 0,
-                        MonoKind::Legato => playing_sample.rate_converter.source().idx,
-                    };
-                    let vel = playing_sample.note_on_vel;
-                    if let Some(sample) = play_sample_from_playhead_idx(idx, hz, vel, map) {
-                        *playing_sample = sample;
-                    }
-                }
-            }
-        }
-
-        // No need to manually set voices to `None` as this will be done when frames yielded by
-        // `instrument` run out.
-    }
-
-}
-
-impl Mode for Poly {
-
-    fn note_on<A>(&self,
-                  note_hz: pitch::Hz,
-                  note_vel: Velocity,
-                  map: &Map<A>,
-                  voices: &mut [Option<PlayingSample<A>>])
-        where A: Audio,
-    {
-        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 oldest_time_of_note_on = std::time::Instant::now();
-        for voice in voices.iter_mut() {
-            if let None = *voice {
-                *voice = Some(sample);
-                return;
-            }
-            let time_of_note_on = voice.as_ref().unwrap().time_of_note_on;
-            if time_of_note_on < oldest_time_of_note_on {
-                oldest_time_of_note_on = time_of_note_on;
-                oldest = voice.as_mut();
-            }
-        }
-        if let Some(voice) = oldest {
-            *voice = sample;
-        }
-    }
-
-    fn note_off<A>(&self,
-                   _note_hz: pitch::Hz,
-                   _map: &Map<A>,
-                   _voices: &mut [Option<PlayingSample<A>>])
-        where A: Audio,
-    {
-        // No need to do anything here as voices will be set to `None` when frames yielded by
-        // `instrument` run out.
-    }
-
-}
-
-impl Mode for Dynamic {
-
-    fn note_on<A>(&self,
-                  note_hz: pitch::Hz,
-                  note_vel: Velocity,
-                  map: &Map<A>,
-                  voices: &mut [Option<PlayingSample<A>>])
-        where A: Audio,
-    {
-        match *self {
-            Dynamic::Mono(ref mono) => mono.note_on(note_hz, note_vel, map, voices),
-            Dynamic::Poly(ref poly) => poly.note_on(note_hz, note_vel, map, voices),
-        }
-    }
-
-    fn note_off<A>(&self,
-                   note_hz: pitch::Hz,
-                   map: &Map<A>,
-                   voices: &mut [Option<PlayingSample<A>>])
-        where A: Audio,
-    {
-        match *self {
-            Dynamic::Mono(ref mono) => mono.note_off(note_hz, map, voices),
-            Dynamic::Poly(ref poly) => poly.note_off(note_hz, map, voices),
-        }
-    }
-
-}

+ 0 - 400
src/sampler.rs

@@ -1,400 +0,0 @@
-use audio::Audio;
-use instrument::{self, Instrument};
-use map::{self, Map};
-use pitch;
-use sample::{self, Frame, Sample as PcmSample};
-use std;
-use time;
-use Velocity;
-
-/// A Sampler instrument.
-#[derive(Clone, Debug)]
-pub struct Sampler<M, NFG, A>
-    where NFG: instrument::NoteFreqGenerator,
-          A: Audio,
-{
-    pub instrument: Instrument<M, NFG>,
-    pub map: Map<A>,
-    voices: Voices<A>,
-}
-
-/// Samples that are currently active along with the `Hz` with which they were triggered.
-///
-/// A new pair is pushed on each `note_on`, and pairs are removed on their associated `note_off`.
-///
-/// In `Mono` mode, the sampler always fills the buffer using the last pair on the stack.
-///
-/// In `Poly` mode, each pair is mapped directly to each of the `Instrument`'s `voices` via their
-/// `Vec` indices.
-#[derive(Clone)]
-pub struct Voices<A>
-    where A: Audio,
-{
-    map: Vec<Option<PlayingSample<A>>>,
-}
-
-/// A sample that is currently being played back.
-#[derive(Clone)]
-pub struct PlayingSample<A>
-    where A: Audio,
-{
-    /// The pitch in hz at which the `note_on` was triggered.
-    pub note_on_hz: pitch::Hz,
-    pub note_on_vel: Velocity,
-    base_hz: pitch::Hz,
-    base_vel: Velocity,
-    /// Rate-adjustable interpolation of audio.
-    pub rate_converter: sample::rate::Converter<Playhead<A>>,
-    /// The time at which the `PlayingSample` was constructed.
-    pub time_of_note_on: std::time::Instant,
-}
-
-/// An owned iterator that wraps an audio file but does not 
-#[derive(Clone)]
-pub struct Playhead<A>
-    where A: Audio,
-{
-    /// The position of the playhead over the `Sample`.
-    pub idx: usize,
-    audio: A,
-}
-
-/// An iterator yielding one frame from the `Sampler` at a time.
-pub struct Frames<'a, A: 'a, NF: 'a>
-    where A: Audio,
-{
-    voices: &'a mut Voices<A>,
-    instrument_frames: instrument::Frames<'a, NF>,
-}
-
-
-impl<A> std::fmt::Debug for Voices<A>
-    where A: Audio,
-{
-    fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
-        write!(f, "Voices {{ num: {:?} }}", self.map.len())
-    }
-}
-
-impl<NFG, A> Sampler<instrument::mode::Mono, NFG, A>
-    where NFG: instrument::NoteFreqGenerator,
-          A: Audio,
-{
-    /// Construct a `Sampler` with a `Mono::Legato` playback mode.
-    pub fn legato(nfg: NFG, map: Map<A>) -> Self {
-        Self::new(instrument::mode::Mono::legato(), nfg, map)
-    }
-}
-
-impl<NFG, A> Sampler<instrument::mode::Mono, NFG, A>
-    where NFG: instrument::NoteFreqGenerator,
-          A: Audio,
-{
-    /// Construct a `Sampler` with a `Mono::Retrigger` playback mode.
-    pub fn retrigger(nfg: NFG, map: Map<A>) -> Self {
-        Self::new(instrument::mode::Mono::retrigger(), nfg, map)
-    }
-}
-
-impl<NFG, A> Sampler<instrument::mode::Poly, NFG, A>
-    where NFG: instrument::NoteFreqGenerator,
-          A: Audio,
-{
-    /// Construct a `Sampler` with a `Poly` playback mode.
-    pub fn poly(nfg: NFG, map: Map<A>) -> Self {
-        Self::new(instrument::mode::Poly, nfg, map)
-    }
-}
-
-
-impl<M, NFG, A> Sampler<M, NFG, A>
-    where NFG: instrument::NoteFreqGenerator,
-          A: Audio,
-{
-
-    /// Construct a new `Sampler`.
-    pub fn new(mode: M, note_freq_gen: NFG, map: Map<A>) -> Self {
-        let instrument = Instrument::new(mode, note_freq_gen);
-        let n_voices = instrument.voices.len();
-        Sampler {
-            map: map,
-            voices: Voices { map: vec![None; n_voices] },
-            instrument: instrument,
-        }
-    }
-
-    /// Map the `Instrument` to a new `Instrument` in place.
-    ///
-    /// This is useful for providing wrapper builder methods for the Synth.
-    #[inline]
-    pub fn map_instrument<Map, NewM, NewNFG>(self, f: Map) -> Sampler<NewM, NewNFG, A>
-        where Map: FnOnce(Instrument<M, NFG>) -> Instrument<NewM, NewNFG>,
-              NewNFG: instrument::NoteFreqGenerator,
-    {
-        let Sampler {
-            map,
-            voices,
-            instrument,
-        } = self;
-
-        Sampler {
-            map: map,
-            voices: voices,
-            instrument: f(instrument),
-        }
-    }
-
-    /// Build the `Sampler` with the given number of voices.
-    pub fn num_voices(mut self, n: usize) -> Self {
-        self.set_num_voices(n);
-        self
-    }
-
-    /// Return the number of voices for use within the `Sampler`.
-    pub fn voice_count(&self) -> usize {
-        self.voices.map.len()
-    }
-
-    /// Detune the `note_on` hz by the given amount.
-    pub fn detune(self, detune: f32) -> Self {
-        self.map_instrument(|inst| inst.detune(detune))
-    }
-
-    /// Set the attack.
-    pub fn attack<Attack>(self, attack: Attack) -> Self
-        where Attack: Into<time::Ms>,
-    {
-        self.map_instrument(|inst| inst.attack(attack))
-    }
-
-    /// Set the release.
-    pub fn release<Release>(self, release: Release) -> Self
-        where Release: Into<time::Ms>,
-    {
-        self.map_instrument(|inst| inst.release(release))
-    }
-
-    /// Set the number of voices to use for 
-    pub fn set_num_voices(&mut self, n: usize) {
-        self.instrument.set_num_voices(n);
-        self.voices.map.resize(n, None);
-    }
-
-    /// Begin playback of a note.
-    #[inline]
-    pub fn note_on<T>(&mut self, note_hz: T, note_vel: Velocity)
-        where M: instrument::Mode + super::Mode,
-              T: Into<pitch::Hz>
-    {
-        let Sampler { ref mut instrument, ref mut voices, ref map, .. } = *self;
-        let hz = note_hz.into();
-        instrument.note_on(hz, note_vel);
-        super::Mode::note_on(&mut instrument.mode, hz, note_vel, map, &mut voices.map);
-    }
-
-    /// Stop playback of the note that was triggered with the matching frequency.
-    #[inline]
-    pub fn note_off<T>(&mut self, note_hz: T)
-        where M: instrument::Mode + super::Mode,
-              T: Into<pitch::Hz>
-    {
-        let Sampler { ref mut instrument, ref mut voices, ref map, .. } = *self;
-        let hz = note_hz.into();
-        super::Mode::note_off(&mut instrument.mode, hz, map, &mut voices.map);
-        instrument.note_off(hz);
-    }
-
-    /// Stop playback and clear the current notes.
-    #[inline]
-    pub fn stop(&mut self)
-        where M: instrument::Mode,
-    {
-        let Sampler { ref mut instrument, ref mut voices, .. } = *self;
-        instrument.stop();
-        voices.map.clear();
-    }
-
-    /// Produces an iterator that yields `Frame`s of audio data.
-    pub fn frames(&mut self, sample_hz: f64) -> Frames<A, NFG::NoteFreq>
-        where A: Audio,
-              <A::Frame as Frame>::Sample: sample::Duplex<f64>,
-              <<A::Frame as Frame>::Sample as PcmSample>::Float: sample::FromSample<f32>,
-    {
-        Frames {
-            voices: &mut self.voices,
-            instrument_frames: self.instrument.frames(sample_hz),
-        }
-    }
-
-    /// Returns whether or not the `Sampler` is currently playing any notes.
-    pub fn is_active(&self) -> bool {
-        for voice in &self.voices.map {
-            if voice.is_some() {
-                return true;
-            }
-        }
-        false
-    }
-
-    /// Fills the given slice of frames with the `Sampler::frames` iterator.
-    pub fn fill_slice<F>(&mut self, output: &mut [F], sample_hz: f64)
-        where F: Frame,
-              F::Sample: sample::Duplex<f64>,
-              <F::Sample as PcmSample>::Float: sample::FromSample<f32>,
-              A: Audio<Frame=F>,
-    {
-        let mut frames = self.frames(sample_hz);
-        sample::slice::map_in_place(output, |f| {
-            f.zip_map(frames.next_frame(), |a, b| {
-                a.add_amp(b.to_sample::<<F::Sample as PcmSample>::Signed>())
-            })
-        });
-    }
-
-}
-
-
-#[cfg(feature="serde_serialization")]
-pub mod private {
-    use audio::Audio;
-    use instrument::{self, Instrument};
-    use map::Map;
-
-    /// A private constructor for use within serde.rs.
-    pub fn new<M, NFG, A>(instrument: Instrument<M, NFG>,
-                          map: Map<A>,
-                          num_voices: usize) -> super::Sampler<M, NFG, A>
-        where NFG: instrument::NoteFreqGenerator,
-              A: Audio,
-    {
-        super::Sampler {
-            instrument: instrument,
-            map: map,
-            voices: super::Voices { map: vec![None; num_voices] },
-        }
-    }
-}
-
-
-impl<A> PlayingSample<A>
-    where A: Audio,
-{
-
-    /// Construct a new `PlayingSample` from the given note hz, velocity and the associated
-    /// `Sample` from the `Map`.
-    pub fn new(hz: pitch::Hz, vel: Velocity, sample: map::Sample<A>) -> Self {
-        Self::from_playhead_idx(0, hz, vel, sample)
-    }
-
-    /// Construct a new `PlayingSample` from the given note hz, velocity and the associated
-    /// `Sample` from the `Map`.
-    ///
-    /// The given `Sample`'s audio will begin playing from the given `idx`.
-    pub fn from_playhead_idx(idx: usize,
-                             hz: pitch::Hz,
-                             vel: Velocity,
-                             sample: map::Sample<A>) -> Self
-    {
-        let map::Sample { base_hz, base_vel, audio } = sample;
-        let playhead = Playhead::from_idx(idx, audio);
-        let rate_converter = sample::rate::Converter::scale_playback_hz(playhead, 1.0);
-        PlayingSample {
-            note_on_hz: hz,
-            note_on_vel: vel,
-            base_hz: base_hz,
-            base_vel: base_vel,
-            rate_converter: rate_converter,
-            time_of_note_on: std::time::Instant::now(),
-        }
-    }
-
-}
-
-
-impl<A> Playhead<A>
-    where A: Audio,
-{
-    /// Wrap the given `Audio` with a `Playhead` starting from 0.
-    pub fn new(audio: A) -> Self {
-        Self::from_idx(0, audio)
-    }
-
-    /// Wrap the given `Audio` with a `Playhead` starting from the given playhead index.
-    pub fn from_idx(idx: usize, audio: A) -> Self {
-        Playhead {
-            idx: idx,
-            audio: audio,
-        }
-    }
-}
-
-impl<A> Iterator for Playhead<A>
-    where A: Audio,
-{
-    type Item = A::Frame;
-    #[inline]
-    fn next(&mut self) -> Option<Self::Item> {
-        let idx = self.idx;
-        self.idx += 1;
-        Audio::data(&self.audio).get(idx).map(|&f| f)
-    }
-}
-
-
-impl<'a, A, NF> Frames<'a, A, NF>
-    where A: Audio,
-          <A::Frame as Frame>::Sample: sample::Duplex<f64>,
-          <<A::Frame as Frame>::Sample as PcmSample>::Float: sample::FromSample<f32>,
-          NF: instrument::NoteFreq,
-{
-    /// Yields the next audio `Frame`.
-    #[inline]
-    pub fn next_frame(&mut self) -> A::Frame {
-        let Frames {
-            ref mut voices,
-            ref mut instrument_frames,
-        } = *self;
-
-        let frame_per_voice = instrument_frames.next_frame_per_voice();
-        let equilibrium = <A::Frame as Frame>::equilibrium();
-        voices.map.iter_mut()
-            .zip(frame_per_voice)
-            .fold(equilibrium, |frame, (voice, amp_hz)| {
-                if let Some((amp, hz)) = amp_hz {
-                    match *voice {
-                        None => return frame,
-                        Some(ref mut voice) => {
-                            let playback_hz_scale = hz / voice.base_hz.hz();
-                            voice.rate_converter.set_playback_hz_scale(playback_hz_scale as f64);
-                            match voice.rate_converter.next_frame() {
-                                Some(wave) => {
-                                    let amp = amp * voice.base_vel;
-                                    let scaled = wave.scale_amp(amp.to_sample());
-                                    return frame.zip_map(scaled, |f, s| {
-                                        f.add_amp(s.to_sample::<<<A::Frame as Frame>::Sample as PcmSample>::Signed>())
-                                    });
-                                },
-                                None => return frame,
-                            }
-                        },
-                    }
-                }
-
-                // If we made it this far, the voice has finished playback of the note.
-                *voice = None;
-                frame
-            })
-    }
-}
-
-impl<'a, A, NF> Iterator for Frames<'a, A, NF>
-    where A: Audio,
-          <A::Frame as Frame>::Sample: sample::Duplex<f64>,
-          <<A::Frame as Frame>::Sample as PcmSample>::Float: sample::FromSample<f32>,
-          NF: instrument::NoteFreq,
-{
-    type Item = A::Frame;
-    fn next(&mut self) -> Option<Self::Item> {
-        Some(self.next_frame())
-    }
-}

File diff suppressed because it is too large
+ 0 - 1219
src/serde.rs