Reorganize the conversions module

This commit is contained in:
Pierre Krieger 2015-09-11 15:43:00 +02:00
parent 803c9ac192
commit cefae3aa51
11 changed files with 534 additions and 521 deletions

View file

@ -0,0 +1,38 @@
use conversions::Sample;
pub struct AmplifierIterator<I> where I: Iterator {
input: I,
amplication: f32,
}
impl<I> AmplifierIterator<I> where I: Iterator {
#[inline]
pub fn new(input: I, amplication: f32) -> AmplifierIterator<I> {
AmplifierIterator {
input: input,
amplication: amplication,
}
}
#[inline]
pub fn set_amplification(&mut self, new_value: f32) {
self.amplication = new_value;
}
}
impl<I> Iterator for AmplifierIterator<I> where I: Iterator, I::Item: Sample {
type Item = I::Item;
#[inline]
fn next(&mut self) -> Option<I::Item> {
self.input.next().map(|value| value.amplify(self.amplication))
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
self.input.size_hint()
}
}
impl<I> ExactSizeIterator for AmplifierIterator<I>
where I: ExactSizeIterator, I::Item: Sample {}

104
src/conversions/channels.rs Normal file
View file

@ -0,0 +1,104 @@
use cpal;
/// Iterator that converts from a certain channels count to another.
pub struct ChannelsCountConverter<I> where I: Iterator {
input: I,
from: cpal::ChannelsCount,
to: cpal::ChannelsCount,
sample_repeat: Option<I::Item>,
next_output_sample_pos: cpal::ChannelsCount,
}
impl<I> ChannelsCountConverter<I> where I: Iterator {
///
///
/// # Panic
///
/// Panicks if `from` or `to` are equal to 0.
///
#[inline]
pub fn new(input: I, from: cpal::ChannelsCount, to: cpal::ChannelsCount)
-> ChannelsCountConverter<I>
{
assert!(from >= 1);
assert!(to >= 1);
ChannelsCountConverter {
input: input,
from: from,
to: to,
sample_repeat: None,
next_output_sample_pos: 0,
}
}
}
impl<I> Iterator for ChannelsCountConverter<I> where I: Iterator, I::Item: Clone {
type Item = I::Item;
fn next(&mut self) -> Option<I::Item> {
let result = if self.next_output_sample_pos == self.from - 1 {
let value = self.input.next();
self.sample_repeat = value.clone();
value
} else if self.next_output_sample_pos < self.from {
self.input.next()
} else {
self.sample_repeat.clone()
};
self.next_output_sample_pos += 1;
if self.next_output_sample_pos == self.to {
self.next_output_sample_pos -= self.to;
if self.from > self.to {
for _ in (self.to .. self.from) {
self.input.next(); // discarding extra input
}
}
}
result
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
let (min, max) = self.input.size_hint();
let min = (min / self.from as usize) * self.to as usize + self.next_output_sample_pos as usize;
let max = max.map(|max| (max / self.from as usize) * self.to as usize + self.next_output_sample_pos as usize);
(min, max)
}
}
impl<I> ExactSizeIterator for ChannelsCountConverter<I>
where I: ExactSizeIterator, I::Item: Clone {}
#[cfg(test)]
mod test {
use super::ChannelsCountConverter;
#[test]
fn remove_channels() {
let input = vec![1u16, 2, 3, 1, 2, 3];
let output = ChannelsCountConverter::new(input.into_iter(), 3, 2).collect::<Vec<_>>();
assert_eq!(output, [1, 2, 1, 2]);
let input = vec![1u16, 2, 3, 4, 1, 2, 3, 4];
let output = ChannelsCountConverter::new(input.into_iter(), 4, 1).collect::<Vec<_>>();
assert_eq!(output, [1, 1]);
}
#[test]
fn add_channels() {
let input = vec![1u16, 2, 1, 2];
let output = ChannelsCountConverter::new(input.into_iter(), 2, 3).collect::<Vec<_>>();
assert_eq!(output, [1, 2, 2, 1, 2, 2]);
let input = vec![1u16, 2, 1, 2];
let output = ChannelsCountConverter::new(input.into_iter(), 2, 4).collect::<Vec<_>>();
assert_eq!(output, [1, 2, 2, 2, 1, 2, 2, 2]);
}
}

