rodio/source/
speed.rs

1//! Playback Speed control Module.
2//!
3//! The main concept of this module is the [`Speed`] struct, which
4//! encapsulates playback speed controls of the current sink.
5//!
6//! In order to speed up a sink, the speed struct:
7//! - Increases the current sample rate by the given factor
8//! - Updates the total duration function to cover for the new factor by dividing by the factor
9//! - Updates the try_seek function by multiplying the audio position by the factor
10//!
11//! To speed up a source from sink all you need to do is call the   `set_speed(factor: f32)` function
12//! For example, here is how you speed up your sound by using sink or playing raw
13//!
14//! ```no_run
15//!# use std::fs::File;
16//!# use std::io::BufReader;
17//!# use rodio::{Decoder, Sink, OutputStream, source::{Source, SineWave}};
18//!
19//! // Get an output stream handle to the default physical sound device.
20//! // Note that no sound will be played if _stream is dropped
21//! let (_stream, stream_handle) = OutputStream::try_default().unwrap();
22//! // Load a sound from a file, using a path relative to Cargo.toml
23//! let file = BufReader::new(File::open("examples/music.ogg").unwrap());
24//! // Decode that sound file into a source
25//! let source = Decoder::new(file).unwrap();
26//! // Play the sound directly on the device 2x faster
27//! stream_handle.play_raw(source.convert_samples().speed(2.0));
28
29//! std::thread::sleep(std::time::Duration::from_secs(5));
30//! ```
31//! here is how you would do it using the sink
32//! ```
33//! let source = SineWave::new(440.0)
34//! .take_duration(Duration::from_secs_f32(20.25))
35//! .amplify(0.20);
36//!
37//! let sink = Sink::try_new(&stream_handle)?;
38//! sink.set_speed(2.0);
39//! sink.append(source);
40//! std::thread::sleep(std::time::Duration::from_secs(5));
41//! ```
42//! Notice the increase in pitch as the factor increases
43//!
44//! Since the samples are played faster the audio wave get shorter increasing their frequencies
45
46use std::time::Duration;
47
48use crate::{Sample, Source};
49
50use super::SeekError;
51
52/// Internal function that builds a `Speed` object.
53pub fn speed<I>(input: I, factor: f32) -> Speed<I> {
54    Speed { input, factor }
55}
56
57/// Filter that modifies each sample by a given value.
58#[derive(Clone, Debug)]
59pub struct Speed<I> {
60    input: I,
61    factor: f32,
62}
63
64impl<I> Speed<I>
65where
66    I: Source,
67    I::Item: Sample,
68{
69    /// Modifies the speed factor.
70    #[inline]
71    pub fn set_factor(&mut self, factor: f32) {
72        self.factor = factor;
73    }
74
75    /// Returns a reference to the inner source.
76    #[inline]
77    pub fn inner(&self) -> &I {
78        &self.input
79    }
80
81    /// Returns a mutable reference to the inner source.
82    #[inline]
83    pub fn inner_mut(&mut self) -> &mut I {
84        &mut self.input
85    }
86
87    /// Returns the inner source.
88    #[inline]
89    pub fn into_inner(self) -> I {
90        self.input
91    }
92}
93
94impl<I> Iterator for Speed<I>
95where
96    I: Source,
97    I::Item: Sample,
98{
99    type Item = I::Item;
100
101    #[inline]
102    fn next(&mut self) -> Option<I::Item> {
103        self.input.next()
104    }
105
106    #[inline]
107    fn size_hint(&self) -> (usize, Option<usize>) {
108        self.input.size_hint()
109    }
110}
111
112impl<I> ExactSizeIterator for Speed<I>
113where
114    I: Source + ExactSizeIterator,
115    I::Item: Sample,
116{
117}
118
119impl<I> Source for Speed<I>
120where
121    I: Source,
122    I::Item: Sample,
123{
124    #[inline]
125    fn current_frame_len(&self) -> Option<usize> {
126        self.input.current_frame_len()
127    }
128
129    #[inline]
130    fn channels(&self) -> u16 {
131        self.input.channels()
132    }
133
134    #[inline]
135    fn sample_rate(&self) -> u32 {
136        (self.input.sample_rate() as f32 * self.factor) as u32
137    }
138
139    #[inline]
140    fn total_duration(&self) -> Option<Duration> {
141        self.input.total_duration().map(|d| d.div_f32(self.factor))
142    }
143
144    #[inline]
145    fn try_seek(&mut self, pos: Duration) -> Result<(), SeekError> {
146        let pos_accounting_for_speedup = pos.mul_f32(self.factor);
147        self.input.try_seek(pos_accounting_for_speedup)
148    }
149}