geng_rodio/source/
mix.rs

1use std::cmp;
2use std::time::Duration;
3
4use crate::source::uniform::UniformSourceIterator;
5use crate::{Sample, Source};
6use cpal::{FromSample, Sample as CpalSample};
7
8/// Internal function that builds a `Mix` object.
9pub fn mix<I1, I2>(input1: I1, input2: I2) -> Mix<I1, I2>
10where
11    I1: Source,
12    I1::Item: FromSample<I2::Item> + Sample,
13    I2: Source,
14    I2::Item: Sample,
15{
16    let channels = input1.channels();
17    let rate = input1.sample_rate();
18
19    Mix {
20        input1: UniformSourceIterator::new(input1, channels, rate),
21        input2: UniformSourceIterator::new(input2, channels, rate),
22    }
23}
24
25/// Filter that modifies each sample by a given value.
26#[derive(Clone)]
27pub struct Mix<I1, I2>
28where
29    I1: Source,
30    I1::Item: FromSample<I2::Item> + Sample,
31    I2: Source,
32    I2::Item: Sample,
33{
34    input1: UniformSourceIterator<I1, I1::Item>,
35    input2: UniformSourceIterator<I2, I2::Item>,
36}
37
38impl<I1, I2> Iterator for Mix<I1, I2>
39where
40    I1: Source,
41    I1::Item: FromSample<I2::Item> + Sample,
42    I2: Source,
43    I2::Item: Sample,
44{
45    type Item = I1::Item;
46
47    #[inline]
48    fn next(&mut self) -> Option<I1::Item> {
49        let s1 = self.input1.next();
50        let s2 = self.input2.next();
51
52        match (s1, s2) {
53            (Some(s1), Some(s2)) => Some(s1.saturating_add(CpalSample::from_sample(s2))),
54            (Some(s1), None) => Some(s1),
55            (None, Some(s2)) => Some(CpalSample::from_sample(s2)),
56            (None, None) => None,
57        }
58    }
59
60    #[inline]
61    fn size_hint(&self) -> (usize, Option<usize>) {
62        let s1 = self.input1.size_hint();
63        let s2 = self.input2.size_hint();
64
65        let min = cmp::max(s1.0, s2.0);
66        let max = match (s1.1, s2.1) {
67            (Some(s1), Some(s2)) => Some(cmp::max(s1, s2)),
68            _ => None,
69        };
70
71        (min, max)
72    }
73}
74
75impl<I1, I2> ExactSizeIterator for Mix<I1, I2>
76where
77    I1: Source + ExactSizeIterator,
78    I1::Item: FromSample<I2::Item> + Sample,
79    I2: Source + ExactSizeIterator,
80    I2::Item: Sample,
81{
82}
83
84impl<I1, I2> Source for Mix<I1, I2>
85where
86    I1: Source,
87    I1::Item: FromSample<I2::Item> + Sample,
88    I2: Source,
89    I2::Item: Sample,
90{
91    #[inline]
92    fn current_frame_len(&self) -> Option<usize> {
93        let f1 = self.input1.current_frame_len();
94        let f2 = self.input2.current_frame_len();
95
96        match (f1, f2) {
97            (Some(f1), Some(f2)) => Some(cmp::min(f1, f2)),
98            _ => None,
99        }
100    }
101
102    #[inline]
103    fn channels(&self) -> u16 {
104        self.input1.channels()
105    }
106
107    #[inline]
108    fn sample_rate(&self) -> u32 {
109        self.input1.sample_rate()
110    }
111
112    #[inline]
113    fn total_duration(&self) -> Option<Duration> {
114        let f1 = self.input1.total_duration();
115        let f2 = self.input2.total_duration();
116
117        match (f1, f2) {
118            (Some(f1), Some(f2)) => Some(cmp::max(f1, f2)),
119            _ => None,
120        }
121    }
122}