Przeglądaj źródła

Merge pull request #6 from mitchmindtree/develop

Change HzRange to StepRange. Move Audio to its own crate. Introduce audio::Range type. Update to latest hound.
mitchmindtree 8 lat temu
rodzic
commit
18d3af6341
8 zmienionych plików z 532 dodań i 362 usunięć
  1. 4 4
      Cargo.toml
  2. 255 0
      src/audio.rs
  3. 2 1
      src/dynamic.rs
  4. 9 1
      src/lib.rs
  5. 26 281
      src/map.rs
  6. 14 13
      src/mode.rs
  7. 22 20
      src/sampler.rs
  8. 200 42
      src/serde.rs

+ 4 - 4
Cargo.toml

@@ -1,6 +1,6 @@
 [package]
 name = "sampler"
-version = "0.1.0"
+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"
@@ -10,13 +10,13 @@ repository = "https://github.com/RustAudio/sampler.git"
 homepage = "https://github.com/RustAudio/sampler"
 
 [dependencies]
-instrument = "0.1.0"
+instrument = "0.2.0"
 pitch_calc = "0.11.0"
 time_calc = "0.11.0"
 sample = "0.6.0"
 
 # optional dependencies
-hound = { optional = true, version = "1.1.0" }
+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" }
@@ -35,4 +35,4 @@ serde_serialization = [
 
 [dev-dependencies]
 find_folder = "0.3.0"
-portaudio = "0.6.2"
+portaudio = "0.6.4"

+ 255 - 0
src/audio.rs

@@ -0,0 +1,255 @@
+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)
+        }
+    }
+
+}

+ 2 - 1
src/dynamic.rs

@@ -1,3 +1,4 @@
+use audio;
 use instrument;
 use map;
 use sampler;
@@ -12,7 +13,7 @@ pub type NoteFreqGenerator = instrument::note_freq::DynamicGenerator;
 pub type Sampler<A> = sampler::Sampler<Mode, NoteFreqGenerator, A>;
 
 impl<A> Sampler<A>
-    where A: map::Audio,
+    where A: audio::Audio,
 {
 
     /// Construct a dynamic `Sampler`.

+ 9 - 1
src/lib.rs

@@ -4,10 +4,12 @@ pub extern crate sample;
 extern crate pitch_calc as pitch;
 extern crate time_calc as time;
 
-pub use map::{Audio, Map, Sample};
+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;
@@ -16,4 +18,10 @@ 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;

+ 26 - 281
src/map.rs

@@ -1,7 +1,6 @@
+use {Step, Velocity, MIN_STEP, MAX_STEP};
+use audio::Audio;
 use pitch;
-use sample;
-use std;
-use Velocity;
 
 
 /// A type that maps frequncy and velocity ranges to audio samples.
@@ -10,18 +9,6 @@ pub struct Map<A> {
     pub pairs: Vec<SampleOverRange<A>>,
 }
 
-/// 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 performable `Sample` with some base playback Hz and Velocity.
 #[derive(Clone, Debug, PartialEq)]
 pub struct Sample<A> {
@@ -32,15 +19,15 @@ pub struct Sample<A> {
 
 /// A 2-dimensional space, represented as a frequency range and a velocity range.
 #[derive(Clone, Debug, PartialEq, PartialOrd)]
-pub struct HzVelRange {
-    pub hz: Range<pitch::Hz>,
+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: HzVelRange,
+    pub range: StepVelRange,
     pub sample: Sample<A>,
 }
 
@@ -52,19 +39,10 @@ pub struct Range<T> {
 }
 
 
-impl<T> Audio for std::sync::Arc<T>
-    where T: Audio,
-{
-    type Frame = T::Frame;
-    fn data(&self) -> &[Self::Frame] {
-        T::data(self)
-    }
-}
-
-impl Range<pitch::Hz> {
-    /// Is the given hz greater than or equal to the `min` and smaller than the `max`.
-    pub fn is_over(&self, hz: pitch::Hz) -> bool {
-        self.min <= hz && hz < self.max
+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
     }
 }
 
@@ -110,27 +88,26 @@ impl<A> Map<A>
     }
 
     /// Construct a `Map` from a series of mappings, starting from (-C2, 1.0).
-    pub fn from_sequential_mappings<I>(mappings: I) -> Self
-        where I: IntoIterator<Item=(pitch::Hz, Velocity, Sample<A>)>,
+    pub fn from_sequential_steps<I>(mappings: I) -> Self
+        where I: IntoIterator<Item=(Step, Velocity, Sample<A>)>,
     {
-        const MIN_HZ: pitch::Hz = pitch::Hz(0.0);
-        let (mut last_hz, mut last_vel) = (MIN_HZ, 1.0);
-        let pairs = mappings.into_iter().map(|(hz, vel, sample)| {
-            let range = HzVelRange {
-                hz: Range { min: last_hz, max: hz },
+        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_hz = hz;
+            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 Hz and Velocity range.
+    /// 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 = HzVelRange {
-            hz: Range { min: pitch::Hz(0.0), max: pitch::Hz(std::f32::MAX) },
+        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 }];
@@ -138,7 +115,7 @@ impl<A> Map<A>
     }
 
     /// Inserts a range -> audio mapping into the Map.
-    pub fn insert(&mut self, range: HzVelRange, sample: Sample<A>) {
+    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 });
@@ -152,8 +129,9 @@ impl<A> Map<A>
     ///
     /// 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.hz.is_over(hz) && range.vel.is_over(vel) {
+            if range.step.is_over(step) && range.vel.is_over(vel) {
                 return Some(sample.clone());
             }
         }
@@ -165,120 +143,16 @@ impl<A> Map<A>
 
 #[cfg(feature="wav")]
 pub mod wav {
-    use hound;
+    use audio;
     use map;
     use pitch;
     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,
-    }
 
     /// An alias for the `wav` `Sample` type.
-    pub type Sample<F> = super::Sample<std::sync::Arc<Audio<F>>>;
-
-    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>,
-    {
+    pub type Sample<F> = super::Sample<std::sync::Arc<audio::wav::Audio<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, hound::Error>
-            where P: AsRef<std::path::Path>,
-        {
-            use sample::Signal;
-
-            let path = path.as_ref();
-            let mut wav_reader = try!(hound::WavReader::open(path));
-
-            let spec = wav_reader.spec();
-            // TODO: Return an error instead of panic!ing! OR do some sort of frame /
-            // channel layout conversion.
-            assert!(spec.channels as usize == F::n_channels(),
-                    "The number of channels in the audio file differs from the number of \
-                    channels in the frame");
-
-            // 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.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));
-                    }
-                },
-                _ => return Err(hound::Error::Unsupported),
-            }
-
-            let boxed_samples = samples.into_boxed_slice();
-            let boxed_frames: Box<[F]> = match sample::slice::to_boxed_frame_slice(boxed_samples) {
-                Some(slice) => slice,
-                // TODO: Return an error instead of panic!ing! OR do some sort of frame /
-                // channel layout conversion.
-                None => panic!("The number of samples produced from the wav file does not \
-                               match the number of channels ({}) in the given `Frame` type",
-                               F::n_channels()),
-            };
-
-            // 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<F> Sample<F>
         where F: sample::Frame,
