Make silence more efficient

This commit is contained in:
Imbris 2020-01-25 11:09:54 -05:00 committed by est31
parent 2c7d171670
commit 9c874b7690
2 changed files with 36 additions and 19 deletions

View file

@ -206,7 +206,7 @@ where
if next.len() == 0 { if next.len() == 0 {
if self.input.keep_alive_if_empty.load(Ordering::Acquire) { if self.input.keep_alive_if_empty.load(Ordering::Acquire) {
// Play a short silence in order to avoid spinlocking. // Play a short silence in order to avoid spinlocking.
let silence = Zero::<S>::new(1, 44000); // TODO: meh let silence = Zero::<S>::new(1, 44100); // TODO: meh
( (
Box::new(silence.take_duration(Duration::from_millis(10))) as Box<_>, Box::new(silence.take_duration(Duration::from_millis(10))) as Box<_>,
None, None,

View file

@ -4,8 +4,14 @@ use Sample;
use Source; use Source;
/// Internal function that builds a `TakeDuration` object. /// Internal function that builds a `TakeDuration` object.
pub fn take_duration<I>(input: I, duration: Duration) -> TakeDuration<I> { pub fn take_duration<I>(input: I, duration: Duration) -> TakeDuration<I>
where
I: Source,
I::Item: Sample,
{
TakeDuration { TakeDuration {
current_frame_len: input.current_frame_len(),
duration_per_sample: TakeDuration::get_duration_per_sample(&input),
input: input, input: input,
remaining_duration: duration, remaining_duration: duration,
requested_duration: duration, requested_duration: duration,
@ -35,6 +41,8 @@ impl DurationFilter
} }
} }
const NANOS_PER_SEC: u64 = 1_000_000_000;
/// A source that repeats the given source. /// A source that repeats the given source.
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct TakeDuration<I> { pub struct TakeDuration<I> {
@ -42,6 +50,10 @@ pub struct TakeDuration<I> {
remaining_duration: Duration, remaining_duration: Duration,
requested_duration: Duration, requested_duration: Duration,
filter: Option<DurationFilter>, filter: Option<DurationFilter>,
// Remaining samples in current frame.
current_frame_len: Option<usize>,
// Only updated when the current frame len is exausted.
duration_per_sample: Duration,
} }
impl<I> TakeDuration<I> impl<I> TakeDuration<I>
@ -51,8 +63,8 @@ where
{ {
/// Returns the duration elapsed for each sample extracted. /// Returns the duration elapsed for each sample extracted.
#[inline] #[inline]
fn get_duration_per_sample(&self) -> Duration { fn get_duration_per_sample(input: &I) -> Duration {
let ns = 1000000000 / (self.input.sample_rate() as u64 * self.channels() as u64); let ns = NANOS_PER_SEC / input.sample_rate() as u64 * input.channels() as u64;
// \|/ the maximum value of `ns` is one billion, so this can't fail // \|/ the maximum value of `ns` is one billion, so this can't fail
Duration::new(0, ns as u32) Duration::new(0, ns as u32)
} }
@ -92,9 +104,17 @@ where
type Item = <I as Iterator>::Item; type Item = <I as Iterator>::Item;
fn next(&mut self) -> Option<<I as Iterator>::Item> { fn next(&mut self) -> Option<<I as Iterator>::Item> {
let duration_per_sample = self.get_duration_per_sample(); if let Some(frame_len) = self.current_frame_len.take() {
if frame_len > 0 {
self.current_frame_len = Some(frame_len - 1);
} else {
self.current_frame_len = self.input.current_frame_len();
// Sample rate might have changed
self.duration_per_sample = Self::get_duration_per_sample(&self.input);
}
}
if self.remaining_duration <= duration_per_sample { if self.remaining_duration <= self.duration_per_sample {
None None
} else { } else {
if let Some(sample) = self.input.next() { if let Some(sample) = self.input.next() {
@ -102,7 +122,9 @@ where
Some(filter) => filter.apply(sample, &self), Some(filter) => filter.apply(sample, &self),
None => sample, None => sample,
}; };
self.remaining_duration = self.remaining_duration - duration_per_sample;
self.remaining_duration = self.remaining_duration - self.duration_per_sample;
Some(sample) Some(sample)
} else { } else {
None None
@ -120,20 +142,15 @@ where
{ {
#[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_nanos = self.remaining_duration.as_secs() * NANOS_PER_SEC
+ self.remaining_duration.subsec_nanos() as u64; + self.remaining_duration.subsec_nanos() as u64;
let remaining_samples = remaining_nanosecs * self.input.sample_rate() as u64 let nanos_per_sample = self.duration_per_sample.as_secs() * NANOS_PER_SEC
* self.channels() as u64 / 1000000000; + self.duration_per_sample.subsec_nanos() as u64;
let remaining_samples = (remaining_nanos / nanos_per_sample) as usize;
if let Some(value) = self.input.current_frame_len() { self.input.current_frame_len()
if (value as u64) < remaining_samples { .filter(|value| *value < remaining_samples)
Some(value) .or(Some(remaining_samples))
} else {
Some(remaining_samples as usize)
}
} else {
Some(remaining_samples as usize)
}
} }
#[inline] #[inline]