mirror of
https://github.com/RustAudio/rodio
synced 2024-12-13 13:42:34 +00:00
commit
21f2da5c64
32 changed files with 189 additions and 156 deletions
18
.rustfmt.toml
Normal file
18
.rustfmt.toml
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
fn_args_density = "Compressed"
|
||||||
|
fn_args_layout = "Visual"
|
||||||
|
fn_brace_style = "SameLineWhere"
|
||||||
|
fn_call_style = "Visual"
|
||||||
|
fn_empty_single_line = false
|
||||||
|
format_strings = true
|
||||||
|
generics_indent = "Visual"
|
||||||
|
impl_empty_single_line = false
|
||||||
|
match_block_trailing_comma = true
|
||||||
|
reorder_imported_names = true
|
||||||
|
reorder_imports = true
|
||||||
|
reorder_imports_in_group = true
|
||||||
|
spaces_around_ranges = true
|
||||||
|
use_try_shorthand = true
|
||||||
|
where_density = "Tall"
|
||||||
|
where_style = "Legacy"
|
||||||
|
wrap_match_arms = false
|
||||||
|
write_mode = "Overwrite"
|
|
@ -14,16 +14,18 @@ fn main() {
|
||||||
let file = std::fs::File::open("examples/music.ogg").unwrap();
|
let file = std::fs::File::open("examples/music.ogg").unwrap();
|
||||||
let source = rodio::Decoder::new(BufReader::new(file)).unwrap();
|
let source = rodio::Decoder::new(BufReader::new(file)).unwrap();
|
||||||
sink.append(source);
|
sink.append(source);
|
||||||
|
|
||||||
// A sound emitter playing the music starting at the left gradually moves to the right
|
// A sound emitter playing the music starting at the left gradually moves to the right
|
||||||
// eventually passing through the listener, then it continues on to the right for a distance until it
|
// eventually passing through the listener, then it continues on to the right for a distance
|
||||||
// stops and begins traveling to the left, it will eventually pass through the listener again.
|
// until it stops and begins traveling to the left, it will eventually pass through the
|
||||||
|
// listener again.
|
||||||
// This is repeated 5 times.
|
// This is repeated 5 times.
|
||||||
for _ in 0..5 {
|
for _ in 0 .. 5 {
|
||||||
for i in 1..1001 {
|
for i in 1 .. 1001 {
|
||||||
thread::sleep(Duration::from_millis(5));
|
thread::sleep(Duration::from_millis(5));
|
||||||
sink.set_emitter_position([(i - 500) as f32 / 50.0, 0.0, 0.0]);
|
sink.set_emitter_position([(i - 500) as f32 / 50.0, 0.0, 0.0]);
|
||||||
}
|
}
|
||||||
for i in 1..1001 {
|
for i in 1 .. 1001 {
|
||||||
thread::sleep(Duration::from_millis(5));
|
thread::sleep(Duration::from_millis(5));
|
||||||
sink.set_emitter_position([-(i - 500) as f32 / 50.0, 0.0, 0.0]);
|
sink.set_emitter_position([-(i - 500) as f32 / 50.0, 0.0, 0.0]);
|
||||||
}
|
}
|
||||||
|
|
|
@ -45,7 +45,7 @@ impl<S> SamplesBuffer<S>
|
||||||
|
|
||||||
let data = data.into();
|
let data = data.into();
|
||||||
let duration_ns = 1_000_000_000u64.checked_mul(data.len() as u64).unwrap() /
|
let duration_ns = 1_000_000_000u64.checked_mul(data.len() as u64).unwrap() /
|
||||||
samples_rate as u64 / channels as u64;
|
samples_rate as u64 / channels as u64;
|
||||||
let duration = Duration::new(duration_ns / 1_000_000_000,
|
let duration = Duration::new(duration_ns / 1_000_000_000,
|
||||||
(duration_ns % 1_000_000_000) as u32);
|
(duration_ns % 1_000_000_000) as u32);
|
||||||
|
|
||||||
|
|
|
@ -22,9 +22,7 @@ impl<I> ChannelsCountConverter<I>
|
||||||
/// Panicks if `from` or `to` are equal to 0.
|
/// Panicks if `from` or `to` are equal to 0.
|
||||||
///
|
///
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn new(input: I,
|
pub fn new(input: I, from: cpal::ChannelsCount, to: cpal::ChannelsCount)
|
||||||
from: cpal::ChannelsCount,
|
|
||||||
to: cpal::ChannelsCount)
|
|
||||||
-> ChannelsCountConverter<I> {
|
-> ChannelsCountConverter<I> {
|
||||||
assert!(from >= 1);
|
assert!(from >= 1);
|
||||||
assert!(to >= 1);
|
assert!(to >= 1);
|
||||||
|
@ -68,7 +66,7 @@ impl<I> Iterator for ChannelsCountConverter<I>
|
||||||
self.next_output_sample_pos -= self.to;
|
self.next_output_sample_pos -= self.to;
|
||||||
|
|
||||||
if self.from > self.to {
|
if self.from > self.to {
|
||||||
for _ in self.to..self.from {
|
for _ in self.to .. self.from {
|
||||||
self.input.next(); // discarding extra input
|
self.input.next(); // discarding extra input
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -82,10 +80,10 @@ impl<I> Iterator for ChannelsCountConverter<I>
|
||||||
let (min, max) = self.input.size_hint();
|
let (min, max) = self.input.size_hint();
|
||||||
|
|
||||||
let min = (min / self.from as usize) * self.to as usize +
|
let min = (min / self.from as usize) * self.to as usize +
|
||||||
self.next_output_sample_pos as usize;
|
self.next_output_sample_pos as usize;
|
||||||
let max = max.map(|max| {
|
let max = max.map(|max| {
|
||||||
(max / self.from as usize) * self.to as usize +
|
(max / self.from as usize) * self.to as usize +
|
||||||
self.next_output_sample_pos as usize
|
self.next_output_sample_pos as usize
|
||||||
});
|
});
|
||||||
|
|
||||||
(min, max)
|
(min, max)
|
||||||
|
|
|
@ -4,9 +4,10 @@ This module contains function that will convert from one PCM format to another.
|
||||||
This includes conversion between samples formats, channels or sample rates.
|
This includes conversion between samples formats, channels or sample rates.
|
||||||
|
|
||||||
*/
|
*/
|
||||||
pub use self::sample::Sample;
|
|
||||||
pub use self::sample::DataConverter;
|
|
||||||
pub use self::channels::ChannelsCountConverter;
|
pub use self::channels::ChannelsCountConverter;
|
||||||
|
pub use self::sample::DataConverter;
|
||||||
|
pub use self::sample::Sample;
|
||||||
pub use self::samples_rate::SamplesRateConverter;
|
pub use self::samples_rate::SamplesRateConverter;
|
||||||
|
|
||||||
mod channels;
|
mod channels;
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
use std::marker::PhantomData;
|
|
||||||
use cpal;
|
use cpal;
|
||||||
|
use std::marker::PhantomData;
|
||||||
|
|
||||||
/// Converts the samples data type to `O`.
|
/// Converts the samples data type to `O`.
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
|
@ -86,7 +87,8 @@ pub trait Sample: cpal::Sample {
|
||||||
fn to_f32(&self) -> f32;
|
fn to_f32(&self) -> f32;
|
||||||
|
|
||||||
/// Converts any sample type to this one by calling `to_i16`, `to_u16` or `to_f32`.
|
/// Converts any sample type to this one by calling `to_i16`, `to_u16` or `to_f32`.
|
||||||
fn from<S>(&S) -> Self where S: Sample;
|
fn from<S>(&S) -> Self
|
||||||
|
where S: Sample;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Sample for u16 {
|
impl Sample for u16 {
|
||||||
|
@ -141,7 +143,7 @@ impl Sample for i16 {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn lerp(first: i16, second: i16, numerator: u32, denominator: u32) -> i16 {
|
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
|
(first as i32 + (second as i32 - first as i32) * numerator as i32 / denominator as i32) as
|
||||||
i16
|
i16
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
use cpal;
|
|
||||||
use conversions::Sample;
|
use conversions::Sample;
|
||||||
|
use cpal;
|
||||||
|
|
||||||
use std::mem;
|
use std::mem;
|
||||||
|
|
||||||
|
@ -38,9 +39,7 @@ impl<I> SamplesRateConverter<I>
|
||||||
/// Panicks if `from` or `to` are equal to 0.
|
/// Panicks if `from` or `to` are equal to 0.
|
||||||
///
|
///
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn new(mut input: I,
|
pub fn new(mut input: I, from: cpal::SamplesRate, to: cpal::SamplesRate,
|
||||||
from: cpal::SamplesRate,
|
|
||||||
to: cpal::SamplesRate,
|
|
||||||
num_channels: cpal::ChannelsCount)
|
num_channels: cpal::ChannelsCount)
|
||||||
-> SamplesRateConverter<I> {
|
-> SamplesRateConverter<I> {
|
||||||
let from = from.0;
|
let from = from.0;
|
||||||
|
@ -98,7 +97,7 @@ impl<I> SamplesRateConverter<I>
|
||||||
|
|
||||||
mem::swap(&mut self.current_frame, &mut self.next_frame);
|
mem::swap(&mut self.current_frame, &mut self.next_frame);
|
||||||
self.next_frame.clear();
|
self.next_frame.clear();
|
||||||
for _ in 0..self.next_frame.capacity() {
|
for _ in 0 .. self.next_frame.capacity() {
|
||||||
if let Some(i) = self.input.next() {
|
if let Some(i) = self.input.next() {
|
||||||
self.next_frame.push(i);
|
self.next_frame.push(i);
|
||||||
} else {
|
} else {
|
||||||
|
@ -142,7 +141,7 @@ impl<I> Iterator for SamplesRateConverter<I>
|
||||||
} else {
|
} else {
|
||||||
// Finding the position of the first sample of the linear interpolation.
|
// Finding the position of the first sample of the linear interpolation.
|
||||||
let req_left_sample = (self.from * self.next_output_frame_pos_in_chunk / self.to) %
|
let req_left_sample = (self.from * self.next_output_frame_pos_in_chunk / self.to) %
|
||||||
self.from;
|
self.from;
|
||||||
|
|
||||||
// Advancing `self.current_frame`, `self.next_frame` and
|
// Advancing `self.current_frame`, `self.next_frame` and
|
||||||
// `self.current_frame_pos_in_chunk` until the latter variable
|
// `self.current_frame_pos_in_chunk` until the latter variable
|
||||||
|
@ -162,7 +161,8 @@ impl<I> Iterator for SamplesRateConverter<I>
|
||||||
self.current_frame
|
self.current_frame
|
||||||
.iter()
|
.iter()
|
||||||
.zip(self.next_frame.iter())
|
.zip(self.next_frame.iter())
|
||||||
.enumerate() {
|
.enumerate()
|
||||||
|
{
|
||||||
let sample = Sample::lerp(cur.clone(), next.clone(), numerator, self.to);
|
let sample = Sample::lerp(cur.clone(), next.clone(), numerator, self.to);
|
||||||
|
|
||||||
if off == 0 {
|
if off == 0 {
|
||||||
|
@ -209,8 +209,8 @@ impl<I> Iterator for SamplesRateConverter<I>
|
||||||
let samples_after_chunk = samples_after_chunk
|
let samples_after_chunk = samples_after_chunk
|
||||||
.saturating_sub(self.from
|
.saturating_sub(self.from
|
||||||
.saturating_sub(self.current_frame_pos_in_chunk + 2) as
|
.saturating_sub(self.current_frame_pos_in_chunk + 2) as
|
||||||
usize *
|
usize *
|
||||||
self.current_frame.capacity());
|
self.current_frame.capacity());
|
||||||
// calculating the number of samples after the transformation
|
// calculating the number of samples after the transformation
|
||||||
// TODO: this is wrong here \|/
|
// TODO: this is wrong here \|/
|
||||||
let samples_after_chunk = samples_after_chunk * self.to as usize / self.from as usize;
|
let samples_after_chunk = samples_after_chunk * self.to as usize / self.from as usize;
|
||||||
|
@ -218,7 +218,7 @@ impl<I> Iterator for SamplesRateConverter<I>
|
||||||
// `samples_current_chunk` will contain the number of samples remaining to be output
|
// `samples_current_chunk` will contain the number of samples remaining to be output
|
||||||
// for the chunk currently being processed
|
// for the chunk currently being processed
|
||||||
let samples_current_chunk = (self.to - self.next_output_frame_pos_in_chunk) as usize *
|
let samples_current_chunk = (self.to - self.next_output_frame_pos_in_chunk) as usize *
|
||||||
self.current_frame.capacity();
|
self.current_frame.capacity();
|
||||||
|
|
||||||
samples_current_chunk + samples_after_chunk + self.output_buffer.len()
|
samples_current_chunk + samples_after_chunk + self.output_buffer.len()
|
||||||
};
|
};
|
||||||
|
@ -240,8 +240,8 @@ impl<I> ExactSizeIterator for SamplesRateConverter<I>
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
use cpal::SamplesRate;
|
|
||||||
use super::SamplesRateConverter;
|
use super::SamplesRateConverter;
|
||||||
|
use cpal::SamplesRate;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn zero() {
|
fn zero() {
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
use std::mem;
|
|
||||||
use std::io::{Read, Seek, SeekFrom};
|
use std::io::{Read, Seek, SeekFrom};
|
||||||
|
use std::mem;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
use Source;
|
use Source;
|
||||||
|
@ -34,7 +35,7 @@ impl<R> FlacDecoder<R>
|
||||||
Ok(FlacDecoder {
|
Ok(FlacDecoder {
|
||||||
reader: reader,
|
reader: reader,
|
||||||
current_block: Vec::with_capacity(spec.max_block_size as usize *
|
current_block: Vec::with_capacity(spec.max_block_size as usize *
|
||||||
spec.channels as usize),
|
spec.channels as usize),
|
||||||
current_block_channel_len: 1,
|
current_block_channel_len: 1,
|
||||||
current_block_off: 0,
|
current_block_off: 0,
|
||||||
bits_per_sample: spec.bits_per_sample,
|
bits_per_sample: spec.bits_per_sample,
|
||||||
|
@ -79,8 +80,8 @@ impl<R> Iterator for FlacDecoder<R>
|
||||||
if self.current_block_off < self.current_block.len() {
|
if self.current_block_off < self.current_block.len() {
|
||||||
// Read from current block.
|
// Read from current block.
|
||||||
let real_offset = (self.current_block_off % self.channels as usize) *
|
let real_offset = (self.current_block_off % self.channels as usize) *
|
||||||
self.current_block_channel_len +
|
self.current_block_channel_len +
|
||||||
self.current_block_off / self.channels as usize;
|
self.current_block_off / self.channels as usize;
|
||||||
let raw_val = self.current_block[real_offset];
|
let raw_val = self.current_block[real_offset];
|
||||||
self.current_block_off += 1;
|
self.current_block_off += 1;
|
||||||
let real_val = if self.bits_per_sample == 16 {
|
let real_val = if self.bits_per_sample == 16 {
|
||||||
|
@ -100,7 +101,7 @@ impl<R> Iterator for FlacDecoder<R>
|
||||||
Ok(Some(block)) => {
|
Ok(Some(block)) => {
|
||||||
self.current_block_channel_len = (block.len() / block.channels()) as usize;
|
self.current_block_channel_len = (block.len() / block.channels()) as usize;
|
||||||
self.current_block = block.into_buffer();
|
self.current_block = block.into_buffer();
|
||||||
}
|
},
|
||||||
_ => return None,
|
_ => return None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,14 +35,14 @@ impl<R> Decoder<R>
|
||||||
Err(data) => data,
|
Err(data) => data,
|
||||||
Ok(decoder) => {
|
Ok(decoder) => {
|
||||||
return Ok(Decoder(DecoderImpl::Wav(decoder)));
|
return Ok(Decoder(DecoderImpl::Wav(decoder)));
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
let data = match flac::FlacDecoder::new(data) {
|
let data = match flac::FlacDecoder::new(data) {
|
||||||
Err(data) => data,
|
Err(data) => data,
|
||||||
Ok(decoder) => {
|
Ok(decoder) => {
|
||||||
return Ok(Decoder(DecoderImpl::Flac(decoder)));
|
return Ok(Decoder(DecoderImpl::Flac(decoder)));
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Ok(decoder) = vorbis::VorbisDecoder::new(data) {
|
if let Ok(decoder) = vorbis::VorbisDecoder::new(data) {
|
||||||
|
|
|
@ -77,18 +77,20 @@ impl<R> Iterator for VorbisDecoder<R>
|
||||||
if let Some(sample) = self.current_data.next() {
|
if let Some(sample) = self.current_data.next() {
|
||||||
if self.current_data.len() == 0 {
|
if self.current_data.len() == 0 {
|
||||||
if let Some(data) = self.stream_reader
|
if let Some(data) = self.stream_reader
|
||||||
.read_dec_packet_itl()
|
.read_dec_packet_itl()
|
||||||
.ok()
|
.ok()
|
||||||
.and_then(|v| v) {
|
.and_then(|v| v)
|
||||||
|
{
|
||||||
self.current_data = data.into_iter();
|
self.current_data = data.into_iter();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return Some(sample);
|
return Some(sample);
|
||||||
} else {
|
} else {
|
||||||
if let Some(data) = self.stream_reader
|
if let Some(data) = self.stream_reader
|
||||||
.read_dec_packet_itl()
|
.read_dec_packet_itl()
|
||||||
.ok()
|
.ok()
|
||||||
.and_then(|v| v) {
|
.and_then(|v| v)
|
||||||
|
{
|
||||||
self.current_data = data.into_iter();
|
self.current_data = data.into_iter();
|
||||||
}
|
}
|
||||||
return self.current_data.next();
|
return self.current_data.next();
|
||||||
|
|
|
@ -67,7 +67,10 @@ impl<R> Iterator for SamplesIterator<R>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<R> ExactSizeIterator for SamplesIterator<R> where R: Read + Seek {}
|
impl<R> ExactSizeIterator for SamplesIterator<R>
|
||||||
|
where R: Read + Seek
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
impl<R> Source for WavDecoder<R>
|
impl<R> Source for WavDecoder<R>
|
||||||
where R: Read + Seek
|
where R: Read + Seek
|
||||||
|
@ -110,7 +113,10 @@ impl<R> Iterator for WavDecoder<R>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<R> ExactSizeIterator for WavDecoder<R> where R: Read + Seek {}
|
impl<R> ExactSizeIterator for WavDecoder<R>
|
||||||
|
where R: Read + Seek
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns true if the stream contains WAV data, then resets it to where it was.
|
/// Returns true if the stream contains WAV data, then resets it to where it was.
|
||||||
fn is_wave<R>(mut data: R) -> bool
|
fn is_wave<R>(mut data: R) -> bool
|
||||||
|
|
|
@ -17,8 +17,7 @@ use Sample;
|
||||||
/// added to the mixer will be converted to these values.
|
/// added to the mixer will be converted to these values.
|
||||||
///
|
///
|
||||||
/// After creating a mixer, you can add new sounds with the controller.
|
/// After creating a mixer, you can add new sounds with the controller.
|
||||||
pub fn mixer<S>(channels: u16,
|
pub fn mixer<S>(channels: u16, samples_rate: u32)
|
||||||
samples_rate: u32)
|
|
||||||
-> (Arc<DynamicMixerController<S>>, DynamicMixer<S>)
|
-> (Arc<DynamicMixerController<S>>, DynamicMixer<S>)
|
||||||
where S: Sample + Send + 'static
|
where S: Sample + Send + 'static
|
||||||
{
|
{
|
||||||
|
@ -143,8 +142,8 @@ impl<S> Iterator for DynamicMixer<S>
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use dynamic_mixer;
|
|
||||||
use buffer::SamplesBuffer;
|
use buffer::SamplesBuffer;
|
||||||
|
use dynamic_mixer;
|
||||||
use source::Source;
|
use source::Source;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
|
@ -1,21 +1,21 @@
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::collections::hash_map::Entry;
|
use std::collections::hash_map::Entry;
|
||||||
use std::thread::Builder;
|
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::sync::Mutex;
|
use std::sync::Mutex;
|
||||||
use std::sync::Weak;
|
use std::sync::Weak;
|
||||||
|
use std::thread::Builder;
|
||||||
|
|
||||||
use futures::stream::Stream;
|
use futures::stream::Stream;
|
||||||
use futures::task;
|
use futures::task;
|
||||||
use futures::task::Executor;
|
use futures::task::Executor;
|
||||||
use futures::task::Run;
|
use futures::task::Run;
|
||||||
|
|
||||||
use cpal;
|
|
||||||
use cpal::UnknownTypeBuffer;
|
|
||||||
use cpal::EventLoop;
|
|
||||||
use cpal::Voice;
|
|
||||||
use cpal::Endpoint;
|
|
||||||
use conversions::Sample;
|
use conversions::Sample;
|
||||||
|
use cpal;
|
||||||
|
use cpal::Endpoint;
|
||||||
|
use cpal::EventLoop;
|
||||||
|
use cpal::UnknownTypeBuffer;
|
||||||
|
use cpal::Voice;
|
||||||
use dynamic_mixer;
|
use dynamic_mixer;
|
||||||
use source::Source;
|
use source::Source;
|
||||||
|
|
||||||
|
@ -77,7 +77,7 @@ impl Engine {
|
||||||
e.insert(Arc::downgrade(&mixer));
|
e.insert(Arc::downgrade(&mixer));
|
||||||
voice_to_start = Some(voice);
|
voice_to_start = Some(voice);
|
||||||
mixer
|
mixer
|
||||||
}
|
},
|
||||||
Entry::Occupied(mut e) => {
|
Entry::Occupied(mut e) => {
|
||||||
if let Some(m) = e.get().upgrade() {
|
if let Some(m) = e.get().upgrade() {
|
||||||
m.clone()
|
m.clone()
|
||||||
|
@ -87,7 +87,7 @@ impl Engine {
|
||||||
voice_to_start = Some(voice);
|
voice_to_start = Some(voice);
|
||||||
mixer
|
mixer
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -100,8 +100,7 @@ impl Engine {
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: handle possible errors here
|
// TODO: handle possible errors here
|
||||||
fn new_voice(endpoint: &Endpoint,
|
fn new_voice(endpoint: &Endpoint, events_loop: &Arc<EventLoop>)
|
||||||
events_loop: &Arc<EventLoop>)
|
|
||||||
-> (Arc<dynamic_mixer::DynamicMixerController<f32>>, Voice) {
|
-> (Arc<dynamic_mixer::DynamicMixerController<f32>>, Voice) {
|
||||||
// Determine the format to use for the new voice.
|
// Determine the format to use for the new voice.
|
||||||
let format = endpoint
|
let format = endpoint
|
||||||
|
@ -145,17 +144,17 @@ fn new_voice(endpoint: &Endpoint,
|
||||||
for (o, i) in buffer.iter_mut().zip(mixer_rx.by_ref()) {
|
for (o, i) in buffer.iter_mut().zip(mixer_rx.by_ref()) {
|
||||||
*o = i.to_u16();
|
*o = i.to_u16();
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
UnknownTypeBuffer::I16(ref mut buffer) => {
|
UnknownTypeBuffer::I16(ref mut buffer) => {
|
||||||
for (o, i) in buffer.iter_mut().zip(mixer_rx.by_ref()) {
|
for (o, i) in buffer.iter_mut().zip(mixer_rx.by_ref()) {
|
||||||
*o = i.to_i16();
|
*o = i.to_i16();
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
UnknownTypeBuffer::F32(ref mut buffer) => {
|
UnknownTypeBuffer::F32(ref mut buffer) => {
|
||||||
for (o, i) in buffer.iter_mut().zip(mixer_rx.by_ref()) {
|
for (o, i) in buffer.iter_mut().zip(mixer_rx.by_ref()) {
|
||||||
*o = i;
|
*o = i;
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
|
@ -92,14 +92,14 @@ extern crate lazy_static;
|
||||||
extern crate lewton;
|
extern crate lewton;
|
||||||
extern crate cgmath;
|
extern crate cgmath;
|
||||||
|
|
||||||
pub use cpal::{Endpoint, get_endpoints_list, get_default_endpoint};
|
pub use cpal::{Endpoint, get_default_endpoint, get_endpoints_list};
|
||||||
|
|
||||||
pub use conversions::Sample;
|
pub use conversions::Sample;
|
||||||
pub use decoder::Decoder;
|
pub use decoder::Decoder;
|
||||||
pub use engine::play_raw;
|
pub use engine::play_raw;
|
||||||
pub use sink::Sink;
|
pub use sink::Sink;
|
||||||
pub use spatial_sink::SpatialSink;
|
|
||||||
pub use source::Source;
|
pub use source::Source;
|
||||||
|
pub use spatial_sink::SpatialSink;
|
||||||
|
|
||||||
use std::io::{Read, Seek};
|
use std::io::{Read, Seek};
|
||||||
|
|
||||||
|
@ -119,7 +119,7 @@ pub mod source;
|
||||||
pub fn play_once<R>(endpoint: &Endpoint, input: R) -> Result<Sink, decoder::DecoderError>
|
pub fn play_once<R>(endpoint: &Endpoint, input: R) -> Result<Sink, decoder::DecoderError>
|
||||||
where R: Read + Seek + Send + 'static
|
where R: Read + Seek + Send + 'static
|
||||||
{
|
{
|
||||||
let input = try!(decoder::Decoder::new(input));
|
let input = decoder::Decoder::new(input)?;
|
||||||
let sink = Sink::new(endpoint);
|
let sink = Sink::new(endpoint);
|
||||||
sink.append(input);
|
sink.append(input);
|
||||||
Ok(sink)
|
Ok(sink)
|
||||||
|
|
|
@ -217,8 +217,8 @@ impl<S> SourcesQueueOutput<S>
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use queue;
|
|
||||||
use buffer::SamplesBuffer;
|
use buffer::SamplesBuffer;
|
||||||
|
use queue;
|
||||||
use source::Source;
|
use source::Source;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -260,7 +260,7 @@ mod tests {
|
||||||
assert_eq!(rx.next(), Some(10));
|
assert_eq!(rx.next(), Some(10));
|
||||||
assert_eq!(rx.next(), Some(-10));
|
assert_eq!(rx.next(), Some(-10));
|
||||||
|
|
||||||
for _ in 0..100000 {
|
for _ in 0 .. 100000 {
|
||||||
assert_eq!(rx.next(), Some(0));
|
assert_eq!(rx.next(), Some(0));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -270,7 +270,7 @@ mod tests {
|
||||||
fn no_delay_when_added() {
|
fn no_delay_when_added() {
|
||||||
let (tx, mut rx) = queue::queue(true);
|
let (tx, mut rx) = queue::queue(true);
|
||||||
|
|
||||||
for _ in 0..500 {
|
for _ in 0 .. 500 {
|
||||||
assert_eq!(rx.next(), Some(0));
|
assert_eq!(rx.next(), Some(0));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
30
src/sink.rs
30
src/sink.rs
|
@ -1,15 +1,16 @@
|
||||||
|
|
||||||
|
use std::sync::Arc;
|
||||||
|
use std::sync::Mutex;
|
||||||
use std::sync::atomic::AtomicBool;
|
use std::sync::atomic::AtomicBool;
|
||||||
use std::sync::atomic::Ordering;
|
use std::sync::atomic::Ordering;
|
||||||
use std::sync::mpsc::Receiver;
|
use std::sync::mpsc::Receiver;
|
||||||
use std::sync::Arc;
|
|
||||||
use std::sync::Mutex;
|
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
|
use Endpoint;
|
||||||
|
use Sample;
|
||||||
|
use Source;
|
||||||
use play_raw;
|
use play_raw;
|
||||||
use queue;
|
use queue;
|
||||||
use Endpoint;
|
|
||||||
use Source;
|
|
||||||
use Sample;
|
|
||||||
|
|
||||||
/// Handle to an endpoint that outputs sounds.
|
/// Handle to an endpoint that outputs sounds.
|
||||||
///
|
///
|
||||||
|
@ -58,15 +59,16 @@ impl Sink {
|
||||||
.pausable(false)
|
.pausable(false)
|
||||||
.amplify(1.0)
|
.amplify(1.0)
|
||||||
.stoppable()
|
.stoppable()
|
||||||
.periodic_access(Duration::from_millis(5),
|
.periodic_access(Duration::from_millis(5), move |src| {
|
||||||
move |src| if stopped.load(Ordering::SeqCst) {
|
if stopped.load(Ordering::SeqCst) {
|
||||||
src.stop();
|
src.stop();
|
||||||
} else {
|
} else {
|
||||||
src.inner_mut().set_factor(*volume.lock().unwrap());
|
src.inner_mut().set_factor(*volume.lock().unwrap());
|
||||||
src.inner_mut()
|
src.inner_mut()
|
||||||
.inner_mut()
|
.inner_mut()
|
||||||
.set_paused(pause.load(Ordering::SeqCst));
|
.set_paused(pause.load(Ordering::SeqCst));
|
||||||
})
|
}
|
||||||
|
})
|
||||||
.convert_samples();
|
.convert_samples();
|
||||||
|
|
||||||
*self.sleep_until_end.lock().unwrap() = Some(self.queue_tx.append_with_signal(source));
|
*self.sleep_until_end.lock().unwrap() = Some(self.queue_tx.append_with_signal(source));
|
||||||
|
|
|
@ -55,9 +55,7 @@ impl<I> Iterator for Amplify<I>
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn next(&mut self) -> Option<I::Item> {
|
fn next(&mut self) -> Option<I::Item> {
|
||||||
self.input
|
self.input.next().map(|value| value.amplify(self.factor))
|
||||||
.next()
|
|
||||||
.map(|value| value.amplify(self.factor))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
|
|
@ -75,8 +75,10 @@ impl<I> Iterator for BltFilter<I>
|
||||||
Some(s) => s,
|
Some(s) => s,
|
||||||
};
|
};
|
||||||
|
|
||||||
let result = self.applier.as_ref().unwrap().apply(sample, self.x_n1, self.x_n2,
|
let result = self.applier
|
||||||
self.y_n1, self.y_n2);
|
.as_ref()
|
||||||
|
.unwrap()
|
||||||
|
.apply(sample, self.x_n1, self.x_n2, self.y_n1, self.y_n2);
|
||||||
|
|
||||||
self.y_n2 = self.y_n1;
|
self.y_n2 = self.y_n1;
|
||||||
self.x_n2 = self.x_n1;
|
self.x_n2 = self.x_n1;
|
||||||
|
@ -151,7 +153,7 @@ impl BltFormula {
|
||||||
a1: a1 / a0,
|
a1: a1 / a0,
|
||||||
a2: a2 / a0,
|
a2: a2 / a0,
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,8 +2,8 @@ use std::cmp;
|
||||||
use std::sync::{Arc, Mutex};
|
use std::sync::{Arc, Mutex};
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
use Source;
|
|
||||||
use Sample;
|
use Sample;
|
||||||
|
use Source;
|
||||||
|
|
||||||
/// Internal function that builds a `Buffered` object.
|
/// Internal function that builds a `Buffered` object.
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -106,7 +106,7 @@ impl<I> Buffered<I>
|
||||||
&Frame::Input(ref input) => {
|
&Frame::Input(ref input) => {
|
||||||
let input = input.lock().unwrap().take().unwrap();
|
let input = input.lock().unwrap().take().unwrap();
|
||||||
extract(input)
|
extract(input)
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
*next_frame_ptr = next_frame.clone();
|
*next_frame_ptr = next_frame.clone();
|
||||||
|
@ -134,12 +134,12 @@ impl<I> Iterator for Buffered<I>
|
||||||
current_sample = Some(data[self.position_in_frame].clone());
|
current_sample = Some(data[self.position_in_frame].clone());
|
||||||
self.position_in_frame += 1;
|
self.position_in_frame += 1;
|
||||||
advance_frame = self.position_in_frame >= data.len();
|
advance_frame = self.position_in_frame >= data.len();
|
||||||
}
|
},
|
||||||
|
|
||||||
&Frame::End => {
|
&Frame::End => {
|
||||||
current_sample = None;
|
current_sample = None;
|
||||||
advance_frame = false;
|
advance_frame = false;
|
||||||
}
|
},
|
||||||
|
|
||||||
&Frame::Input(_) => unreachable!(),
|
&Frame::Input(_) => unreachable!(),
|
||||||
};
|
};
|
||||||
|
|
|
@ -26,7 +26,7 @@ impl<I> ChannelVolume<I>
|
||||||
I::Item: Sample
|
I::Item: Sample
|
||||||
{
|
{
|
||||||
let mut sample = I::Item::zero_value();
|
let mut sample = I::Item::zero_value();
|
||||||
for _ in 0..input.channels() {
|
for _ in 0 .. input.channels() {
|
||||||
if let Some(s) = input.next() {
|
if let Some(s) = input.next() {
|
||||||
sample = sample.saturating_add(s);
|
sample = sample.saturating_add(s);
|
||||||
}
|
}
|
||||||
|
@ -61,7 +61,7 @@ impl<I> Iterator for ChannelVolume<I>
|
||||||
if self.current_channel >= self.channel_volumes.len() {
|
if self.current_channel >= self.channel_volumes.len() {
|
||||||
self.current_channel = 0;
|
self.current_channel = 0;
|
||||||
let mut sample = I::Item::zero_value();
|
let mut sample = I::Item::zero_value();
|
||||||
for _ in 0..self.input.channels() {
|
for _ in 0 .. self.input.channels() {
|
||||||
if let Some(s) = self.input.next() {
|
if let Some(s) = self.input.next() {
|
||||||
sample = sample.saturating_add(s);
|
sample = sample.saturating_add(s);
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
use Source;
|
|
||||||
use Sample;
|
use Sample;
|
||||||
|
use Source;
|
||||||
|
|
||||||
/// Internal function that builds a `Delay` object.
|
/// Internal function that builds a `Delay` object.
|
||||||
pub fn delay<I>(input: I, duration: Duration) -> Delay<I>
|
pub fn delay<I>(input: I, duration: Duration) -> Delay<I>
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
use std::marker::PhantomData;
|
|
||||||
use std::time::Duration;
|
|
||||||
use Sample;
|
use Sample;
|
||||||
use Source;
|
use Source;
|
||||||
|
use std::marker::PhantomData;
|
||||||
|
use std::time::Duration;
|
||||||
|
|
||||||
/// An empty source.
|
/// An empty source.
|
||||||
#[derive(Debug, Copy, Clone)]
|
#[derive(Debug, Copy, Clone)]
|
||||||
|
|
|
@ -42,7 +42,7 @@ impl<I> Iterator for FadeIn<I>
|
||||||
|
|
||||||
let factor = 1.0 - self.remaining_ns / self.total_ns;
|
let factor = 1.0 - self.remaining_ns / self.total_ns;
|
||||||
self.remaining_ns -= 1000000000.0 /
|
self.remaining_ns -= 1000000000.0 /
|
||||||
(self.input.samples_rate() as f32 * self.channels() as f32);
|
(self.input.samples_rate() as f32 * self.channels() as f32);
|
||||||
self.input.next().map(|value| value.amplify(factor))
|
self.input.next().map(|value| value.amplify(factor))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
use source::from_iter;
|
|
||||||
use source::FromIter;
|
use source::FromIter;
|
||||||
|
use source::from_iter;
|
||||||
|
|
||||||
/// Builds a source that chains sources built from a factory.
|
/// Builds a source that chains sources built from a factory.
|
||||||
///
|
///
|
||||||
|
|
|
@ -137,19 +137,19 @@ impl<I> Source for FromIter<I>
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use buffer::SamplesBuffer;
|
use buffer::SamplesBuffer;
|
||||||
use source::from_iter;
|
|
||||||
use source::Source;
|
use source::Source;
|
||||||
|
use source::from_iter;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn basic() {
|
fn basic() {
|
||||||
let mut rx =
|
let mut rx =
|
||||||
from_iter((0..2).map(|n| if n == 0 {
|
from_iter((0 .. 2).map(|n| if n == 0 {
|
||||||
SamplesBuffer::new(1, 48000, vec![10i16, -10, 10, -10])
|
SamplesBuffer::new(1, 48000, vec![10i16, -10, 10, -10])
|
||||||
} else if n == 1 {
|
} else if n == 1 {
|
||||||
SamplesBuffer::new(2, 96000, vec![5i16, 5, 5, 5])
|
SamplesBuffer::new(2, 96000, vec![5i16, 5, 5, 5])
|
||||||
} else {
|
} else {
|
||||||
unreachable!()
|
unreachable!()
|
||||||
}));
|
}));
|
||||||
|
|
||||||
assert_eq!(rx.channels(), 1);
|
assert_eq!(rx.channels(), 1);
|
||||||
assert_eq!(rx.samples_rate(), 48000);
|
assert_eq!(rx.samples_rate(), 48000);
|
||||||
|
@ -159,7 +159,7 @@ mod tests {
|
||||||
assert_eq!(rx.next(), Some(-10));
|
assert_eq!(rx.next(), Some(-10));
|
||||||
/*assert_eq!(rx.channels(), 2);
|
/*assert_eq!(rx.channels(), 2);
|
||||||
assert_eq!(rx.samples_rate(), 96000);*/
|
assert_eq!(rx.samples_rate(), 96000);*/
|
||||||
// FIXME: not working
|
// FIXME: not working
|
||||||
assert_eq!(rx.next(), Some(5));
|
assert_eq!(rx.next(), Some(5));
|
||||||
assert_eq!(rx.next(), Some(5));
|
assert_eq!(rx.next(), Some(5));
|
||||||
assert_eq!(rx.next(), Some(5));
|
assert_eq!(rx.next(), Some(5));
|
||||||
|
|
|
@ -7,18 +7,18 @@ use Sample;
|
||||||
pub use self::amplify::Amplify;
|
pub use self::amplify::Amplify;
|
||||||
pub use self::blt::BltFilter;
|
pub use self::blt::BltFilter;
|
||||||
pub use self::buffered::Buffered;
|
pub use self::buffered::Buffered;
|
||||||
|
pub use self::channel_volume::ChannelVolume;
|
||||||
pub use self::delay::Delay;
|
pub use self::delay::Delay;
|
||||||
pub use self::empty::Empty;
|
pub use self::empty::Empty;
|
||||||
pub use self::fadein::FadeIn;
|
pub use self::fadein::FadeIn;
|
||||||
pub use self::from_factory::{from_factory, FromFactoryIter};
|
pub use self::from_factory::{FromFactoryIter, from_factory};
|
||||||
pub use self::from_iter::{from_iter, FromIter};
|
pub use self::from_iter::{FromIter, from_iter};
|
||||||
pub use self::mix::Mix;
|
pub use self::mix::Mix;
|
||||||
pub use self::pausable::Pausable;
|
pub use self::pausable::Pausable;
|
||||||
pub use self::periodic::PeriodicAccess;
|
pub use self::periodic::PeriodicAccess;
|
||||||
pub use self::repeat::Repeat;
|
pub use self::repeat::Repeat;
|
||||||
pub use self::samples_converter::SamplesConverter;
|
pub use self::samples_converter::SamplesConverter;
|
||||||
pub use self::sine::SineWave;
|
pub use self::sine::SineWave;
|
||||||
pub use self::channel_volume::ChannelVolume;
|
|
||||||
pub use self::spatial::Spatial;
|
pub use self::spatial::Spatial;
|
||||||
pub use self::speed::Speed;
|
pub use self::speed::Speed;
|
||||||
pub use self::stoppable::Stoppable;
|
pub use self::stoppable::Stoppable;
|
||||||
|
@ -269,7 +269,8 @@ pub trait Source: Iterator
|
||||||
/// **Warning**: Probably buggy.
|
/// **Warning**: Probably buggy.
|
||||||
#[inline]
|
#[inline]
|
||||||
fn low_pass(self, freq: u32) -> BltFilter<Self>
|
fn low_pass(self, freq: u32) -> BltFilter<Self>
|
||||||
where Self: Sized, Self: Source<Item = f32>
|
where Self: Sized,
|
||||||
|
Self: Source<Item = f32>
|
||||||
{
|
{
|
||||||
blt::low_pass(self, freq)
|
blt::low_pass(self, freq)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
use std::time::Duration;
|
|
||||||
use Source;
|
use Source;
|
||||||
|
use std::time::Duration;
|
||||||
|
|
||||||
/// An infinite source that produces a sine.
|
/// An infinite source that produces a sine.
|
||||||
///
|
///
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
use Sample;
|
use Sample;
|
||||||
use Source;
|
use Source;
|
||||||
use source::ChannelVolume;
|
|
||||||
use std::time::Duration;
|
|
||||||
use std::fmt::Debug;
|
|
||||||
use cgmath::{InnerSpace, Point3};
|
use cgmath::{InnerSpace, Point3};
|
||||||
|
use source::ChannelVolume;
|
||||||
|
use std::fmt::Debug;
|
||||||
|
use std::time::Duration;
|
||||||
|
|
||||||
/// Combines channels in input into a single mono source, then plays that mono sound
|
/// Combines channels in input into a single mono source, then plays that mono sound
|
||||||
/// to each channel at the volume given for that channel.
|
/// to each channel at the volume given for that channel.
|
||||||
|
@ -19,19 +19,19 @@ impl<I> Spatial<I>
|
||||||
where I: Source,
|
where I: Source,
|
||||||
I::Item: Sample + Debug
|
I::Item: Sample + Debug
|
||||||
{
|
{
|
||||||
pub fn new(input: I, emitter_position: [f32; 3], left_ear: [f32; 3], right_ear: [f32; 3]) -> Spatial<I>
|
pub fn new(input: I, emitter_position: [f32; 3], left_ear: [f32; 3], right_ear: [f32; 3])
|
||||||
|
-> Spatial<I>
|
||||||
where I: Source,
|
where I: Source,
|
||||||
I::Item: Sample
|
I::Item: Sample
|
||||||
{
|
{
|
||||||
let mut ret = Spatial {
|
let mut ret = Spatial { input: ChannelVolume::new(input, vec![0.0, 0.0]) };
|
||||||
input: ChannelVolume::new(input, vec![0.0, 0.0]),
|
|
||||||
};
|
|
||||||
ret.set_positions(emitter_position, left_ear, right_ear);
|
ret.set_positions(emitter_position, left_ear, right_ear);
|
||||||
ret
|
ret
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sets the position of the emitter and ears in the 3D world.
|
/// Sets the position of the emitter and ears in the 3D world.
|
||||||
pub fn set_positions(&mut self, emitter_pos: [f32; 3], left_ear: [f32; 3], right_ear: [f32; 3]) {
|
pub fn set_positions(&mut self, emitter_pos: [f32; 3], left_ear: [f32; 3],
|
||||||
|
right_ear: [f32; 3]) {
|
||||||
let emitter_position = Point3::from(emitter_pos);
|
let emitter_position = Point3::from(emitter_pos);
|
||||||
let left_ear = Point3::from(left_ear);
|
let left_ear = Point3::from(left_ear);
|
||||||
let right_ear = Point3::from(right_ear);
|
let right_ear = Point3::from(right_ear);
|
||||||
|
@ -42,8 +42,10 @@ impl<I> Spatial<I>
|
||||||
let right_diff_modifier = ((right_distance - left_distance) / max_diff + 1.0) / 4.0 + 0.5;
|
let right_diff_modifier = ((right_distance - left_distance) / max_diff + 1.0) / 4.0 + 0.5;
|
||||||
let left_dist_modifier = (1.0 / left_distance.powi(2)).min(1.0);
|
let left_dist_modifier = (1.0 / left_distance.powi(2)).min(1.0);
|
||||||
let right_dist_modifier = (1.0 / right_distance.powi(2)).min(1.0);
|
let right_dist_modifier = (1.0 / right_distance.powi(2)).min(1.0);
|
||||||
self.input.set_volume(0, left_diff_modifier * left_dist_modifier);
|
self.input
|
||||||
self.input.set_volume(1, right_diff_modifier * right_dist_modifier);
|
.set_volume(0, left_diff_modifier * left_dist_modifier);
|
||||||
|
self.input
|
||||||
|
.set_volume(1, right_diff_modifier * right_dist_modifier);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
use Source;
|
|
||||||
use Sample;
|
use Sample;
|
||||||
|
use Source;
|
||||||
|
|
||||||
/// Internal function that builds a `Repeat` object.
|
/// Internal function that builds a `Repeat` object.
|
||||||
pub fn take_duration<I>(input: I, duration: Duration) -> TakeDuration<I>
|
pub fn take_duration<I>(input: I, duration: Duration) -> TakeDuration<I>
|
||||||
|
@ -72,10 +72,9 @@ impl<I> Source for TakeDuration<I>
|
||||||
#[inline]
|
#[inline]
|
||||||
fn current_frame_len(&self) -> Option<usize> {
|
fn current_frame_len(&self) -> Option<usize> {
|
||||||
let remaining_nanosecs = self.remaining_duration.as_secs() * 1000000000 +
|
let remaining_nanosecs = self.remaining_duration.as_secs() * 1000000000 +
|
||||||
self.remaining_duration.subsec_nanos() as u64;
|
self.remaining_duration.subsec_nanos() as u64;
|
||||||
let remaining_samples = remaining_nanosecs * self.input.samples_rate() as u64 *
|
let remaining_samples = remaining_nanosecs * self.input.samples_rate() as u64 *
|
||||||
self.channels() as u64 /
|
self.channels() as u64 / 1000000000;
|
||||||
1000000000;
|
|
||||||
|
|
||||||
if let Some(value) = self.input.current_frame_len() {
|
if let Some(value) = self.input.current_frame_len() {
|
||||||
if (value as u64) < remaining_samples {
|
if (value as u64) < remaining_samples {
|
||||||
|
|
|
@ -3,9 +3,9 @@ use std::time::Duration;
|
||||||
|
|
||||||
use cpal;
|
use cpal;
|
||||||
|
|
||||||
|
use conversions::ChannelsCountConverter;
|
||||||
use conversions::DataConverter;
|
use conversions::DataConverter;
|
||||||
use conversions::SamplesRateConverter;
|
use conversions::SamplesRateConverter;
|
||||||
use conversions::ChannelsCountConverter;
|
|
||||||
|
|
||||||
use Sample;
|
use Sample;
|
||||||
use Source;
|
use Source;
|
||||||
|
@ -33,9 +33,7 @@ impl<I, D> UniformSourceIterator<I, D>
|
||||||
D: Sample
|
D: Sample
|
||||||
{
|
{
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn new(input: I,
|
pub fn new(input: I, target_channels: u16, target_samples_rate: u32)
|
||||||
target_channels: u16,
|
|
||||||
target_samples_rate: u32)
|
|
||||||
-> UniformSourceIterator<I, D> {
|
-> UniformSourceIterator<I, D> {
|
||||||
let total_duration = input.total_duration();
|
let total_duration = input.total_duration();
|
||||||
let input = UniformSourceIterator::bootstrap(input, target_channels, target_samples_rate);
|
let input = UniformSourceIterator::bootstrap(input, target_channels, target_samples_rate);
|
||||||
|
@ -49,9 +47,7 @@ impl<I, D> UniformSourceIterator<I, D>
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn bootstrap(input: I,
|
fn bootstrap(input: I, target_channels: u16, target_samples_rate: u32)
|
||||||
target_channels: u16,
|
|
||||||
target_samples_rate: u32)
|
|
||||||
-> DataConverter<ChannelsCountConverter<SamplesRateConverter<Take<I>>>, D> {
|
-> DataConverter<ChannelsCountConverter<SamplesRateConverter<Take<I>>>, D> {
|
||||||
let frame_len = input.current_frame_len();
|
let frame_len = input.current_frame_len();
|
||||||
|
|
||||||
|
@ -180,4 +176,7 @@ impl<I> Iterator for Take<I>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<I> ExactSizeIterator for Take<I> where I: ExactSizeIterator {}
|
impl<I> ExactSizeIterator for Take<I>
|
||||||
|
where I: ExactSizeIterator
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
use std::marker::PhantomData;
|
|
||||||
use std::time::Duration;
|
|
||||||
use Sample;
|
use Sample;
|
||||||
use Source;
|
use Source;
|
||||||
|
use std::marker::PhantomData;
|
||||||
|
use std::time::Duration;
|
||||||
|
|
||||||
/// An infinite source that produces zero.
|
/// An infinite source that produces zero.
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
|
|
|
@ -1,12 +1,13 @@
|
||||||
use std::f32;
|
|
||||||
use std::sync::{Arc, Mutex};
|
|
||||||
use Sink;
|
|
||||||
use Endpoint;
|
use Endpoint;
|
||||||
use Source;
|
|
||||||
use Sample;
|
use Sample;
|
||||||
|
use Sink;
|
||||||
|
use Source;
|
||||||
use source::Spatial;
|
use source::Spatial;
|
||||||
use std::time::Duration;
|
use std::f32;
|
||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
|
use std::sync::{Arc, Mutex};
|
||||||
|
use std::time::Duration;
|
||||||
|
|
||||||
pub struct SpatialSink {
|
pub struct SpatialSink {
|
||||||
sink: Sink,
|
sink: Sink,
|
||||||
|
@ -22,18 +23,16 @@ struct SoundPositions {
|
||||||
impl SpatialSink {
|
impl SpatialSink {
|
||||||
/// Builds a new `SpatialSink`.
|
/// Builds a new `SpatialSink`.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn new(endpoint: &Endpoint,
|
pub fn new(endpoint: &Endpoint, emitter_position: [f32; 3], left_ear: [f32; 3],
|
||||||
emitter_position: [f32; 3],
|
|
||||||
left_ear: [f32; 3],
|
|
||||||
right_ear: [f32; 3])
|
right_ear: [f32; 3])
|
||||||
-> SpatialSink {
|
-> SpatialSink {
|
||||||
SpatialSink {
|
SpatialSink {
|
||||||
sink: Sink::new(endpoint),
|
sink: Sink::new(endpoint),
|
||||||
positions: Arc::new(Mutex::new(SoundPositions {
|
positions: Arc::new(Mutex::new(SoundPositions {
|
||||||
emitter_position,
|
emitter_position,
|
||||||
left_ear,
|
left_ear,
|
||||||
right_ear,
|
right_ear,
|
||||||
})),
|
})),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -56,19 +55,18 @@ impl SpatialSink {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn append<S>(&self, source: S)
|
pub fn append<S>(&self, source: S)
|
||||||
where S: Source + Send + 'static,
|
where S: Source + Send + 'static,
|
||||||
S::Item: Sample + Send + Debug,
|
S::Item: Sample + Send + Debug
|
||||||
{
|
{
|
||||||
let positions = self.positions.clone();
|
let positions = self.positions.clone();
|
||||||
let pos_lock = self.positions.lock().unwrap();
|
let pos_lock = self.positions.lock().unwrap();
|
||||||
let source = Spatial::new(
|
let source = Spatial::new(source,
|
||||||
source,
|
pos_lock.emitter_position,
|
||||||
pos_lock.emitter_position,
|
pos_lock.left_ear,
|
||||||
pos_lock.left_ear,
|
pos_lock.right_ear)
|
||||||
pos_lock.right_ear
|
.periodic_access(Duration::from_millis(10), move |i| {
|
||||||
).periodic_access(Duration::from_millis(10), move |i| {
|
let pos = positions.lock().unwrap();
|
||||||
let pos = positions.lock().unwrap();
|
i.set_positions(pos.emitter_position, pos.left_ear, pos.right_ear);
|
||||||
i.set_positions(pos.emitter_position, pos.left_ear, pos.right_ear);
|
});
|
||||||
});
|
|
||||||
self.sink.append(source);
|
self.sink.append(source);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue