diff --git a/src/source/crossfade.rs b/src/source/crossfade.rs index d9d29db..2059ef2 100644 --- a/src/source/crossfade.rs +++ b/src/source/crossfade.rs @@ -5,9 +5,11 @@ use cpal::FromSample; use crate::source::{FadeIn, Mix, TakeDuration}; use crate::{Sample, Source}; -/// Mixes one sound fading out with another sound fading in for the given duration. +/// Mixes one sound fading out with another sound fading in for the given +/// duration. /// -/// Only the crossfaded portion (beginning of fadeout, beginning of fadein) is returned. +/// Only the crossfaded portion (beginning of fadeout, beginning of fadein) is +/// returned. pub fn crossfade( input_fadeout: I1, input_fadein: I2, @@ -37,7 +39,7 @@ mod tests { } #[test] - fn test_crossfade() { + fn test_crossfade_with_self() { let source1 = dummysource(10); let source2 = dummysource(10); let mut mixed = crossfade( @@ -51,7 +53,10 @@ mod tests { assert_eq!(mixed.next(), Some(4.0)); assert_eq!(mixed.next(), Some(5.0)); assert_eq!(mixed.next(), None); + } + #[test] + fn test_crossfade() { let source1 = dummysource(10); let source2 = dummysource(10).amplify(0.0); let mut mixed = crossfade( diff --git a/src/source/fadein.rs b/src/source/fadein.rs index 8a28bd9..dcf118e 100644 --- a/src/source/fadein.rs +++ b/src/source/fadein.rs @@ -54,12 +54,12 @@ where #[inline] fn next(&mut self) -> Option { - self.inner_mut().next() + self.input.next() } #[inline] fn size_hint(&self) -> (usize, Option) { - self.inner().size_hint() + self.input.size_hint() } } diff --git a/src/source/linear_ramp.rs b/src/source/linear_ramp.rs index 5080259..cc64e85 100644 --- a/src/source/linear_ramp.rs +++ b/src/source/linear_ramp.rs @@ -15,7 +15,7 @@ where I: Source, I::Item: Sample, { - let duration_nanos = duration.as_secs_f32(); + let duration_nanos = duration.as_nanos() as f32; assert!(duration_nanos > 0.0f32); LinearGainRamp { @@ -77,7 +77,7 @@ where let factor: f32; let remaining_ns = self.total_ns - self.elapsed_ns; - if remaining_ns <= 0.0 { + if remaining_ns < 0.0 { if self.clamp_end { factor = self.end_gain; } else { @@ -85,18 +85,14 @@ where } } else { self.sample_idx += 1; - - factor = f32::lerp( - self.start_gain, - self.end_gain, - remaining_ns as u32, - self.total_ns as u32, - ); + + let p = self.elapsed_ns / self.total_ns; + factor = self.start_gain * (1.0f32 - p) + self.end_gain * p; } - // FIXME: the way this use to work was calculating a new elapsed value for every sample, - // but this is not exactly correct for multichannel inputs. This is a new implementation - // but it is presently causing the crossfade unit tests to fail. + println!("Factor: {}, remaining: {}, total: {}", factor, remaining_ns, + self.total_ns); + if self.sample_idx % (self.channels() as u64) == 0 { self.elapsed_ns += 1000000000.0 / (self.input.sample_rate() as f32); @@ -152,5 +148,52 @@ where #[cfg(test)] mod tests { - + use super::*; + use crate::buffer::SamplesBuffer; + + fn dummysource(length: u8) -> SamplesBuffer { + // shamelessly copied from crossfade.rs + let data: Vec = (1..=length).map(f32::from).collect(); + SamplesBuffer::new(1, 1, data) + } + + #[test] + fn test_linearramp() { + let source1 = dummysource(10); + let mut faded = linear_gain_ramp(source1, + Duration::from_secs(4), + 0.0, 1.0, true); + + assert_eq!(faded.next(), Some(0.0)); + assert_eq!(faded.next(), Some(0.5)); + assert_eq!(faded.next(), Some(1.5)); + assert_eq!(faded.next(), Some(3.0)); + assert_eq!(faded.next(), Some(5.0)); + assert_eq!(faded.next(), Some(6.0)); + assert_eq!(faded.next(), Some(7.0)); + assert_eq!(faded.next(), Some(8.0)); + assert_eq!(faded.next(), Some(9.0)); + assert_eq!(faded.next(), Some(10.0)); + assert_eq!(faded.next(), None); + } + + #[test] + fn test_linearramp_clamped() { + let source1 = dummysource(10); + let mut faded = linear_gain_ramp(source1, + Duration::from_secs(4), + 0.0, 0.5, true); + + assert_eq!(faded.next(), Some(0.0)); + assert_eq!(faded.next(), Some(0.25)); + assert_eq!(faded.next(), Some(0.75)); + assert_eq!(faded.next(), Some(1.5)); + assert_eq!(faded.next(), Some(2.5)); + assert_eq!(faded.next(), Some(3.0)); + assert_eq!(faded.next(), Some(3.5)); + assert_eq!(faded.next(), Some(4.0)); + assert_eq!(faded.next(), Some(4.5)); + assert_eq!(faded.next(), Some(5.0)); + assert_eq!(faded.next(), None); + } }