45
src/conversions/mod.rs Normal file
View file

@ -0,0 +1,45 @@
/*!
This module contains function that will convert from one PCM format to another.
This includes conversion between samples formats, channels or sample rates.
*/
use std::iter;
use cpal::UnknownTypeBuffer;
pub use self::sample::Sample;
pub use self::channels::ChannelsCountConverter;
pub use self::samples_rate::SamplesRateConverter;
pub use self::amplifier::AmplifierIterator;
mod amplifier;
mod channels;
mod sample;
mod samples_rate;
///
pub fn convert_and_write<I, S>(samples: I, output: &mut UnknownTypeBuffer)
where I: Iterator<Item=S>, S: Sample
{
let samples = samples.chain(iter::repeat(Sample::zero_value()));
match output {
&mut UnknownTypeBuffer::U16(ref mut buffer) => {
for (i, o) in samples.zip(buffer.iter_mut()) {
*o = i.to_u16();
}
},
&mut UnknownTypeBuffer::I16(ref mut buffer) => {
for (i, o) in samples.zip(buffer.iter_mut()) {
*o = i.to_i16();
}
},
&mut UnknownTypeBuffer::F32(ref mut buffer) => {
for (i, o) in samples.zip(buffer.iter_mut()) {
*o = i.to_f32();
}
},
}
}

199
src/conversions/sample.rs Normal file
View file

