/usr/share/audacity/plug-ins/clipfix.ny is in audacity-data 2.2.1-1.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
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 | ;nyquist plug-in
;version 4
;type process
;preview enabled
;name "Clip Fix..."
;manpage "Clip_Fix"
;action "Reconstructing clips..."
;author "Benjamin Schwartz and Steve Daulton"
;copyright "Licensing confirmed under terms of the GNU General Public License version 2"
;; Algorithm by Benjamin Schwartz
;; Clip Fix is a simple, stupid (but not blind) digital-clipping-corrector
;; The algorithm is fairly simple:
;; 1. Find all clipped regions
;; 2. Get the slope immediately on either side of the region
;; 3. Do a cubic spline interpolation.
;; 4. Go to next region
;control threshold "Threshold of Clipping (%)" float "" 95 0 100
;control gain "Reduce amplitude to allow for restored peaks (dB)" float "" -9 -30 0
(setf threshold (/ threshold 100))
(setf gain (db-to-linear gain))
(setf buffersize 100000)
(setf slopelength 4) ; number of samples used to calculate the exit / re-entry slope
(defun declip (sig thresh peak)
(let* ((threshold (* thresh peak))
(ln (truncate len))
(finalbufsize (rem ln buffersize)))
;; Calculate the number of buffers we can process.
;; if final buffer is not large enough for de-clipping we
;; will just add it on the end as is.
(if (>= finalbufsize slopelength)
(setf buffercount (1+ (/ ln buffersize)))
(setf buffercount (/ ln buffersize)))
;;; Make output sequence from processed buffers
(setf out
(seqrep (i buffercount)
(let* ((step (min buffersize (- ln (* i buffersize))))
(buffer (snd-fetch-array sig step step))
(processed (process buffer threshold step)))
(cue (mult gain
(snd-from-array 0 *sound-srate* processed))))))
;;; If there's unprocessed audio remaining, add it to the end
(if (and (> finalbufsize 0)(< finalbufsize slopelength))
(seq out (cue (getfinalblock sig finalbufsize gain)))
out)))
(defun getfinalblock (sig step gain)
(let ((block (snd-fetch-array sig step step)))
(mult gain (snd-from-array 0 *sound-srate* block))))
(defun process (buffer threshold bufferlength)
;;; Find threshold crossings
(setf exit-list ()) ; list of times when waveform exceeds threshold
(setf return-list ()) ; list of times when waveform returns below threshold
;; Limitation of algorithm: the first and last 'slopelength' at ends of buffer are ignored
;; so that we have enough samples beyond the threshold crossing to calculate the slope.
(let ((last-sample (- bufferlength slopelength)))
(do ((i slopelength (1+ i)))
((>= i last-sample))
(if (>= (abs (aref buffer i)) threshold)
(when (< (abs (aref buffer (- i 1))) threshold) ; we just crossed threshold
(push (- i 1) exit-list))
(when (>= (abs (aref buffer (- i 1))) threshold) ; we just got back in range
(push i return-list)))))
;; Reverse lists back into chronological order.
;; This is faster than appending values in chronological order.
(setf exit-list (reverse exit-list))
(setf return-list (reverse return-list))
;; If the audio begins in a clipped region, discard the first return
(when (>= (abs (aref buffer (1- slopelength))) threshold)
(setq return-list (cdr return-list)))
;; Interpolate between each pair of exit / entry points
(let ((slopelen (1- slopelength)))
(mapc (lambda (t0 t1)
(interpolate buffer t0 t1 slopelen))
exit-list return-list))
buffer)
(defun interpolate (buffer t0 t1 dur)
"Cubic spline interpolation"
(let* ((d0 (/ (- (aref buffer t0) (aref buffer (- t0 dur))) dur)) ; slope at start
(d1 (/ (- (aref buffer (+ t1 dur)) (aref buffer t1)) dur)) ; slope at end
(m (/ (+ d1 d0) (* (- t1 t0) (- t1 t0))))
(b (- (/ d1 (- t1 t0)) (* m t1))))
(do ((j (1+ t0) (1+ j)))
((= j t1))
(setf (aref buffer j)
(+ (* (- t1 j) (/ (aref buffer t0) (- t1 t0)))
(* (- j t0) (/ (aref buffer t1) (- t1 t0)))
(* (- j t0) (- j t1) (+ (* m j) b)))))))
;; (get '*selection* 'peak) introduced in Audacity 2.1.3
(multichan-expand #'declip *track* threshold (get '*selection* 'peak))
|