Auralise annotations in Audacity

(I’m using Debian wheezy and installed Audacity from Debian package repository.)

Is there a way to auralise the label track in Audacity? What I want to achieve is each point label making sound when file is played and cursor goes over it. This will allow to check if they are placed right. I’m doing a beat annotation, so it is hard to check them the other way (you have to listen to bigger fragment of file to get the “beat sensation”; I get initial labels by listening to file and hitting Ctrl+M on beat-down).
Is there a way to do it in Audacity or using some Audacity plugin? Maybe there’s a way to get exported annotation file back to audacity to generate “click track”, then I will be able to mix it with file. Any solution including programming or using any other not-commercial tool is also acceptable.

I will be grateful for any ideas on this issue :slight_smile:

It would be possible to create a Nyquist plug-in that can read data from an exported label track, but as far as I’m aware such a plug-in has not yet been written. Unfortunately plug-ins are not currently able to read label tracks directly.

There may be easier approaches.
Have you tried the Beat Per Minute labels plug-in?
If you can create a Click Track that matches the music, then you can create the labels using “Beat Per Minute labels” with the same tempo and the same starting point as the click track.

Thanks for very fast reply :slight_smile:

I will be working on files where beat period changes significantly so unfortunatelly I cannot just match bpm.

Two choices then I think.

If this is a one-off job then manual editing will be fastest.
If you will be doing this type of job regularly then writing a plug-in may be better.

Do you want help with how to best do this manually, or with writing a plug-in?

You mean creating the Nyquist plugin that will make a short tick on each label? That would be great :slight_smile: Do you think it’s hard to do it? I may try it.

(I’m not sure what do you mean by manual way, I can employ someone to knock everytime they see cursor moving over label, but I don’t expect it to be very accurate :wink: )

Yes, definitely possible, though with the limitation that it cannot “read” labels directly, so you would need to either:

  • Export the label track, open it in a text editor, then copy and paste the label data (text) into a text window in the plug-in (much easier to code).
  • Export the label track and make the plug-in read the exported track (harder to code).

I would recommend going for the easier option. The harder option could be added later if required.

Have you done any programming previously? (not required)

I’d suggest that you start by having a read through this document (don’t worry if you don’t understand it all straight away):
and for some hands-on experience try out some of the simple examples (don’t bother with the “SAL” examples for now) here:

Also, read through this (particularly the final section) so that you know what we are dealing with:

I’ll have a think about how best to approach the task.
Feel free to ask questions.

I think I will start from reading time labels from some list hard-coded in program.
I’m trying to understand clicktrack.ny plugin from Audacity distribution. (I think it’s a good base it is a Generate type of plugin and has alread “make tick” code in it.)
I don’t understand how do you “move in time” there.

For example I understand

(osc pitch)

makes a sound of defined pitch. But how do you define for how long it lasts and at which time instant it happends?

Have a look at the list.
As long as you are not using label text, the list should look something like this:

2.052789	2.052789	
4.105578	4.105578	
6.033197	6.033197

Because you are creating “point” labels with Ctrl+M, the start and end time of each label is the same.
This will be useful to us as it means that all that we need to extract from the list is every other value.

There is also a convenient function hz-to-step
Because osc uses MIDI step values for the frequency, it is often convenient to use the hz-to-step function.
Some examples to try in the Nyquist Prompt effect

; generate a 440 Hz tone
(osc (hz-to-step 440))

; generate a 1000 Hz tone
(osc (hz-to-step 1000))

; generate a 440 Hz tone that is twice as long as the selection
; Note that the "length" parameter is relative to the selection length
(osc (hz-to-step 440) 2)

; generate a 1000 Hz tone that is half the length of the selection
(osc (hz-to-step 1000) 0.5)

; generate a 440 Hz tone that exactly 3 seconds long
; note the use of ABS-ENV to create absolute time values
  (osc (hz-to-step 440) 3))

You can probably see how all of these brackets are working.
Nyquist is based on the programming language XLISP, which uses “fully parenthesized Polish prefix” notation.
What that means is that “functions” or “command” always come before (prefix) the “arguments” (values).
So for example, rather than writing:
3 + 2
The “+” is the “Add” function, so that goes first and the “arguments” follow:

  • 3 2

“Fully parenthesized” just means that every function goes inside its own set of brackets, so we end up with:
(+ 3 2)

So in our last example we have the function hz-to-step that converts 440 Hz into its “step” value (MIDI note number).

(hz-to-step 440) and 3 are then the “arguments” for the function osc to give us:

(osc (hz-to-step 440) 3)

In turn, that becomes the argument for the function abs-env.

All of the sounds so far have been “full volume”. We can make them bigger or smaller by scaling them. Scaling or amplifying a sound is the same as “multiplying” the sound by a value, so to make a sound have a peak level of half the track height, we can simply multiply it by 0.5

(mult 0.5 (osc 72))

to be continued…

So far we’ve got how to generate tones and how to amplify them.
What would be useful would be if we could “shape” them so that they are not just a constant volume.

To do this we need to “multiply” them by something that varies - a number does not vary, it is a “constant”.

Nyquist provides a feature called “control signals”.
A Control signal is much like a sound (a waveform) but to improve efficiency they use a low sample rate, typically 1/20th of the track sample rate.
When a control signal is multiplied by a sound, the higher sample rate of the two is used for the output.

To create control signals we can use “piece-wise approximations”

The version that we will use is pwlv

