Following Steve’s invaluable help in https://forum.audacityteam.org/t/macro-how-to-make-a-selection-relative-to-labels/51042/1 I created a plugin which I remember working just fine over the course of last year. After a long pause (most probably including an update of Audacity to 2.3.3), I tried using it again and it keeps running into the error condition of “Cursor must be before or between two labels” (last line). No need to say that of course I do have my cursor position surrounded by 2 (or more, for a test) labels.
- Have there been any changes in Nyquist command/syntax that may have rendered my script unusable in the meantime?
- If not, could someone please help me with hints to debugging the code. I would like to print the list of labels and the cursor position (of which it says it is not between the labels), but so far I failed at finding/applying the correct syntax for adding debug-print statements or any other way to show me some debug output.
(BTW the comments marked with “Qu” I just took over from Steve, but don’t really understand. Any insights in understanding these lines would also be appreciated)
Here is the code:
;nyquist plug-in ;version 4 ;type tool ;name "fade 'n silence" ;author "Steve Daulton & Samse26" ;release 2.3.1 ;copyright "Released under terms of the GNU General Public License version 2" ; This script helps you cutting a continuous recording of multiple tracks (eg. vinyl or tape) into individual tracks. ; Prerequisite: ; ============ ; - label1 set at the detected end of the signal of the previous track, i.e. at the point where the music completely ; gets submerged by the turntable rumble/noise or tape noise (end of musical fade-out) ; - label2 set at the beginning of the signal of the next track, i.e. just before the first note or at first audible ; signs of a musical fade-in. ; - The cursor needs to sit ; anywhere between labels 1 and 2 ; or ; anywhere left to label1, as long as there is no (third) label left to the cursor ; caveat: in this case the effect will happen between labels 1 and 2. ; Else the effect will happen between the labels to the left and right of the cursor. ; Upon execution the script does the following: ; ============================================= ; - It prompts you to specify the duration of the to-be ; fade-out of previous track (min 0.01s, max 2s, default: 0.2s) ; fade-in of next track (min 0.01s, max 2s, default: 0.2s) ; silence between the fades (1, 2, 3, or 4 s, default: 2s) ; - fades-out the previous track so that fade-out is done (at 0%) at label1 ; this indeed may affect some audible sigal, so label1 should only sit where the signal is already weak anyway. ; - fades-in the next track, so that fade-in is done (at 100%) at label2 ; - replaces background noise between end and beginining of fade areas with silence of the desired duration ; (i.o.w. it cuts out the audio of any lenth and inserts silence of specified length) ; - deletes labels 1 and 2 ; - adds a new label at former positon of label1 (= begin of silence) with cursor in text field, ; so you can type the name of the next track right in. ; Once you're done processing all tracks of the recording you can export the individual tracks with File > Export > Export Multiple ; according to the label list. ; ; The script will abort with errors if : ; ====================================== ; - initially the cursor is placed to the right of label 2 and there is no further label to the right ; - the specified fade-in time is longer than the distance between the labels (which means that fade-in would overlap with the fade-out range) ; Define control to prompt user for fade and silence times ;;name "Set fade-out/-in times and duration of silence" ; a second ";name" line would override the script name (?!) ;control fto "Fade-out time" float "seconds" 0.2 0.01 2 ;control fti "Fade-in time" float "seconds" 0.2 0.01 2 ;control sit "Silence" int "seconds" 2 1 4 ;; define function "select", with 2 args, based on Audacity "Select:" macro ;; this one works with the default value for "RelativeTo=" -- whatever this is ... (defun select (start end) (aud-do (format nil "Select:Start=~a End=~a Mode=Set" start end))) ;; define another select function "select-start", working relative to SelectionStart ;; I need this because of the unknown default for "RelativeTo=" in "select" above. ;; Here is definitely need the selection relative to the selection start, and nothing else. (defun select-start (start end) (aud-do (format nil "Select:Start=~a End=~a Mode=Set RelativeTo=SelectionStart" start end))) ;; define function "get-region" with one arg ;; Qu: suspecting this creates a list with cursor positions ;; Qu: where does the value for "labels" come? Or is this a return value? ;; Qu: is "now" a predefined variable? (defun get-region (labels) (do* ((j 1 (1+ j)) (next (first (nth j labels)) (first (nth j labels)))) ((or (>= j (length labels)) (>= next now)) (list (first (nth (1- j) labels)) next)))) ;; get list of (manually set) labels: ;; 1st label sits at end of to-be fade-out (i.e. signal just died) ;; 2nd label sits at end of to-be fade-in (i.e. just before signal starts) (setf labels (second (aud-get-info "Labels"))) (setf now (get '*selection* 'start)) ; Qu: get current cursor position (?) (defconstant ld-min fti) ; define minimal distance between lables in sec (cond ((>= (length labels) 2) ; if there is 2 or more labels (setf region (get-region labels)) (cond ((not (second region)) ; ERROR: if there is no region (= label) to the right of the cursor "Cursor is not between labels") ((> (- (second region)(first region)) ld-min) ; if length of region is more than ld-min sec (select (- (first region) fto) (first region)) ; Select range of (1st label-ft) up to 1st label (aud-do "FadeOut:") ; Fade-out with duration of ft (select (- (second region) fti) (second region)) ; Select range of (2nd label-ft) up to 2nd label (aud-do "FadeIn:") ; Fade-in with duration of ft ; Select region from end of fade-out up to beginning of fade-in (= pos X) (select (first region) (- (second region) fti)) (aud-do "Cut:") ; cut this range (select-start 0 sit) ; select sit seconds (desired duration of silence) from current position (aud-do "Copy:") ; copy audio in range (could be anything) (select-start 0 0) ; set cursor back to left border of selection (= pos X) (aud-do "Paste:") ; insert copied audio (aud-do "Silence:") ; mute inserted audio (aud-do "MoveToNextLabel:") ; jump ahead to next label to the right (aud-do "Delete:") ; delete this label (we don't need this any more once the cursor is there) (select-start (- 0 sit fti) 0) ; select a range backwards from here (= negative) with a duration of sit+fti ; this makes sure that the silence ends just at the beginning of the fade-in, ; no matter what values for silence and fade-in durations are selected (aud-do "CursSelStart:") ; set cursor to the left border of selection (aud-do "AddLabel:") ; add a label here, ; do this as the last thing so we can type the title of the next track right in ;; now we have: ;; - deleted (left) label 1 while cutting the range from end of fade-out to beginning of fade-in ;; - deleted (right) label 2 explicitly ;; - inserted a new label at the original position of label 1, i.e. after fade-out = beginnnig of silence ;; This is the beginning of the next track (starting with sit seconds of silence) when later ;; exporting audio, split at labels. ) ; ERROR: if distance between labels is too small to accommodate the fade-in range (the fade-out range is outside!) (t "Region between labels is less than the fade-in time required before 2nd label") ; Qu: how could I use the value of a variable (ld-min) in a string output? ) ) (t "Cursor must be before or between two labels") )