Skip to content

Instantly share code, notes, and snippets.



Created Jul 10, 2016
What would you like to do?
Audacity Plugin for Keeping Second Track Volume Around First Track
;nyquist plug-in
;version 4
;type effect
;name "Test"
;action "Testing..."
;codetype lisp
;;debugflags trace ;Set debugging yes or no (; = yes, ;; = no)
(defconstant DB_DIFF 6) ;The level of difference in loudness you want
(defconstant CHANGE_THRESHOLD 0.01) ; the level of change needed to be "different" when converting from a song to an array
;Now a bit of a misnomer, abs-lowpass was meant to approximate the loudness of a song
;Now it works by squaring the wave, doubling it, taking the square root, and passing through a lowpass filter
;Essentially, it takes the absolute value times the square root of 2 passed through the filter
(defun abs-lowpass (sound &optional (freq 1))
"Gets the result of running the absolute values of the samples filtered through a lowpass filter"
(if (arrayp sound) ;Check for stereo, if so call functions separately and group
(abs-lowpass (aref sound 0) freq)
(abs-lowpass (aref sound 1) freq))
(lp (snd-sqrt (prod sound sound 2)) freq) ;If mono, approximate loudness
;Converts a sound wave into something pwl-list can use
(defun make-piecewise (sound &optional (THRESHOLD CHANGE_THRESHOLD))
"Returns an array of the form time1, value1, time2, value2, ... for the times sound changes loudness"
(if (arrayp sound) ;Check for stereo or mono
(vector ;If stereo, split and recombine
(make-piecewise (aref sound 0) THRESHOLD)
(make-piecewise (aref sound 1) THRESHOLD))
(let ((s (snd-copy sound)) ;If mono, copy the sound and process it
(r '()) ;Get our empty list for filling
(p 99999) ;Choose an absurd value to force the first sample to be far off
(n 0) ;Set our counter to 0
(c 0)) ;Set our current value to 0
(loop ;Iterate over the samples
(if (eq (setf c (snd-fetch s)) nil) ;If this is the last one
(return r) ;Then return
(when (> (abs (- p c)) THRESHOLD) ;Otherwise, if we have passed the threshold
(setf p c) ;Update the previous level
(setf r (append r (list (/ n LEN) c)))) ;And add the sample to the list
(setf n (+ 1 n)) ;Increment our counter, for timing purposes
(setf r (append r (list 1 p))) ;Add the very end of the list, since audacity wants the last point at 0
(setf r (append r (list 1))) ;Define the last point, just '(1)
;Makes sound roughly dif db quieter than a track stored as a list in arr
(defun quiet-track (sound arr dif)
(let* ((s1 (control-srate-abs *SOUND-SRATE* (pwl-list (aref arr 0)))) ;Convert the list back to sound
(s2 (control-srate-abs *SOUND-SRATE* (pwl-list (aref arr 1))))
(ars (vector s1 s2)) ;Make it stereo
(difference (vector dif dif))) ;Used for making us quieter by dif decibels
;Now we actually modify the sound by multiplying the linear difference in db, offset by dif, by the sound wave
(prod (db-to-linear (diff (linear-to-db ars) (sum (linear-to-db (abs-lowpass sound)) difference))) sound)
;Processing code for Track1
(defun Track1 ()
(setf arr (make-piecewise (abs-lowpass *TRACK*))) ;Get the loudness of the first track and store it as a list
(putprop '*SCRATCH* arr 'jsjwt) ;Put that list in the global variable *SCRATCH* so the second track can use it
*TRACK* ;Return the same sound so nothing changes
;Processing code for Track2
(defun Track2 ()
(setf t1sl (get '*SCRATCH* 'jsjwt)) ;Get the track one loudness list
(remprop '*SCRATCH* 'jsjwt) ;clean up the global variable *SCRATCH*
(quiet-track *TRACK* t1sl DB_DIFF) ;Now make us quiter than track 1
;This is the code that gets run below
(if (arrayp *TRACK*) ;Curse the user if we aren't modifying a stereo track
(if (eq (get '*TRACK* 'INDEX) 1) ; Test if we are on the first track
(Track1) ;If so, run Track1
(Track2));Else run Track2
(print "Not Stereo!"))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.