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#![cfg_attr(not(feature = "playback"), doc = "```ignore")]
15#![cfg_attr(feature = "playback", doc = "```no_run")]
16//!# use std::fs::File;
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 the _stream is dropped.
21//! let stream_handle = rodio::OutputStreamBuilder::open_default_stream()
22//!         .expect("open default audio stream");
23//! // Load a sound from a file, using a path relative to `Cargo.toml`
24//! let file = File::open("examples/music.ogg").unwrap();
25//! // Decode that sound file into a source
26//! let source = Decoder::try_from(file).unwrap();
27//! // Play the sound directly on the device 2x faster
28//! stream_handle.mixer().add(source.speed(2.0));
29//! std::thread::sleep(std::time::Duration::from_secs(5));
30//! ```
31//! Here is how you would do it using the sink:
32#![cfg_attr(not(feature = "playback"), doc = "```ignore")]
33#![cfg_attr(feature = "playback", doc = "```no_run")]
34//! use rodio::source::{Source, SineWave};
35//! let source = SineWave::new(440.0)
36//!    .take_duration(std::time::Duration::from_secs_f32(20.25))
37//!    .amplify(0.20);
38//! let stream_handle = rodio::OutputStreamBuilder::open_default_stream()
39//!         .expect("open default audio stream");
40//! let sink = rodio::Sink::connect_new(&stream_handle.mixer());
41//! sink.set_speed(2.0);
42//! sink.append(source);
43//! std::thread::sleep(std::time::Duration::from_secs(5));
44//! ```
45//! Notice the increase in pitch as the factor increases
46//!
47//! Since the samples are played faster the audio wave get shorter increasing their frequencies
48
49use std::time::Duration;
50
51use super::SeekError;
52use crate::common::{ChannelCount, SampleRate};
53use crate::Source;
54
55/// Internal function that builds a `Speed` object.
56pub fn speed<I>(input: I, factor: f32) -> Speed<I> {
57    Speed { input, factor }
58}
59
60/// Filter that modifies each sample by a given value.
61#[derive(Clone, Debug)]
62pub struct Speed<I> {
63    input: I,
64    factor: f32,
65}
66
67impl<I> Speed<I>
68where
69    I: Source,
70{
71    /// Modifies the speed factor.
72    #[inline]
73    pub fn set_factor(&mut self, factor: f32) {
74        self.factor = factor;
75    }
76
77    /// Returns a reference to the inner source.
78    #[inline]
79    pub fn inner(&self) -> &I {
80        &self.input
81    }
82
83    /// Returns a mutable reference to the inner source.
84    #[inline]
85    pub fn inner_mut(&mut self) -> &mut I {
86        &mut self.input
87    }
88
89    /// Returns the inner source.
90    #[inline]
91    pub fn into_inner(self) -> I {
92        self.input
93    }
94}
95
96impl<I> Iterator for Speed<I>
97where
98    I: Source,
99{
100    type Item = I::Item;
101
102    #[inline]
103    fn next(&mut self) -> Option<I::Item> {
104        self.input.next()
105    }
106
107    #[inline]
108    fn size_hint(&self) -> (usize, Option<usize>) {
109        self.input.size_hint()
110    }
111}
112
113impl<I> ExactSizeIterator for Speed<I> where I: Source + ExactSizeIterator {}
114
115impl<I> Source for Speed<I>
116where
117    I: Source,
118{
119    #[inline]
120    fn current_span_len(&self) -> Option<usize> {
121        self.input.current_span_len()
122    }
123
124    #[inline]
125    fn channels(&self) -> ChannelCount {
126        self.input.channels()
127    }
128
129    #[inline]
130    fn sample_rate(&self) -> SampleRate {
131        (self.input.sample_rate() as f32 * self.factor) as u32
132    }
133
134    #[inline]
135    fn total_duration(&self) -> Option<Duration> {
136        self.input.total_duration().map(|d| d.div_f32(self.factor))
137    }
138
139    #[inline]
140    fn try_seek(&mut self, pos: Duration) -> Result<(), SeekError> {
141        let pos_accounting_for_speedup = pos.mul_f32(self.factor);
142        self.input.try_seek(pos_accounting_for_speedup)
143    }
144}