Nyquist plug-in to transpose chords in label track

Audacity offers a high quality function to pitch shift audio. To the audio I often add a label track with the chord changes, which I either created manually or automatically by the chord recognition program Chordino (NNLS Chroma). For automatic transposition of these chords I have not found any macros or plug-ins in this forum. Therefore I tried to write a Nyquist plug-in myself that solves this simple but boring task automatically:

The plug-in given below uses optionally either the last found label track or the last found label track whose name begins with “Chord”. In the found label track, all labels that begin with a chord letter (C/D/E…A/B/c/d/e…b) are transposed by selected semitones. The rest of the label remains unchanged. As 2nd character # for sharp or b for flat can be used.
A new label track is inserted with the changed chords at the end. Labels that are not recognized as chords are taken over unchanged. Optionally, point labels can be converted to region labels (and vice versa). If a pitch change of 0 semitones is selected, all labels are taken over unchanged. The Nyquist plug-in requires exactly one selected audio track the label track refers to, and this also determines an optional offset if the audio track does not start at 0 in timeline. If a label track is selected in addition to the audio track, then Audacity does not create a new label track, but inserts the new labels there. In addition, the Nyquist plug-in can change the pitch of the selected audio itself using a Nyquist function in a second pass.
Maybe the plug-in is also of interest for others, if indeed no such program/macro should be available. It was written and tested by me using Audacity 3.2.4 under Windows and should be used with caution as my Nyquist programming skills are limited.


That looks very good.

Nice to see well formatted code. Just a couple of points about indentation:

  • “IF” statements should be indented like this: Indentation | Nyquist-Style-Guide

  • When there’s a vertical list of arguments, such as in a LET block, the indentation should be the same on each line, including any “(” characters. So:

(let ((first-var 1)
      (second-var 2)

rather than:

(let ((first-var 1)
      (second-var 2)

Regarding the actual code, Nyquist defines “constants” for note names (They are only really “constant” by convention, as Nyquist allows you to assign a different value to any symbol).
For example, MIDI note 60 is middle C (C4).
(print C4) ; prints 60.0
This is documented in the “Adagio” section of the Nyquist manual: https://www.cs.cmu.edu/~rbd/doc/nyquist/part12.html#index979

Unfortunately it uses S for sharp and F for flat, rather than # and b.
(print CS4) ; prints 61.0
Nevertheless, it might be useful to use MIDI note values / Adagio note names for calculating the new pitches.

Finally, Nyquist now has an improved pitch shift algorithm based on a phase-vocoder:
A simple example using the new algorithm:

;control transposeval "Transpose (semitones)" float "" 2 -12 12
(setf transposeval (power 2.0  (/ transposeval 12.0)))
(pv-time-pitch *track* (const 1) (const transposeval) (get-duration 1))

Thanks a lot for all the constructive comments. I learned about the Nyquist pitch shift function that I used in this forum, where it was mentioned that it is supposed to be of lower quality than the one built into Audacity. Nevertheless, I used it to preserve the plug-in feature and not generate a Nyquist macro. I did not know about the new improved Nyquist algorithm. I will try to use this function in the plug-in and also to consider the other recommendations.

@steve: Regarding your recommendations, I changed the indentations in some lines (cosmetic) and replaced the pitch shifting function with the new Nyquist algorithm (higher quality). So far I have no experience with MIDI (except a small Delphi program to control my old Behringer V-Amp via MIDI port) and I’m not sure that I could significantly shorten the source code with it.