1$nyquist plug-in
2$version 4
3$type process
4$name (_ "Limiter")
5$manpage "Limiter"
6$debugbutton false
7$action (_ "Limiting...")
8$preview enabled
9$author (_ "Steve Daulton")
10$release 3.0.4
11$copyright (_ "GNU General Public License v2.0 or later")
12
13;; limiter.ny by Steve Daulton November 2011, updated May 2015.
14
15;; Released under terms of the GNU General Public License v2.0 or later:
16;; http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
17;;
18;; For information about writing and modifying Nyquist plug-ins:
19;; https://wiki.audacityteam.org/wiki/Nyquist_Plug-ins_Reference
20
21$control type (_ "Type") choice (
22   ("SoftLimit" (_ "Soft Limit"))
23   ("HardLimit" (_ "Hard Limit"))
24   ;i18n-hint: clipping of wave peaks and troughs, not division of a track into clips
25   ("SoftClip" (_ "Soft Clip"))
26   ("HardClip" (_ "Hard Clip"))
27) 0
28$control gain-L (_ "Input Gain (dB)
29mono/Left") real "" 0 0 10
30$control gain-R (_ "Input Gain (dB)
31Right channel") real "" 0 0 10
32$control thresh (_ "Limit to (dB)") real "" -3 -10 0
33$control hold (_ "Hold (ms)") real "" 10 1 50
34$control makeup (_ "Apply Make-up Gain") choice (
35   (_ "No")
36   (_ "Yes")
37) 0
38
39(if (not (boundp 'type))
40    (setf type 0))
41
42(if (boundp 'gain-L)
43    (setf gain-L (db-to-linear gain-L))
44    (setf gain-L 1))
45
46(if (boundp 'gain-R)
47    (setf gain-R (db-to-linear gain-R))
48    (setf gain-R 1))
49
50(if (boundp 'thresh)
51    (setf thresh (db-to-linear thresh))
52    (setf thresh (db-to-linear -3.0)))
53
54(if (not (boundp 'hold))
55    (setf hold 10.0))
56
57(if (boundp 'makeup)
58    (if (= makeup 1) (setf makeup T) (setf makeup nil))
59    (setf makeup nil))
60
61;;; brick wall limiter
62(defun hardlimit (sig limit hld)
63  (let* ((time (/ hld 3000.0))  ; lookahead time (seconds)
64         (samples (round (* time *sound-srate*)))  ; lookahead in samples
65         (peak-env (get-env sig samples time limit)))
66    (mult sig
67      (snd-exp
68        (mult -1 (snd-log peak-env))))))
69
70;;; Envelope follower for brick wall limiter
71(defun get-env (sig step lookahead limit)
72  (let* ((sig (mult (/ limit) sig))
73         (pad-time (* 3 lookahead))       ; padding required at start (seconds)
74         (pad-s (* 3 step))               ; padding samples
75         (padding (snd-const (peak sig pad-s) 0 *sound-srate* pad-time))
76         (peak-env (snd-avg sig (* 4 step) step OP-PEAK)))
77    (extract 0 1
78      (s-max 1
79        (sim padding
80          (at-abs pad-time (cue peak-env)))))))
81
82(defun softlimit (sig thresh hld)
83  (let* ((sig (hardlimit sig 1 hold))
84         (step (truncate (* (/ hld 3000.0) *sound-srate*)))
85         (waveshape (snd-avg sig (* 4 step) step op-peak))
86         (env (sum thresh (mult thresh (diff 1 waveshape))))
87         (env (clip env 1))
88         (offset (/ (* 3 step) *sound-srate*))
89         (initial (peak sig (* 2 step)))
90         (pause-lev (sum thresh (mult thresh (diff 1 initial))))
91         (pause-lev (clip pause-lev 0.9))
92         (pause (snd-const pause-lev 0 *sound-srate* offset)))
93    (setf env
94      (sim
95         pause
96         (at-abs offset (cue env))))
97    (mult sig env)))
98
99
100(defun soft-clip-table ()
101"Lookup table for soft clipping wave-shaper"
102  (abs-env
103    (sound-srate-abs 44100
104      (Control-srate-abs 44100
105        (let* ((knee (- 1 (/ 1.0 pi)))
106               (kcurve (mult knee (osc (hz-to-step (/ (* 4 knee))) knee)))
107               (ikcurve (mult knee (osc (hz-to-step (/ (* 4 knee))) knee *sine-table* -90)))
108               (lin (pwlv -0.5 knee -0.5
109                               (+ knee (/ 2.0 pi)) 0.5
110                               2.0 0.5
111                               2.0 (+ 0.5 knee)
112                               2.1 (+ 0.5 knee))))
113          (mult (/ 2.0 pi)
114            (sim
115              (at-abs 0 (cue ikcurve))
116              (at-abs 0 (cue lin))
117              (at-abs (+ knee (/ 2.0 pi)) (cue kcurve)))))))))
118
119(defun soft-clip (sig)
120  (let* ((knee (- 1 (/ 1.0 pi)))
121         (clip-level (* (+ 0.5 knee)(/ 2.0 pi)))
122         (sig (mult clip-level (/ thresh) sig)))
123    (if makeup
124        (mult 0.999
125              (/ clip-level)
126              (shape sig (soft-clip-table) 1.0))
127        (mult thresh
128              (/ clip-level)
129              (shape sig (soft-clip-table) 1.0)))))
130
131
132(defun makupgain (sig)
133  (if makeup
134      (mult (/ 0.999 thresh) sig) ;keep below 0dB
135      sig))
136
137;; Pre-gain
138(setf *track*
139  (if (arrayp *track*)
140      (vector (mult (aref *track* 0) gain-L)
141              (mult (aref *track* 1) gain-R))
142      (mult *track* gain-L)))
143
144
145(case type
146  (0 (makupgain (multichan-expand #'softlimit *track* thresh hold)))
147  (1 (makupgain (multichan-expand #'hardlimit *track* thresh hold)))
148  (2 (soft-clip *track*))
149  (T (makupgain (clip *track* thresh))))
150