diff --git a/src/source/mod.rs b/src/source/mod.rs index f44df89..c173ea8 100644 --- a/src/source/mod.rs +++ b/src/source/mod.rs @@ -30,7 +30,7 @@ pub use self::skippable::Skippable; pub use self::spatial::Spatial; pub use self::speed::Speed; pub use self::stoppable::Stoppable; -pub use self::synth_waveforms::SynthWaveform; +pub use self::synth_waveforms::{BufferedSynthWaveform, SynthWaveformFunction}; pub use self::take::TakeDuration; pub use self::uniform::UniformSourceIterator; pub use self::zero::Zero; diff --git a/src/source/synth_waveforms.rs b/src/source/synth_waveforms.rs index b335b91..ad910c0 100644 --- a/src/source/synth_waveforms.rs +++ b/src/source/synth_waveforms.rs @@ -4,6 +4,16 @@ use std::time::Duration; use super::SeekError; use crate::{buffer::SamplesBuffer, source::Repeat, Source}; + +/// Express a frequency as a rational number. +/// .0 Cycles per time quanta +/// .1 Time quanta per second +/// +/// Examples: +/// 1000,1 1000 Hz +/// 12345,100 123.45 Hz +pub struct RationalFrequency(u32, u32); + /// Syntheizer waveform functions. All of the synth waveforms are in the /// codomain [-1.0, 1.0]. #[derive(Clone, Debug)] @@ -15,60 +25,67 @@ pub enum SynthWaveformFunction { } impl SynthWaveformFunction { - /// Create a `SamplesBuffer` containing one period of `self` with the given - /// sample rate and frequency. - pub fn create_buffer(&self, sample_rate: u32, frequency: u32) -> SamplesBuffer { - let p: usize = (sample_rate / frequency) as usize; - let mut samples_vec = vec![0.0f32; p]; - - fn _pwm_impl(duty: f32, t: f32) -> f32 { - if t < duty.abs() { - 1f32 - } else { - -1f32 - } - } - - for i in 0..p { - let i_div_p: f32 = i as f32 / p as f32; - samples_vec[i] = match self { - Self::Sine => (TAU * i_div_p).sin(), - Self::Triangle => 4.0f32 * (i_div_p - (i_div_p + 0.5f32).floor()).abs() - 1f32, - Self::Square => { + /// Create a single sample for the given waveform + #[inline] + pub fn render(&self, sample: u32, period: u32) -> f32 { + let i_div_p: f32 = sample as f32 / period as f32; + + match self { + Self::Sine => (TAU * i_div_p).sin(), + Self::Triangle => 04.0f32 * (i_div_p - (i_div_p + 0.5f32).floor()).abs() - 1f32, + Self::Square => { if i_div_p < 0.5f32 { 1.0f32 } else { -1.0f32 } - } - Self::Sawtooth => 2.0f32 * (i_div_p - (i_div_p + 0.5f32).floor()), - } + }, + Self::Sawtooth => 2.0f32 * (i_div_p - (i_div_p + 0.5f32).floor()), + } + } + + /// Create a `SamplesBuffer` containing one period of `self` with the given + /// sample rate and frequency. + pub fn create_buffer( + &self, + sample_rate: cpal::SampleRate, + frequency: u32, + ) -> SamplesBuffer { + let period: usize = (sample_rate.0 / frequency) as usize; + let mut samples_vec = vec![0.0f32; period]; + + for i in 0..period { + samples_vec[i] = self.render(i as u32, period as u32); } - SamplesBuffer::new(1, sample_rate, samples_vec) + SamplesBuffer::new(1, sample_rate.0, samples_vec) } } /// An infinite source that produces one of a selection of synthesizer /// waveforms from a buffered source. #[derive(Clone)] -pub struct SynthWaveform { +pub struct BufferedSynthWaveform { input: Repeat>, } -impl SynthWaveform { +impl BufferedSynthWaveform { /// Create a new `SynthWaveform` object that generates an endless waveform /// `f`. #[inline] - pub fn new(sample_rate: u32, frequency: u32, f: SynthWaveformFunction) -> SynthWaveform { + pub fn new( + sample_rate: cpal::SampleRate, + frequency: u32, + f: SynthWaveformFunction, + ) -> BufferedSynthWaveform { let buffer = f.create_buffer(sample_rate, frequency); - SynthWaveform { + BufferedSynthWaveform { input: buffer.repeat_infinite(), } } } -impl Iterator for SynthWaveform { +impl Iterator for BufferedSynthWaveform { type Item = f32; #[inline] @@ -77,7 +94,7 @@ impl Iterator for SynthWaveform { } } -impl Source for SynthWaveform { +impl Source for BufferedSynthWaveform { #[inline] fn current_frame_len(&self) -> Option { self.input.current_frame_len() @@ -110,7 +127,8 @@ mod tests { #[test] fn square() { - let mut wf = SynthWaveform::new(1000, 250, SynthWaveformFunction::Square); + let mut wf = + BufferedSynthWaveform::new(cpal::SampleRate(1000), 250, SynthWaveformFunction::Square); assert_eq!(wf.next(), Some(1.0f32)); assert_eq!(wf.next(), Some(1.0f32)); assert_eq!(wf.next(), Some(-1.0f32)); @@ -123,7 +141,11 @@ mod tests { #[test] fn triangle() { - let mut wf = SynthWaveform::new(8000, 1000, SynthWaveformFunction::Triangle); + let mut wf = BufferedSynthWaveform::new( + cpal::SampleRate(8000), + 1000, + SynthWaveformFunction::Triangle, + ); assert_eq!(wf.next(), Some(-1.0f32)); assert_eq!(wf.next(), Some(-0.5f32)); assert_eq!(wf.next(), Some(0.0f32)); @@ -144,7 +166,8 @@ mod tests { #[test] fn saw() { - let mut wf = SynthWaveform::new(200, 50, SynthWaveformFunction::Sawtooth); + let mut wf = + BufferedSynthWaveform::new(cpal::SampleRate(200), 50, SynthWaveformFunction::Sawtooth); assert_eq!(wf.next(), Some(0.0f32)); assert_eq!(wf.next(), Some(0.5f32)); assert_eq!(wf.next(), Some(-1.0f32));