@ -0,0 +1,199 @@
use cpal;
/// Trait for containers that contain PCM data.
pub trait Sample: cpal::Sample {
fn lerp(first: Self, second: Self, numerator: u32, denominator: u32) -> Self;
fn amplify(self, value: f32) -> Self;
fn zero_value() -> Self;
fn to_i16(&self) -> i16;
fn to_u16(&self) -> u16;
fn to_f32(&self) -> f32;
}
impl Sample for u16 {
#[inline]
fn lerp(first: u16, second: u16, numerator: u32, denominator: u32) -> u16 {
(first as u32 + (second as u32 - first as u32) * numerator / denominator) as u16
}
#[inline]
fn amplify(self, value: f32) -> u16 {
((self as f32) * value) as u16
}
#[inline]
fn zero_value() -> u16 {
32768
}
#[inline]
fn to_i16(&self) -> i16 {
if *self >= 32768 {
(*self - 32768) as i16
} else {
(*self as i16) - 32767 - 1
}
}
#[inline]
fn to_u16(&self) -> u16 {
*self
}
#[inline]
fn to_f32(&self) -> f32 {
self.to_i16().to_f32()
}
}
impl Sample for i16 {
#[inline]
fn lerp(first: i16, second: i16, numerator: u32, denominator: u32) -> i16 {
(first as i32 + (second as i32 - first as i32) * numerator as i32 / denominator as i32) as i16
}
#[inline]
fn amplify(self, value: f32) -> i16 {
((self as f32) * value) as i16
}
#[inline]
fn zero_value() -> i16 {
0
}
#[inline]
fn to_i16(&self) -> i16 {
*self
}
#[inline]
fn to_u16(&self) -> u16 {
if *self < 0 {
(*self - ::std::i16::MIN) as u16
} else {
(*self as u16) + 32768
}
}
#[inline]
fn to_f32(&self) -> f32 {
if *self < 0 {
*self as f32 / -(::std::i16::MIN as f32)
} else {
*self as f32 / ::std::i16::MAX as f32
}
}
}
impl Sample for f32 {
#[inline]
fn lerp(first: f32, second: f32, numerator: u32, denominator: u32) -> f32 {
first + (second - first) * numerator as f32 / denominator as f32
}
#[inline]
fn amplify(self, value: f32) -> f32 {
self * value
}
#[inline]
fn zero_value() -> f32 {
0.0
}
#[inline]
fn to_i16(&self) -> i16 {
if *self >= 0.0 {
(*self * ::std::i16::MAX as f32) as i16
} else {
(-*self * ::std::i16::MIN as f32) as i16
}
}
#[inline]
fn to_u16(&self) -> u16 {
(((*self + 1.0) * 0.5) * ::std::u16::MAX as f32).round() as u16
}
#[inline]
fn to_f32(&self) -> f32 {
*self
}
}
#[cfg(test)]
mod test {
use super::Sample;
#[test]
fn i16_to_i16() {
assert_eq!(0i16.to_i16(), 0);
assert_eq!((-467i16).to_i16(), -467);
assert_eq!(32767i16.to_i16(), 32767);
assert_eq!((-32768i16).to_i16(), -32768);
}
#[test]
fn i16_to_u16() {
assert_eq!(0i16.to_u16(), 32768);
assert_eq!((-16384i16).to_u16(), 16384);
assert_eq!(32767i16.to_u16(), 65535);
assert_eq!((-32768i16).to_u16(), 0);
}
#[test]
fn i16_to_f32() {
assert_eq!(0i16.to_f32(), 0.0);
assert_eq!((-16384i16).to_f32(), -0.5);
assert_eq!(32767i16.to_f32(), 1.0);
assert_eq!((-32768i16).to_f32(), -1.0);
}
#[test]
fn u16_to_i16() {
assert_eq!(32768u16.to_i16(), 0);
assert_eq!(16384u16.to_i16(), -16384);
assert_eq!(65535u16.to_i16(), 32767);
assert_eq!(0u16.to_i16(), -32768);
}
#[test]
fn u16_to_u16() {
assert_eq!(0u16.to_u16(), 0);
assert_eq!(467u16.to_u16(), 467);
assert_eq!(32767u16.to_u16(), 32767);
assert_eq!(65535u16.to_u16(), 65535);
}
#[test]
fn u16_to_f32() {
assert_eq!(0u16.to_f32(), -1.0);
assert_eq!(32768u16.to_f32(), 0.0);
assert_eq!(65535u16.to_f32(), 1.0);
}
#[test]
fn f32_to_i16() {
assert_eq!(0.0f32.to_i16(), 0);
assert_eq!((-0.5f32).to_i16(), ::std::i16::MIN / 2);
assert_eq!(1.0f32.to_i16(), ::std::i16::MAX);
assert_eq!((-1.0f32).to_i16(), ::std::i16::MIN);
}
#[test]
fn f32_to_u16() {
assert_eq!((-1.0f32).to_u16(), 0);
assert_eq!(0.0f32.to_u16(), 32768);
assert_eq!(1.0f32.to_u16(), 65535);
}
#[test]
fn f32_to_f32() {
assert_eq!(0.1f32.to_f32(), 0.1);
assert_eq!((-0.7f32).to_f32(), -0.7);
assert_eq!(1.0f32.to_f32(), 1.0);
}
}

View file

