Difference between revisions of "Nyquist Plug-ins Reference"
m (Changed stuff at the top of page) |
Windinthew (talk | contribs) (remove template brackets from URL) |
||
Line 407: | Line 407: | ||
The Nyquist Workbench is an Audacity module, which currently [Audacity 1.3.9, November 2009] is no official part of the Audacity distribution. The source code can be downloaded from | The Nyquist Workbench is an Audacity module, which currently [Audacity 1.3.9, November 2009] is no official part of the Audacity distribution. The source code can be downloaded from | ||
− | + | http://audacity.homerow.net/index.php?dir=modules%2F. | |
Download the "NyqBench" zip-archive from the URL above and unpack it on your harddisk. In the "Readme.txt" file in the Nyquist Workbench source code directory you will find instructions how to compile the Nyquist Workbench on your operation system. | Download the "NyqBench" zip-archive from the URL above and unpack it on your harddisk. In the "Readme.txt" file in the Nyquist Workbench source code directory you will find instructions how to compile the Nyquist Workbench on your operation system. |
Revision as of 02:42, 5 November 2010
This page offers a detailed look at Nyquist Plug-ins. It is intended for people who wish to write their own plug-ins.
|
Related article(s):
Please note: Nyquist supports both a LISP syntax and a more conventional syntax called SAL. You can choose a manual from a link above based on which syntax you are using.
|
Contents
The Audacity Nyquist Interface is implemented in the following files in the Audacity source code:
- audacity/src/effects/nyquist/Nyquist.cpp
- audacity/lib-src/libnyquist/nyx.c
Overview
Nyquist plug-ins are simple text files ending with the filename extension ".ny". When Audacity starts, it looks in a plug-ins directory for files and automatically adds the effects it finds there to the Audacity menus. The plug-ins can be written in either LISP or SAL syntax. When the user selects the plug-in from the menu, Audacity causes the Nyquist language runtime system (built into Audacity) to run the plug-in code to process or generate audio. You can also compute strings to display to the user or compute labels to be shown on a new label track.
Before running the plug-in, Audacity parses some of the plug-in text looking for specially formatted comments that describe "widgets" -- controls that the user can use to set parameters for the effect. For example, your plug-in can display a slider to control volume or filter frequency. Values from the widgets are passed through global variables to the plug-in.
For a full description of the plug-in language, read the Nyquist Reference Manual. There are, however, some details of how plug-in code is processed that is unique to plug-ins and therefore not covered in the Nyquist manual. The main thing to know is that the variable s is the selected sound. This is probably the main input to your effect. The second thing to know is how sound is returned from Nyquist to Audacity.
SAL syntax is inherently command oriented. A SAL plug-in should consist of a sequence of SAL commands including define commands to define variables and functions. There must be a function definition for main. After performing the commands in sequence, Audacity calls main (with no parameters). The value returned from main is the result of the plug-in (normally this should be a sound).
One exception to this is the
effect. Since defining main just to evaluate and return a simple expression is so awkward, you can simply typereturn expression
Normally, this is not a legal statement as a top-level command in SAL, but in
, special processing embeds the return statement into a declaration of function main, which is then called. This trick also works for regular plug-ins, but defining main is the preferred style.For LISP syntax plug-ins, Lisp expressions are read and evaluated one-at-a-time. The value returned by the last expression is the result of the plug-in. The same semantics applies to the {{Menu|Nyquist Prompt...} effect. There is only one "Nyquist Prompt" for both SAL and LISP syntax. Audacity looks for the first non-space character that is not part of a comment. If it is an open paren "(", then the code is assumed to be LISP; otherwise, SAL is assumed.
The "Nyquist Prompt" effect is not equivalent to plug-ins because Audacity processes the plug-in header information from plug-in files, but the "Nyquist Prompt" effect ignores them (they are just comments).
Nyquist Plugin Header
The Nyquist Lisp interpreter as well as the Nyquist SAL compiler in contrast recognize everything after the first semicolon up to the end of the line as a comment and just simply ignores it. So in the Nyquist code, below the plugin header, comments can also be started with several semicolons in a row.
;nyquist plug-in ;version version ;type type ;name "name" ;action "text" ;categories "text" ;info "text" ;control parameters ;codetype type ;debugflags flags
The "categories", "info", "control", "codetype", and "debugflags" lines are optional and can be omitted.
Required plugin header lines
nyquist plug-in
Tells Audacity "this is a Nyquist plugin":
;nyquist plug-in
version 1
Only the Slider widget is supported:
;version 1
version 2
The Text input widget was added in Audacity 1.2:
;version 2
version 3
The multiple-Choice widget was added in Audacity 1.3:
;version 3
type generate
Plugin appears in the Audacity
menu:;type generate
type process
Plugin appears in the Audacity
menu:;type process
type analyze
Plugin appears in the Audacity
menu:;type analyze
name
Name of the plug-in as it will appear in the Audacity menu:
;name "name"
action
Text to be displayed while the plugin is working:
;action "text"
Optional plug-in header lines
categories
LV2 categories, see Categories below.
;categories "text"
info
Text to be displayed at the top border of the plug-in window:
;info "text"
A two-character sequence "\n" within "text" causes a line break. It is not possible to "quote" a line break in the plug-in code with a backslash '\' at the end of the line. In the plug-in header, the text in the "action" and "info" lines must be written in one single line.
control
Define a plug-in widget. There can be several "control" lines in the plug-in header. Add one for each widget to appear in the dialog box -- see Nyquist Plug-in Widgets below:
;control parameters
codetype lisp
The syntax of the plugin is Lisp. This is the default if the "codetype" line is missing:
;codetype lisp
codetype sal
The syntax of the plugin is SAL. The default is "lisp".
;codetype sal
debugflags
See Internal Debug Options below:
;debugflags flags
LV2 categories were introduced in Audacity as part of "Google Summer of Code 2008": [Support].
The categories were tried out in the 1.3.6 Beta version of Audacity, but it was unpopular with the majority of users because of the extra navigation involved to reach the effects. Categories will not be re-introduced until it is provided with a way by which the user can turn the grouping on and off in the interface.
The "categories" header line is currently optional.
There is an optional "debugflags" line available, which skips the plug-in window and directly executes the plug-in code, so if a "debugflags" line is found in the plug-in header no user-interaction is possible.
Set *tracenable* to true. The plug-in behaves as if the "Debug" button was clicked by the user. This is the default:
;debugflags trace
Set *tracenable* to 'false'. The plug-in behaves as if the 'OK' button was clicked by the user:
;debugflags notrace
Set *sal-compiler-debug* to true. This prints the compiler's translation of SAL to LISP before evaluating the translated code:
;debugflags compiler
Set *sal-compiler-debug* to 'false'. This is the default.
;debugflags nocompilerIn the Nyquist Workbench, the "compiler" and "nocompiler" debugflags control whether the generated Lisp code from the SAL compiler will be sent to "stdout" or to the output window in the Nyquist Workbench.
Nyquist Plug-in Widgets
Every ";control" line gets parsed by Audacity into several tokens, where each token is separated by one or several whitespaces:
;control | var-name | text-left | widget-type | text-right | initial-value | minimum | maximum |
---|---|---|---|---|---|---|---|
;control | symbol | string | int | string | integer | integer | integer |
;control | symbol | string | real | string | float | float | float |
;control | symbol | string | string | string | string | - | - |
;control | symbol | string | choice | string | integer | - | - |
Italic words in the table denote data types. Because tokens are separated by whitepace, strings containing whitespace must be written within quotation marks. Do not try to memorize this table, use it as a reference. The detailed syntax for each widget type is described in the following sections.
Slider Widget
Slider widgets are supported in all Audacity Nyquist plugin versions.
;control variable-name "text-left" variable-type "text-right" initial-value minimum maximum
- variable-name - a Lisp symbol.
- text-left - text that will appear to the left of the slider.
- variable-type - a "number" type, either int or real:
- int - integer [FIXNUM, an XLISP number without a dot]
- real - floating point [FLONUM, an XLISP number with a dot]
- text-right - text that will appear to the right of the slider.
- initial-value - variable value [and slider position] at the first start of the plug-in.
- minimum - numerical variable value when the slider is moved to the left border.
- maximum - numerical variable value when the slider is moved to the right border.
The variable value [the slider position] can be referenced by the variable name in the plug-in code.
In more recent versions of Audacity there appears a text input box beside the slider, where the user can type in a variable value via the keyboard. Note that it's up to the plug-in programmer to catch undesired values typed in by the user.
Text Input Widget
The text input widget is supported in plugins version 2 or above, it will not work in Audacity 1.1 and below.
;control variable-name "text-left" string "text-right" "initial-string"
- variable-name - a Lisp symbol.
- text-left - text that will appear to the left of the text input field.
- text-right - text that will appear to the right of the text input field.
- initial-string - the string will appear inside the text field.
The text typed in by the user in the text field of the plug-in window can be referred as a string variable from within the plug-in code.
Examples how to use the text input widget can be found in the source code of the Apropos plugin.
Multiple-Choice Widget
The choice widget is supported in plug-ins version 3 or above, it will not work in Audacity 1.2 or below.
;control variable-name "text-left" choice "string-1,string-2,..." initial-value
- variable-name - a Lisp symbol.
- text-left - text that will appear to the left of the multiple-choice list.
- string-1,... - for every string an entry in a list to choose from will be produced.
- initial-value - the number of the list entry that will be displayed as the default choice at the first start of the plug-in.
The list entries string-1, string-2, etc. are internally represented by integer numbers. The first, top-most list entry string-1 will be represented by the number 0. The list entry chosen by the user can be determined by the integer value of the variable from within the plug-in code.
Examples how to use the 'choice' widget can be found in the source code of the Apropos plugin.
Nyquist Variables
The variables given from Audacity to Nyquist are defined in the file "audacity/lib-src/libnyquist/nyx/nyx.c" in the Audacity source code.
The following variables are given from Audacity to Nyquist:
- s - the Audacity sound [the selected part of the Audacity audio track]
- len - the number of samples contained in s
- *sound-srate* - the sample frequency of the Audacity track
- *warp* - information that communicates start-time and duration to Nyquist functions. In Audacity, the start-time is always considered to be zero (regardless of the actual start time of the selection) and the duration indicates the duration of the selection.
- *scratch* - a symbol whose value and property list are preserved from one effect invocation to the next. See "The *scratch* Symbol" below.
The length of the sound in seconds can be computed one of the following ways:
(/ len *sound-srate*) ; in LISP (get-duration 1) ; in LISP
len / *sound-srate* ; in SAL get-duration(1) </i>; in SAL</i>
The *scratch* Symbol
Since Audacity 1.3.9, there is a new global symbol *scratch*, which is not deleted in-between plugin runs.
The point of *scratch* is to provide some way for information to survive from one invocation of a plug-in to the next. Because of the possibility that different effects could interact in undesirable ways by setting *scratch*, it is recommended to use only property lists of *scratch*. That way, you get a whole name space rather than a single variable name.
To pass data from plugin "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:
exec remprop(quote(*scratch*), quote(effectx)) ;; in SAL
(remprop '*scratch* 'effectx) ;; in LISP
3. "effectX-partA" should compute a new property value v and save it:
exec putprop(quote(*scratch*), v, quote(effectx)) ;; in SAL
(putprop '*scratch* v 'effectx) ;; in LISP
4. "effectX-partB" should access the property using:
set v = get(quote(*scratch*), quote(effectx)) ;; in SAL
(get '*scratch* 'effectx) ;; in LISP
5. When "effectX-partB" finishes, it should remove the property:
exec remprop(quote(*scratch*), quote(effectx)) ;; in SAL
(remprop '*scratch* 'effectx) ;; in LISP
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:
exec remprop(quote(*scratch*), quote(effectx)) ;; in SAL
(remprop '*scratch* 'effectx) ;; in LISP
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.
Stereo Tracks
If a sound from an Audacity stereo track was given to Nyquist, the s variable contains an array of sounds. Because all Nyquist "snd-..." low-level functions only can process mono signals, to use such a function, the s 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:
if arrayp(s) then return vector(snd-function(s[0]), snd-function(s[1])) else return snd-function(s)
Or in LISP, one could write:
(if (arrayp s) (vector (snd-function (aref s 0)) ; left stereo channel (snd-function (aref s 1))) ; right stereo channel (snd-function s)) ; mono signal
- (arrayp s) - tests if 's' is an array
- (vector ... ) - re-combines the two mono signals into a stereo signal. A "vector" is an one-dimensional array
- (aref s 0) - the left stereo channel [the 0-th slot of the array]
- (aref s 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 [Audacity 1.3.9, November 2009].
multichan-expand
In the "nyquist.lsp" file in the Audacity "nyquist" sub-directory there is a function "multichan-expand" defined that 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:
return multichan-expand(quote(snd-function), s) ;; in SAL
(multichan-expand #'snd-function s) ;; in LISP
This looks a bit more cryptic and reads less intelligibly [to some], but it can help to clean up the code in long-winded audio processing functions.
Return Values
The result of the last computation within the plugin code will be given back from Nyquist to Audacity. According to the data type of the Nyquist return value one of the following actions will be invoked in Audacity:
- sound - the sound will be re-inserted into the selected part of the Audacity track. If the returned sound is shorter or longer than the original sound, the selection will be reduced or augmented. If a mono sound is returned to a stereo track, so in both channels of the stereo track the same mono sound will be inserted. If a stereo sound is returned to a mono track, an error message will be displayed.
- string - a dialog window will appear with the string being displayed as text.
- list - if a specially formatted list [see below] will be given back to Audacity, a label track will be created below the audio track[s].
The list to create a label track must have the following format:
((int-or-float "string") (int-or-float "string") ... )
- int-or-float - the time in seconds from the beginning of the Audacity selection, where the label will appear.
- "string" - a string to be displayed in the label's text field.
Math Functions
n-th power of x:
power(x, n) ;; in SAL (power x n) ;; in LISP
n-th root of a number:
power(x, 1.0 / n) ;; in SAL (power x (/ 1.0 n)) ;; in LISP
n-th root of a sound s:
return s-exp(s-log(s) * (1.0 / n)) ;; in SAL (s-exp (mult (s-log s) (/ 1.0 n))) ;; in LISP
n-th root with two sounds x and n:
return s-exp(s-log(x) * s-recip(n)) ;; in SAL (s-exp (mult (s-log x) (s-recip n))) ;; in LISP
Nyquist Workbench
The Nyquist Workbench gives the ability to run arbitrary Nyquist code in Audacity from a graphical IDE.
The Nyquist Workbench is an Audacity module, which currently [Audacity 1.3.9, November 2009] is no official part of the Audacity distribution. The source code can be downloaded from http://audacity.homerow.net/index.php?dir=modules%2F.
Download the "NyqBench" zip-archive from the URL above and unpack it on your harddisk. In the "Readme.txt" file in the Nyquist Workbench source code directory you will find instructions how to compile the Nyquist Workbench on your operation system.
Here is how it works on Linux:
1. First type "./configure" in the Audacity source code directory:
./configure
After "configure" has finished, do not type "make", you first need to compile the Nyquist Workbench.
2. Open the Makefile in the Nyquist Workbench directory and make the AUDACITY_DIR variable at the top of the Makefile point to the base of the Audacity source code directory:
AUDACITY_DIR ?= /home/edgar/downloads/audacity
Of course you need to replace "/home/edgar/downloads/audacity" with the Audacity source code directory on your hard disk.
3. After saving the changes in the Makefile, compile the Nyquist Workbench. In the Nyquist Workbench directory type:
make
After "make" has finished you should see a message like:
NyqBench.so has been copied to /home/edgar/downloads/audacity/modules
4. Now compile Audacity. In the Audacity source code directory type:
make
5. If 'make' has finished successfully, still in the Audacity source code directory, type:
sudo make install
6. Currently [Audacity 1.3.10-alpha, November 2009] the Audacity "make install" does not copy the "modules" directory, so type:
sudo cp -r modules /usr/local/share/audacity
This copies the "modules" directory including everything inside from the Audacity source code directory to "/usr/local/share/audacity/modules".
7. After the next start of Audacity, you should have an additional Audacity "Tools" menu with a "Nyquist Workbench" entry inside.
Nyquist Apropos Plugin
Because not all functions, documented in the Nyquist manual, are implemented in Audacity and also not even all Nyquist functions are documented in the Nyquist manual [Lisp is a "programmable programming language", only functions which are considered as stable are documented], it is often helpful to have a tool to find out whether a particular Nyquist function is implemented or not.
Basically only Nyquist functions beginning with "snd-..." are implemented in C within the Nyquist interpreter [in the Nyquist manual they are called 'low-level' functions], while all other Nyquist functions are implemented in the Lisp files within the Audacity "nyquist" sub-directory and can be changed, improved and extended with no need to re-compile Audacity [as long as no C-implemented Nyquist "low-level" function is needed which is not included with Nyquist in Audacity].
All Nyquist/XLISP symbols [e.g. all variable and function names] are stored in the XLISP *obarray*. To find out from within Audacity, whether a particular function is implemented or not, you can e.g. first create and select a "dummy" audio track with any generator from the Audacity
menu, then open [doesn't work without a selected audio track] and copy the following line into the "Nyquist Prompt" text input field:(print (fboundp 'snd-abs))
Important: now please click "Debug" instead of the "OK" button.
First a dialog appears telling you: "Nyquist did not return audio" [or similar]. In this dialog, click the "OK" button. Then another dialog "Nyquist output" appears with the result of the "print" function:
- T - meaning "true", function is implemented
- NIL - meaning "false", function is not implemented
I had typed this so often in the past that I have written an Audacity Nyquist "Apropos" plug-in:
Download: Apropos-Plugin
Right-Click on the plug-in link, choose "save target as", and save the file "apropos.ny" file in the Audacity "Plug-Ins" sub-directory. After a re-start of Audacity you can find the "Apropos" plugin in the
menu, the only menu that works without a "dummy" audio track.The "Apropos" plugin offers a pattern search through the Nyquist/XLISP *obarray*. You can also choose between "Functions only", "Variables only" and "All symbols":
Note: with no search pattern [empty field], the plug-in matches all symbol names.
First appears a dialog that reminds me that I have forgotten to press the "Debug" button:
In the first dialog above, just klick the "OK" button. Afterwards, but only if you have clicked the "Debug" button in the plug-in window, appears the window with the results, sorted in alphabetical order: