Export individual label when multiple labels in project

Thanks a lot again, Steve, for your great help. It now works as I wanted.
If you think by any chance this plugin may help others, let me know and how to post it on audacity site.
Best regards,
Paul

Please do post it here, and I’ll move this topic to the Nyquist Plug-ins forum board.

Here it is :

;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 "C:" slash "TMP")); 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))); grab first of the possibly several selected label tracks only

(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
  
  ; 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 "Label track  id = ~a, name = ~a~%has been exported to the file named: ~%~a" selected-label-track-id selected-label-track-name outputfile); display all data+filename
 )
 (print "No LABEL TRACK selected.  Please select ONE first.")
)

Thanks again to you for this, Steve.

Is it somehow possible to add unicode support? I get underscore symbols instread of cyrillic

What are you referring to? agua’s plug-in?

well… yes. I’m not familiar with LISP and plugin development, so i don’t know where to start. Is it possible?

I need to add labels to an audio track. Audacity projects take much space so I want to store original audio file and txt files with labels. If I have two label tracks I have to remove one of them, export, ctrl-z, remove another one, export, ctrl-z.

Audacity supports Unicode but Nyquist doesn’t. Nyquist expects characters to be 8 bits. Converting Nyquist to support multi-byte characters would be a very big job.
Nyquist is a programming language written by Professor Dannenberg at CMU https://www.cs.cmu.edu/~music/nyquist/ It was designed for working with sounds and MIDI rather than text, hence it has fantastic abilities for manipulating sounds, but rather limited abilities with text.

hmm… Completely different solution: read all labels tracks to Python script using “GetInfo: Type=Labels” scripting command and then save them individually. And there’s no unicode problem.

agua, You feel my pain. I am new to Audacity and just using it to splice my language instructors audio for seperate words into labels and exporting multiple labels. Can you help me install this nyquist plug in to do this very same thing you have done? thanks

[using v2.4.2]
I tried the above plugin after copying to plug-in directory and selecting one of my label tracks (clicking on “select”) - but nothing happened.
From the code I assume the export should land in C:\temp, but nothing was there.
Then I loaded the code into the Nyquist prompt and ran it using “debug”, which produced the following:

error: bad argument type - NIL
Function: #<Subr-CLOSE: #452c868>
Arguments:
  NIL
Function: #<FSubr-PROGN: #452ee48>
Arguments:
  (SETF SELECTED-LABEL-TRACK-ID (FIRST SELECTED-LABEL-TRACK))
  (SETF SELECTED-LABEL-TRACK-NAME (SECOND SELECTED-LABEL-TRACK))
  (SETF SELECTED-LABEL-TRACK-CONTENT (SECOND (NTH SELECTED-LABEL-TRACK-ID (AUD-GET-INFO "labels"))))
  (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 "Label track  id = ~a, name = ~a~%has been exported to the file named: ~%~a" SELECTED-LABEL-TRACK-ID SELECTED-LABEL-TRACK-NAME OUTPUTFILE)
Function: #<FSubr-IF: #452e4b8>
Arguments:
  (FIRST SELECTED-LABEL-TRACK)
  (PROGN (SETF SELECTED-LABEL-TRACK-ID (FIRST SELECTED-LABEL-TRACK)) (SETF SELECTED-LABEL-TRACK-NAME (SECOND SELECTED-LABEL-TRACK)) (SETF SELECTED-LABEL-TRACK-CONTENT (SECOND (NTH SELECTED-LABEL-TRACK-ID (AUD-GET-INFO "labels")))) (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 "Label track  id = ~a, name = ~a~%has been exported to the file named: ~%~a" SELECTED-LABEL-TRACK-ID SELECTED-LABEL-TRACK-NAME OUTPUTFILE))
  (PRINT "No LABEL TRACK selected.  Please select ONE first.")
1>

Any clue what’s wrong here? From the debug output I can’t even tell at what line of code it bailed out.
Thanks for any hints.

OK OK - user error.
It seems that the destination directory has to exist. It didn’t (C:\tmp, not C:\temp), hence the macro bailed out.
Would be nice to provide either an explanatory message or document in the code that this is a requirement.

On a sidenote I found that the label names don’t get correctly exported if they contain non-ASCII characters (e.g. German umlauts: replaced by underscore) or double quotes (first occurrence replaced by \ and following text truncated).
Given Steve’s comment on Nyquist’s limitations on string processing (and my limitations on NYquist programming), I won’t venture into fixing the code :wink:
I’m just stating this here to set expectations for future potential users.
I will therefore revert to the “classical” way of exporting single label tracks (close all but one, export, undo closing).

A related problem is that the code will only work on Windows ("C:" does not exist on Mac or Linux), and there is no guarantee that “C:\tmp” will be writeable.

A simple solution would be to query Audacity for the location of the “Documents” directory (which should be writeable on all platforms):

(setf savepath (string-right-trim "\/"(get '*system-dir* 'documents)))

To be absolutely sure that the output directory is writeable, a test function could be added:

(defun iswriteable (path fname)
  ;; Return T if path is writeable, else NIL.
  (setf path (string-right-trim "\/" path))
  (setf path (format nil "~a~a~a"
                  path *file-separator* fname))
  (let ((fp (open path :direction :output))
       rslt)
    (if fp
        (progn (close fp)
          t)
        nil)))

(print (iswriteable "C:\tmp" "test.txt"))

However, the above code will create a zero byte file “C:\tmp\test.txt” if the directory is writeable, so in practice it would be better to use the actual filename that you intend to write to.

just for the record: Challenged by the same question again (exporting individual label tracks) I ran - again - across this thread and tried @agua 's code from Oct 2020 (with v3.4.2).
Exporting worked, but:

  1. I found that in the generated label file start and end times are seperated by ‘)’ instead of a tab character. This was easy to fix, but more surprised was I to find that

  2. start and end times were rounded to milliseconds, compared to the original location of the labels. As a result the label positions of the single-exported label file were up to several hundred samples off the correct location.

Example:
correct location:

|179.243214|179.243214|label1|
|221.066630|221.066630|label2|

exported location:

|179.243000|179.243000|label1|
|221.067000|221.067000|label2|

They are rounded to 4 decimal places. I posted an enhancement request regarding this in January last year: Scripting: Don't limit precision of values from GetInfo: · Issue #4220 · audacity/audacity · GitHub
Sadly the developers decided that the request was “out of scope”, which I guess means that they don’t want to improve it.

Thanks @steve for clarifying this here - for setting expection with users of the macro.
I will stick to the “classic” way of exporting one label track at a time …