diff --git a/src/source/amplify.rs b/src/source/amplify.rs index 87f41fa3..dd30414b 100644 --- a/src/source/amplify.rs +++ b/src/source/amplify.rs @@ -12,6 +12,11 @@ where Amplify { input, factor } } +/// Internal function that converts decibels to linear +pub fn to_linear(decibels: f32) -> f32 { + f32::powf(10f32, decibels * 0.05) +} + /// Filter that modifies each sample by a given value. #[derive(Clone, Debug)] pub struct Amplify { @@ -26,6 +31,12 @@ impl Amplify { self.factor = factor; } + /// Modifies the amplification factor logarithmically. + #[inline] + pub fn set_log_factor(&mut self, factor: f32) { + self.factor = to_linear(factor); + } + /// Returns a reference to the inner source. #[inline] pub fn inner(&self) -> &I { @@ -93,3 +104,50 @@ where self.input.try_seek(pos) } } + +#[cfg(test)] +mod test { + use super::*; + + const EPSILON: f32 = 0.3; + /// Based on [Wikipedia's Decibel article]. + /// + /// [Wikipedia's Decibel article]: https://web.archive.org/web/20230810185300/https://en.wikipedia.org/wiki/Decibel + const DECIBELS_LINEAR_TABLE: [(f32, f32); 27] = [ + (100., 100000.), + (90., 31623.), + (80., 10000.), + (70., 3162.), + (60., 1000.), + (50., 316.2), + (40., 100.), + (30., 31.62), + (20., 10.), + (10., 3.162), + (5.998, 1.995), + (3.003, 1.413), + (1.002, 1.122), + (0., 1.), + (-1.002, 0.891), + (-3.003, 0.708), + (-5.998, 0.501), + (-10., 0.3162), + (-20., 0.1), + (-30., 0.03162), + (-40., 0.01), + (-50., 0.003162), + (-60., 0.001), + (-70., 0.0003162), + (-80., 0.0001), + (-90., 0.00003162), + (-100., 0.00001), + ]; + + #[test] + fn convert_decibels_to_linear() { + for (db, linear) in DECIBELS_LINEAR_TABLE { + dbg!(db, linear, f32::abs(to_linear(db) - linear)); + assert!(f32::abs(to_linear(db) - linear) < EPSILON,) + } + } +} diff --git a/src/source/mod.rs b/src/source/mod.rs index aefbd1b2..29d3692c 100644 --- a/src/source/mod.rs +++ b/src/source/mod.rs @@ -5,6 +5,7 @@ use core::time::Duration; use crate::common::{ChannelCount, SampleRate}; use crate::Sample; +use amplify::to_linear; use dasp_sample::FromSample; pub use self::agc::AutomaticGainControl; @@ -233,6 +234,15 @@ pub trait Source: Iterator { skip::skip_duration(self, duration) } + /// Amplifies the sound logarithmically by the given value. + #[inline] + fn amplify_decibel(self, value: f32) -> Amplify + where + Self: Sized, + { + amplify::amplify(self, to_linear(value)) + } + /// Amplifies the sound by the given value. #[inline] fn amplify(self, value: f32) -> Amplify