Skip to main content

rodio/source/
channel_volume.rs

1use std::time::Duration;
2
3use super::SeekError;
4use crate::common::{ChannelCount, SampleRate};
5use crate::{Float, Sample, Source};
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{
14    input: I,
15    channel_volumes: Vec<Float>,
16    current_channel: usize,
17    current_sample: Option<Sample>,
18}
19
20impl<I> ChannelVolume<I>
21where
22    I: Source,
23{
24    /// Wrap the input source and make it mono. Play that mono sound to each
25    /// channel at the volume set by the user. The volume can be changed using
26    /// [`ChannelVolume::set_volume`].
27    pub fn new(input: I, channel_volumes: Vec<Float>) -> ChannelVolume<I> {
28        let channel_count = channel_volumes.len(); // See next() implementation.
29        ChannelVolume {
30            input,
31            channel_volumes,
32            current_channel: channel_count,
33            current_sample: None,
34        }
35    }
36
37    /// Sets the volume for a given channel number. Will panic if channel number
38    /// is invalid.
39    pub fn set_volume(&mut self, channel: usize, volume: Float) {
40        self.channel_volumes[channel] = volume;
41    }
42
43    /// Returns a reference to the inner source.
44    #[inline]
45    pub fn inner(&self) -> &I {
46        &self.input
47    }
48
49    /// Returns a mutable reference to the inner source.
50    #[inline]
51    pub fn inner_mut(&mut self) -> &mut I {
52        &mut self.input
53    }
54
55    /// Returns the inner source.
56    #[inline]
57    pub fn into_inner(self) -> I {
58        self.input
59    }
60}
61
62impl<I> Iterator for ChannelVolume<I>
63where
64    I: Source,
65{
66    type Item = Sample;
67
68    #[inline]
69    fn next(&mut self) -> Option<Self::Item> {
70        // TODO Need a test for this
71        if self.current_channel >= self.channel_volumes.len() {
72            self.current_channel = 0;
73            self.current_sample = None;
74            let num_channels = self.input.channels();
75            for _ in 0..num_channels.get() {
76                if let Some(s) = self.input.next() {
77                    self.current_sample = Some(self.current_sample.unwrap_or(0.0) + s);
78                }
79            }
80            self.current_sample.map(|s| s / num_channels.get() as Float);
81        }
82        let result = self
83            .current_sample
84            .map(|s| s * self.channel_volumes[self.current_channel]);
85        self.current_channel += 1;
86        result
87    }
88
89    #[inline]
90    fn size_hint(&self) -> (usize, Option<usize>) {
91        self.input.size_hint()
92    }
93}
94
95impl<I> ExactSizeIterator for ChannelVolume<I> where I: Source + ExactSizeIterator {}
96
97impl<I> Source for ChannelVolume<I>
98where
99    I: Source,
100{
101    #[inline]
102    fn current_span_len(&self) -> Option<usize> {
103        self.input.current_span_len()
104    }
105
106    #[inline]
107    fn channels(&self) -> ChannelCount {
108        ChannelCount::new(self.channel_volumes.len() as u16)
109            .expect("checked to be non-empty in new implementation")
110    }
111
112    #[inline]
113    fn sample_rate(&self) -> SampleRate {
114        self.input.sample_rate()
115    }
116
117    #[inline]
118    fn total_duration(&self) -> Option<Duration> {
119        self.input.total_duration()
120    }
121
122    #[inline]
123    fn try_seek(&mut self, pos: Duration) -> Result<(), SeekError> {
124        self.input.try_seek(pos)
125    }
126}