Skip to content

Commit

Permalink
fadeout: add a structure to fade out a stream
Browse files Browse the repository at this point in the history
Fixes: #179
  • Loading branch information
mathstuf committed Jan 28, 2019
1 parent fcd0edb commit 353ed54
Show file tree
Hide file tree
Showing 2 changed files with 106 additions and 0 deletions.
95 changes: 95 additions & 0 deletions src/source/fadeout.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
use std::time::Duration;

use Sample;
use Source;

/// Internal function that builds a `FadeOut` object.
pub fn fadeout<I>(input: I, duration: Duration) -> FadeOut<I> {
let duration = duration.as_secs() * 1000000000 + duration.subsec_nanos() as u64;

FadeOut {
input: input,
remaining_ns: duration as f32,
total_ns: duration as f32,
}
}

/// Filter that modifies reduces the volume to silence over a time period.
#[derive(Clone, Debug)]
pub struct FadeOut<I> {
input: I,
remaining_ns: f32,
total_ns: f32,
}

impl<I> FadeOut<I> {
/// Starts the fade to silence.
#[inline]
pub fn start(&mut self) {
self.remaining_ns = self.total_ns;
}

/// Clears the fade out time.
#[inline]
pub fn reset(&mut self) {
self.remaining_ns = -1.0;
}
}

impl<I> Iterator for FadeOut<I>
where
I: Source,
I::Item: Sample,
{
type Item = I::Item;

#[inline]
fn next(&mut self) -> Option<I::Item> {
if self.remaining_ns <= 0.0 {
return self.input.next();
}

let factor = self.remaining_ns / self.total_ns;
self.remaining_ns -=
1000000000.0 / (self.input.sample_rate() as f32 * self.channels() as f32);
self.input.next().map(|value| value.amplify(factor))
}

#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
self.input.size_hint()
}
}

impl<I> ExactSizeIterator for FadeOut<I>
where
I: Source + ExactSizeIterator,
I::Item: Sample,
{
}

impl<I> Source for FadeOut<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()
}
}
11 changes: 11 additions & 0 deletions src/source/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ pub use self::delay::Delay;
pub use self::done::Done;
pub use self::empty::Empty;
pub use self::fadein::FadeIn;
pub use self::fadeout::FadeOut;
pub use self::from_factory::{from_factory, FromFactoryIter};
pub use self::from_iter::{from_iter, FromIter};
pub use self::mix::Mix;
Expand All @@ -35,6 +36,7 @@ mod delay;
mod done;
mod empty;
mod fadein;
mod fadeout;
mod from_factory;
mod from_iter;
mod mix;
Expand Down Expand Up @@ -211,6 +213,15 @@ where
fadein::fadein(self, duration)
}

/// Fades out the sound.
#[inline]
fn fade_out(self, duration: Duration) -> FadeOut<Self>
where
Self: Sized,
{
fadeout::fadeout(self, duration)
}

/// Calls the `access` closure on `Self` every time `period` elapsed.
#[inline]
fn periodic_access<F>(self, period: Duration, access: F) -> PeriodicAccess<Self, F>
Expand Down

0 comments on commit 353ed54

Please sign in to comment.