Nyquist-Macros are a special kind of Nyquist plug-in that instruct Audacity to perform tasks using Audacity's scripting interface.
To use this feature effectively, it is necessary to use the correct commands and syntax, and also understand that when Nyquist is used in this way, Nyquist is not allowed, or able, to modify the project. Nyquist-Macros may instruct Audacity to modify the project, but unlike ''ordinary'' Nyquist plug-ins, Nyquist cannot itself modify the project.
Nyquist-Macros are potentially far more powerful than normal Macros in that they may make use of logic, loops and conditionally executing code, rather than only running through a simple list. They can also accept user input via the usual Nyquist plug-in GUI, and most other features of Nyquist plug-ins.
Nyquist Macros are a fairly advanced topic, so this tutorial is aimed at users with an intermediate to advanced level of experience with Nyquist programming.
In this tutorial, we will be reimplementing Audacity's Tone generator as a Nyquist Macro. During the course of the tutorial, many of the abilities and core concepts of Nyquist Macros will be discussed, along with tips and potential pitfalls to watch out for in your own programming.
Nyquist Macros are a powerful extension of Audacity's features. With great power comes great responsibility. Nyquist Macros bypass much of Audacity's built-in validation, so it is relatively easy to pass invalid commands that can cause Audacity to crash. Test your Nyquist Macros thoroughly before using them for important production work.
Audacity provides a rich set of scripting commands, which are documented in the Scripting Reference section of the Audacity manual. These commands may be sent from Nyquist, to tell Audacity what to do, using the function call "AUD-DO". As a very simple example, Nyquist can tell Audacity to start playing by sending the command "Play:"
(aud-do "Play")
Some things to note:
The command "Play:" is a string (text).
The command is case sensitive. It must be capitalized exactly as stated in the Scripting Reference.
The Nyquist function is AUD-DO, which like any other Nyquist function is case insensitive, and usually written in lower case in code.
The function AUD-DO takes exactly one parameter, which is the command string.
As Nyquist cannot modify the project when used to send Macro scripting commands, most Nyquist-Macros will be written as "tool" type plug-ins.
The examples in this section may be run in the Nyquist Prompt, but ensure that you make a selection in an audio track first.
As described above, the "AUD-DO" function takes exactly one argument (parameter), which is the command that will be sent to Audacity. However, we may sometimes want to send a command that has multiple parameters. For example, to generate a 10 second, 200 Hz, 0.5 amplitude sine tone, the Macro Scripting command is:
Tone: Frequency=200 Amplitude=0.5 Waveform="Sine"
With AUD-DO we can send the command, including it's parameters, as one string:
(aud-do "Tone: Frequency=200 Amplitude=0.5 Waveform=Sine")
Using the above example, the macro command string could be passed as the value of a variable:
As with other Nyquist commands, a string argument does not need to be a string literal, it may be a variable that evaluates to a string.
(setf command "Tone: Frequency=200 Amplitude=0.5 Waveform=Sine")
(aud-do command)
In this slightly more complex example we use the FORMAT command to construct the command string. This approach is very useful if scripting command parameters are to be generated programmatically or obtained from user input.
If we incorporate this code in an installable Nyquist Macro, we see that we are getting close to re-implementing Audacity's Tone generator as a Nyquist macro.
Here is a simplified implementation of Audacity's Tone Generator:
Some important things to note in this example Nyquist Macro:
The plug-in type is "tool". If it were set as a "generate" type, running the plug-in without a track would crash because of the duplicate attempt to create a new track (once from the plug-in being a generate type, and again from the Audacity scripting command).
This simplified version does not provide a "Duration" control, so the generated tone will be the length of the selection (if there is a selection), or 30 seconds (default).
In the Scripting command, the Waveform parameter must be quoted because its value may include a space. We therefore use ~S rather than ~A in the FORMAT function.
If you are familiar with Nyquist's LISP syntax, you will have noticed that the syntax described above is not very Lisp-like. The ''magic string'' commands are case sensitive, and constructing the strings is inelegant. However, for many of the scripting commands, a lisp equivalent exists.
Each of these functions have names beginning '''AUD-''', suffixed with the scripting command name. The scripting command parameters are passed as keyword arguments.
There is a small performance penalty when using these LISP syntax commands, so for performance critical applications (such as batch processing many small files), it may be preferred to use the AUD-DO versions.''
In Audacity 2.3.2 and later, the following scripting commands have equivalent LISP functions:
Generate menu effects.
Built-in effects.
Tip: Remember that Nyquist Macros cannot call Nyquist effects.
Example: The scripting command for Audacity's built-in "Amplify" effect is:
Amplify: Ratio=<number>
The equivalent imported LISP function for Audacity's built-in Amplify effect is:
(aud-amplify :ratio <number>)
In both versions, the ratio is a floating point number representing the gain on a linear scale. If we want to Amplify by -3 dB, we can apply the Amplify effect:
Tip: Although the imported function names, and keys are case insensitive, note that if the keyword value is a string, the value is case sensitive.
In this next code sample, we reproduce the simple "Tone" generator from above, using the imported AUD-TONE function:
Unlike Nyquist's generator functions, Audacity's built-in generator functions do not have a parameter for the duration of the sound that is generated. Instead, the duration is set by the length of the track selection. If there is no track selection, then the length defaults to 30 seconds.
One limitation of Nyquist plug-ins that we cannot yet work around, is that the plug-in UI is not dynamic and cannot be changed programmatically. Where as Audacity's built-in Tone generator will automatically show the length of the selected audio, this is not yet possible for Nyquist plug-ins. As a compromise solution, we can:
Add a "Duration" control.
If there is no selection, create a selection of the length specified by the Duration control.
If there is a selection, ignore the Duration control and generate into the selection.
Note: In order to generate audio into a selection, there has to be a ''track'' selection before running the generate command. It is not enough to have a time selection without a track being selected.
As we want to mimic the behaviour of Audacity's Tone generator, we need to handle cases where:
There is a selection in an audio track.
There is a time selection but no track selection.
There is a track selection but no time selection.
While is is possible to find what is selected using the scripting command GetInfo:, a simpler way is to use the Nyquist global property list *SELECTION*.
In Audacity 2.3.0 and later, there is a "[Nyquist_Plug-ins_Widgets#Time_Widget time widget]", which greatly simplifies handling durations, and is in keeping with Audacity's built-in effects.
;control duration "Duration" time "" 30 0 nil
Then we want to check if an audio track is selected, and if not, add a new track. Note that there isn't a LISP function for adding a new track, so we fall back on AUD-DO instead:
And to handle the time selection:
The completed Nyquist Macro plug-in:
When using built-in effects or "Scriptable" commands, it is recommended to use the optional LISP functions. Not only are they more Lisp-like and convenient to use, they also provide a little more error checking, which can be very helpful when debugging. Note however that there is a small performance penalty when using these LISP syntax commands. For performance critical applications (such as batch processing many small files), it may be preferred to use the AUD-DO versions.
Be flexible in your thinking. Scripting commands are available for many, but not all of Audacity's functions. If you need to do something that appears to be missing from the available commands, consider other ways to achieve the desired result.
If you get stuck, ask for help. As with other aspects of Nyquist programming, support requests may be made on the Nyquist board of the Audacity forum.
See also:
This tutorial provides a brief introduction to using stereo tracks in Nyquist programming.
If a sound from an Audacity stereo track was given to Nyquist, the *TRACK* variable contains an array of sounds. Because all Nyquist "snd-..." low-level functions only can process mono signals, to use such a function, the *TRACK* array first must be split into single mono signals and afterwards be re-combined into an array before it is given back to Audacity.
In Sal, one could write:
Or in LISP, one could write:
(arrayp *track*) - tests if '*track*' is an array
(vector ... ) - re-combines the two mono signals into a stereo signal. A "vector" is an one-dimensional array
(aref *track* 0) - the left stereo channel [the 0-th slot of the array]
(aref *track* 1) - the right stereo channel [the 1-st slot of the array]
Important: The Nyquist interface within Audacity can handle a maximum of two channels simultaneously [Audacity stereo tracks]. If in Audacity more than one audio track were selected, each of the selected tracks will be given sequentially, one after the other, with a maximum of two channels simultaneously [stereo] to Nyquist for processing. It is not possible with Nyquist in Audacity e.g. to copy audio signals from one Audacity track into another track.
In the "nyquist.lsp" file in the Audacity "nyquist" sub-directory, there is a function "multichan-expand" defined, which simplifies the handling of multi-channel sounds [e.g. stereo tracks]:
(multichan-expand function &rest arguments)
So the "arrayp" constuct from above can also be written:
This may look a bit more cryptic at first, but it can help to avoid long-winded audio processing functions.
In general terms, a variable is a symbol which contains a value. The symbol can be any valid name, and its value may be changed (hence "variable"). In Nyquist, the value may be of any data type (for example, a number, a character, or even a sound) and may be changed from one data type to another. Unlike some programming languages, variables do not need to be declared before use - they can just be set, and then they exist.
In addition to the value of the variable, one or more "properties" may also be attached to the symbol. Each "property" has a name and a value. The properties are known collectively as the symbol's "property list".
Setting the value of a symbol "binds" the value to the symbol. A symbol that has no value (not even "nil") is said to be "unbound".
In addition to the value of a symbol, we can also attach properties. This is a way of associating a list of items, each with their own value, to a single variable. Each item is called a key or indicator, and we can give each key a value. This list of items is called a "property list" (or plist for short).
To get the value of a property, we use the GET command.
When getting the value of a property, we do NOT want to evaluate either the variable (symbol) or the key symbol, so we must "quote" both symbols to prevent evaluation.
The following examples may be run in the Nyquist Prompt.
For a full list of global properties, see the Plugin reference.
When the type of a plug-in is process or analyze, Audacity sets the value of *TRACK* to the currently selected audio, and sets a lists of properties related to that track. The plug-in processes one track at a time in sequence, and the *TRACK* variable is set each time for the track that is being processed.
The value of *TRACK* provides direct access to the selected audio, and its property list provides access to other properties of the track. The NAME property provides the name of the Audacity track that is currently being processed. To access the value of the NAME property, we use the GET command.
The GET command returns the value of the property (the name of the track), which may be assigned to another variable and used elsewhere in the code. For example, to print a pretty message:
Although we can change the value of the NAME property (using PUTPROP), doing so will NOT change the name of the Audacity track. The value of the NAME property is only a copy of the track name, created by Audacity when the plug-in runs. If required, the name of the track could be changed using the scripting command SetTrackStatus. More generally, modifying a *TRACK* property does not modify the track.
See also Property List Functions in the XLisp manual.
This property contains a list of start and end times of each audio clip in the track. This property is more likely to find uses in Nyquist Macros than in standard Nyquist plug-ins. Note that this property refers to the entire selected track, and not only the selected portion of the track.
For mono tracks, the CLIPS property is a list, containing a two element list for each clip in the selected track. A mono track with two audio clips will look like ((s1 e1)(s2 e2))
where s1 and s2 to are the start times of the two clips, and e1 and e2 are the end times.
This code snippet will print the start and end times of the first audio clip in a mono track:
It is important to remember that Nyquist sees the start of the current selection as "time=zero". Thus if we wish to actual track times in Nyquist, we must offset the times by the start time of the current selection. We can create a point label at time=0 with (list (list 0 0 ""))
, but this is relative to the start of the current selection. If we want to create a label at time=zero as shown in the Timeline regardless of where the selection starts, then we must offset the label times by the start time of the selection.
Fortunately it is easy to find the absolute start time of the selection by using "START" property of the *SELECTION* variable: (get '*selection* 'start)
. We can create a label at an absolute time (relative to Audacity's Timeline) like this:
We can now put this all together and create a label for each audio clip in the selected track:
Just as stereo sounds are represented as an array of sounds, so the track "clip" data for stereo tracks is an array of lists (one list per channel). A stereo track with two audio clips in each channel will look like: #(((s1 e1)(s2 e2))((s3 e3)(s4 e3)))
where s1 to s4 to are the start times, and e1 to e4 are the end times.
This code snippet will print the start and end times of the first audio clip in the left channel of a stereo track:
In a similar manner to the mono example, we can create a label for each clip in a stereo track:
This tutorial provides a description and examples of how to create and use a File-Button Widget in Nyquist Plugins.
The File-Button Widget provides a means to select one or more files via a graphical file browser.
For some plug-ins it is necessary to read from or write to files. In order to do this, it is necessary to define precisely which file is required, where the file is located, and whether it is required for read access or write access (for read access, the file must exist, whereas for write access this is not always a requirement).
Prior to the availability of the File-Button Widget, file names could be hard coded into the Nyquist script, or a text box could be provided for the user to enter the name of the file. Hard coded file paths lack flexibility, are platform specific (a path starting with "C:\" does not work on Mac or Linux), and may point to locations that do not exist on some machines. While a text box may provide a better solution than hard coding a file path, it remains inconvenient and prone to user error, especially for long file paths. The File-Button Widget was introduced in Audacity 2.3.0 to solve these problems, by providing access to a graphical "file browser window" similar to using File menu > Open or File menu > Save in other applications.
The File-Button Widget, as shown above, has an editable text input field that allows a file path to be typed (or pasted). After the text input field is a button that launches a file browser. Below is an example of the familiar file browser window on Windows 10.
Note that selecting a file in this file browser does NOT open the file.
When a file is selected in the file browser window, the full name and path of the selected file is passed to the Nyquist script as the value of the File-Button Widget variable.
The syntax for creating a File-Button Widget is similar to all other Nyquist Plug-in widgets.
;control : Start of header statement. The leading semicolon ";" (or dollar character "$") tells Nyquist to treat this line as a comment and ignore it. The keyword "control" tells Audacity to create a GUI widget to be used by the Nyquist script.
variable-name : [symbol] The variable name that will be set.
text-left : [string] Text on the left side of the widget.
file : [keyword] Declares a "file" type widget.
button-text : [string] Text on the button. Normally this would be two double quotes (an empty string), which gives the default text: "Select a file"
default-file-path : [string] Default file path for the file browser. This supports keywords to aid cross-platform support.
wildcard-filters : [string] This is a magic "wildcard" string that follows the same syntax as wxFileDialog. The string comprises pairs of "description", pipe symbol ("|"), "file extension(s)". Multiple file extensions may be listed, separated by semi-colons (";").
flags : [string] This is a "magic" string that sets options for the file browser, following the same syntax as wxFileDialog.
The final three arguments, default-file-path, wildcard-filters, and flags, use special keywords that define the behavior of the File-Button Widget and the associated File Browser.
Note that unlike Nyquist symbols, these keywords are case sensitive.
The "Windows", "macOS" and "Linux" examples below refer to standard file paths for modern operating systems, though may be different on some machines.
"<username>" is the name of the computer user's account (log-in name).
"default file path" supports the keywords:
*home*" : The current user's "home" directory.
Windows: C:\Users\<username>
\
macOS: /Users/<username>
/
Linux: /home/<username>
/
~ : An alias for *home*.
*default* : The default "Documents" path.
Windows: C:\Users\<username>
\Documents\Audacity
macOS: /Users/<username>/
Documents/
Linux: /home/<username>
/Documents/
*export* The default "Export" path.
Windows: C:\Users\<username>
\Desktop\
macOS: /Users/<username>
/Documents/
Linux: /home/<username>
/Documents/
*save* The default "Save" path.
Windows: C:\Users\<username>
\Desktop\
macOS: /Users/<username>
/Documents/
Linux: /home/<username>
/Documents/
*config* The default configuration file directory.
Windows: C:\Users\<username>
\AppData\Roaming\audacity\
macOS: /Users/<username>
/Library/Application Support/audacity/
Linux: /home/<username>
/.audacity-data/
These keywords may be combined with a file name to specify which file to open. For example, if you want the default file to be called "sample-data.txt", and you want the default location to be the default "Documents" path, you could write the default file path parameter as: "*default*/sample-data.txt"
.
File paths should be quoted with double quotes, otherwise spaces in file name will fail. If no file path is provided, the default is "default". If no file name is provided, the default file name is "untitled". The default file extension is taken from the wildcard-filters.
The "wildcard-filters" determine which file types are visible in the file browser. An empty string will default to all files types.
This "magic string" follows the same syntax as wxFileDialog. The string comprises pairs of "description" and "file extension(s)", separated by a pipe character ("|"). Multiple file extensions may be listed, separated by semi-colons (";").
Example:
"Text file|*.txt;*.TXT|All files|*.*;*"
In this example we have two pairs:
Text file|*.txt;*.TXT: Description: "Text file" File extension "*.txt" matches: "anything.txt" File extension "*.TXT" matches: "anything.TXT"
All files|*.*;*: Description: "All files" File extension "*.*" matches: "anything.anything" File extension "*" matches: "anything"
The magic "flags" string is similar to the "Styles" options in wxFileDialog. Flags may be an empty string, a single keyword, or a comma separated list of keywords.
Available keywords are:
open : This is a "file open" dialog. Usually this means that the default button's label of the dialog is "Open". Cannot be combined with "save"
save : This is a "file save" dialog. Usually this means that the default button's label of the dialog is "Save". Cannot be combined with "open".
overwrite : For save dialog only: prompt for a confirmation if a file will be overwritten.
exists : For open dialog only: the user may only select files that actually exist
multiple : For open dialog only: allows selecting multiple files.
Example: Open file dialog for one or more files that must exist.
"open,exists,multiple"
Example: Save file dialog with overwrite prompt if file exists.
"save,overwrite"
The File-Button widget attempts to create a valid file path as a string, and assign it to the "variable-name" symbol.
If a single file is selected using the file browser, then the widget text box is updated to show the full path to the selected file.
If multiple files are selected using the file browser (requires "multiple" flag to be set), each file path is enclosed in double quotes. Note: The list of file paths is NOT a LISP list. It is still a string. See example below for how to deal with multiple file paths.
If the file path text box is empty, then the widget variable symbol is set to the default path.
If the file path text box contains only a file name (or any string that is not a path), then it is prepended with the default path and assigned as the value of the widget variable.
In the event of programming or user errors, the File-Button Widget may return an error message. Understanding these messages can be a great help when debugging a new plug-in.
<Path>
is not a valid file path.
****This error occurs if the returned file path is invalid, for example, if the directory does not exist. : This error is most likely to be due to the user manually editing the file path text box with an invalid file path.
Mismatched quotes in <string>
****When the "multiple" flag is set, the file browser returns a list of quoted strings for each path. This error is thrown if the opening quotes do not have matching closing quotes. : This error is most likely to be due to the user manually editing the file path text box and missing one or more quote characters.
Invalid wildcard string in 'path' control. Using empty string instead. ****This error occurs if the 'wildcard' magic string is malformed. : This is a programming error. Check the syntax of your wildcard string.
Simple "Open File" Example
;control var "Select file to open" file "" "" "" ""
In this example. only the variable ("var") and the "text-left" ("Select file to open") are explicitly set. Empty strings are passed to the other parameters, so they will all take default values.
In reverse order: the default "flag" is "open", the default wildcard filter is "All files", the default file path is "*default*", the default file name is "untitled", and the default button text is "Select a file".
Simple "Save File" Example
;control var "Select file to save" file "" "" "" "save"
Very much like the simple "open file" example above, except this one is selecting a file for writing.
Advanced "Open File" Example
;control filename "Select file" file "" "*default*/sample-data.txt" "Text file|*.txt;*.TXT|All files|*.*;*" "open,exists"
Unlike the previous examples, all parameters are explicitly defined. The default file name is "sample-data.txt", and by default the file browser filters the file list to show Text files only (ending in ".txt" or ".TXT"). The file browser also has an option to show all files.
Note that the file browser is created by the underlying operating system, so there are subtle differences across platforms. The "exists" flag is only relevant for file browsers that allow you to type the file name. For a purely graphical browser it is not possible to select a file that does not exist.
Note also that the "exists" flag only affects the file browser - it does not prevent the user typing a non-existent file name in the file path text field. If the plug-in requires the file to exist, then the plug-in code should run a test to ensure that it does. A simple test for the existence of a file, is to try and open it, for example:
Advanced "Save File" Example
;control filename "Export data to" file "Select a file" "*default*/sample-data.txt" "Text file|*.txt;*.TXT|CSV files|*.csv;*.CSV|HTML files|*.html;*.HTML;*.htm;*.HTM|All files|*.*;*" "save,overwrite"
In this example, all parameters are explicitly defined:
variable-name: filename
text-left: "Export data to"
button-text: "Select a file"
default-file-path: "*default*/sample-data.txt"
wildcard-filters: ****Text file|*.txt;*.TXT| CSV files|*.csv;*.CSV| HTML files|*.html;*.HTML;*.htm;*.HTM| All files|*.*;*"
flags : "save,overwrite"
The wildcard filters provide options in the file browser to show either text files (.txt or .TXT), which is the default, or CSV files (.csv pr .CSV), or HTML files (.html, or .HTML, or .htm, or .HTM), or "All files" (any file name).
Note that on Windows, file extensions are not case sensitive, but Linux, and some Mac computers are case sensitive, so for cross-platform portability it is recommended to use both upper and lower case file name extensions.
Open Multiple Files
;control var "Select one or more files" file "Select" "*default*" "Text file|*.txt;*.TXT|All files|*.*;*" "open,multiple"
In this example, the variable that will be set is var
, the default directory is *default*
, and the default file type filter is for text files (with an option to show all files). Unlike the previous versions, the file browser may be used to select multiple files (requires Audacity 2.3.1 or later).
If the users selects one or more files using the file browser, then each file path will be enclosed in double quotes. However, the user could type in the path to a single file without quotes, or, as in this case, the default could be an unquoted single file path, so we should check for and support both versions.
To extract all of the the paths from the returned string, we first need to convert it to a more useful form, such as a LISP list:
(setf path-string
(format nil "(list ~s )" (string-trim "\"" var)))
Here we have stripped the outer double quotes (if present), and then formatted it into a string that describes a LISP list. So, for example, if the selected files were: "C:\first.txt" and "C:\second.txt", then the value of var
would be ""C:\first.txt""C:\second.txt""
, and the value of path-string
would be "(list "C:\first.txt" "C:\second.text")"
.
Important: Note that this is still only a string value, not a LISP list.
To convert this string into a LISP list, we need to evaluate the string as if it were code. Fortunately in Audacity 2.3.1 and later, there is an easy way to do this with the EVAL-STRING
function:
(setf paths (eval-string path-string))
paths
is now a valid LISP list of strings, which we can iterate through like this:
(dolist (p paths)
(print p))
The complete example that can run in the Nyquist Prompt:
These example applications may be run in the Nyquist Prompt, or could be converted to plug-ins by adding full plug-in headers.
These code examples are excessively commented so as to explain what they are doing. For production code, comments should be concise and provide clarification where the intent is not obvious. As far as possible, the code should be self explanatory, but as this is intended for learning purposes, additional explanatory comments are included.
In this example, we use a File-Button widget to specify a file that will be written to. It is important to note that selecting the file does NOT write to the file, it only captures the file path and file name, which we then write to later in the script. The plug-in will get some information about the selected audio, and write (append) it to a file.
First we start with a couple of headers to set the syntax version and plug-in type.
;version 4
;type analyze
Next is our File-Button widget. Note that it has the "save" flag because we are selecting a file to write to.
;control filename "Export to" file "" "data.txt" "Text file|*.txt;*.TXT|All files|*.*;*" "save"
The next three code lines gather the raw information that we will be writing to the file.
When we write to a file with Nyquist, the file is overwritten by the data that we are writing. As we want to append the new data to the file rather than overwriting it, we must first read the existing text from the file and store it in a variable. We can then write the old data, plus the new data back to the file. Here is a function that will read the contents of the file if it exists, and returns the data to the function caller.
As this code is designed to work with text files, we can check that the file name ends with ".txt".
The file name extension is NOT a reliable way to test the file type. In any situation where security is a concern, the file extension must not be relied as an indicator of the file type.
First we assign an empty string as the value of the variable ext
.
If the file name is at least 4 characters long, we extract the last 4 characters and assign it as the value of ext
.
We can then apply a case insensitive string comparison. If ext
is equal to .txt, then we assume it is a plain text file.
So now we can run our main program, which is within a program prog block.
The program block begins by binding a local variable {{inlineCode|data}}
{=mediawiki} to the data returned by the {{inlineCode|read-file}}
{=mediawiki} function (defined above).
Then we open the file for writing.
And then the data can be written to the open file.
After reading or writing to a file, the file should be closed again.
Finally we return an acknowledgment message.
If the file did not end with .txt, we return an error message.
The Complete Code:
This is an advanced example that uses the File-Button widget to read data from one or more text files. Text handling is not one of Nyquist's strengths (Nyquist is primarily designed for handling audio), hence parsing the text file data is quite complex.
In this example, we will import (read) labels from one or more text files.
For simplicity, we will deal only with the basic label format and not support "spectral" labels.
The data format we will use is compatible with exported labels, provided that Spectral Selections are NOT used.
For this plug-in, we will specify that the label data file has one label definition per line, and each label definition has a start time (in seconds), and end time (in seconds) and optional label text. The numbers and optional label text may be separated by spaces or tabs. The data should be saved as plain text, with a ".txt" file extension.
Example Data:
The Complete Code:
This page provides a brief introduction to using the *SCRATCH* symbol in Nyquist programming.
*SCRATCH* is a global symbol, specific to Nyquist in Audacity, which is not deleted in-between plug-in runs. It provides a way for information to survive from one invocation of a plug-in to the next. However, you should not rely on the "value" of *SCRATCH* beyond a single invocation of a plug-in as it could be overwritten by another plug-in. It is better to use property lists of *SCRATCH*. That way, you get a whole name space rather than a single variable name, and with careful naming of the property keys, name collisions can be avoided.
To pass data from plug-in "effectX-partA" to "effectX-partB":
1. Assign a property name based on the effect name, e.g.: 'EFFECTX [or in SAL, which does not support the single-quote notation of LISP, write QUOTE(EFFECTX). ]
2. "effectX-partA" should delete any old property value:
3. "effectX-partA" should compute a new property value v and save it:
4. "effectX-partB" should access the property using:
5. When "effectX-partB" finishes, it should remove the property:
But there may be cases where you do some analysis and want to use the analysis data multiple times. You might even have multiple analysis plug-ins operating on different inputs to collect data to feed into a plug-in with multiple inputs. In this case, which might be quite common, you should not call REMPROP(), but this has the problem of leaving data on the *SCRATCH* property list indefinitely.
In cases where *SCRATCH* data is not deleted immediately after use, and where there is the potential to leave large amounts of memory there, there should be another effect, e.g. "effectX-partCleanup", that simply calls:
allowing the user to explicitly free up any data stored on the 'EFFECTX property. It would be reasonable to omit the "effectX-partCleanup" effect if the data stored on the property list has a maximum size of, say, 10KB. The problem we want to avoid is properties with unbounded size getting left in the heap until Audacity is restarted.