diff --git a/src/source/channel_volume.rs b/src/source/channel_volume.rs index 69dc869e..995769c0 100644 --- a/src/source/channel_volume.rs +++ b/src/source/channel_volume.rs @@ -103,7 +103,32 @@ where #[inline] fn size_hint(&self) -> (usize, Option) { - self.input.size_hint() + let map_size_hint = |input_hint: usize| -> usize { + // The input source provides a number of samples ceil(input_hint / channels); + // We return 1 item per channel per sample => * channel_volumes + let input_channels = self.input.channels() as usize; + let input_chunks = (input_hint / input_channels) + + if input_hint % input_channels != 0 { + 1 + } else { + 0 + }; + + let input_provides = input_chunks * self.channel_volumes.len(); + + // In addition, we may be in the process of emitting additional values from + // self.current_sample + let current_sample = if self.current_sample.is_some() { + self.channel_volumes.len() - self.current_channel + } else { + 0 + }; + + input_provides + current_sample + }; + + let (min, max) = self.input.size_hint(); + (map_size_hint(min), max.map(map_size_hint)) } } @@ -139,3 +164,76 @@ where self.input.total_duration() } } + +#[cfg(test)] +mod tests { + use super::*; + use crate::buffer::SamplesBuffer; + + fn dummysource(samples: usize, channels: usize) -> SamplesBuffer { + let data: Vec = (1..=(samples * channels)).map(|v| v as f32).collect(); + SamplesBuffer::new(channels as _, 1, data) + } + + fn make_test(samples: usize, channels_source: usize, channels_result: usize) { + let original = dummysource(samples, channels_source); + assert_eq!(original.size_hint().0, samples * channels_source); + + let mono = ChannelVolume::new(original, vec![1.0; channels_result]); + + let (hint_min, hint_max) = mono.size_hint(); + assert_eq!(Some(hint_min), hint_max); + + let actual_size = mono.count(); + assert_eq!(hint_min, actual_size); + } + + #[test] + fn size_stereo_mono() { + make_test(100, 2, 1); + } + #[test] + fn size_stereo_mono_offset() { + make_test(101, 2, 1); + } + #[test] + fn size_mono_stereo() { + make_test(100, 1, 2); + } + + #[test] + fn size_stereo_eight() { + make_test(100, 2, 8); + } + #[test] + fn size_stereo_eight_offset() { + make_test(101, 2, 8); + } + + #[test] + fn size_stereo_five() { + make_test(100, 2, 5); + } + #[test] + fn size_stereo_five_offset() { + make_test(101, 2, 5); + } + + #[test] + fn size_eight_stereo() { + make_test(100 * 8, 8, 2); + } + #[test] + fn size_eight_stereo_offset() { + make_test(100 * 8 + 1, 8, 2); + } + + #[test] + fn size_five_stereo() { + make_test(100, 5, 2); + } + #[test] + fn size_five_stereo_offset() { + make_test(101, 5, 2); + } +}