diff --git a/src/queue.rs b/src/queue.rs index 64e6aad..8bbd4fc 100644 --- a/src/queue.rs +++ b/src/queue.rs @@ -86,8 +86,15 @@ where self.keep_alive_if_empty .store(keep_alive_if_empty, Ordering::Release); } -} + /// Removes all the sounds from the queue. Returns the number of sounds cleared. + pub fn clear(&self) -> usize { + let mut sounds = self.next_sounds.lock().unwrap(); + let len = sounds.len(); + sounds.clear(); + len + } +} /// The output of the queue. Implements `Source`. pub struct SourcesQueueOutput { // The current iterator that produces samples. diff --git a/src/sink.rs b/src/sink.rs index e4166a7..5d51030 100644 --- a/src/sink.rs +++ b/src/sink.rs @@ -26,6 +26,8 @@ struct Controls { volume: Mutex, stopped: AtomicBool, speed: Mutex, + do_skip: AtomicBool, + to_clear: Mutex, } impl Sink { @@ -50,6 +52,8 @@ impl Sink { volume: Mutex::new(1.0), stopped: AtomicBool::new(false), speed: Mutex::new(1.0), + do_skip: AtomicBool::new(false), + to_clear: Mutex::new(0), }), sound_count: Arc::new(AtomicUsize::new(0)), detached: false, @@ -79,20 +83,29 @@ impl Sink { .speed(1.0) .pausable(false) .amplify(1.0) + .skippable() .stoppable() .periodic_access(Duration::from_millis(5), move |src| { if controls.stopped.load(Ordering::SeqCst) { src.stop(); - } else { - src.inner_mut().set_factor(*controls.volume.lock().unwrap()); - src.inner_mut() - .inner_mut() - .set_paused(controls.pause.load(Ordering::SeqCst)); - src.inner_mut() - .inner_mut() - .inner_mut() - .set_factor(*controls.speed.lock().unwrap()); } + if controls.do_skip.load(Ordering::SeqCst) { + let _ = src.inner_mut().skip(); + let mut to_clear = controls.to_clear.lock().unwrap(); + if *to_clear == 1 { + controls.do_skip.store(false, Ordering::SeqCst); + *to_clear = 0; + } else if *to_clear > 0 { + *to_clear -= 1; + } + } + let amp = src.inner_mut().inner_mut(); + amp.set_factor(*controls.volume.lock().unwrap()); + amp.inner_mut() + .set_paused(controls.pause.load(Ordering::SeqCst)); + amp.inner_mut() + .inner_mut() + .set_factor(*controls.speed.lock().unwrap()); }) .convert_samples(); self.sound_count.fetch_add(1, Ordering::Relaxed); @@ -161,6 +174,25 @@ impl Sink { self.controls.pause.load(Ordering::SeqCst) } + /// Removes all currently loaded `Source`s from the `Sink`, and pauses it. + /// + /// See `pause()` for information about pausing a `Sink`. + pub fn clear(&self) { + let len = self.sound_count.load(Ordering::SeqCst) as u32; + *self.controls.to_clear.lock().unwrap() = len; + self.skip_one(); + self.pause(); + } + + /// Skips to the next `Source` in the `Sink` + /// + /// If there are more `Source`s appended to the `Sink` at the time, + /// it will play the next one. Otherwise, the `Sink` will finish as if + /// it had finished playing a `Source` all the way through. + pub fn skip_one(&self) { + self.controls.do_skip.store(true, Ordering::SeqCst); + } + /// Stops the sink by emptying the queue. #[inline] pub fn stop(&self) { diff --git a/src/source/mod.rs b/src/source/mod.rs index 74a312e..45796fe 100644 --- a/src/source/mod.rs +++ b/src/source/mod.rs @@ -24,6 +24,7 @@ pub use self::repeat::Repeat; pub use self::samples_converter::SamplesConverter; pub use self::sine::SineWave; pub use self::skip::SkipDuration; +pub use self::skippable::Skippable; pub use self::spatial::Spatial; pub use self::speed::Speed; pub use self::stoppable::Stoppable; @@ -49,6 +50,7 @@ mod repeat; mod samples_converter; mod sine; mod skip; +mod skippable; mod spatial; mod speed; mod stoppable; @@ -321,6 +323,13 @@ where stoppable::stoppable(self) } + fn skippable(self) -> Skippable + where + Self: Sized, + { + skippable::skippable(self) + } + /// Applies a low-pass filter to the source. /// **Warning**: Probably buggy. #[inline] diff --git a/src/source/skippable.rs b/src/source/skippable.rs new file mode 100644 index 0000000..44ee7a7 --- /dev/null +++ b/src/source/skippable.rs @@ -0,0 +1,92 @@ +use std::time::Duration; + +use crate::Sample; +use crate::Source; + +/// Internal function that builds a `Skippable` object. +pub fn skippable(source: I) -> Skippable { + Skippable { + input: source, + do_skip: false, + } +} + +#[derive(Clone, Debug)] +pub struct Skippable { + input: I, + do_skip: bool, +} + +impl Skippable { + /// Skips the current source + #[inline] + pub fn skip(&mut self) { + self.do_skip = true; + } + + /// Returns a reference to the inner source. + #[inline] + pub fn inner(&self) -> &I { + &self.input + } + + /// Returns a mutable reference to the inner source. + #[inline] + pub fn inner_mut(&mut self) -> &mut I { + &mut self.input + } + + /// Returns the inner source. + #[inline] + pub fn into_inner(self) -> I { + self.input + } +} + +impl Iterator for Skippable +where + I: Source, + I::Item: Sample, +{ + type Item = I::Item; + + #[inline] + fn next(&mut self) -> Option { + if self.do_skip { + None + } else { + self.input.next() + } + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + self.input.size_hint() + } +} + +impl Source for Skippable +where + I: Source, + I::Item: Sample, +{ + #[inline] + fn current_frame_len(&self) -> Option { + self.input.current_frame_len() + } + + #[inline] + fn channels(&self) -> u16 { + self.input.channels() + } + + #[inline] + fn sample_rate(&self) -> u32 { + self.input.sample_rate() + } + + #[inline] + fn total_duration(&self) -> Option { + self.input.total_duration() + } +}