@ -0,0 +1,145 @@
use cpal;
use conversions::Sample;
/// Iterator that converts from a certain samples rate to another.
pub struct SamplesRateConverter<I> where I: Iterator {
/// The iterator that gives us samples.
input: I,
/// We convert chunks of `from` samples into chunks of `to` samples.
from: u32,
/// We convert chunks of `from` samples into chunks of `to` samples.
to: u32,
/// One sample extracted from `input`.
current_sample: Option<I::Item>,
/// Position of `current_sample` modulo `from`.
current_sample_pos_in_chunk: u32,
/// The sample right after `current_sample`, extracted from `input`.
next_sample: Option<I::Item>,
/// The position of the next sample that the iterator should return, modulo `to`.
/// This counter is incremented (modulo `to`) every time the iterator is called.
next_output_sample_pos_in_chunk: u32,
}
impl<I> SamplesRateConverter<I> where I: Iterator {
///
///
/// # Panic
///
/// Panicks if `from` or `to` are equal to 0.
///
#[inline]
pub fn new(mut input: I, from: cpal::SamplesRate, to: cpal::SamplesRate)
-> SamplesRateConverter<I>
{
let from = from.0;
let to = to.0;
assert!(from >= 1);
assert!(to >= 1);
// finding greatest common divisor
let gcd = {
#[inline]
fn gcd(a: u32, b: u32) -> u32 {
if b == 0 {
a
} else {
gcd(b, a % b)
}
}
gcd(from, to)
};
let first_sample = input.next();
let second_sample = input.next();
SamplesRateConverter {
input: input,
from: from / gcd,
to: to / gcd,
current_sample_pos_in_chunk: 0,
next_output_sample_pos_in_chunk: 0,
current_sample: first_sample,
next_sample: second_sample,
}
}
}
impl<I> Iterator for SamplesRateConverter<I> where I: Iterator, I::Item: Sample + Clone {
type Item = I::Item;
fn next(&mut self) -> Option<I::Item> {
// The sample we are going to return from this function will be a linear interpolation
// between `self.current_sample` and `self.next_sample`.
// Finding the position of the first sample of the linear interpolation.
let req_left_sample = (self.from * self.next_output_sample_pos_in_chunk / self.to) %
self.from;
// Advancing `self.current_sample`, `self.next_sample` and
// `self.current_sample_pos_in_chunk` until the latter variable matches `req_left_sample`.
while self.current_sample_pos_in_chunk != req_left_sample {
self.current_sample_pos_in_chunk += 1;
self.current_sample_pos_in_chunk %= self.from;
self.current_sample = self.next_sample;
self.next_sample = self.input.next();
}
// Doing the linear interpolation. We handle a possible end of stream here.
let result = match (self.current_sample, self.next_sample) {
(Some(ref cur), Some(ref next)) => {
let numerator = (self.from * self.next_output_sample_pos_in_chunk) % self.to;
Sample::lerp(cur.clone(), next.clone(), numerator, self.to)
},
(Some(ref cur), None) if self.next_output_sample_pos_in_chunk == 0 => {
cur.clone()
},
_ => return None,
};
// Incrementing the counter for the next iteration.
self.next_output_sample_pos_in_chunk += 1;
self.next_output_sample_pos_in_chunk %= self.to;
Some(result)
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
let (min, max) = self.input.size_hint();
// TODO: inexact?
let min = (min / self.from as usize) * self.to as usize;
let max = max.map(|max| (max / self.from as usize) * self.to as usize);
(min, max)
}
}
impl<I> ExactSizeIterator for SamplesRateConverter<I>
where I: ExactSizeIterator, I::Item: Sample + Clone {}
#[cfg(test)]
mod test {
/*use super::SamplesRateConverter;
#[test]
fn half_samples_rate() {
let result = convert_samples_rate(&[1u16, 16, 2, 17, 3, 18, 4, 19],
::SamplesRate(44100), ::SamplesRate(22050), 2);
assert_eq!(result, [1, 16, 3, 18]);
}
#[test]
fn double_samples_rate() {
let result = convert_samples_rate(&[2u16, 16, 4, 18, 6, 20, 8, 22],
::SamplesRate(22050), ::SamplesRate(44100), 2);
assert_eq!(result, [2, 16, 3, 17, 4, 18, 5, 19, 6, 20, 7, 21, 8, 22]);
}*/
}

View file

