How to specify a list of timepoints for a plugin to operate on?

I am in the process of teaching myself enough Nyquist[1] to implement a plugin to do the operation I described in an earlier post[2].

The first thing I need to figure out is a way for the user to specify a set of timepoints on a stereo track, using the Audacity interface, and in a way that a Nyquist plugin can access and use as an argument to a function. I would like the user to specify the timepoints for this set by clicking directly at the desired times on the track.

On the Audacity GUI, if I click directly on a track, a vertical line, going through the point where I clicked, appears. If I click at a second location on the track, to the left or the right of the first location, the first vertical line disappears, and a new vertical line appears at the point where I last clicked.

I have two related questions about this:

  1. Is there a way to keep/record all the horizontal locations I am clicking on? (Ideally this would also retain the vertical lines that show up on the GUI, to remind the user what timepoints have already been added to the list.)
  2. How can a Nyquist plugin access the timepoints thus specified?

[1] Luckily, I have done a fair bit of Scheme and Emacs Lisp programming, so Nyquist looks very familiar to me. On the downside, however, I am completely lost when it comes to terminology, which makes it very difficult for me to use text-based search tools (notably, search engines, the browser’s “find in page” function, and grep for downloaded source code).
[2] Actually, after reading the information I got from the response to that post, I realized that it would be simpler to specify the operation in terms of two arguments: (1) a desired interval length T; and (2) a (chronologically ordered) list of timepoints (t(1), t(2), t(3), …, t(N)), such that t(k) - t(k-1) <= T for all k. The plugin would then insert silences of length T - (t(k) - t(k-1)) at each timepoint t(k).

After clicking at each location on the track, Press Ctrl-B to create a label at that position.

We need to consult Steve to answer this question. I know that Nyquist can output label tracks, but I’m not sure about importing them. Audacity can export a label track to an external file, but again, Steve can help us find out whether this information can be loaded into Nyquist.

Nyquist “can” read label tracks, but it’s a bit tricky, and may not actually be necessary in this case.
I need to do a few other things right now, but I’ll move this topic to the Nyquist forum board and get back to it asap.

From your original brief,

Suppose that the current selection of audio corresponds to 1.19 seconds of duration. I am looking for a convenient way to insert a stretch of silence to the right of this selection (aka “(right-)padding”) so that the duration of the selection plus the newly added right-padding is 2 seconds.

This can be done quite easily with Nyquist, but unfortunately there is a bug in Audacity 3.0.2 that prevents it from working. It should work in Audacity 2.4.2 or earlier, and will work in Audacity 3.0.3 when it becomes available (hopefully quite soon).

This is the required code:

;type process

(setf target-length 10)

(sim (abs-env (s-rest target-length))
     *track*)

Explanation:

Tell Audacity that we are processing the selection:

;type process

Set the required length:

(setf target-length 10)

Generate silence equivalent to the entire length:

(abs-env (s-rest target-length))

and add (mix) it with the original track audio:

(sim (abs-env (s-rest target-length))
     *track*)

