Export individual label when multiple labels in project

Is there any project to make export multiple label tracks separately possible in a near future ? The process of temporarily deleting other label tracks to export one separately and then undo the deletes is a bit unatural, to say the least. Would it be difficult to enable this separate export feature ?
If not a future target, is there a Nyquist code which could do it ?

It could be done with a Nyquist plug-in, though I’m not aware of any existing plug-in that does that.
Have you used (programmed) Nyquist at all?

Yes I have already coded a little with Nyquist, like making a plugin to export audio tracks with their name as filename. But I don’t know what code to use for doing so to a label track. Could you help putting me on the right way to do it ?

Sure.

To get label data with Nyquist, use the “GetInfo:” scripting (Macro) command.
(Scripting Reference - Audacity Manual)

Try this in the Nyquist Prompt:

;type tool
(setf label-data (aud-do-command "GetInfo:" :type "Labels" :format "LISP"))

(format nil "~a" label-data)

If the project contains label tracks, you will see a list printed.
The first item in the list is a list containing the label data. The second (final) element is “T”.

Because “label-data” is a Lisp list, you can access the first element with (first label-data)

Example:

;type tool
(setf label-data (aud-do-command "GetInfo:" :type "Labels" :format "LISP"))

(format nil "~a" (first label-data))

Returns:

((1
    ((0 0 "Start")
      (180 180 "Middle")
      (360 360 "End")))
  (2
    ((120 180 "Hello")
      (180 240 "World"))))

Notice that the first item in this list is the first label track, and the second item is the second label track.

To get the label data for the second label track, you could use:
(second (first label-data))
which gives the list:
(2 ((120 180 “Hello”) (180 240 “World”)))
where the first item is the track index (zero indexed, so “2” = third track)
and the second item is the labels:
(list 120 180 “Hello”)
and
(list 180 240 “World”)


To write a text file to disk, see: XLISP open
You can use the FORMAT command to write to the file pointer.
Example:

(setf file-pointer (open "C:\output directory\test-file.txt" :direction :output))
(format file-pointer "text to write to the file")
(close file-pointer)

For the plug-in’s GUI, you will probably want to use the “file widget”.
This is the most complex Nyquist widget, but it is well documented:

  1. Missing features - Audacity Support
  2. Missing features - Audacity Support
  3. Missing features - Audacity Support

Thanks a lot, Steve. I’ll work on this and let you know how it come out. :slight_smile:)

Hi, Steve. Is there a Nyquist way to get the name of the currently selected label track (assuming I select only one at a time) ?

There’s the Macro / Scripting command: GetInfo: Type=“Tracks”

You can call that command like this:

 (aud-do-command "GetInfo:" :type "Tracks" :format "LISP")

or a slightly simpler (more convenient) way:

(aud-get-info "Tracks")

Hi Steve. I think I am almost there, but still cant solve the filename problem with backslashes… Here is my code :

