This plug-in can be helpful in situations where you have a project that has a lot (possibly hundreds) of labels, and you want to locate one specific label quickly by searching for the label text.
While it is perfectly possible to scroll through the Label Editor window and look for the label text, the Label Editor does not have a search function, so it can be quite arduous if there is a very large number of labels. This plug-in makes life more convenient in this situation.
How to use the “Find Label” plug-in
The plug-in is installed in the usual way. For Audacity 3.1.3 and earlier, the plug-in must be enabled after installing, using the plug-in manager. When installed and enabled, the plug-in will appear as “Find Label…” in the Tools menu.
To find a label, enter the label text in the text box. For case sensitive searching, enable “Case Sensitive” in the “Capitalization” drop-down menu. Then click the “OK” button.
If the search term is found in a label, Audacity will select and zoom in on the region marked by the label. If the search term is not found, a notification is displayed to say so.
Note that the plug-in locates the first occurrence of the search term only, so the search term must be unique to the label of interest. For long label text it is not necessary to enter the full text. The plug-in searches for the search string in any part of the label text. Thus, if you have labels:
- Label 01
- Label 02
- Label 03
Then it is sufficient to search for “2” to find “Label 02”.
How it works
This is the part that will be of interest to plug-in developers.
Searching the labels
1 2 3 4 5 6 7 |
(defun find (str) (let ((labeltracks (aud-get-info "Labels"))) (dolist (trk labeltracks nil) (dolist (label (second trk)) (when (found-in str (third label)) (return-from find (list (first label) (second label)))))))) |
The function “find” (above) uses the AUD-GET-INFO command to acquire the label track(s) data.
The label data is in the form of nested lists:
1 2 3 4 5 |
(((track-num ((start end text) ...)) (track-num ((start end text) ...)) ...) . T) |
The first element of the list is a list of label tracks. Each label track is in the form of a list:
1 2 |
(track-number (label-1 label-2 ...)) |
and each label is in the form of a list:
1 2 |
(start-time end-time "label-text") |
Having acquired the data as “labeltracks”, we then loop through each label track, and for each label track we loop through each label.
For each label, we extract the label text, which is the third element of the label, and pass it, along with the search string “str” to the function “found-in”.
When the search term “str” is found in the label text, we have located the label of interest, and return its start and end times as a list: (start-time end-time)
Searching the text
As we saw above, the function “found-in” is called with arguments str (the search term) and (third label) (the label text). Here’s the “found-in” function:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
(defun found-in (needle stack) ;; Return true if "needle" is in "stack". (let ((nlen (length needle)) (slen (length stack))) (when (< slen nlen) (return-from found-in nil)) (dotimes (i (- (1+ slen) nlen) nil) (setf substr (subseq stack i (+ i nlen))) (if (= casesensitive 0) (when (string-equal needle substr) (return-from found-in t)) (when (string= needle substr) (return-from found-in t)))))) |
This implements a naive “find needle in haystack” search. nlen is the length of the search term, and slen is the length of the label text.
1 2 3 |
(when (< slen nlen) (return-from found-in nil)) |
Clearly, if the label text is shorter than the search term, then the label does not contain the search term, so we can return False ( nil) immediately.
If the label text is long enough to contain the search term, then we loop with a sliding window, the length of the search term, through the label text. If the search term is found, then True ( t) is returned.
Note that the code performs a case-sensitive, or case-insensitive comparison, depending on the value of casesensitive.
string-equal is the case-insensitive comparison, whereas string= is case-sensitive.