geng_rodio/source/
channel_volume.rs

1use std::time::Duration;
2
3use crate::{Sample, Source};
4
5/// Combines channels in input into a single mono source, then plays that mono sound
6/// to each channel at the volume given for that channel.
7#[derive(Clone, Debug)]
8pub struct ChannelVolume<I>
9where
10    I: Source,
11    I::Item: Sample,
12{
13    input: I,
14    // Channel number is used as index for amplification value.
15    channel_volumes: Vec<f32>,
16    // Current listener being processed.
17    current_channel: usize,
18    current_sample: Option<I::Item>,
19}
20
21impl<I> ChannelVolume<I>
22where
23    I: Source,
24    I::Item: Sample,
25{
26    pub fn new(mut input: I, channel_volumes: Vec<f32>) -> ChannelVolume<I>
27    where
28        I: Source,
29        I::Item: Sample,
30    {
31        let mut sample = None;
32        for _ in 0..input.channels() {
33            if let Some(s) = input.next() {
34                sample = Some(
35                    sample
36                        .get_or_insert_with(I::Item::zero_value)
37                        .saturating_add(s),
38                );
39            }
40        }
41        ChannelVolume {
42            input,
43            channel_volumes,
44            current_channel: 0,
45            current_sample: sample,
46        }
47    }
48
49    /// Sets the volume for a given channel number.  Will panic if channel number
50    /// was invalid.
51    pub fn set_volume(&mut self, channel: usize, volume: f32) {
52        self.channel_volumes[channel] = volume;
53    }
54
55    /// Returns a reference to the inner source.
56    #[inline]
57    pub fn inner(&self) -> &I {
58        &self.input
59    }
60
61    /// Returns a mutable reference to the inner source.
62    #[inline]
63    pub fn inner_mut(&mut self) -> &mut I {
64        &mut self.input
65    }
66
67    /// Returns the inner source.
68    #[inline]
69    pub fn into_inner(self) -> I {
70        self.input
71    }
72}
73
74impl<I> Iterator for ChannelVolume<I>
75where
76    I: Source,
77    I::Item: Sample,
78{
79    type Item = I::Item;
80
81    #[inline]
82    fn next(&mut self) -> Option<I::Item> {
83        // return value
84        let ret = self
85            .current_sample
86            .map(|sample| sample.amplify(self.channel_volumes[self.current_channel]));
87        self.current_channel += 1;
88        if self.current_channel >= self.channel_volumes.len() {
89            self.current_channel = 0;
90            self.current_sample = None;
91            for _ in 0..self.input.channels() {
92                if let Some(s) = self.input.next() {
93                    self.current_sample = Some(
94                        self.current_sample
95                            .get_or_insert_with(I::Item::zero_value)
96                            .saturating_add(s),
97                    );
98                }
99            }
100        }
101        ret
102    }
103
104    #[inline]
105    fn size_hint(&self) -> (usize, Option<usize>) {
106        self.input.size_hint()
107    }
108}
109
110impl<I> ExactSizeIterator for ChannelVolume<I>
111where
112    I: Source + ExactSizeIterator,
113    I::Item: Sample,
114{
115}
116
117impl<I> Source for ChannelVolume<I>
118where
119    I: Source,
120    I::Item: Sample,
121{
122    #[inline]
123    fn current_frame_len(&self) -> Option<usize> {
124        self.input.current_frame_len()
125    }
126
127    #[inline]
128    fn channels(&self) -> u16 {
129        self.channel_volumes.len() as u16
130    }
131
132    #[inline]
133    fn sample_rate(&self) -> u32 {
134        self.input.sample_rate()
135    }
136
137    #[inline]
138    fn total_duration(&self) -> Option<Duration> {
139        self.input.total_duration()
140    }
141}