(setq exportableLabelTrack "none")
(let ((tracks (aud-get-info "tracks")))
 (dotimes (j (length tracks))
  (setf track (nth j tracks))
  (setf isSelected (if (= 1 (second (assoc 'selected track))) "oui" "non"))
  (setf isLabel (if (equal "label" (second (assoc 'kind track))) "oui" "non"))
  ;(print (strcat (second (assoc 'name track)) "/selected:" isSelected "/islabel:" isLabel))
  (setf bothYes (strcat isSelected isLabel))
  (cond ((equal bothYes "ouioui")
    (print (second (assoc 'name track)))
	( setq exportableLabelTrack (second (assoc 'name track)))
    )
	;(t (print bothYes))
  )
 )
)
(cond ((not(equal exportableLabelTrack "none"))
    (setf filename "D:\\Myproject\\tests\\test-file.txt")
    (setf file-pointer (open filename :direction :output))
    (format file-pointer exportableLabelTrack)
    (close file-pointer)
    (print exportableLabelTrack)
	)
)

It does not work with simple backslashes either, nor with file-separator audacity variable. Would you have a workaround I could use ?
Also, I don’t know yet how to get the label track text content once I know which track it is (as I did above)… that’s why I temporarily just put the trackname as content.

I’ll put together some code for you, but may not be until after the weekend (I’ll do it sooner if possible).

This is extremely kind of you, Steve, I appreciate a lot as it is an operation I have to do a lot in musical arrangements. I wish I were more at ease with Nyquist, but it seems difficult if not practiced regurlarly… :wink:

You’ve picked quite a complex task for Nyquist as it requires lots of parsing of scripting data. (Nyquist was designed primarily for manipulating audio rather than text).


This is one part of the puzzle:

(defun get-selected-label-tracks ()
  ;; Returns a list of selected label tracks as (list (list ID TrackName) ...)
  (let ((tracks (aud-get-info "Tracks"))
         (tracklist ())
         (id 0)
         trackname
         selected
         is-label)
    (dolist (track tracks tracklist)
      ;; Get name if a selected label track
      (dolist (e track)
        (let ((tn (member 'NAME e))
              (sel (member 'SELECTED e))
              (kind (member 'KIND e)))
        (when tn
          (setf trackname (second tn)))
        (when sel
          (setf selected (second sel)))
        (when kind
          (setf is-label (string-equal (second kind) "label")))))
      ;; If selected label track found, push it to the tracklist.
      (when (and trackname selected (= selected 1) is-label)
        (push (list id trackname) tracklist))
      (incf id))))

Waou! Wonderful and fast, thanks a lot. Works like a charm. I’ll have to study the code more closely to understand it all, though! :smiley:
Also, my problem about backslashes in pathname was a stupid one as I just made some keystroke error in the name itself. Once corrected, the problem of backslashes disappeared…

With your help, I am arriving at the following piece of code which displays the first selected label track info :

(defun get-selected-label-tracks ()
  ;; Returns a list of selected label tracks as (list (list ID TrackName) ...)
  (let ((tracks (aud-get-info "Tracks"))
         (tracklist ())
         (id 0)
         trackname
         selected
         is-label)
    (dolist (track tracks tracklist)
      ;; Get name if a selected label track
      (dolist (e track)
        (let ((tn (member 'NAME e))
              (sel (member 'SELECTED e))
              (kind (member 'KIND e)))
        (when tn
          (setf trackname (second tn)))
        (when sel
          (setf selected (second sel)))
        (when kind
          (setf is-label (string-equal (second kind) "label")))))
      ;; If selected label track found, push it to the tracklist.
      (when (and trackname selected is-label)
		(if (= selected 1)
         (push (list id trackname) tracklist))
        (incf id)); index (0-based) relative to label track (only) list
      ;(incf id); index (0-based) relative to all tracks (audio and labels)
	)))
(setf selected-label-track (first (get-selected-label-tracks))); get first of the possibly several selected label tracks
(format nil "~a" selected-label-track); display this track
(setf selected-label-track-id (first selected-label-track)); get its track id (relative to label track (only) list)
(format nil "~a" selected-label-track-id); display this track id
(setf selected-label-track-name (second selected-label-track)); get its track name
(format nil "~a" selected-label-track-name); display this track name
(setf selected-label-track-content (second (nth selected-label-track-id (aud-get-info "labels")))); get its track content
(format nil "~a" selected-label-track-content); display this content
;(format nil "~a" (strcat selected-label-track-name "\n" (selected-label-track-content))); display this content
(format nil "Track id: = ~a name = ~a content = ~a" selected-label-track-id selected-label-track-name selected-label-track-content)

Quite happy to getting closer to my target, which is to export/save this track content under the filename of it track name, in a fixed chosen directory (as I cannot find what the audacity variable is for the last saving directory used).

I would recommend using the “file widget” to enter the target directory.
Unfortunately it will be a bit weird because the file widget is intended for selecting files, not folders, and as you want to use the label track’s name as the file name, the actual file name is not known until the plug-in runs.

Nevertheless, I think this is a usable workaround - you just need to be aware that only the directory and not the file name will be used by the plug-in:

;type tool

;control filename "Select destination folders" file "Select a folder" "*default*/<track name>.txt" "Text file|*.txt;*.TXT|All files|*.*;*" "save"

(defun extract-path (filename)
  ;; Returns the directory part of a fully qualified file name.
  (do ((i (1- (length filename)) (1- i)))
      ((< i 0) "")
    (when (char= (char filename i) *file-separator*)
      (return-from extract-path (subseq filename 0 (1+ i))))))

(setf fname "test")

;; Replace the name of the file with "fname"
(format nil "~a~a.txt" (extract-path filename) fname)

Thank you for this. I’ll work on it.

Do you know what is the audacity variable for the last directory used for exporting track ? I mean, when you export a label track, I noticed audacity open the explorer dialog to the last directory you have been saving labels, not the project home directory. So, that must be have been memorized in some variable which I hope might be accessible to Nyquist user. Am I right ?

Try:

(first (aud-do "GetPreference:Name=\"Export/Path\""))

Hi Steve. Thanks for this cue on the last saving directory. It seems to work well after exporting an audio track. It does not seem to do so though, if the exported track was a label one…

I have an additional question. When I launch my plugin which seems to work quite better now, I get the message “You must first select an audio track…”, although I am obviously only addressing label tracks in this plugin. Is there a way to avoid this ?

Make it a “tool” type plug-in.

;type tool

This will only work for a real installed plug-in, not the Nyquist Prompt.

I just did, using the Nyquist Plug-ins Installer in the Tools Menu, but once “Enabled” it keeps showing up in the Effects Menu and still sends this “You must first…” message…
I put the code here :

;nyquist plug-in
;version 1
;type tool
;name "ExportLabelTrack"

(setq slash (format nil "~a" *file-separator*)) 
(setq ch #\tab)
(setq *float-format* "%#1.6f")

(defun home ()
  (strcat "D:" slash "X" slash "Y" slash "Z")); customized
(setq savepath (string-right-trim slash (home)))

(defun get-selected-label-tracks ()
  ;; Returns a list of selected label tracks as (list (list ID TrackName) ...)
  (let ((tracks (aud-get-info "Tracks"))
         (tracklist ())
         (id 0)
         trackname
         selected
         is-label)
    (dolist (track tracks tracklist)
      ;; Get name if a selected label track
      (dolist (e track)
        (let ((tn (member 'NAME e))
              (sel (member 'SELECTED e))
              (kind (member 'KIND e)))
        (when tn
          (setf trackname (second tn)))
        (when sel
          (setf selected (second sel)))
        (when kind
          (setf is-label (string-equal (second kind) "label")))))
      ;; If selected label track found, push it to the tracklist.
      (when (and trackname selected is-label)
		(if (= selected 1)
         (push (list id trackname) tracklist))
        (incf id)); index (0-based) relative to label track (only) list
      ;(incf id); index (0-based) relative to all tracks (audio and labels)
	)))
(setf selected-label-track (first (get-selected-label-tracks))); get first of the possibly several selected label tracks

(if (first selected-label-track)
 (progn
  ;(format nil "~a" selected-label-track); display this track
  (setf selected-label-track-id (first selected-label-track)); get its track id (relative to label track (only) list)
  ;(format nil "~a" selected-label-track-id); display this track id
  (setf selected-label-track-name (second selected-label-track)); get its track name
  ;(format nil "~a" selected-label-track-name); display this track name
  (setf selected-label-track-content (second (nth selected-label-track-id (aud-get-info "labels")))); get its track content
  ;(format nil "~a" selected-label-track-content); display this content
  ;(format nil "Track id: = ~a name = ~a content = ~a" selected-label-track-id selected-label-track-name selected-label-track-content); display all data
  
  ; Write data to label track name named outputfile in fixed save path location
  (setq outputfile (format nil "~a~a~a (labels).txt" savepath slash selected-label-track-name))
  (setf file-pointer (open outputfile :direction :output));
  (dolist (line selected-label-track-content)
   (format file-pointer (format nil "~a~a~a~a~a~%" (first line) ch (second line) ch (third line)))
  )
  (close file-pointer)
  (format nil "Track~%  id: = ~a~%  name = ~a~%  content = ~a~%~%  has been saved to this output file: ~%~a" selected-label-track-id selected-label-track-name selected-label-track-content outputfile); display all data+filename
 )
 (print "No LABEL TRACK selected.  Please select ONE first.")
)

Do you see any discrepancy which would make it happen that way ?

If you initially installed it as an “Effect” (;type process), then you will need to reset plug-ins and then re-enable the effect.
To reset plug-ins, delete the files:
pluginregistry.cfg
and
pluginsettings.cfg

(both are in the same directory as the “audacity.cfg” Preferences file Preferences - Audacity Manual)