@@ -295,7 +169,7 @@ pub mod wav {
         ///
         /// 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, hound::Error>
+        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();
@@ -305,141 +179,12 @@ pub mod wav {
             let base_hz = base_letter_octave.to_hz();
             let base_vel = 1.0;
 
-            let audio = std::sync::Arc::new(try!(Audio::from_file(path, target_sample_hz)));
+            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))
         }
     }
 
-    // impl<F> map::Map<F>
-    //     where F: sample::Frame,
-    //           F::Sample: sample::Duplex<f64> + hound::Sample,
-    //           Box<[F::Sample]>: sample::ToBoxedFrameSlice<F>,
-    // {
-
-    //     /// Loads a `Map` from the given directory.
-    //     ///
-    //     /// All `.wav` files that can be successfully loaded will be loaded into the `Map`.
-    //     ///
-    //     /// 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`.
-    //     ///
-    //     /// For efficiency, all files will be re-sampled upon loading (rather than at playback) to the
-    //     /// given target sample rate.
-    //     pub fn from_wav_directory<P>(path: P, target_sample_hz: f64) -> Result<Self, hound::Error>
-    //         where P: AsRef<std::path::Path>,
-    //     {
-    //         use sample::Signal;
-    //         use std::cmp::Ordering;
-
-    //         let path = path.as_ref();
-
-    //         struct SampleReader {
-    //             base_letter_octave: Option<pitch::LetterOctave>,
-    //             wav_reader: hound::WavReader<std::io::BufReader<std::fs::File>>,
-    //         }
-
-    //         let mut sample_readers: Vec<SampleReader> = Vec::new();
-
-    //         // Find all .wav files in the given directory and store them as `SampleReader`s.
-    //         for entry in try!(std::fs::read_dir(path)) {
-    //             let file_name = try!(entry).file_name();
-
-    //             // If the entry is a wave file, add it to our list.
-    //             if has_wav_ext(file_name.as_ref()) {
-    //                 let wav_reader = try!(hound::WavReader::open(&file_name));
-    //                 let sample_reader = SampleReader {
-    //                     base_letter_octave: read_base_letter_octave(file_name.as_ref()),
-    //                     wav_reader: wav_reader,
-    //                 };
-    //                 sample_readers.push(sample_reader);
-    //             }
-    //         }
-
-    //         // Sort the readers by their base hz.
-    //         sample_readers.sort_by(|a, b| match (a.base_letter_octave, b.base_letter_octave) {
-    //             (Some(_), None) => Ordering::Less,
-    //             (None, Some(_)) => Ordering::Greater,
-    //             (Some(a), Some(b)) => a.cmp(&b),
-    //             (None, None) => Ordering::Equal,
-    //         });
-
-    //         const DEFAULT_LETTER_OCTAVE: pitch::LetterOctave =
-    //             pitch::LetterOctave(pitch::Letter::C, 1);
-    //         let mut maybe_last_step = None;
-
-    //         // We must imperatively collect the mappings so that we can handle any errors.
-    //         let mut mappings = Vec::with_capacity(sample_readers.len());
-    //         for SampleReader { base_letter_octave, mut wav_reader } in sample_readers {
-    //             let base_vel = 1.0;
-    //             let base_hz = match base_letter_octave {
-    //                 Some(letter_octave) => {
-    //                     maybe_last_step = Some(letter_octave.step());
-    //                     letter_octave.to_hz()
-    //                 },
-    //                 None => {
-    //                     let last_step = maybe_last_step.unwrap_or(DEFAULT_LETTER_OCTAVE.step());
-    //                     let step = last_step + 1.0;
-    //                     maybe_last_step = Some(step);
-    //                     pitch::Step(step).to_hz()
-    //                 },
-    //             };
-
-    //             let audio = {
-    //                 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();
-    //                 for sample in wav_reader.samples() {
-    //                     samples.push(try!(sample));
-    //                 }
-
-    //                 let boxed_samples = samples.into_boxed_slice();
-    //                 let boxed_frames: Box<[F]> = match sample::slice::to_boxed_frame_slice(boxed_samples) {
-    //                     Some(slice) => slice,
-    //                     // TODO: Return an error instead of panic!ing! OR do some sort of frame /
-    //                     // channel layout conversion.
-    //                     None => panic!("The number of samples produced from the wav file does not \
-    //                                    match the number of channels ({}) in the given `Frame` type",
-    //                                    F::n_channels()),
-    //                 };
-
-    //                 // 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();
-
-    //                 map::Audio::new(frames.into_boxed_slice())
-    //             };
-
-    //             let sample = map::Sample::new(base_hz, base_vel, audio);
-
-    //             // The `Hz` range that triggers this sample will span from the last sample's Hz (or
-    //             // the minimum if there is no last sample) to the following `to_hz` value.
-    //             //
-    //             // TODO: Investigate a nicer way of evenly spreading samples across the keyboard.
-    //             let to_hz = pitch::Step(base_hz.step() + 0.5).to_hz();
-    //             let to_vel = base_vel;
-    //             mappings.push((to_hz, to_vel, sample));
-    //         }
-
-    //         Ok(Self::from_sequential_mappings(mappings))
-    //     }
-
-    // }
-
-    ///// Utility functions.
-
-    // /// Determines whether the given `Path` leads to a wave file.
-    // fn has_wav_ext(path: &std::path::Path) -> bool {
-    //     let ext = path.extension()
-    //         .and_then(|s| s.to_str())
-    //         .map_or("".into(), std::ascii::AsciiExt::to_ascii_lowercase);
-    //     match &ext[..] {
-    //         "wav" | "wave" => true,
-    //         _ => false,
-    //     }
-    // }
 
     /// Scans the given path for an indication of its pitch.
     fn read_base_letter_octave(path: &std::path::Path) -> Option<pitch::LetterOctave> {

+ 14 - 13
src/mode.rs

@@ -1,12 +1,13 @@
-pub use instrument::mode::{Mono, MonoKind, Poly, Dynamic};
+use audio::Audio;
 use instrument;
-use map::{self, Map};
+use map::Map;
 use pitch;
-use sample::Frame;
 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 {
 
@@ -18,20 +19,20 @@ pub trait Mode {
                   note_velocity: Velocity,
                   map: &Map<A>,
                   voices: &mut [Option<PlayingSample<A>>])
-        where A: map::Audio;
+        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: map::Audio;
+        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: map::Audio,
+    where A: Audio,
 {
     play_sample_from_playhead_idx(0, hz, vel, map)
 }
@@ -41,7 +42,7 @@ fn play_sample_from_playhead_idx<A>(idx: usize,
                                     hz: pitch::Hz,
                                     vel: Velocity,
                                     map: &Map<A>) -> Option<PlayingSample<A>>
-    where A: map::Audio,
+    where A: Audio,
 {
     map.sample(hz, vel).map(|sample| PlayingSample::from_playhead_idx(idx, hz, vel, sample))
 }
@@ -54,7 +55,7 @@ impl Mode for Mono {
                   note_vel: Velocity,
                   map: &Map<A>,
                   voices: &mut [Option<PlayingSample<A>>])
-        where A: map::Audio,
+        where A: Audio,
     {
         let Mono(ref kind, ref note_stack) = *self;
 
@@ -88,7 +89,7 @@ impl Mode for Mono {
                    note_hz: pitch::Hz,
                    map: &Map<A>,
                    voices: &mut [Option<PlayingSample<A>>])
-        where A: map::Audio,
+        where A: Audio,
     {
         let Mono(kind, ref note_stack) = *self;
 
@@ -130,7 +131,7 @@ impl Mode for Poly {
                   note_vel: Velocity,
                   map: &Map<A>,
                   voices: &mut [Option<PlayingSample<A>>])
-        where A: map::Audio,
+        where A: Audio,
     {
         let sample = match play_sample(note_hz, note_vel, map) {
             Some(sample) => sample,
@@ -160,7 +161,7 @@ impl Mode for Poly {
                    _note_hz: pitch::Hz,
                    _map: &Map<A>,
                    _voices: &mut [Option<PlayingSample<A>>])
-        where A: map::Audio,
+        where A: Audio,
     {
         // No need to do anything here as voices will be set to `None` when frames yielded by
         // `instrument` run out.
@@ -175,7 +176,7 @@ impl Mode for Dynamic {
                   note_vel: Velocity,
                   map: &Map<A>,
                   voices: &mut [Option<PlayingSample<A>>])
-        where A: map::Audio,
+        where A: Audio,
     {
         match *self {
             Dynamic::Mono(ref mono) => mono.note_on(note_hz, note_vel, map, voices),
@@ -187,7 +188,7 @@ impl Mode for Dynamic {
                    note_hz: pitch::Hz,
                    map: &Map<A>,
                    voices: &mut [Option<PlayingSample<A>>])
-        where A: map::Audio,
+        where A: Audio,
     {
         match *self {
             Dynamic::Mono(ref mono) => mono.note_off(note_hz, map, voices),

+ 22 - 20
src/sampler.rs

@@ -1,3 +1,4 @@
+use audio::Audio;
 use instrument::{self, Instrument};
 use map::{self, Map};
 use pitch;
@@ -10,7 +11,7 @@ use Velocity;
 #[derive(Clone, Debug)]
 pub struct Sampler<M, NFG, A>
     where NFG: instrument::NoteFreqGenerator,
-          A: map::Audio,
+          A: Audio,
 {
     pub instrument: Instrument<M, NFG>,
     pub map: Map<A>,
@@ -27,7 +28,7 @@ pub struct Sampler<M, NFG, A>
 /// `Vec` indices.
 #[derive(Clone)]
 pub struct Voices<A>
-    where A: map::Audio,
+    where A: Audio,
 {
     map: Vec<Option<PlayingSample<A>>>,
 }
@@ -35,7 +36,7 @@ pub struct Voices<A>
 /// A sample that is currently being played back.
 #[derive(Clone)]
 pub struct PlayingSample<A>
-    where A: map::Audio,
+    where A: Audio,
 {
     /// The pitch in hz at which the `note_on` was triggered.
     pub note_on_hz: pitch::Hz,
@@ -51,7 +52,7 @@ pub struct PlayingSample<A>
 /// An owned iterator that wraps an audio file but does not 
 #[derive(Clone)]
 pub struct Playhead<A>
-    where A: map::Audio,
+    where A: Audio,
 {
     /// The position of the playhead over the `Sample`.
     pub idx: usize,
@@ -60,7 +61,7 @@ pub struct Playhead<A>
 
 /// An iterator yielding one frame from the `Sampler` at a time.
 pub struct Frames<'a, A: 'a, NF: 'a>
-    where A: map::Audio,
+    where A: Audio,
 {
     voices: &'a mut Voices<A>,
     instrument_frames: instrument::Frames<'a, NF>,
@@ -68,7 +69,7 @@ pub struct Frames<'a, A: 'a, NF: 'a>
 
 
 impl<A> std::fmt::Debug for Voices<A>
-    where A: map::Audio,
+    where A: Audio,
 {
     fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
         write!(f, "Voices {{ num: {:?} }}", self.map.len())
@@ -77,7 +78,7 @@ impl<A> std::fmt::Debug for Voices<A>
 
 impl<NFG, A> Sampler<instrument::mode::Mono, NFG, A>
     where NFG: instrument::NoteFreqGenerator,
-          A: map::Audio,
+          A: Audio,
 {
     /// Construct a `Sampler` with a `Mono::Legato` playback mode.
     pub fn legato(nfg: NFG, map: Map<A>) -> Self {
@@ -87,7 +88,7 @@ impl<NFG, A> Sampler<instrument::mode::Mono, NFG, A>
 
 impl<NFG, A> Sampler<instrument::mode::Mono, NFG, A>
     where NFG: instrument::NoteFreqGenerator,
-          A: map::Audio,
+          A: Audio,
 {
     /// Construct a `Sampler` with a `Mono::Retrigger` playback mode.
     pub fn retrigger(nfg: NFG, map: Map<A>) -> Self {
@@ -97,7 +98,7 @@ impl<NFG, A> Sampler<instrument::mode::Mono, NFG, A>
 
 impl<NFG, A> Sampler<instrument::mode::Poly, NFG, A>
     where NFG: instrument::NoteFreqGenerator,
-          A: map::Audio,
+          A: Audio,
 {
     /// Construct a `Sampler` with a `Poly` playback mode.
     pub fn poly(nfg: NFG, map: Map<A>) -> Self {
@@ -108,7 +109,7 @@ impl<NFG, A> Sampler<instrument::mode::Poly, NFG, A>
 
 impl<M, NFG, A> Sampler<M, NFG, A>
     where NFG: instrument::NoteFreqGenerator,
-          A: map::Audio,
+          A: Audio,
 {
 
     /// Construct a new `Sampler`.
@@ -215,7 +216,7 @@ impl<M, NFG, A> Sampler<M, NFG, A>
 
     /// Produces an iterator that yields `Frame`s of audio data.
     pub fn frames(&mut self, sample_hz: f64) -> Frames<A, NFG::NoteFreq>
-        where A: map::Audio,
+        where A: Audio,
               <A::Frame as Frame>::Sample: sample::Duplex<f64>,
               <<A::Frame as Frame>::Sample as PcmSample>::Float: sample::FromSample<f32>,
     {
@@ -240,7 +241,7 @@ impl<M, NFG, A> Sampler<M, NFG, A>
         where F: Frame,
               F::Sample: sample::Duplex<f64>,
               <F::Sample as PcmSample>::Float: sample::FromSample<f32>,
-              A: map::Audio<Frame=F>,
+              A: Audio<Frame=F>,
     {
         let mut frames = self.frames(sample_hz);
         sample::slice::map_in_place(output, |f| {
@@ -255,15 +256,16 @@ impl<M, NFG, A> Sampler<M, NFG, A>
 
 #[cfg(feature="serde_serialization")]
 pub mod private {
+    use audio::Audio;
     use instrument::{self, Instrument};
-    use map::{self, Map};
+    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: map::Audio,
+              A: Audio,
     {
         super::Sampler {
             instrument: instrument,
@@ -275,7 +277,7 @@ pub mod private {
 
 
 impl<A> PlayingSample<A>
-    where A: map::Audio,
+    where A: Audio,
 {
 
     /// Construct a new `PlayingSample` from the given note hz, velocity and the associated
@@ -310,7 +312,7 @@ impl<A> PlayingSample<A>
 
 
 impl<A> Playhead<A>
-    where A: map::Audio,
+    where A: Audio,
 {
     /// Wrap the given `Audio` with a `Playhead` starting from 0.
     pub fn new(audio: A) -> Self {
@@ -327,20 +329,20 @@ impl<A> Playhead<A>
 }
 
 impl<A> Iterator for Playhead<A>
-    where A: map::Audio,
+    where A: Audio,
 {
     type Item = A::Frame;
     #[inline]
     fn next(&mut self) -> Option<Self::Item> {
         let idx = self.idx;
         self.idx += 1;
-        map::Audio::data(&self.audio).get(idx).map(|&f| f)
+        Audio::data(&self.audio).get(idx).map(|&f| f)
     }
 }
 
 
 impl<'a, A, NF> Frames<'a, A, NF>
-    where A: map::Audio,
+    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,
@@ -386,7 +388,7 @@ impl<'a, A, NF> Frames<'a, A, NF>
 }
 
 impl<'a, A, NF> Iterator for Frames<'a, A, NF>
-    where A: map::Audio,
+    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,

+ 200 - 42
src/serde.rs

@@ -1,6 +1,171 @@
 extern crate serde;
 
 
+mod audio_range {
+    use audio::Range;
+    use super::serde;
+    use std;
+
+    impl<T> serde::Serialize for Range<T>
+        where T: serde::Serialize,
+    {
+        fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error>
+            where S: serde::Serializer,
+        {
+            struct Visitor<'a, T: 'a> {
+                t: &'a Range<T>,
+                field_idx: u8,
+            }
+
+            impl<'a, T> serde::ser::MapVisitor for Visitor<'a, T>
+                where T: serde::Serialize,
+            {
+                fn visit<S>(&mut self, serializer: &mut S) -> Result<Option<()>, S::Error>
+                    where S: serde::Serializer,
+                {
+                    match self.field_idx {
+                        0 => {
+                            self.field_idx += 1;
+                            Ok(Some(try!(serializer.serialize_struct_elt("start", &self.t.start))))
+                        },
+                        1 => {
+                            self.field_idx += 1;
+                            Ok(Some(try!(serializer.serialize_struct_elt("end", &self.t.end))))
+                        },
+                        2 => {
+                            self.field_idx += 1;
+                            Ok(Some(try!(serializer.serialize_struct_elt("audio", &self.t.audio))))
+                        },
+                        _ => Ok(None),
+                    }
+                }
+
+                fn len(&self) -> Option<usize> {
+                    Some(3)
+                }
+            }
+
+            serializer.serialize_struct("Range", Visitor { t: self, field_idx: 0 })
+        }
+    }
+
+    impl<T> serde::Deserialize for Range<T>
+        where T: serde::Deserialize,
+    {
+        fn deserialize<D>(deserializer: &mut D) -> Result<Self, D::Error>
+            where D: serde::Deserializer,
+        {
+            struct Visitor<T> {
+                t: std::marker::PhantomData<T>,
+            };
+
+            impl<T> serde::de::Visitor for Visitor<T>
+                where T: serde::Deserialize,
+            {
+                type Value = Range<T>;
+
+                fn visit_map<V>(&mut self, mut visitor: V) -> Result<Range<T>, V::Error>
+                    where V: serde::de::MapVisitor,
+                {
+                    let mut start = None;
+                    let mut end = None;
+                    let mut audio = None;
+
+                    enum Field { Start, End, Audio }
+
+                    impl serde::Deserialize for Field {
+                        fn deserialize<D>(deserializer: &mut D) -> Result<Field, D::Error>
+                            where D: serde::de::Deserializer,
+                        {
+                            struct FieldVisitor;
+
+                            impl serde::de::Visitor for FieldVisitor {
+                                type Value = Field;
+
+                                fn visit_str<E>(&mut self, value: &str) -> Result<Field, E>
+                                    where E: serde::de::Error,
+                                {
+                                    match value {
+                                        "start" => Ok(Field::Start),
+                                        "end" => Ok(Field::End),
+                                        "audio" => Ok(Field::Audio),
+                                        _ => Err(serde::de::Error::custom("expected start, end or audio")),
+                                    }
+                                }
+                            }
+
+                            deserializer.deserialize(FieldVisitor)
+                        }
+                    }
+
+                    loop {
+                        match try!(visitor.visit_key()) {
+                            Some(Field::Start) => { start = Some(try!(visitor.visit_value())); },
+                            Some(Field::End) => { end = Some(try!(visitor.visit_value())); },
+                            Some(Field::Audio) => { audio = Some(try!(visitor.visit_value())); },
+                            None => { break; }
+                        }
+                    }
+
+                    let start = match start {
+                        Some(start) => start,
+                        None => return Err(serde::de::Error::missing_field("start")),
+                    };
+
+                    let end = match end {
+                        Some(end) => end,
+                        None => return Err(serde::de::Error::missing_field("end")),
+                    };
+
+                    let audio = match audio {
+                        Some(audio) => audio,
+                        None => return Err(serde::de::Error::missing_field("audio")),
+                    };
+
+                    try!(visitor.end());
+
+                    Ok(Range {
+                        start: start,
+                        end: end,
+                        audio: audio,
+                    })
+                }
+            }
+
+            static FIELDS: &'static [&'static str] = &["start", "end", "audio"];
+
+            let visitor = Visitor { t: std::marker::PhantomData };
+
+            deserializer.deserialize_struct("Range", FIELDS, visitor)
+        }
+    }
+
+    #[test]
+    fn test() {
+        extern crate serde_json;
+
+        use audio::Audio;
+
+        impl Audio for () {
+            type Frame = [f32; 2];
+            fn data(&self) -> &[Self::Frame] { &[] }
+        }
+
+        let range = Range { start: 0, end: 0, audio: () };
+        let serialized = serde_json::to_string(&range).unwrap();
+
+        println!("{}", serialized);
+        assert_eq!("{\"start\":0,\"end\":0,\"audio\":null}", serialized);
+
+        let deserialized: Range<()> = serde_json::from_str(&serialized).unwrap();
+
+        println!("{:?}", deserialized);
+        assert_eq!(range, deserialized);
+    }
+
+
+}
+
 mod range {
     use super::serde;
     use map::Range;
@@ -286,13 +451,6 @@ mod sample {
     fn test() {
         extern crate serde_json;
 
-        use map;
-
-        impl map::Audio for () {
-            type Frame = [f32; 2];
-            fn data(&self) -> &[Self::Frame] { &[] }
-        }
-
         let sample = Sample { base_hz: 440.0.into(), base_vel: 1.0, audio: () };
         let serialized = serde_json::to_string(&sample).unwrap();
 
@@ -436,14 +594,14 @@ mod sample_over_range {
 
         use map;
 
-        // impl map::Audio for () {
+        // impl Audio for () {
         //     type Frame = [f32; 2];
         //     fn data(&self) -> &[Self::Frame] { &[] }
         // }
 
         let sample = map::Sample { base_hz: 440.0.into(), base_vel: 1.0, audio: () };
-        let range = map::HzVelRange {
-            hz: map::Range { min: 220.0.into(), max: 440.0.into() },
+        let range = map::StepVelRange {
+            step: map::Range { min: 0, max: 127 },
             vel: map::Range { min: 0.0, max: 1.0 },
         };
 
@@ -451,7 +609,7 @@ mod sample_over_range {
         let serialized = serde_json::to_string(&sample_over_range).unwrap();
 
         println!("{}", serialized);
-        assert_eq!("{\"range\":{\"hz\":{\"min\":220,\"max\":440},\"vel\":{\"min\":0,\"max\":1}},\"sample\":{\"base_hz\":440,\"base_vel\":1,\"audio\":null}}", serialized);
+        assert_eq!("{\"range\":{\"step\":{\"min\":0,\"max\":127},\"vel\":{\"min\":0,\"max\":1}},\"sample\":{\"base_hz\":440,\"base_vel\":1,\"audio\":null}}", serialized);
         
         let deserialized: SampleOverRange<()> = serde_json::from_str(&serialized).unwrap();
 
@@ -462,16 +620,16 @@ mod sample_over_range {
 }
 
 
-mod hz_vel_range {
+mod step_vel_range {
     use super::serde;
-    use map::HzVelRange;
+    use map::StepVelRange;
 
-    impl serde::Serialize for HzVelRange {
+    impl serde::Serialize for StepVelRange {
         fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error>
             where S: serde::Serializer,
         {
             struct Visitor<'a> {
-                t: &'a HzVelRange,
+                t: &'a StepVelRange,
                 field_idx: u8,
             }
 
@@ -482,7 +640,7 @@ mod hz_vel_range {
                     match self.field_idx {
                         0 => {
                             self.field_idx += 1;
-                            Ok(Some(try!(serializer.serialize_struct_elt("hz", &self.t.hz))))
+                            Ok(Some(try!(serializer.serialize_struct_elt("step", &self.t.step))))
                         },
                         1 => {
                             self.field_idx += 1;
@@ -497,26 +655,26 @@ mod hz_vel_range {
                 }
             }
 
-            serializer.serialize_struct("HzVelRange", Visitor { t: self, field_idx: 0 })
+            serializer.serialize_struct("StepVelRange", Visitor { t: self, field_idx: 0 })
         }
     }
 
-    impl serde::Deserialize for HzVelRange {
+    impl serde::Deserialize for StepVelRange {
         fn deserialize<D>(deserializer: &mut D) -> Result<Self, D::Error>
             where D: serde::Deserializer,
         {
             struct Visitor;
 
             impl serde::de::Visitor for Visitor {
-                type Value = HzVelRange;
+                type Value = StepVelRange;
 
-                fn visit_map<V>(&mut self, mut visitor: V) -> Result<HzVelRange, V::Error>
+                fn visit_map<V>(&mut self, mut visitor: V) -> Result<StepVelRange, V::Error>
                     where V: serde::de::MapVisitor,
                 {
-                    let mut hz = None;
+                    let mut step = None;
                     let mut vel = None;
 
-                    enum Field { Hz, Vel }
+                    enum Field { Step, Vel }
 
                     impl serde::Deserialize for Field {
                         fn deserialize<D>(deserializer: &mut D) -> Result<Field, D::Error>
@@ -531,9 +689,9 @@ mod hz_vel_range {
                                     where E: serde::de::Error,
                                 {
                                     match value {
-                                        "hz" => Ok(Field::Hz),
+                                        "step" => Ok(Field::Step),
                                         "vel" => Ok(Field::Vel),
-                                        _ => Err(serde::de::Error::custom("expected hz or vel")),
+                                        _ => Err(serde::de::Error::custom("expected step or vel")),
                                     }
                                 }
                             }
@@ -544,15 +702,15 @@ mod hz_vel_range {
 
                     loop {
                         match try!(visitor.visit_key()) {
-                            Some(Field::Hz) => { hz = Some(try!(visitor.visit_value())); },
+                            Some(Field::Step) => { step = Some(try!(visitor.visit_value())); },
                             Some(Field::Vel) => { vel = Some(try!(visitor.visit_value())); },
                             None => { break; }
                         }
                     }
 
-                    let hz = match hz {
-                        Some(hz) => hz,
-                        None => return Err(serde::de::Error::missing_field("hz")),
+                    let step = match step {
+                        Some(step) => step,
+                        None => return Err(serde::de::Error::missing_field("step")),
                     };
 
                     let vel = match vel {
@@ -562,15 +720,15 @@ mod hz_vel_range {
 
                     try!(visitor.end());
 
-                    Ok(HzVelRange { hz: hz, vel: vel })
+                    Ok(StepVelRange { step: step, vel: vel })
                 }
             }
 
-            static FIELDS: &'static [&'static str] = &["hz", "vel"];
+            static FIELDS: &'static [&'static str] = &["step", "vel"];
 
             let visitor = Visitor;
 
-            deserializer.deserialize_struct("HzVelRange", FIELDS, visitor)
+            deserializer.deserialize_struct("StepVelRange", FIELDS, visitor)
         }
     }
 
@@ -579,16 +737,16 @@ mod hz_vel_range {
         extern crate serde_json;
         use map;
 
-        let range = HzVelRange {
-            hz: map::Range { min: 220.0.into(), max: 440.0.into() },
+        let range = StepVelRange {
+            step: map::Range { min: 0, max: 127 },
             vel: map::Range { min: 0.0, max: 1.0 },
         };
         let serialized = serde_json::to_string(&range).unwrap();
 
         println!("{}", serialized);
-        assert_eq!("{\"hz\":{\"min\":220,\"max\":440},\"vel\":{\"min\":0,\"max\":1}}", serialized);
+        assert_eq!("{\"step\":{\"min\":0,\"max\":127},\"vel\":{\"min\":0,\"max\":1}}", serialized);
         
-        let deserialized: HzVelRange = serde_json::from_str(&serialized).unwrap();
+        let deserialized: StepVelRange = serde_json::from_str(&serialized).unwrap();
 
         println!("{:?}", deserialized);
         assert_eq!(range, deserialized);
@@ -728,8 +886,8 @@ mod map {
 
 
 mod sampler {
+    use audio::Audio;
     use instrument;
-    use map;
     use super::serde;
     use sampler::{self, Sampler};
     use std;
@@ -738,14 +896,14 @@ mod sampler {
         where M: serde::Serialize,
               NFG: serde::Serialize + instrument::NoteFreqGenerator,
               NFG::NoteFreq: serde::Serialize,
-              A: serde::Serialize + map::Audio,
+              A: serde::Serialize + Audio,
     {
         fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error>
             where S: serde::Serializer,
         {
             struct Visitor<'a, M: 'a, NFG: 'a, A: 'a>
                 where NFG: instrument::NoteFreqGenerator,
-                      A: map::Audio,
+                      A: Audio,
             {
                 t: &'a Sampler<M, NFG, A>,
                 field_idx: u8,
@@ -755,7 +913,7 @@ mod sampler {
                 where M: serde::Serialize,
                       NFG: serde::Serialize + instrument::NoteFreqGenerator,
                       NFG::NoteFreq: serde::Serialize,
-                      A: serde::Serialize + map::Audio,
+                      A: serde::Serialize + Audio,
             {
                 fn visit<S>(&mut self, serializer: &mut S) -> Result<Option<()>, S::Error>
                     where S: serde::Serializer,
@@ -791,7 +949,7 @@ mod sampler {
         where M: serde::Deserialize,
               NFG: serde::Deserialize + instrument::NoteFreqGenerator,
               NFG::NoteFreq: serde::Deserialize,
-              A: serde::Deserialize + map::Audio,
+              A: serde::Deserialize + Audio,
     {
         fn deserialize<D>(deserializer: &mut D) -> Result<Self, D::Error>
             where D: serde::Deserializer,
@@ -806,7 +964,7 @@ mod sampler {
                 where M: serde::Deserialize,
                       NFG: serde::Deserialize + instrument::NoteFreqGenerator,
                       NFG::NoteFreq: serde::Deserialize,
-                      A: serde::Deserialize + map::Audio,
+                      A: serde::Deserialize + Audio,
             {
                 type Value = Sampler<M, NFG, A>;
 
@@ -914,7 +1072,7 @@ mod sampler {
 mod wav_audio {
     extern crate find_folder;
 
-    use map::wav;
+    use audio::wav;
     use sample;
     use super::serde;
     use std;