mirror of
https://github.com/RustAudio/rodio
synced 2025-01-20 23:43:52 +00:00
Make silence more efficient
This commit is contained in:
parent
2c7d171670
commit
9c874b7690
2 changed files with 36 additions and 19 deletions
|
@ -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,
|
||||||
|
|
|
@ -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]
|
||||||
|
|
Loading…
Reference in a new issue