Automate specific tasks

Is it possible to automate the following tasks using macros or scripting?
1 - From an audio track, create n equal tracks in the same project (one over the other in the window project), which the user can inform the value of n, or define directly in the code;
2 - Increment each of these n tracks with a different pitch gain, unique to each track;
3 - Apply an effect recursively until the audio track reaches a certain range of values for a certain audio characteristic.

My notebook has Windows 10, and Audacity version 3.0.3 .

until the audio track reaches a certain range of values

That lets Macros out. They can’t make decisions. IF range is good, THEN do something. Can’t do that.

I think you’re into one of the programming languages. Nyquist?

Koz

“Nyquist Macros” are what you need: https://manual.audacityteam.org/man/nyquist_macros.html

Alternatively, if you already know a programming language that supports “named pipes” (such as “Python”) then you could control Audacity remotely via mod-script-pipe (https://manual.audacityteam.org/man/scripting.html)

Thanks, steve and kozikowski!

Oops… I analyzed some examples of Nyquist and Python (pipe “flavor”) and it greatly extrapolated my ability. As for programming my limit is pascal and basic, at most a very simple VBA macros in Excel. I know what needs to be done (I even made a flowchart of the process), but I don’t know how these specific languages work, how they handle repeating and conditional structures, how to select and define “objects and their properties” in an audio project, etc. .
If anyone is interested in doing it, I’ve created a little task on Fiverr, but I don’t think anyone capable of doing it will appear there… I’ll even post the code here if someone does it…

Thanks for your help, guys.

To get you started with Nyquist Macros:

  1. Create a new Audacity project containing 1 track
  2. Run this code in the Nyquist Prompt effect (https://manual.audacityteam.org/man/nyquist_prompt.html). The Nyquist Prompt is an easy way to test out short Nyquist scripts.
(aud-do "SelectAll:")
(aud-do "Duplicate:")
(print "Done")

If you wanted to create three tracks:

(aud-do "SelectAll:")
(aud-do "Duplicate:")
(aud-do "SelectTracks: Track=0 TrackCount=1 Mode=Set")
(aud-do "Duplicate:")
(print "Done")

You can also use loops:

(aud-do "SelectAll:") ;selects the track and time region

(dotimes (i 6)
  (aud-do-command "SelectTracks" :track 0 :trackcount 1 :mode "Set")
  (aud-do "Duplicate:"))

(print "Done")

There’s a good amount of documentation for Nyquist these days. See: https://forum.audacityteam.org/t/manuals-and-reference-material/32817/1

God bless you, Steve. You are the guy!

:laughing:

Topic moved to the “Macros and Scripting” board.

@pathfinder73, play with the code snippets that I posted, and see how far you can get with the task that you want. Feel free to ask questions if you get stuck. Specific questions are usually better than general questions.

Thanks, Steve.

One difficulty I’ve noticed, and the reference material isn’t helping me, is that I can’t find a list of the objects, methods and properties that exist within Audacity and Nyquist.
For example, if I want to list how many tracks there are in a project, how do I do that? In a page it is mentioned that the object is called TRACKS (or TRACKS), but it returns a list, and which method lists the number of elements in that list. Length ?

Example: If I want to change the pitch of track 7, what method do I use to access track 7 (by looking at your code, the track count starts at 0, so I’d risk that it would be something like
(aud-do-command “SelectTracks” :track 6 :trackcount 1 :mode “Set”)
but which property should be modified and how? another bet:
(aud-do “ChangePitch: Percentage=0.1 SBSMS=1”) to increment by 0.1% and SBSMS=1 indicates boolean, will it work without SBSMS?)
An example then, would be this… I created the 6 tracks with your excellent code, now I want to increase the pitch of track 2 by 0.1%, track 3 by 0.2%, successively increasing by 0.1% until the last trail. I could leave that increment value in a separate variable that would increment each time the loop runs, and apply the pitch to the next track. If the “:track” tag accepts incremental variable information it would simplify the code length.

Oh, God… Something happens! Right or wrong, I’m not sure. But the pitch on track 7 is bigger than the pitch of the other tracks.
Is these flag SBSMS really indispensable?

I used this code at the prompt:

(aud-do “SelectAll:”)
;type tool
(aud-do-command “SelectTracks” :track 6 :trackcount 1 :mode “Set”)
(aud-do “ChangePitch: Percentage=0.10 SBSMS=1”)
(print “Done”)

That’s right. Looks like you’re getting there :smiley:

Normally the “;type” line should go at the top of the script (if used):

;type tool
(aud-do "SelectAll:")
(aud-do-command "SelectTracks" :track 6 :trackcount 1 :mode "Set")
(aud-do "ChangePitch: Percentage=0.10 SBSMS=1")
(print "Done")

“SelectTracks:” is “zero indexed”; meaning that the first track is track 0, thus (aud-do-command “SelectTracks” :track 6 :trackcount 1 :mode “Set”) selects the 7th track.

If you prefer to not use SBSMS (use “SoundTouch” instead), then set SBSMS=0

Unfortunately this is a bit tricky.

Often you can work it out from the commands that you are using - for example, if you start with one track, duplicate it, then select all and duplicate again, then you know that you have 4 tracks without having to analyze the project.

If you do need to analyze the project, then the way to do it is:

;type tool
(setf number-of-tracks (length (aud-get-info "Tracks")))
(print number-of-tracks)

Note that this is the total number of all tracks in the project (including label tracks and note tracks, if any).

See AUD-GET-INFO here: Nyquist-Macros - Audacity Manual

The benefit of using AUD-DO-COMMAND rather than just AUD-DO, is that the former is easier to use with variables.
See: https://manual.audacityteam.org/man/nyquist_macros.html#AUD-DO-COMMAND

Well, this code generate 6 additional tracks, but don’t change pitch on neither track.

What is wrong? The variable used for counting “j” could be used in the calculation? Where I must declare global variables for use in all parts of code?

:unamused:


;type tool

(dotimes (i 6)
  (aud-do "SelectAll:") ;selects the track and time region
  (aud-do-command "SelectTracks" :track i :trackcount 1 :mode "Set")
  (aud-do "Duplicate:")
)
 
(dotimes (j 6)
   (define x = 0)
   (x = j*0.01)
   (aud-do "SelectAll:") ;selects the track and time region
   (aud-do-command "SelectTracks" :track j :trackcount 1 :mode "Set")
   (aud-do-command "ChangePitch" :percentage x :SBSMS 0)
)

(print "Done")

It looks like you’re mixing up LISP syntax and SAL syntax. You need to use one or the other. (I use LISP syntax - I don’t know SAL very well.)

Also, 0.01% pitch shift is too small to detect.
Try:

;type tool

(aud-do "SelectAll:") ;selects the track and time region
(dotimes (i 6)
  (aud-do-command "SelectTracks" :track i :trackcount 1 :mode "Set")
  (aud-do "Duplicate:"))

(dotimes (j 6)
   (setq pshift (* j 15.0))
   (aud-do-command "SelectTracks" :track j :trackcount 1 :mode "Set")
   (aud-do-command "ChangePitch" :percentage pshift :SBSMS 0))

(print "Done")

These amazing code creates the 6 tracks, goes through them all in the second loop, but the pitch is the same on all…
Something happens that the code doesn’t perform the pitch change…
But it goes all the way to the end and displays the “Done”… so I think it’s not a syntax error, maybe some feature identifier (percentage, SBSMS)…

Strangely the code Steve posted changed the pitch of some tracks and not others.

Original track: 46.921 Hz

After the process, they were like this:
Track 0: 46.921 Hz
Track 1: 46.921 Hz
Track 2: 46.921 Hz
Track 3: 390.244 Hz
Track 4: 296.296 Hz
Track 5: 324.324 Hz
Track 6: 46.921 Hz

What I believe seems to have happened:

  1. when selecting the tracks to apply the tone changes, the routine did not select the tracks from the first one… considering as the first one that appears in the first position of the project (top of the project);
  2. or even the order that the tracks appear in the project is not the order that the project refers to them, but that would give different results in all tracks, which doesn’t happen…
  3. or the routine counts the tracks from the last one that received the pitch change.

Anyway, track 3 pitch is 731.704% bigger than the original track pitch, so besides the selection of the tracks, the calculation is above correct. In my calculation, it would be {46,921}; {93,842}; {140,763}; {187,684}; {234.605}; {281,526}; {328.447} .

Is there any way to create an Id, preferably numeric to make it easier to use in loops, to ensure that a specific track will receive the pitch change?

How are you measuring the frequencies?

From the code, it is expected that the first and final track will not be pitch shifted.

Those values appear at the top of the window when I select the track and click Effects → Change Pitch. Is there another more correct way to find out?

The first track really shouldn’t be changed, but the last track (track 7, referenced as 6 as it counts from zero) should be pitch-changed. Or no?

The “Change Pitch” effect only provides an approximation of the frequency. It’s not very accurate for low frequencies.

Better accuracy can be achieved with “Plot Spectrum” (Plot Spectrum - Audacity Manual)
The larger the “Size” setting, the more accurate it is, but accuracy at low frequencies is still not fantastic. If you start with a higher frequency (say 1000Hz) it is much easier to verify that the code is working correctly.