rodio/source/
channel_volume.rs

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