|
- package dsp
-
- import "math"
-
- // MPXLimiter is a look-ahead peak limiter for the composite MPX signal.
- // It prevents overmodulation by keeping the composite output within
- // the configured ceiling. The limiter applies gain reduction smoothly
- // to avoid introducing audible artifacts.
- type MPXLimiter struct {
- ceiling float64 // maximum absolute output level (e.g. 1.0)
- attackCoeff float64 // attack smoothing coefficient
- releaseCoeff float64 // release smoothing coefficient
- gainReduction float64 // current gain reduction in linear scale (0 = no reduction)
- }
-
- // NewMPXLimiter creates a limiter with the given ceiling, attack and release
- // times in milliseconds, and sample rate.
- func NewMPXLimiter(ceiling, attackMs, releaseMs, sampleRate float64) *MPXLimiter {
- if ceiling <= 0 {
- ceiling = 1.0
- }
- if attackMs <= 0 {
- attackMs = 0.1 // fast attack for MPX
- }
- if releaseMs <= 0 {
- releaseMs = 50 // moderate release
- }
- attackSamples := attackMs * sampleRate / 1000
- releaseSamples := releaseMs * sampleRate / 1000
-
- return &MPXLimiter{
- ceiling: ceiling,
- attackCoeff: 1.0 - math.Exp(-1.0/attackSamples),
- releaseCoeff: 1.0 - math.Exp(-1.0/releaseSamples),
- }
- }
-
- // Process applies limiting to a single composite sample.
- func (l *MPXLimiter) Process(in float64) float64 {
- absIn := math.Abs(in)
- targetReduction := 0.0
- if absIn > l.ceiling {
- targetReduction = 1.0 - l.ceiling/absIn
- }
-
- if targetReduction > l.gainReduction {
- l.gainReduction += l.attackCoeff * (targetReduction - l.gainReduction)
- } else {
- l.gainReduction += l.releaseCoeff * (targetReduction - l.gainReduction)
- }
-
- gain := 1.0 - l.gainReduction
- return in * gain
- }
-
- // Reset clears the limiter state.
- func (l *MPXLimiter) Reset() {
- l.gainReduction = 0
- }
-
- // HardClip provides a simple hard clipper as a safety net after the limiter.
- func HardClip(sample, ceiling float64) float64 {
- if sample > ceiling {
- return ceiling
- }
- if sample < -ceiling {
- return -ceiling
- }
- return sample
- }
|