The code can be easily converted into an installable plug-in by adding the “required headers” (https://wiki.audacityteam.org/wiki/Nyquist_Plug-ins_Reference)

For a single pair of time points, this is easy.

  1. Click on the waveform at the first time point.
  2. “Shift + Click” on the waveform at the second time point.

This will select the region from the first time point to the second time point.
The selection defines the audio that is sent to Nyquist for processing / analyzing.

An alternative method is to click and drag on the waveform.

Defining multiple time points can be done by creating labels:

  1. Click on the waveform at the first time point.
  2. Press “B” then “Enter”
  3. Click on the waveform at the second time point.
  4. Press “B” then “Enter”
  5. Click on the waveform at the first time point.
  6. Press “B” then “Enter”

The tricky part is getting those labels into Audacity. This requires some fairly new features, and I don’t recall if they are available in Audacity 2.2.2.

Please try this and tell me what happens:

  1. Generate or record a short audio track
  2. Add some point labels as described above
  3. Select the audio track (double click on it)
  4. Open the “Nyquist Prompt” effect (If you have a “Tools” menu it will be there, otherwise you will need to find it in one of the other menus).
  5. Enter the following code:
;version 4
(print (aud-get-info "Labels"))
  1. Click the “Debug” button.

@steve: Thank you for your help! This gives me a ton to work with!

I am still working on what you asked in your last post. I have not been able to find the Nyquist console yet. Unfortunately, my installation does not seem to have included the Audacity documentation, and I have not yet located documentation for this version (2.2.2) online. (To make matters worse, https://web.archive.org/web/*/https://manual.audacityteam.org/index.html resolves to a “Temporarily Offline” page.)

@jademan: thank you, Ctrl-B worked as advertised. I am currently working on Steve’s suggestion for accessing those labels from Nyquist.

Unfortunately that seems to be the case for all Linux packaged versions of Audacity :frowning:

The manual is in HTML format, so the easiest way to read it is to simply download the manual ZIP package, extract it somewhere convenient, and make a Desktop link or launcher that links to the “index.html” file.

You can download the Audacity 2.2.2 manual from here: Old Audacity versions download

In Audacity 2.2.2 the “Nyquist Prompt” is in the “Effect” menu.

Unfortunately it looks like Audacity 2.2.2 is too old to allow Nyquist to read labels.
Which version of Linux are you using?

@steve: Thank you for all the pointers.

Here’s the version info for my current setup:

% uname -srvmpio
Linux 4.19.0-12-amd64 #1 SMP Debian 4.19.152-1 (2020-10-18) x86_64 unknown unknown GNU/Linux

% lsb_release --all
No LSB modules are available.
Distributor ID:	Debian
Description:	Debian GNU/Linux 10 (buster)
Release:	10
Codename:	buster

% dpkg-query --list audacity
Desired=Unknown/Install/Remove/Purge/Hold
| Status=Not/Inst/Conf-files/Unpacked/halF-conf/Half-inst/trig-aWait/Trig-pend
|/ Err?=(none)/Reinst-required (Status,Err: uppercase=bad)
||/ Name           Version      Architecture Description
+++-==============-============-============-=================================
ii  audacity       2.2.2-1+b1   amd64        fast, cross-platform audio editor

Top

I will figure out a way to install a more recent (but not too recent!) version of Audacity, and will report back ASAP.

Thank you again!

Debian Testing (bullseye) and Debian Sid both have Audacity 2.4.2.
Audacity 2.4.2 will be new enough for this.

I do not currently recommend Flatpak, Snap, or AppImage packages, as we are still receiving reports of problems with them.

For the latest Audacity release, the best way to get it is to build from source code. The build process has recently been updated, which makes it pretty easy for anyone that has experience building from source. If you don’t have any experience building from source, then I’d recommend Audacity 2.4.2.

OK, sorry for the delay!

I finally managed to perform the test you posted earlier.

Result: After I clicked on the Debug button, a dialog titled “Nyquist Prompt” popped up with the message “Nyquist returned a list” followed by an “OK” button. After I clicked on this button, another window titled “Nyquist Prompt” popped up, showing the list below:

((1 ((1.11038 1.11038 "") (2.24923 2.24923 "") (3.58738 3.58738 "") (4.92554 4.92554 "") (6.1498 6.1498 "") (7.54489 7.54489 "") (8.85457 8.85457 "") (9.93648 9.93648 "") (11.5878 11.5878 "") (12.8121 12.8121 "") (13.894 13.894 ""))))

Below are the specs for the system I’m doing this on.

% uname -srvmpio
Linux 4.19.0-16-amd64 #1 SMP Debian 4.19.181-1 (2021-03-19) x86_64 unknown unknown GNU/Linux

% lsb_release --all
No LSB modules are available.
Distributor ID:	Debian
Description:	Debian GNU/Linux 10 (buster)
Release:	10
Codename:	buster

% dpkg-query --list audacity
Desired=Unknown/Install/Remove/Purge/Hold
| Status=Not/Inst/Conf-files/Unpacked/halF-conf/Half-inst/trig-aWait/Trig-pend
|/ Err?=(none)/Reinst-required (Status,Err: uppercase=bad)
||/ Name           Version       Architecture Description
+++-==============-=============-============-=================================
ii  audacity       2.4.2~dfsg0-4 amd64        fast, cross-platform audio editor

NB: installing Audacity 2.4.2 on my primary (Debian stable) system would have required installing way too many non-stable dependency packages on it, more than I was comfortable with, so instead I installed Audacity 2.4.2 on a VirtualBox VM (also running Debian stable, but with the non-stable dependencies required by Audacity 2.4.2). My question is: if I use the 2.4.2 version of Audacity on this VM to develop the plugin, would I then be able run this plugin on the Audacity 2.2.2 installed on my primary system?

Super. That’s the expected result.

What happens in Audacity 2.2.2?
I’m expecting it will give an error.

@Steve: I got so caught up with getting Audacity v 2.4.2 installed, that I forgot the pointer you gave me on where to find the Nyquist Prompt on v. 2.2.2!

On v 2.2.2, after I click on Debug, an alert dialog (titled Nyquist Prompt) pops up with the following error message:

Debug Output:

error: unbound function - AUD-GET-INFO
if continued: try evaluating symbol again
1>

…followed by an “OK” button.

I think I should be able to use the Audacity 2.4.2 installed in the VM I mentioned in my previous message.

That shows that the command is not implemented in Audacity 2.2.2, so to answer your previous question …

No, you would not be able to use it in 2.2.2 because the “AUD-GET-INFO” command does not exist in 2.2.2.

Back on topic:

As we have seen in:

;version 4
(print (aud-get-info "Labels"))

(aud-get-info “Labels”) returns a nested list of labels.

Say you have two label tracks.
labels.png
and (print (aud-get-info “Labels”)) returns:

((0 ((1 1 "A") (5 5 "2"))) (1 ((2 4 "C"))))

The outer list contains two lists, one per track:

(0 ((1 1 "A") (5 5 "2")))

and

(1 ((2 4 "C")))

The “0” as the first element of the first list indicates that this is “track zero” (the topmost track in the project)
The “1” as the first element of the second list indicates that this is “track 1” (the second track in the project).

Looking at the first list:
The second element is a list containing the labels:

((1 1 "A") (5 5 "2"))) (1 ((2 4 "C"))

Each label has a start time, an end time, and the label text,
so the first label:

  • start time = 1
  • end time = 1
  • Label text = “A”

If we are interested in the first label track only, then:

(setf all-label-tracks (aud-get-info "Labels"))
(print all-label-tracks)
;prints: ((0 ((1 1 "A") (5 5 "2"))) (1 ((2 4 "C"))))

(setf first-label-track (first all-label-tracks))
(print first-label-track)
;prints: (0 ((1 1 "A") (5 5 "2")))

;; Print the track index of the first label track
(print (first first-label-track))
;prints: 0

;; Print the list of labels from the first label track
(setf labels-in-first-track (second first-label-track))
(print labels-in-first-track)
;prints: ((1 1 "A") (5 5 "2"))

;; Print each label from the first label track
(dolist (label labels-in-first-track)
  (print label))
;prints:
; (1 1 "A")
; (5 5 "2")

Putting that all together, we can print to the debug window:

(let ((first-track-labels (second (first (aud-get-info "Labels")))))
  (dolist (label first-track-labels)
    (format t "Start: ~a  End: ~a  Text: ~s~%"
            (first label)
            (second label)
            (third label)))
  "See Debug window")

which gives this output in the debug window:

Start: 1  End: 1  Text: "A"
Start: 5  End: 5  Text: "2"

@Steve: Thank you much! I will be studying your code for some time. I thought I had enough experience with LISP-like languages, but your code has features I had never seen before (notably the dolist form)…