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}