rodio/source/
channel_volume.rs

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