mirror of
https://github.com/RustAudio/rodio
synced 2025-01-19 06:53:53 +00:00
Reorganize the conversions module
This commit is contained in:
parent
803c9ac192
commit
cefae3aa51
11 changed files with 534 additions and 521 deletions
38
src/conversions/amplifier.rs
Normal file
38
src/conversions/amplifier.rs
Normal 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
104
src/conversions/channels.rs
Normal 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
45
src/conversions/mod.rs
Normal 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
199
src/conversions/sample.rs
Normal 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);
|
||||
}
|
||||
}
|
145
src/conversions/samples_rate.rs
Normal file
145
src/conversions/samples_rate.rs
Normal 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]);
|
||||
}*/
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -1,9 +1,6 @@
|
|||
use std::io::{Read, Seek};
|
||||
|
||||
use cpal::Endpoint;
|
||||
use cpal::Voice;
|
||||
|
||||
mod conversions;
|
||||
mod vorbis;
|
||||
mod wav;
|
||||
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
use std::io::{Read, Seek};
|
||||
use std::mem;
|
||||
use super::Decoder;
|
||||
use super::conversions;
|
||||
use conversions;
|
||||
|
||||
use cpal::{self, Endpoint, Voice};
|
||||
use vorbis;
|
||||
|
|
|
@ -2,11 +2,10 @@ use std::io::{Read, Seek, SeekFrom};
|
|||
use std::cmp;
|
||||
use std::cmp::Ordering;
|
||||
use super::Decoder;
|
||||
use super::conversions;
|
||||
use conversions;
|
||||
|
||||
use cpal::{self, Endpoint, Voice};
|
||||
use hound::WavReader;
|
||||
use hound::WavSpec;
|
||||
|
||||
pub struct WavDecoder {
|
||||
reader: conversions::AmplifierIterator<Box<Iterator<Item=i16> + Send>>,
|
||||
|
|
|
@ -6,7 +6,6 @@ use std::sync::atomic::{AtomicUsize, Ordering};
|
|||
use std::sync::Mutex;
|
||||
|
||||
use cpal::Endpoint;
|
||||
use cpal::Voice;
|
||||
use decoder;
|
||||
use decoder::Decoder;
|
||||
|
||||
|
|
|
@ -9,6 +9,7 @@ pub use cpal::{Endpoint, get_endpoints_list, get_default_endpoint};
|
|||
|
||||
use std::io::{Read, Seek};
|
||||
|
||||
mod conversions;
|
||||
mod decoder;
|
||||
mod engine;
|
||||
|
||||
|
|
Loading…
Reference in a new issue