1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
//! A collection of types and traits useful for high performance envelope detection over a signal.
//!
//! The primary types of interest are:
//!
//! - [**EnvelopeDetector**](./struct.EnvelopeDetector).
//! - [**Rms**](./rms.struct.Rms).
//! - [**Peak**](./peak.struct.Peak).

#![deny(missing_copy_implementations)]
#![deny(missing_docs)]

extern crate sample;

pub use mode::Mode;
pub use peak::Peak;
pub use rms::Rms;
pub use sample::{Frame, Sample};

pub mod mode;
pub mod peak;
pub mod rms;


/// Iteratively extracts the amplitude envelope from an audio signal based on three parameters:
///
/// - Attack time.
/// - Release time.
/// - Detection mode (Either Peak or RMS).
///
/// Supports processing any `sample::Frame`
#[derive(Copy, Clone, Debug)]
pub struct EnvelopeDetector<F, M>
    where F: Frame,
          M: Mode<F>,
{
    attack_gain: f32,
    release_gain: f32,
    last_env_frame: F,
    mode: M,
}

/// An `EnvelopeDetector` that tracks the signal envelope using RMS.
pub type RmsEnvelopeDetector<F> = EnvelopeDetector<F, Rms<F>>;
/// An `EnvelopeDetector` that tracks the full wave `Peak` envelope of a signal.
pub type PeakEnvelopeDetector<F> = EnvelopeDetector<F, Peak<peak::FullWave>>;


fn calc_gain(n_frames: f32) -> f32 {
    ::std::f32::consts::E.powf(-1.0 / n_frames)
}


impl<F> EnvelopeDetector<F, Rms<F>>
    where F: Frame,
{

    /// Construct a new **Rms** **EnvelopeDetector**.
    pub fn rms(rms_window_frames: usize, attack_frames: f32, release_frames: f32) -> Self {
        let rms = Rms::new(rms_window_frames);
        Self::new(rms, attack_frames, release_frames)
    }

    /// Set the duration of the **Rms** window in frames.
    pub fn set_window_frames(&mut self, n_window_frames: usize) {
        self.mode.set_window_frames(n_window_frames);
    }

}

impl<F> EnvelopeDetector<F, Peak<peak::FullWave>>
    where F: Frame,
{

    /// Construct a new **Mono** **Peak** **EnvelopeDetector**.
    pub fn peak(attack_frames: f32, release_frames: f32) -> Self {
        let peak = Peak::full_wave();
        Self::new(peak, attack_frames, release_frames)
    }

}

impl<F, M> EnvelopeDetector<F, M>
    where F: Frame,
          M: Mode<F>,
{

    fn new(mode: M, attack_frames: f32, release_frames: f32) -> Self {
        EnvelopeDetector {
            mode: mode,
            last_env_frame: F::equilibrium(),
            attack_gain: calc_gain(attack_frames),
            release_gain: calc_gain(release_frames),
        }
    }

    /// Set the **EnvelopeDetector**'s attack time as a number of frames.
    pub fn set_attack_frames(&mut self, frames: f32) {
        self.attack_gain = calc_gain(frames);
    }

    /// Set the **EnvelopeDetector**'s release time as a number of frames.
    pub fn set_release_frames(&mut self, frames: f32) {
        self.attack_gain = calc_gain(frames);
    }

    /// Given the next input signal frame, detect and return the next envelope frame.
    pub fn next(&mut self, frame: F) -> F {
        let EnvelopeDetector {
            attack_gain, release_gain, ref mut mode, ref mut last_env_frame,
        } = *self;

        let mode_frame = mode.next_frame(frame);
        let new_env_frame = last_env_frame.zip_map(mode_frame, |l, m| {
            let gain = if l < m { attack_gain } else { release_gain };
            let diff = l.add_amp(-m.to_signed_sample());
            m.add_amp(diff.mul_amp(gain.to_sample()).to_sample())
        });
        *last_env_frame = new_env_frame;
        new_env_frame
    }

    /// Given the next input signal frame, detect and return the next envelope average across each
    /// channel for the frame.
    ///
    /// The returned value will take the form of the signal's equivalent floating point sample
    /// format.
    pub fn next_avg(&mut self, frame: F) -> <F::Sample as Sample>::Float {
        let next_frame = self.next(frame);
        let equilibrium: F::Sample = Sample::equilibrium();
        let sum = next_frame.channels().fold(equilibrium, |sum, s| sum.add_amp(s.to_sample()));
        sum.to_float_sample() / (F::n_channels() as f32).to_sample()
    }

}