rodio/source/
signal_generator.rs

1//! Generator sources for various periodic test waveforms.
2//!
3//! This module provides several periodic, deterministic waveforms for testing other sources and
4//! for simple additive sound synthesis. Every source is monoaural and in the codomain [-1.0f32,
5//! 1.0f32].
6//!
7//! # Example
8//!
9//! ```
10//! use rodio::source::{SignalGenerator,Function};
11//!
12//! let tone = SignalGenerator::new(48000, 440.0, Function::Sine);
13//! ```
14use super::SeekError;
15use crate::common::{ChannelCount, SampleRate};
16use crate::Source;
17use std::f32::consts::TAU;
18use std::time::Duration;
19
20/// Generator function.
21///
22/// A generator function is the core of a signal generator, the `SignalGenerator` type uses these
23/// function to create periodic waveforms.
24///
25/// # Arguments
26///  *  An `f32` representing a time in the signal to generate. The scale of this variable is
27///     normalized to the period of the signal, such that "0.0" is time zero, "1.0" is one period of
28///     the signal, "2.0" is two periods and so on. This function should be written to accept any
29///     float in the range (`f32::MIN`, `f32::MAX`) but `SignalGenerator` will only pass values in
30///     (0.0, 1.0) to mitigate floating point error.
31///
32/// # Returns
33///
34/// An `f32` representing the signal level at the passed time. This value should be normalized
35/// in the range [-1.0,1.0].
36pub type GeneratorFunction = fn(f32) -> f32;
37
38/// Waveform functions.
39#[derive(Clone, Debug)]
40pub enum Function {
41    /// A sinusoidal waveform.
42    Sine,
43    /// A triangle waveform.
44    Triangle,
45    /// A square wave, rising edge at t=0.
46    Square,
47    /// A rising sawtooth wave.
48    Sawtooth,
49}
50
51fn sine_signal(phase: f32) -> f32 {
52    (TAU * phase).sin()
53}
54
55fn triangle_signal(phase: f32) -> f32 {
56    4.0f32 * (phase - (phase + 0.5f32).floor()).abs() - 1f32
57}
58
59fn square_signal(phase: f32) -> f32 {
60    if phase % 1.0f32 < 0.5f32 {
61        1.0f32
62    } else {
63        -1.0f32
64    }
65}
66
67fn sawtooth_signal(phase: f32) -> f32 {
68    2.0f32 * (phase - (phase + 0.5f32).floor())
69}
70
71/// An infinite source that produces one of a selection of test waveforms.
72#[derive(Clone, Debug)]
73pub struct SignalGenerator {
74    sample_rate: SampleRate,
75    function: GeneratorFunction,
76    phase_step: f32,
77    phase: f32,
78    period: f32,
79}
80
81impl SignalGenerator {
82    /// Create a new `SignalGenerator` object that generates an endless waveform
83    /// `f`.
84    ///
85    /// # Panics
86    ///
87    /// Will panic if `frequency` is equal to zero.
88    #[inline]
89    pub fn new(sample_rate: SampleRate, frequency: f32, f: Function) -> Self {
90        let function: GeneratorFunction = match f {
91            Function::Sine => sine_signal,
92            Function::Triangle => triangle_signal,
93            Function::Square => square_signal,
94            Function::Sawtooth => sawtooth_signal,
95        };
96
97        Self::with_function(sample_rate, frequency, function)
98    }
99
100    /// Create a new `SignalGenerator` object that generates an endless waveform
101    /// from the [generator function](crate::source::signal_generator::GeneratorFunction) `generator_function`.
102    ///
103    /// # Panics
104    ///
105    /// Will panic if `frequency` is equal to zero.
106    #[inline]
107    pub fn with_function(
108        sample_rate: SampleRate,
109        frequency: f32,
110        generator_function: GeneratorFunction,
111    ) -> Self {
112        assert!(frequency != 0.0, "frequency must be greater than zero");
113        let period = sample_rate as f32 / frequency;
114        let phase_step = 1.0f32 / period;
115
116        SignalGenerator {
117            sample_rate,
118            function: generator_function,
119            phase_step,
120            phase: 0.0f32,
121            period,
122        }
123    }
124}
125
126impl Iterator for SignalGenerator {
127    type Item = f32;
128
129    #[inline]
130    fn next(&mut self) -> Option<f32> {
131        let f = self.function;
132        let val = Some(f(self.phase));
133        self.phase = (self.phase + self.phase_step).rem_euclid(1.0f32);
134        val
135    }
136}
137
138impl Source for SignalGenerator {
139    #[inline]
140    fn current_span_len(&self) -> Option<usize> {
141        None
142    }
143
144    #[inline]
145    fn channels(&self) -> ChannelCount {
146        1
147    }
148
149    #[inline]
150    fn sample_rate(&self) -> SampleRate {
151        self.sample_rate
152    }
153
154    #[inline]
155    fn total_duration(&self) -> Option<Duration> {
156        None
157    }
158
159    #[inline]
160    fn try_seek(&mut self, duration: Duration) -> Result<(), SeekError> {
161        let seek = duration.as_secs_f32() * (self.sample_rate as f32) / self.period;
162        self.phase = seek.rem_euclid(1.0f32);
163        Ok(())
164    }
165}
166
167#[cfg(test)]
168mod tests {
169    use crate::source::{Function, SignalGenerator};
170    use approx::assert_abs_diff_eq;
171
172    #[test]
173    fn square() {
174        let mut wf = SignalGenerator::new(2000, 500.0f32, Function::Square);
175        assert_eq!(wf.next(), Some(1.0f32));
176        assert_eq!(wf.next(), Some(1.0f32));
177        assert_eq!(wf.next(), Some(-1.0f32));
178        assert_eq!(wf.next(), Some(-1.0f32));
179        assert_eq!(wf.next(), Some(1.0f32));
180        assert_eq!(wf.next(), Some(1.0f32));
181        assert_eq!(wf.next(), Some(-1.0f32));
182        assert_eq!(wf.next(), Some(-1.0f32));
183    }
184
185    #[test]
186    fn triangle() {
187        let mut wf = SignalGenerator::new(8000, 1000.0f32, Function::Triangle);
188        assert_eq!(wf.next(), Some(-1.0f32));
189        assert_eq!(wf.next(), Some(-0.5f32));
190        assert_eq!(wf.next(), Some(0.0f32));
191        assert_eq!(wf.next(), Some(0.5f32));
192        assert_eq!(wf.next(), Some(1.0f32));
193        assert_eq!(wf.next(), Some(0.5f32));
194        assert_eq!(wf.next(), Some(0.0f32));
195        assert_eq!(wf.next(), Some(-0.5f32));
196        assert_eq!(wf.next(), Some(-1.0f32));
197        assert_eq!(wf.next(), Some(-0.5f32));
198        assert_eq!(wf.next(), Some(0.0f32));
199        assert_eq!(wf.next(), Some(0.5f32));
200        assert_eq!(wf.next(), Some(1.0f32));
201        assert_eq!(wf.next(), Some(0.5f32));
202        assert_eq!(wf.next(), Some(0.0f32));
203        assert_eq!(wf.next(), Some(-0.5f32));
204    }
205
206    #[test]
207    fn saw() {
208        let mut wf = SignalGenerator::new(200, 50.0f32, Function::Sawtooth);
209        assert_eq!(wf.next(), Some(0.0f32));
210        assert_eq!(wf.next(), Some(0.5f32));
211        assert_eq!(wf.next(), Some(-1.0f32));
212        assert_eq!(wf.next(), Some(-0.5f32));
213        assert_eq!(wf.next(), Some(0.0f32));
214        assert_eq!(wf.next(), Some(0.5f32));
215        assert_eq!(wf.next(), Some(-1.0f32));
216    }
217
218    #[test]
219    fn sine() {
220        let mut wf = SignalGenerator::new(1000, 100f32, Function::Sine);
221
222        assert_abs_diff_eq!(wf.next().unwrap(), 0.0f32);
223        assert_abs_diff_eq!(wf.next().unwrap(), 0.58778525f32);
224        assert_abs_diff_eq!(wf.next().unwrap(), 0.95105652f32);
225        assert_abs_diff_eq!(wf.next().unwrap(), 0.95105652f32);
226        assert_abs_diff_eq!(wf.next().unwrap(), 0.58778525f32);
227        assert_abs_diff_eq!(wf.next().unwrap(), 0.0f32);
228        assert_abs_diff_eq!(wf.next().unwrap(), -0.58778554f32);
229    }
230}