Converting seconds into human readable format

Hi,

I am new with Nyquist.
I am looking of method to convert time in seconds (float format) into human readable format “00:00:27.765300”.
Is there (in Nyquist) a method to do it easy or do I need to write a function where I will divide by 60 and count everything by myself?

I may be able to save you some time, I’m sure I wrote a function for that somewhere…
Ah yes, here it is:

(defun format-time(sec &optional (n 3))
  ;; Return time formatted to hh:mm:ss + n decimal places.
  (unless (and (numberp sec) (numberp n))
    (error "format-time arguments must be numbers."))
  (flet ((pad (x) (if (< x 10) (format nil "0~a" x) x)))
    (let* ((hh (truncate (/ sec 3600)))
           (mm (truncate (/ sec 60)))
           (ss (- sec (* mm 60)))
           (old-format *float-format*)
           rslt)
      (setf mm (- mm (* hh 60)))
      (setf *float-format* (format nil "%.~af" n))
      (setf rslt (format nil "~a:~a:~a" hh (pad mm) (pad ss)))
      (setf *float-format* old-format)
      rslt)))

That’s great! Thanks a lot Steve, it works perfect.

Did you manage to work out how to set the number of decimal places for fractional seconds?

Yes, it is easy, I use

(format-time (first data-1) 4)

but default=3 is good for my use case. I have spent a couple of hours to understand Lisp’s syntax :slight_smile:
Based on “Export labels” script, I wrote a version for my use case. I have found comma2dot function on this forum that I transformed to dot2comma and use in my script.

(defun dot2comma (txt)
  ;; Replace dot with comma if only one dot
  (let ((c (string-search "." txt)))
    (if c
        (let ((rest (subseq txt (1+ c))))
          (if (string-search "." rest)
              txt
              (strcat (subseq txt 0 c) "," rest)))
        txt)))

(defun format-time(sec &optional (n 3))
  ;; Return time formatted to hh:mm:ss + n decimal places.
  (unless (and (numberp sec) (numberp n))
    (error "format-time arguments must be numbers."))
  (flet ((pad (x) (if (< x 10) (format nil "0~a" x) x)))
    (let* ((hh (truncate (/ sec 3600)))
           (mm (truncate (/ sec 60)))
           (ss (- sec (* mm 60)))
           (old-format *float-format*)
           rslt)
      (setf mm (- mm (* hh 60)))
      (setf *float-format* (format nil "%.~af" n))
      (setf rslt (format nil "~a:~a:~a" hh (pad mm) (pad ss)))
      (setf *float-format* old-format)
      (setf rslt-comma (dot2comma rslt))
      rslt-comma)))

(defun format-data (tracknum trackname data-1 data-2)
  ;; Return formatted label data for one label.
  (setf trk-time-data
    (format nil "~a~a~a~a"
          tracknum
          trackname
          (if (= hastimes 0) ;data-1 times
              (format nil "~a~a~a" (format-time (first data-1)) sep (format-time (second data-1)))
              "")
          (if (= hastimes 0) ;data-2 times
              (format nil "~a~a~a~a" sep (format-time (first data-2)) sep (format-time (second data-2)))
              "")))
              
  (if (= haslabel 0) 
    (strcat trk-time-data (format nil "~a~s~a~s~%" sep (third data-1) sep (third data-2)))
    (strcat trk-time-data "~%"))        
)

(defun export-labels ()
  ;; Main function.
  (let ((info (aud-get-info "labels"))
        (tracknames (track-names))
        (trackname "")
        (tracknum "")
        label-string
        (output ""))
    (dolist (trk info)
      (when (= hasnumber 0)
        (setf tracknum (format nil "~a~a" (1+ (first trk)) sep)))
      (when (= hasname 0)
        (setf trackname (format nil "~s~a" (nth (first trk) tracknames) sep)))
      (setq trklabels (second trk))
      (if (> (rem (length trklabels) 2) 0)
        (return-from export-labels (format nil "Error: Not even number of labels."))) 
      (dotimes (i (/ (length trklabels) 2))
        (setq indx (* i 2))
        (setq label-1 (nth indx trklabels))
        (setq label-2 (nth (1+ indx) trklabels))
        (setf label-string (format-data tracknum trackname label-1 label-2))
        (setf output (strcat output label-string))))
    (write output filename)))

Without track name/num and label strings the script prints times in format (two labels times in one line):

0:01:04,850	0:01:07,250	0:01:15,910	0:01:19,900
0:01:25,480	0:01:27,750	0:01:32,620	0:01:34,700

Thanks of that I can export labels times from Audacity and import to Excel in a few mouse clicks.

Digging in forum about decimal separator I found that audacity developers decided to use always dot as a decimal separator. So I want to replace dot2comma function with more “generic” version but I got error in “if”:

error: bad argument type - #\,
Function: #<Subr-=: #000002BC90D90E88>
Arguments:
  #\,
  "."
Function: #<FSubr-IF: #000002BC90D8FAA8>
Arguments:
  (= *DECIMAL-SEPARATOR* ".")
  (RETURN TXT)
Function: #<Closure-STR-CONVERT-DECIMAL-SEP: #000002BC90CAB898>

function is

(defun str-convert-decimal-sep (txt)
  ;; Replace dot with decimal separator if only one dot
  (if (= *decimal-separator* ".") (return txt))
  (let ((c (string-search "." txt)))
    (if c
        (let ((rest (subseq txt (1+ c))))
          (if (string-search "." rest)
              txt
              (strcat (subseq txt 0 c) *decimal-separator* rest)))
        txt)))

Why decimal-separator is “#,” or “#.” and how to fix that error?
I will be grateful for your help.

In XLISP / Nyquist, “characters” and “strings” are different data types.
(See: XLISP: An Object-oriented Lisp)

decimal-separator is type “char” (a character).
“.” is a string (type “string”).

The equality operator “=” is for comparing numeric types.
For comparing other types, you need to use the appropriate comparison function: string=, string-equal, char=, char-equal.
You can’t compare apples to oranges, or strings to chars.

One way to compare a string and a char is to compare the string representation of the char:

(print (string= (format nil "~a" *decimal-separator*) "."))  ; True

or you could compare decimal-separator with the character #\.

(print (char= *decimal-separator* #\.))  ; True

The functions mentioned in this post are all documented in the XLISP manual: XLISP Language Reference

(DECIMAL-SEPARATOR is not standard to Nyquist or XLISP, but is specific to Audacity’s version of Nyquist.)

thank you for in-depth explanation.