@ -1,513 +0,0 @@
/*!
This module contains function that will convert from one PCM format to another.
This includes conversion between samples formats, channels or sample rates.
*/
use std::borrow::Cow;
use std::cmp;
use std::mem;
use std::iter;
use cpal;
use cpal::UnknownTypeBuffer;
use cpal::SampleFormat;
///
pub fn convert_and_write<I, S>(mut samples: I, output: &mut UnknownTypeBuffer)
where I: Iterator<Item=S>, S: Sample
{
let samples = samples.chain(iter::repeat(Sample::zero_value()));
match output {
&mut UnknownTypeBuffer::U16(ref mut buffer) => {
for (i, o) in samples.zip(buffer.iter_mut()) {
*o = i.to_u16();
}
},
&mut UnknownTypeBuffer::I16(ref mut buffer) => {
for (i, o) in samples.zip(buffer.iter_mut()) {
*o = i.to_i16();
}
},
&mut UnknownTypeBuffer::F32(ref mut buffer) => {
for (i, o) in samples.zip(buffer.iter_mut()) {
*o = i.to_f32();
}
},
}
}
/// Trait for containers that contain PCM data.
pub trait Sample: cpal::Sample {
fn lerp(first: Self, second: Self, numerator: u32, denominator: u32) -> Self;
fn amplify(self, value: f32) -> Self;
fn zero_value() -> Self;
fn to_i16(&self) -> i16;
fn to_u16(&self) -> u16;
fn to_f32(&self) -> f32;
}
impl Sample for u16 {
#[inline]
fn lerp(first: u16, second: u16, numerator: u32, denominator: u32) -> u16 {
(first as u32 + (second as u32 - first as u32) * numerator / denominator) as u16
}
#[inline]
fn amplify(self, value: f32) -> u16 {
((self as f32) * value) as u16
}
#[inline]
fn zero_value() -> u16 {
32768
}
#[inline]
fn to_i16(&self) -> i16 {
if *self >= 32768 {
(*self - 32768) as i16
} else {
(*self as i16) - 32767 - 1
}
}
#[inline]
fn to_u16(&self) -> u16 {
*self
}
#[inline]
fn to_f32(&self) -> f32 {
self.to_i16().to_f32()
}
}
impl Sample for i16 {
#[inline]
fn lerp(first: i16, second: i16, numerator: u32, denominator: u32) -> i16 {
(first as i32 + (second as i32 - first as i32) * numerator as i32 / denominator as i32) as i16
}
#[inline]
fn amplify(self, value: f32) -> i16 {
((self as f32) * value) as i16
}
#[inline]
fn zero_value() -> i16 {
0
}
#[inline]
fn to_i16(&self) -> i16 {
*self
}
#[inline]
fn to_u16(&self) -> u16 {
if *self < 0 {
(*self - ::std::i16::MIN) as u16
} else {
(*self as u16) + 32768
}
}
#[inline]
fn to_f32(&self) -> f32 {
if *self < 0 {
*self as f32 / -(::std::i16::MIN as f32)
} else {
*self as f32 / ::std::i16::MAX as f32
}
}
}
impl Sample for f32 {
#[inline]
fn lerp(first: f32, second: f32, numerator: u32, denominator: u32) -> f32 {
first + (second - first) * numerator as f32 / denominator as f32
}
#[inline]
fn amplify(self, value: f32) -> f32 {
self * value
}
#[inline]
fn zero_value() -> f32 {
0.0
}
#[inline]
fn to_i16(&self) -> i16 {
if *self >= 0.0 {
(*self * ::std::i16::MAX as f32) as i16
} else {
(-*self * ::std::i16::MIN as f32) as i16
}
}
#[inline]
fn to_u16(&self) -> u16 {
(((*self + 1.0) * 0.5) * ::std::u16::MAX as f32).round() as u16
}
#[inline]
fn to_f32(&self) -> f32 {
*self
}
}
/// Iterator that converts from a certain channels count to another.
pub struct ChannelsCountConverter<I> where I: Iterator {
input: I,
from: cpal::ChannelsCount,
to: cpal::ChannelsCount,
sample_repeat: Option<I::Item>,
next_output_sample_pos: cpal::ChannelsCount,
}
impl<I> ChannelsCountConverter<I> where I: Iterator {
///
///
/// # Panic
///
/// Panicks if `from` or `to` are equal to 0.
///
#[inline]
pub fn new(input: I, from: cpal::ChannelsCount, to: cpal::ChannelsCount)
-> ChannelsCountConverter<I>
{
assert!(from >= 1);
assert!(to >= 1);
ChannelsCountConverter {
input: input,
from: from,
to: to,
sample_repeat: None,
next_output_sample_pos: 0,
}
}
}
impl<I> Iterator for ChannelsCountConverter<I> where I: Iterator, I::Item: Clone {
type Item = I::Item;
fn next(&mut self) -> Option<I::Item> {
let result = if self.next_output_sample_pos == self.from - 1 {
let value = self.input.next();
self.sample_repeat = value.clone();
value
} else if self.next_output_sample_pos < self.from {
self.input.next()
} else {
self.sample_repeat.clone()
};
self.next_output_sample_pos += 1;
if self.next_output_sample_pos == self.to {
self.next_output_sample_pos -= self.to;
if self.from > self.to {
for _ in (self.to .. self.from) {
self.input.next(); // discarding extra input
}
}
}
result
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
let (min, max) = self.input.size_hint();
let min = (min / self.from as usize) * self.to as usize + self.next_output_sample_pos as usize;
let max = max.map(|max| (max / self.from as usize) * self.to as usize + self.next_output_sample_pos as usize);
(min, max)
}
}
impl<I> ExactSizeIterator for ChannelsCountConverter<I>
where I: ExactSizeIterator, I::Item: Clone {}
/// Iterator that converts from a certain samples rate to another.
pub struct SamplesRateConverter<I> where I: Iterator {
/// The iterator that gives us samples.
input: I,
/// We convert chunks of `from` samples into chunks of `to` samples.
from: u32,
/// We convert chunks of `from` samples into chunks of `to` samples.
to: u32,
/// One sample extracted from `input`.
current_sample: Option<I::Item>,
/// Position of `current_sample` modulo `from`.
current_sample_pos_in_chunk: u32,
/// The sample right after `current_sample`, extracted from `input`.
next_sample: Option<I::Item>,
/// The position of the next sample that the iterator should return, modulo `to`.
/// This counter is incremented (modulo `to`) every time the iterator is called.
next_output_sample_pos_in_chunk: u32,
}
impl<I> SamplesRateConverter<I> where I: Iterator {
///
///
/// # Panic
///
/// Panicks if `from` or `to` are equal to 0.
///
#[inline]
pub fn new(mut input: I, from: cpal::SamplesRate, to: cpal::SamplesRate)
-> SamplesRateConverter<I>
{
let from = from.0;
let to = to.0;
assert!(from >= 1);
assert!(to >= 1);
// finding greatest common divisor
let gcd = {
#[inline]
fn gcd(a: u32, b: u32) -> u32 {
if b == 0 {
a
} else {
gcd(b, a % b)
}
}
gcd(from, to)
};
let first_sample = input.next();
let second_sample = input.next();
SamplesRateConverter {
input: input,
from: from / gcd,
to: to / gcd,
current_sample_pos_in_chunk: 0,
next_output_sample_pos_in_chunk: 0,
current_sample: first_sample,
next_sample: second_sample,
}
}
}
impl<I> Iterator for SamplesRateConverter<I> where I: Iterator, I::Item: Sample + Clone {
type Item = I::Item;
fn next(&mut self) -> Option<I::Item> {
// The sample we are going to return from this function will be a linear interpolation
// between `self.current_sample` and `self.next_sample`.
// Finding the position of the first sample of the linear interpolation.
let req_left_sample = (self.from * self.next_output_sample_pos_in_chunk / self.to) %
self.from;
// Advancing `self.current_sample`, `self.next_sample` and
// `self.current_sample_pos_in_chunk` until the latter variable matches `req_left_sample`.
while self.current_sample_pos_in_chunk != req_left_sample {
self.current_sample_pos_in_chunk += 1;
self.current_sample_pos_in_chunk %= self.from;
self.current_sample = self.next_sample;
self.next_sample = self.input.next();
}
// Doing the linear interpolation. We handle a possible end of stream here.
let result = match (self.current_sample, self.next_sample) {
(Some(ref cur), Some(ref next)) => {
let numerator = (self.from * self.next_output_sample_pos_in_chunk) % self.to;
Sample::lerp(cur.clone(), next.clone(), numerator, self.to)
},
(Some(ref cur), None) if self.next_output_sample_pos_in_chunk == 0 => {
cur.clone()
},
_ => return None,
};
// Incrementing the counter for the next iteration.
self.next_output_sample_pos_in_chunk += 1;
self.next_output_sample_pos_in_chunk %= self.to;
Some(result)
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
let (min, max) = self.input.size_hint();
// TODO: inexact?
let min = (min / self.from as usize) * self.to as usize;
let max = max.map(|max| (max / self.from as usize) * self.to as usize);
(min, max)
}
}
impl<I> ExactSizeIterator for SamplesRateConverter<I>
where I: ExactSizeIterator, I::Item: Sample + Clone {}
pub struct AmplifierIterator<I> where I: Iterator {
input: I,
amplication: f32,
}
impl<I> AmplifierIterator<I> where I: Iterator {
#[inline]
pub fn new(input: I, amplication: f32) -> AmplifierIterator<I> {
AmplifierIterator {
input: input,
amplication: amplication,
}
}
#[inline]
pub fn set_amplification(&mut self, new_value: f32) {
self.amplication = new_value;
}
}
impl<I> Iterator for AmplifierIterator<I> where I: Iterator, I::Item: Sample {
type Item = I::Item;
#[inline]
fn next(&mut self) -> Option<I::Item> {
self.input.next().map(|value| value.amplify(self.amplication))
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
self.input.size_hint()
}
}
impl<I> ExactSizeIterator for AmplifierIterator<I>
where I: ExactSizeIterator, I::Item: Sample {}
#[cfg(test)]
mod test {
use super::Sample;
use super::ChannelsCountConverter;
#[test]
fn remove_channels() {
let input = vec![1u16, 2, 3, 1, 2, 3];
let output = ChannelsCountConverter::new(input.into_iter(), 3, 2).collect::<Vec<_>>();
assert_eq!(output, [1, 2, 1, 2]);
let input = vec![1u16, 2, 3, 4, 1, 2, 3, 4];
let output = ChannelsCountConverter::new(input.into_iter(), 4, 1).collect::<Vec<_>>();
assert_eq!(output, [1, 1]);
}
#[test]
fn add_channels() {
let input = vec![1u16, 2, 1, 2];
let output = ChannelsCountConverter::new(input.into_iter(), 2, 3).collect::<Vec<_>>();
assert_eq!(output, [1, 2, 2, 1, 2, 2]);
let input = vec![1u16, 2, 1, 2];
let output = ChannelsCountConverter::new(input.into_iter(), 2, 4).collect::<Vec<_>>();
assert_eq!(output, [1, 2, 2, 2, 1, 2, 2, 2]);
}
/*
#[test]
fn half_samples_rate() {
let result = convert_samples_rate(&[1u16, 16, 2, 17, 3, 18, 4, 19],
::SamplesRate(44100), ::SamplesRate(22050), 2);
assert_eq!(result, [1, 16, 3, 18]);
}
#[test]
fn double_samples_rate() {
let result = convert_samples_rate(&[2u16, 16, 4, 18, 6, 20, 8, 22],
::SamplesRate(22050), ::SamplesRate(44100), 2);
assert_eq!(result, [2, 16, 3, 17, 4, 18, 5, 19, 6, 20, 7, 21, 8, 22]);
}*/
#[test]
fn i16_to_i16() {
assert_eq!(0i16.to_i16(), 0);
assert_eq!((-467i16).to_i16(), -467);
assert_eq!(32767i16.to_i16(), 32767);
assert_eq!((-32768i16).to_i16(), -32768);
}
#[test]
fn i16_to_u16() {
assert_eq!(0i16.to_u16(), 32768);
assert_eq!((-16384i16).to_u16(), 16384);
assert_eq!(32767i16.to_u16(), 65535);
assert_eq!((-32768i16).to_u16(), 0);
}
#[test]
fn i16_to_f32() {
assert_eq!(0i16.to_f32(), 0.0);
assert_eq!((-16384i16).to_f32(), -0.5);
assert_eq!(32767i16.to_f32(), 1.0);
assert_eq!((-32768i16).to_f32(), -1.0);
}
#[test]
fn u16_to_i16() {
assert_eq!(32768u16.to_i16(), 0);
assert_eq!(16384u16.to_i16(), -16384);
assert_eq!(65535u16.to_i16(), 32767);
assert_eq!(0u16.to_i16(), -32768);
}
#[test]
fn u16_to_u16() {
assert_eq!(0u16.to_u16(), 0);
assert_eq!(467u16.to_u16(), 467);
assert_eq!(32767u16.to_u16(), 32767);
assert_eq!(65535u16.to_u16(), 65535);
}
#[test]
fn u16_to_f32() {
assert_eq!(0u16.to_f32(), -1.0);
assert_eq!(32768u16.to_f32(), 0.0);
assert_eq!(65535u16.to_f32(), 1.0);
}
#[test]
fn f32_to_i16() {
assert_eq!(0.0f32.to_i16(), 0);
assert_eq!((-0.5f32).to_i16(), ::std::i16::MIN / 2);
assert_eq!(1.0f32.to_i16(), ::std::i16::MAX);
assert_eq!((-1.0f32).to_i16(), ::std::i16::MIN);
}
#[test]
fn f32_to_u16() {
assert_eq!((-1.0f32).to_u16(), 0);
assert_eq!(0.0f32.to_u16(), 32768);
assert_eq!(1.0f32.to_u16(), 65535);
}
#[test]
fn f32_to_f32() {
assert_eq!(0.1f32.to_f32(), 0.1);
assert_eq!((-0.7f32).to_f32(), -0.7);
assert_eq!(1.0f32.to_f32(), 1.0);
}
}