Let’s say that we want to create an envelope that rises from 0.2 up to 0.8 at half way and back down to 0 again at the end.
Much like the Audacity Envelope tool we create a number of “control points” which are pairs of “time and level” values.
The correct order of values for pwlv is:
time1, level1, time2, level2, time3, level3…
The first time value is assumed to be zero so that value is not entered.
So our function for the “envelope” is:

(pwlv 0.2 0.5 0.8 1 0)

If you run that command on its own it will produce a very short waveform because of the low sample rate being “squashed” when it gets back to the Audacity track, so let’s try multiplying it by a sound:

(mult (osc 72)
  (pwlv 0.2 0.5 0.8 1 0))

Or if we want an exact time duration we can use something like:

;; note that we use absolute time values for both the
;; sound and the control signal
  (mult (pwlv 0.2 1.5 0.8 3 0)
    (osc (hz-to-step 440) 3)))

So finally we get round to something useful - a little “beep” for our plug-in.

(setq dur 0.1)
(setq hz 1000)

  (mult (pwlv 0 (* dur 0.1) 0.8 (* dur 0.9) 0.8 dur 0)
   (osc (hz-to-step hz) dur)))

I have used a “variable” called “dur” to hold the required duration - in this case 0.1 seconds,
and the variable “hz” to hold the frequency - in this case 1000 Hz.

To make the code easier to use in our bigger plug-in, I’ll wrap the whole thing in a “function”.
We will create our own custom function called “beep” and it will take 2 “arguments” (parameter values) which will be the frequency and the duration.

;;; make a beep
(defun beep (hz dur)
    (mult (pwlv 0 (* dur 0.1) 0.8 (* dur 0.9) 0.8 dur 0)
     (osc (hz-to-step hz) dur))))

On its own this function does nothing. To make it do something we have to call the function (use it):

;;; make a beep
(defun beep (hz dur)
    (mult (pwlv 0 (* dur 0.1) 0.8 (* dur 0.9) 0.8 dur 0)
     (osc (hz-to-step hz) dur))))

; use the function 'beep' with a frequency of 440 Hz and a duration of 0.5 seconds
(beep 440 0.5)

to be continued…

Topic moved to the Nyquist forum.

So now that we have a “beep” to use, we want it to play at specific times.
Probably the easiest way to do that is to use the function at, but Audacity will give us times relative to the length of the selection, so we will use the “absolute” version which is at-abs

First we need to understand a little peculiarity of Nyquist in Audacity. When sound is returned from Nyquist, Audacity always assumes that the cursor position or start of the selection is “time zero”.
This will not work:

(at-abs time make-a-sound)

The reason that it does not work is that although Nyquist sets “make-a-sound” to start at “time”, Audacity will place the start of the actual sound at the cursor position.
To get round this problem we need to also have a sound that starts at time=0. This can be any sound, it can be silence, it can even be a “dummy” sound such as zero length silence.

We will use the function sim to combine out beep with the a dummy sound (
In pseudo-code we will use:

  (at-abs 0.0 dummy-sound)
  (at-abs time beep))

Because the start of the sound is assumed to be zero unless otherwise stated, we don’t need the (at-abs 0.0 part, so we can just use:

  (at-abs time beep))

Now there is one thing wrong with this, and that is that at-abs should really be operating on a “behaviour” and not directly on a “sound”.
We’ll not go deeply into this now as it’s rather complicated - instead we’ll jump to the solution which is to cue the sound.

  (at-abs time (cue beep)))

So let’s put this into real code and make some beeps at defined intervals:

;;; make a beep
(defun beep (hz dur)
    (mult (pwlv 0 (* dur 0.1) 0.8 (* dur 0.9) 0.8 dur 0)
     (osc (hz-to-step hz) dur))))

;; make some beeps
  (s-rest 0)  ; dummy sound
  (at-abs 1 (cue (beep 400 0.5)))
  (at-abs 2.5 (cue (beep 800 0.25)))
  (at-abs 5 (cue (beep 1200 0.1))))

Rather a long answer, but hopefully some stuff that you can use :wink:

At first didn’t noticed the second page of the thread :blush:
Thank you very much for such a detailous explanation! The most important to me is the third part, I didn’t know how to move ticks in time :slight_smile:
But envelope shaping is also useful I think, this can make ticks sound better.
I’m also glad I learned something about Lisp :wink:
So now labels have to be exported to file and read back.
Do you think it will be possible in future Audacity releases to read label tracks directly?

I would very much like labels to be available to Nyquist plug-ins. Currently Nyquist plug-ins can create labels, but they cannot read existing label tracks. Unfortunately I don’t expect that there will be many changes to what Nyquist plug-ins can do in the near future as there are few Audacity developers working in this area.

Exporting the labels is an option in the Audacity file menu: Try it out if you haven’t already.

To be able to paste the data into the Nyquist plug-in you will need to use a Text Input Widget.
See this section and see if you can create a “generate” type plug-in that appears in the Generate menu and has a text input widget:
To “install” your plug-in you need to put the plug-in into the Audacity plug-ins folder and restart Audacity.

Text input widgets provide Nyquist with “string” data (text). We will not be able to use this directly because we will need to “convert” the data into a list of number. Don’t worry about this too much just yet, concentrate on just getting a Generate plug-in to appear in the Generate menu, and see if you can get the various types of input widgets to appear.

If you want the plug-in to generate a sound, the last line of the plug-in must “return” the sound (see here: A simple way to “return” a text message is to use the print function:

(print "hello world")

Let me know how you get on.