diff --git a/assets/RL.ogg b/assets/RL.ogg new file mode 100644 index 00000000..9899c229 Binary files /dev/null and b/assets/RL.ogg differ diff --git a/examples/spatial.rs b/examples/spatial.rs index adb205ce..b2e9513e 100644 --- a/examples/spatial.rs +++ b/examples/spatial.rs @@ -2,33 +2,51 @@ use std::io::BufReader; use std::thread; use std::time::Duration; +use rodio::Source; + fn main() { + let iter_duration = Duration::from_secs(5); + let iter_distance = 5.; + + let refresh_duration = Duration::from_millis(10); + + let num_steps = iter_duration.as_secs_f32() / refresh_duration.as_secs_f32(); + let step_distance = iter_distance / num_steps; + let num_steps = num_steps as u32; + + let repeats = 5; + + let total_duration = iter_duration * 2 * repeats; + let (_stream, handle) = rodio::OutputStream::try_default().unwrap(); - let sink = rodio::SpatialSink::try_new( - &handle, - [-10.0, 0.0, 0.0], - [1.0, 0.0, 0.0], - [-1.0, 0.0, 0.0], - ) - .unwrap(); + let mut positions = ([0., 0., 0.], [-1., 0., 0.], [1., 0., 0.]); + let sink = rodio::SpatialSink::try_new(&handle, positions.0, positions.1, positions.2).unwrap(); let file = std::fs::File::open("assets/music.ogg").unwrap(); - let source = rodio::Decoder::new(BufReader::new(file)).unwrap(); + let source = rodio::Decoder::new(BufReader::new(file)) + .unwrap() + .repeat_infinite() + .take_duration(total_duration); 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 + // A sound emitter playing the music starting at the centre gradually moves to the right // until it stops and begins traveling to the left, it will eventually pass through the - // listener again. + // listener again and go to the far left. // This is repeated 5 times. - 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 _ in 0..repeats { + for _ in 0..num_steps { + thread::sleep(refresh_duration); + positions.0[0] += step_distance; + sink.set_emitter_position(positions.0); + } + for _ in 0..(num_steps * 2) { + thread::sleep(refresh_duration); + positions.0[0] -= step_distance; + sink.set_emitter_position(positions.0); } - 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 _ in 0..num_steps { + thread::sleep(refresh_duration); + positions.0[0] += step_distance; + sink.set_emitter_position(positions.0); } } sink.sleep_until_end(); diff --git a/examples/stereo.rs b/examples/stereo.rs new file mode 100644 index 00000000..fb1ada56 --- /dev/null +++ b/examples/stereo.rs @@ -0,0 +1,12 @@ +//! Plays a tone alternating between right and left ears, with right being first. +use std::io::BufReader; + +fn main() { + let (_stream, handle) = rodio::OutputStream::try_default().unwrap(); + let sink = rodio::Sink::try_new(&handle).unwrap(); + + let file = std::fs::File::open("assets/RL.ogg").unwrap(); + sink.append(rodio::Decoder::new(BufReader::new(file)).unwrap()); + + sink.sleep_until_end(); +} diff --git a/src/queue.rs b/src/queue.rs index 04fc2eef..64e6aadb 100644 --- a/src/queue.rs +++ b/src/queue.rs @@ -100,6 +100,7 @@ pub struct SourcesQueueOutput { input: Arc>, } +const THRESHOLD: usize = 512; impl Source for SourcesQueueOutput where S: Sample + Send + 'static, @@ -116,12 +117,16 @@ where // If the `size_hint` is `None` as well, we are in the worst case scenario. To handle this // situation we force a frame to have a maximum number of samples indicate by this // constant. - const THRESHOLD: usize = 512; // Try the current `current_frame_len`. if let Some(val) = self.current.current_frame_len() { if val != 0 { return Some(val); + } else if self.input.keep_alive_if_empty.load(Ordering::Acquire) + && self.input.next_sounds.lock().unwrap().is_empty() + { + // The next source will be a filler silence which will have the length of `THRESHOLD` + return Some(THRESHOLD); } } @@ -198,13 +203,10 @@ where let mut next = self.input.next_sounds.lock().unwrap(); if next.len() == 0 { + let silence = Box::new(Zero::::new_samples(1, 44100, THRESHOLD)) as Box<_>; if self.input.keep_alive_if_empty.load(Ordering::Acquire) { // Play a short silence in order to avoid spinlocking. - let silence = Zero::::new(1, 44100); // TODO: meh - ( - Box::new(silence.take_duration(Duration::from_millis(10))) as Box<_>, - None, - ) + (silence, None) } else { return Err(()); } diff --git a/src/source/zero.rs b/src/source/zero.rs index 42cbf24b..079d8588 100644 --- a/src/source/zero.rs +++ b/src/source/zero.rs @@ -8,6 +8,7 @@ use crate::{Sample, Source}; pub struct Zero { channels: u16, sample_rate: u32, + num_samples: Option, marker: PhantomData, } @@ -17,6 +18,16 @@ impl Zero { Zero { channels, sample_rate, + num_samples: None, + marker: PhantomData, + } + } + #[inline] + pub fn new_samples(channels: u16, sample_rate: u32, num_samples: usize) -> Zero { + Zero { + channels, + sample_rate, + num_samples: Some(num_samples), marker: PhantomData, } } @@ -30,7 +41,16 @@ where #[inline] fn next(&mut self) -> Option { - Some(S::zero_value()) + if let Some(num_samples) = self.num_samples { + if num_samples > 0 { + self.num_samples = Some(num_samples - 1); + Some(S::zero_value()) + } else { + None + } + } else { + Some(S::zero_value()) + } } } @@ -40,7 +60,7 @@ where { #[inline] fn current_frame_len(&self) -> Option { - None + self.num_samples } #[inline]