View file

@ -1,9 +1,6 @@
use std::io::{Read, Seek}; use std::io::{Read, Seek};
use cpal::Endpoint; use cpal::Endpoint;
use cpal::Voice;
mod conversions;
mod vorbis; mod vorbis;
mod wav; mod wav;

View file

@ -1,7 +1,6 @@
use std::io::{Read, Seek}; use std::io::{Read, Seek};
use std::mem;
use super::Decoder; use super::Decoder;
use super::conversions; use conversions;
use cpal::{self, Endpoint, Voice}; use cpal::{self, Endpoint, Voice};
use vorbis; use vorbis;

View file

@ -2,11 +2,10 @@ use std::io::{Read, Seek, SeekFrom};
use std::cmp; use std::cmp;
use std::cmp::Ordering; use std::cmp::Ordering;
use super::Decoder; use super::Decoder;
use super::conversions; use conversions;
use cpal::{self, Endpoint, Voice}; use cpal::{self, Endpoint, Voice};
use hound::WavReader; use hound::WavReader;
use hound::WavSpec;
pub struct WavDecoder { pub struct WavDecoder {
reader: conversions::AmplifierIterator<Box<Iterator<Item=i16> + Send>>, reader: conversions::AmplifierIterator<Box<Iterator<Item=i16> + Send>>,

View file

@ -6,7 +6,6 @@ use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::Mutex; use std::sync::Mutex;
use cpal::Endpoint; use cpal::Endpoint;
use cpal::Voice;
use decoder; use decoder;
use decoder::Decoder; use decoder::Decoder;

View file

@ -9,6 +9,7 @@ pub use cpal::{Endpoint, get_endpoints_list, get_default_endpoint};
use std::io::{Read, Seek}; use std::io::{Read, Seek};
mod conversions;
mod decoder; mod decoder;
mod engine; mod engine;