Implement clear() and skip_one() functionality (continuation of #287) (#442)

* Clear and Skip functionality added

Added a clear() and skip_one() method to the Sink impl

* Use one lock for clear

Return the length in the queue clear function so that we don't have to get a lock twice.

* Rework skip to mark all sources as skippable


---------

Co-authored-by: Nathan Abel <abel8706@kettering.edu>
Co-authored-by: Ivar Kamsvåg <ivaka037@student.liu.se>
Co-authored-by: est31 <est31@users.noreply.github.com>
This commit is contained in:
ivakam 2023-02-19 13:46:18 +01:00 committed by GitHub
parent 56360d789c
commit e9a85ec254
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 150 additions and 10 deletions

View file

@ -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<S> {
// The current iterator that produces samples.

View file

@ -26,6 +26,8 @@ struct Controls {
volume: Mutex<f32>,
stopped: AtomicBool,
speed: Mutex<f32>,
do_skip: AtomicBool,
to_clear: Mutex<u32>,
}
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) {

View file

@ -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<Self>
where
Self: Sized,
{
skippable::skippable(self)
}
/// Applies a low-pass filter to the source.
/// **Warning**: Probably buggy.
#[inline]

92
src/source/skippable.rs Normal file
View file

@ -0,0 +1,92 @@
use std::time::Duration;
use crate::Sample;
use crate::Source;
/// Internal function that builds a `Skippable` object.
pub fn skippable<I>(source: I) -> Skippable<I> {
Skippable {
input: source,
do_skip: false,
}
}
#[derive(Clone, Debug)]
pub struct Skippable<I> {
input: I,
do_skip: bool,
}
impl<I> Skippable<I> {
/// 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<I> Iterator for Skippable<I>
where
I: Source,
I::Item: Sample,
{
type Item = I::Item;
#[inline]
fn next(&mut self) -> Option<I::Item> {
if self.do_skip {
None
} else {
self.input.next()
}
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
self.input.size_hint()
}
}
impl<I> Source for Skippable<I>
where
I: Source,
I::Item: Sample,
{
#[inline]
fn current_frame_len(&self) -> Option<usize> {
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<Duration> {
self.input.total_duration()
}
}