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 source = rodio::Decoder::new(BufReader::new(file)).unwrap();
|
||||
sink.append(source);
|
||||
|
||||
// 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
|
||||
// stops and begins traveling to the left, it will eventually pass through the listener again.
|
||||
// eventually passing through the listener, then it continues on to the right for a distance
|
||||
// until it stops and begins traveling to the left, it will eventually pass through the
|
||||
// listener again.
|
||||
// This is repeated 5 times.
|
||||
for _ in 0..5 {
|
||||
for i in 1..1001 {
|
||||
for _ in 0 .. 5 {
|
||||
for i in 1 .. 1001 {
|
||||
thread::sleep(Duration::from_millis(5));
|
||||
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));
|
||||
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 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,
|
||||
(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.
|
||||
///
|
||||
#[inline]
|
||||
pub fn new(input: I,
|
||||
from: cpal::ChannelsCount,
|
||||
to: cpal::ChannelsCount)
|
||||
pub fn new(input: I, from: cpal::ChannelsCount, to: cpal::ChannelsCount)
|
||||
-> ChannelsCountConverter<I> {
|
||||
assert!(from >= 1);
|
||||
assert!(to >= 1);
|
||||
|
@ -68,7 +66,7 @@ impl<I> Iterator for ChannelsCountConverter<I>
|
|||
self.next_output_sample_pos -= 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
|
||||
}
|
||||
}
|
||||
|
@ -82,10 +80,10 @@ impl<I> Iterator for ChannelsCountConverter<I>
|
|||
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;
|
||||
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
|
||||
self.next_output_sample_pos as usize
|
||||
});
|
||||
|
||||
(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.
|
||||
|
||||
*/
|
||||
pub use self::sample::Sample;
|
||||
pub use self::sample::DataConverter;
|
||||
|
||||
pub use self::channels::ChannelsCountConverter;
|
||||
pub use self::sample::DataConverter;
|
||||
pub use self::sample::Sample;
|
||||
pub use self::samples_rate::SamplesRateConverter;
|
||||
|
||||
mod channels;
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
use std::marker::PhantomData;
|
||||
|
||||
use cpal;
|
||||
use std::marker::PhantomData;
|
||||
|
||||
/// Converts the samples data type to `O`.
|
||||
#[derive(Clone, Debug)]
|
||||
|
@ -86,7 +87,8 @@ pub trait Sample: cpal::Sample {
|
|||
fn to_f32(&self) -> 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 {
|
||||
|
@ -141,7 +143,7 @@ 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
|
||||
i16
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
use cpal;
|
||||
|
||||
use conversions::Sample;
|
||||
use cpal;
|
||||
|
||||
use std::mem;
|
||||
|
||||
|
@ -38,9 +39,7 @@ impl<I> SamplesRateConverter<I>
|
|||
/// Panicks if `from` or `to` are equal to 0.
|
||||
///
|
||||
#[inline]
|
||||
pub fn new(mut input: I,
|
||||
from: cpal::SamplesRate,
|
||||
to: cpal::SamplesRate,
|
||||
pub fn new(mut input: I, from: cpal::SamplesRate, to: cpal::SamplesRate,
|
||||
num_channels: cpal::ChannelsCount)
|
||||
-> SamplesRateConverter<I> {
|
||||
let from = from.0;
|
||||
|
@ -98,7 +97,7 @@ impl<I> SamplesRateConverter<I>
|
|||
|
||||
mem::swap(&mut self.current_frame, &mut self.next_frame);
|
||||
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() {
|
||||
self.next_frame.push(i);
|
||||
} else {
|
||||
|
@ -142,7 +141,7 @@ impl<I> Iterator for SamplesRateConverter<I>
|
|||
} else {
|
||||
// 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) %
|
||||
self.from;
|
||||
self.from;
|
||||
|
||||
// Advancing `self.current_frame`, `self.next_frame` and
|
||||
// `self.current_frame_pos_in_chunk` until the latter variable
|
||||
|
@ -162,7 +161,8 @@ impl<I> Iterator for SamplesRateConverter<I>
|
|||
self.current_frame
|
||||
.iter()
|
||||
.zip(self.next_frame.iter())
|
||||
.enumerate() {
|
||||
.enumerate()
|
||||
{
|
||||
let sample = Sample::lerp(cur.clone(), next.clone(), numerator, self.to);
|
||||
|
||||
if off == 0 {
|
||||
|
@ -209,8 +209,8 @@ impl<I> Iterator for SamplesRateConverter<I>
|
|||
let samples_after_chunk = samples_after_chunk
|
||||
.saturating_sub(self.from
|
||||
.saturating_sub(self.current_frame_pos_in_chunk + 2) as
|
||||
usize *
|
||||
self.current_frame.capacity());
|
||||
usize *
|
||||
self.current_frame.capacity());
|
||||
// calculating the number of samples after the transformation
|
||||
// TODO: this is wrong here \|/
|
||||
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
|
||||
// for the chunk currently being processed
|
||||
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()
|
||||
};
|
||||
|
@ -240,8 +240,8 @@ impl<I> ExactSizeIterator for SamplesRateConverter<I>
|
|||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use cpal::SamplesRate;
|
||||
use super::SamplesRateConverter;
|
||||
use cpal::SamplesRate;
|
||||
|
||||
#[test]
|
||||
fn zero() {
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
use std::mem;
|
||||
|
||||
use std::io::{Read, Seek, SeekFrom};
|
||||
use std::mem;
|
||||
use std::time::Duration;
|
||||
|
||||
use Source;
|
||||
|
@ -34,7 +35,7 @@ impl<R> FlacDecoder<R>
|
|||
Ok(FlacDecoder {
|
||||
reader: reader,
|
||||
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_off: 0,
|
||||
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() {
|
||||
// Read from current block.
|
||||
let real_offset = (self.current_block_off % self.channels as usize) *
|
||||
self.current_block_channel_len +
|
||||
self.current_block_off / self.channels as usize;
|
||||
self.current_block_channel_len +
|
||||
self.current_block_off / self.channels as usize;
|
||||
let raw_val = self.current_block[real_offset];
|
||||
self.current_block_off += 1;
|
||||
let real_val = if self.bits_per_sample == 16 {
|
||||
|
@ -100,7 +101,7 @@ impl<R> Iterator for FlacDecoder<R>
|
|||
Ok(Some(block)) => {
|
||||
self.current_block_channel_len = (block.len() / block.channels()) as usize;
|
||||
self.current_block = block.into_buffer();
|
||||
}
|
||||
},
|
||||
_ => return None,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -35,14 +35,14 @@ impl<R> Decoder<R>
|
|||
Err(data) => data,
|
||||
Ok(decoder) => {
|
||||
return Ok(Decoder(DecoderImpl::Wav(decoder)));
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
let data = match flac::FlacDecoder::new(data) {
|
||||
Err(data) => data,
|
||||
Ok(decoder) => {
|
||||
return Ok(Decoder(DecoderImpl::Flac(decoder)));
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
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 self.current_data.len() == 0 {
|
||||
if let Some(data) = self.stream_reader
|
||||
.read_dec_packet_itl()
|
||||
.ok()
|
||||
.and_then(|v| v) {
|
||||
.read_dec_packet_itl()
|
||||
.ok()
|
||||
.and_then(|v| v)
|
||||
{
|
||||
self.current_data = data.into_iter();
|
||||
}
|
||||
}
|
||||
return Some(sample);
|
||||
} else {
|
||||
if let Some(data) = self.stream_reader
|
||||
.read_dec_packet_itl()
|
||||
.ok()
|
||||
.and_then(|v| v) {
|
||||
.read_dec_packet_itl()
|
||||
.ok()
|
||||
.and_then(|v| v)
|
||||
{
|
||||
self.current_data = data.into_iter();
|
||||
}
|
||||
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>
|
||||
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.
|
||||
fn is_wave<R>(mut data: R) -> bool
|
||||
|
|
|
@ -17,8 +17,7 @@ use Sample;
|
|||
/// added to the mixer will be converted to these values.
|
||||
///
|
||||
/// After creating a mixer, you can add new sounds with the controller.
|
||||
pub fn mixer<S>(channels: u16,
|
||||
samples_rate: u32)
|
||||
pub fn mixer<S>(channels: u16, samples_rate: u32)
|
||||
-> (Arc<DynamicMixerController<S>>, DynamicMixer<S>)
|
||||
where S: Sample + Send + 'static
|
||||
{
|
||||
|
@ -143,8 +142,8 @@ impl<S> Iterator for DynamicMixer<S>
|
|||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use dynamic_mixer;
|
||||
use buffer::SamplesBuffer;
|
||||
use dynamic_mixer;
|
||||
use source::Source;
|
||||
|
||||
#[test]
|
||||
|
|
|
@ -1,21 +1,21 @@
|
|||
use std::collections::HashMap;
|
||||
use std::collections::hash_map::Entry;
|
||||
use std::thread::Builder;
|
||||
use std::sync::Arc;
|
||||
use std::sync::Mutex;
|
||||
use std::sync::Weak;
|
||||
use std::thread::Builder;
|
||||
|
||||
use futures::stream::Stream;
|
||||
use futures::task;
|
||||
use futures::task::Executor;
|
||||
use futures::task::Run;
|
||||
|
||||
use cpal;
|
||||
use cpal::UnknownTypeBuffer;
|
||||
use cpal::EventLoop;
|
||||
use cpal::Voice;
|
||||
use cpal::Endpoint;
|
||||
use conversions::Sample;
|
||||
use cpal;
|
||||
use cpal::Endpoint;
|
||||
use cpal::EventLoop;
|
||||
use cpal::UnknownTypeBuffer;
|
||||
use cpal::Voice;
|
||||
use dynamic_mixer;
|
||||
use source::Source;
|
||||
|
||||
|
@ -77,7 +77,7 @@ impl Engine {
|
|||
e.insert(Arc::downgrade(&mixer));
|
||||
voice_to_start = Some(voice);
|
||||
mixer
|
||||
}
|
||||
},
|
||||
Entry::Occupied(mut e) => {
|
||||
if let Some(m) = e.get().upgrade() {
|
||||
m.clone()
|
||||
|
@ -87,7 +87,7 @@ impl Engine {
|
|||
voice_to_start = Some(voice);
|
||||
mixer
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -100,8 +100,7 @@ impl Engine {
|
|||
}
|
||||
|
||||
// TODO: handle possible errors here
|
||||
fn new_voice(endpoint: &Endpoint,
|
||||
events_loop: &Arc<EventLoop>)
|
||||
fn new_voice(endpoint: &Endpoint, events_loop: &Arc<EventLoop>)
|
||||
-> (Arc<dynamic_mixer::DynamicMixerController<f32>>, Voice) {
|
||||
// Determine the format to use for the new voice.
|
||||
let format = endpoint
|
||||
|
@ -145,17 +144,17 @@ fn new_voice(endpoint: &Endpoint,
|
|||
for (o, i) in buffer.iter_mut().zip(mixer_rx.by_ref()) {
|
||||
*o = i.to_u16();
|
||||
}
|
||||
}
|
||||
},
|
||||
UnknownTypeBuffer::I16(ref mut buffer) => {
|
||||
for (o, i) in buffer.iter_mut().zip(mixer_rx.by_ref()) {
|
||||
*o = i.to_i16();
|
||||
}
|
||||
}
|
||||
},
|
||||
UnknownTypeBuffer::F32(ref mut buffer) => {
|
||||
for (o, i) in buffer.iter_mut().zip(mixer_rx.by_ref()) {
|
||||
*o = i;
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
Ok(())
|
||||
|
|
|
@ -92,14 +92,14 @@ extern crate lazy_static;
|
|||
extern crate lewton;
|
||||
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 decoder::Decoder;
|
||||
pub use engine::play_raw;
|
||||
pub use sink::Sink;
|
||||
pub use spatial_sink::SpatialSink;
|
||||
pub use source::Source;
|
||||
pub use spatial_sink::SpatialSink;
|
||||
|
||||
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>
|
||||
where R: Read + Seek + Send + 'static
|
||||
{
|
||||
let input = try!(decoder::Decoder::new(input));
|
||||
let input = decoder::Decoder::new(input)?;
|
||||
let sink = Sink::new(endpoint);
|
||||
sink.append(input);
|
||||
Ok(sink)
|
||||
|
|
|
@ -217,8 +217,8 @@ impl<S> SourcesQueueOutput<S>
|
|||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use queue;
|
||||
use buffer::SamplesBuffer;
|
||||
use queue;
|
||||
use source::Source;
|
||||
|
||||
#[test]
|
||||
|
@ -260,7 +260,7 @@ mod tests {
|
|||
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));
|
||||
}
|
||||
}
|
||||
|
@ -270,7 +270,7 @@ mod tests {
|
|||
fn no_delay_when_added() {
|
||||
let (tx, mut rx) = queue::queue(true);
|
||||
|
||||
for _ in 0..500 {
|
||||
for _ in 0 .. 500 {
|
||||
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::Ordering;
|
||||
use std::sync::mpsc::Receiver;
|
||||
use std::sync::Arc;
|
||||
use std::sync::Mutex;
|
||||
use std::time::Duration;
|
||||
|
||||
use Endpoint;
|
||||
use Sample;
|
||||
use Source;
|
||||
use play_raw;
|
||||
use queue;
|
||||
use Endpoint;
|
||||
use Source;
|
||||
use Sample;
|
||||
|
||||
/// Handle to an endpoint that outputs sounds.
|
||||
///
|
||||
|
@ -58,15 +59,16 @@ impl Sink {
|
|||
.pausable(false)
|
||||
.amplify(1.0)
|
||||
.stoppable()
|
||||
.periodic_access(Duration::from_millis(5),
|
||||
move |src| if stopped.load(Ordering::SeqCst) {
|
||||
src.stop();
|
||||
} else {
|
||||
src.inner_mut().set_factor(*volume.lock().unwrap());
|
||||
src.inner_mut()
|
||||
.inner_mut()
|
||||
.set_paused(pause.load(Ordering::SeqCst));
|
||||
})
|
||||
.periodic_access(Duration::from_millis(5), move |src| {
|
||||
if stopped.load(Ordering::SeqCst) {
|
||||
src.stop();
|
||||
} else {
|
||||
src.inner_mut().set_factor(*volume.lock().unwrap());
|
||||
src.inner_mut()
|
||||
.inner_mut()
|
||||
.set_paused(pause.load(Ordering::SeqCst));
|
||||
}
|
||||
})
|
||||
.convert_samples();
|
||||
|
||||
*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]
|
||||
fn next(&mut self) -> Option<I::Item> {
|
||||
self.input
|
||||
.next()
|
||||
.map(|value| value.amplify(self.factor))
|
||||
self.input.next().map(|value| value.amplify(self.factor))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
|
|
@ -75,8 +75,10 @@ impl<I> Iterator for BltFilter<I>
|
|||
Some(s) => s,
|
||||
};
|
||||
|
||||
let result = self.applier.as_ref().unwrap().apply(sample, self.x_n1, self.x_n2,
|
||||
self.y_n1, self.y_n2);
|
||||
let result = self.applier
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.apply(sample, self.x_n1, self.x_n2, self.y_n1, self.y_n2);
|
||||
|
||||
self.y_n2 = self.y_n1;
|
||||
self.x_n2 = self.x_n1;
|
||||
|
@ -151,7 +153,7 @@ impl BltFormula {
|
|||
a1: a1 / a0,
|
||||
a2: a2 / a0,
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,8 +2,8 @@ use std::cmp;
|
|||
use std::sync::{Arc, Mutex};
|
||||
use std::time::Duration;
|
||||
|
||||
use Source;
|
||||
use Sample;
|
||||
use Source;
|
||||
|
||||
/// Internal function that builds a `Buffered` object.
|
||||
#[inline]
|
||||
|
@ -106,7 +106,7 @@ impl<I> Buffered<I>
|
|||
&Frame::Input(ref input) => {
|
||||
let input = input.lock().unwrap().take().unwrap();
|
||||
extract(input)
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
*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());
|
||||
self.position_in_frame += 1;
|
||||
advance_frame = self.position_in_frame >= data.len();
|
||||
}
|
||||
},
|
||||
|
||||
&Frame::End => {
|
||||
current_sample = None;
|
||||
advance_frame = false;
|
||||
}
|
||||
},
|
||||
|
||||
&Frame::Input(_) => unreachable!(),
|
||||
};
|
||||
|
|
|
@ -26,7 +26,7 @@ impl<I> ChannelVolume<I>
|
|||
I::Item: Sample
|
||||
{
|
||||
let mut sample = I::Item::zero_value();
|
||||
for _ in 0..input.channels() {
|
||||
for _ in 0 .. input.channels() {
|
||||
if let Some(s) = input.next() {
|
||||
sample = sample.saturating_add(s);
|
||||
}
|
||||
|
@ -61,7 +61,7 @@ impl<I> Iterator for ChannelVolume<I>
|
|||
if self.current_channel >= self.channel_volumes.len() {
|
||||
self.current_channel = 0;
|
||||
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() {
|
||||
sample = sample.saturating_add(s);
|
||||
} else {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use std::time::Duration;
|
||||
|
||||
use Source;
|
||||
use Sample;
|
||||
use Source;
|
||||
|
||||
/// Internal function that builds a `Delay` object.
|
||||
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 Source;
|
||||
use std::marker::PhantomData;
|
||||
use std::time::Duration;
|
||||
|
||||
/// An empty source.
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
|
|
|
@ -42,7 +42,7 @@ impl<I> Iterator for FadeIn<I>
|
|||
|
||||
let factor = 1.0 - self.remaining_ns / self.total_ns;
|
||||
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))
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
use source::from_iter;
|
||||
|
||||
use source::FromIter;
|
||||
use source::from_iter;
|
||||
|
||||
/// Builds a source that chains sources built from a factory.
|
||||
///
|
||||
|
|
|
@ -137,19 +137,19 @@ impl<I> Source for FromIter<I>
|
|||
#[cfg(test)]
|
||||
mod tests {
|
||||
use buffer::SamplesBuffer;
|
||||
use source::from_iter;
|
||||
use source::Source;
|
||||
use source::from_iter;
|
||||
|
||||
#[test]
|
||||
fn basic() {
|
||||
let mut rx =
|
||||
from_iter((0..2).map(|n| if n == 0 {
|
||||
SamplesBuffer::new(1, 48000, vec![10i16, -10, 10, -10])
|
||||
} else if n == 1 {
|
||||
SamplesBuffer::new(2, 96000, vec![5i16, 5, 5, 5])
|
||||
} else {
|
||||
unreachable!()
|
||||
}));
|
||||
from_iter((0 .. 2).map(|n| if n == 0 {
|
||||
SamplesBuffer::new(1, 48000, vec![10i16, -10, 10, -10])
|
||||
} else if n == 1 {
|
||||
SamplesBuffer::new(2, 96000, vec![5i16, 5, 5, 5])
|
||||
} else {
|
||||
unreachable!()
|
||||
}));
|
||||
|
||||
assert_eq!(rx.channels(), 1);
|
||||
assert_eq!(rx.samples_rate(), 48000);
|
||||
|
@ -159,7 +159,7 @@ mod tests {
|
|||
assert_eq!(rx.next(), Some(-10));
|
||||
/*assert_eq!(rx.channels(), 2);
|
||||
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));
|
||||
|
|
|
@ -7,18 +7,18 @@ use Sample;
|
|||
pub use self::amplify::Amplify;
|
||||
pub use self::blt::BltFilter;
|
||||
pub use self::buffered::Buffered;
|
||||
pub use self::channel_volume::ChannelVolume;
|
||||
pub use self::delay::Delay;
|
||||
pub use self::empty::Empty;
|
||||
pub use self::fadein::FadeIn;
|
||||
pub use self::from_factory::{from_factory, FromFactoryIter};
|
||||
pub use self::from_iter::{from_iter, FromIter};
|
||||
pub use self::from_factory::{FromFactoryIter, from_factory};
|
||||
pub use self::from_iter::{FromIter, from_iter};
|
||||
pub use self::mix::Mix;
|
||||
pub use self::pausable::Pausable;
|
||||
pub use self::periodic::PeriodicAccess;
|
||||
pub use self::repeat::Repeat;
|
||||
pub use self::samples_converter::SamplesConverter;
|
||||
pub use self::sine::SineWave;
|
||||
pub use self::channel_volume::ChannelVolume;
|
||||
pub use self::spatial::Spatial;
|
||||
pub use self::speed::Speed;
|
||||
pub use self::stoppable::Stoppable;
|
||||
|
@ -269,7 +269,8 @@ pub trait Source: Iterator
|
|||
/// **Warning**: Probably buggy.
|
||||
#[inline]
|
||||
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)
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
use std::time::Duration;
|
||||
|
||||
use Source;
|
||||
use std::time::Duration;
|
||||
|
||||
/// An infinite source that produces a sine.
|
||||
///
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
use Sample;
|
||||
use Source;
|
||||
use source::ChannelVolume;
|
||||
use std::time::Duration;
|
||||
use std::fmt::Debug;
|
||||
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
|
||||
/// to each channel at the volume given for that channel.
|
||||
|
@ -19,19 +19,19 @@ impl<I> Spatial<I>
|
|||
where I: Source,
|
||||
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,
|
||||
I::Item: Sample
|
||||
{
|
||||
let mut ret = Spatial {
|
||||
input: ChannelVolume::new(input, vec![0.0, 0.0]),
|
||||
};
|
||||
let mut ret = Spatial { input: ChannelVolume::new(input, vec![0.0, 0.0]) };
|
||||
ret.set_positions(emitter_position, left_ear, right_ear);
|
||||
ret
|
||||
}
|
||||
|
||||
/// 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 left_ear = Point3::from(left_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 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);
|
||||
self.input.set_volume(0, left_diff_modifier * left_dist_modifier);
|
||||
self.input.set_volume(1, right_diff_modifier * right_dist_modifier);
|
||||
self.input
|
||||
.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 Source;
|
||||
use Sample;
|
||||
use Source;
|
||||
|
||||
/// Internal function that builds a `Repeat` object.
|
||||
pub fn take_duration<I>(input: I, duration: Duration) -> TakeDuration<I>
|
||||
|
@ -72,10 +72,9 @@ impl<I> Source for TakeDuration<I>
|
|||
#[inline]
|
||||
fn current_frame_len(&self) -> Option<usize> {
|
||||
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 *
|
||||
self.channels() as u64 /
|
||||
1000000000;
|
||||
self.channels() as u64 / 1000000000;
|
||||
|
||||
if let Some(value) = self.input.current_frame_len() {
|
||||
if (value as u64) < remaining_samples {
|
||||
|
|
|
@ -3,9 +3,9 @@ use std::time::Duration;
|
|||
|
||||
use cpal;
|
||||
|
||||
use conversions::ChannelsCountConverter;
|
||||
use conversions::DataConverter;
|
||||
use conversions::SamplesRateConverter;
|
||||
use conversions::ChannelsCountConverter;
|
||||
|
||||
use Sample;
|
||||
use Source;
|
||||
|
@ -33,9 +33,7 @@ impl<I, D> UniformSourceIterator<I, D>
|
|||
D: Sample
|
||||
{
|
||||
#[inline]
|
||||
pub fn new(input: I,
|
||||
target_channels: u16,
|
||||
target_samples_rate: u32)
|
||||
pub fn new(input: I, target_channels: u16, target_samples_rate: u32)
|
||||
-> UniformSourceIterator<I, D> {
|
||||
let total_duration = input.total_duration();
|
||||
let input = UniformSourceIterator::bootstrap(input, target_channels, target_samples_rate);
|
||||
|
@ -49,9 +47,7 @@ impl<I, D> UniformSourceIterator<I, D>
|
|||
}
|
||||
|
||||
#[inline]
|
||||
fn bootstrap(input: I,
|
||||
target_channels: u16,
|
||||
target_samples_rate: u32)
|
||||
fn bootstrap(input: I, target_channels: u16, target_samples_rate: u32)
|
||||
-> DataConverter<ChannelsCountConverter<SamplesRateConverter<Take<I>>>, D> {
|
||||
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 Source;
|
||||
use std::marker::PhantomData;
|
||||
use std::time::Duration;
|
||||
|
||||
/// An infinite source that produces zero.
|
||||
#[derive(Clone, Debug)]
|
||||
|
|
|
@ -1,12 +1,13 @@
|
|||
use std::f32;
|
||||
use std::sync::{Arc, Mutex};
|
||||
use Sink;
|
||||
|
||||
use Endpoint;
|
||||
use Source;
|
||||
use Sample;
|
||||
use Sink;
|
||||
use Source;
|
||||
use source::Spatial;
|
||||
use std::time::Duration;
|
||||
use std::f32;
|
||||
use std::fmt::Debug;
|
||||
use std::sync::{Arc, Mutex};
|
||||
use std::time::Duration;
|
||||
|
||||
pub struct SpatialSink {
|
||||
sink: Sink,
|
||||
|
@ -22,18 +23,16 @@ struct SoundPositions {
|
|||
impl SpatialSink {
|
||||
/// Builds a new `SpatialSink`.
|
||||
#[inline]
|
||||
pub fn new(endpoint: &Endpoint,
|
||||
emitter_position: [f32; 3],
|
||||
left_ear: [f32; 3],
|
||||
pub fn new(endpoint: &Endpoint, emitter_position: [f32; 3], left_ear: [f32; 3],
|
||||
right_ear: [f32; 3])
|
||||
-> SpatialSink {
|
||||
SpatialSink {
|
||||
sink: Sink::new(endpoint),
|
||||
positions: Arc::new(Mutex::new(SoundPositions {
|
||||
emitter_position,
|
||||
left_ear,
|
||||
right_ear,
|
||||
})),
|
||||
emitter_position,
|
||||
left_ear,
|
||||
right_ear,
|
||||
})),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -56,19 +55,18 @@ impl SpatialSink {
|
|||
#[inline]
|
||||
pub fn append<S>(&self, source: S)
|
||||
where S: Source + Send + 'static,
|
||||
S::Item: Sample + Send + Debug,
|
||||
S::Item: Sample + Send + Debug
|
||||
{
|
||||
let positions = self.positions.clone();
|
||||
let pos_lock = self.positions.lock().unwrap();
|
||||
let source = Spatial::new(
|
||||
source,
|
||||
pos_lock.emitter_position,
|
||||
pos_lock.left_ear,
|
||||
pos_lock.right_ear
|
||||
).periodic_access(Duration::from_millis(10), move |i| {
|
||||
let pos = positions.lock().unwrap();
|
||||
i.set_positions(pos.emitter_position, pos.left_ear, pos.right_ear);
|
||||
});
|
||||
let source = Spatial::new(source,
|
||||
pos_lock.emitter_position,
|
||||
pos_lock.left_ear,
|
||||
pos_lock.right_ear)
|
||||
.periodic_access(Duration::from_millis(10), move |i| {
|
||||
let pos = positions.lock().unwrap();
|
||||
i.set_positions(pos.emitter_position, pos.left_ear, pos.right_ear);
|
||||
});
|
||||
self.sink.append(source);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue