JSFX file structure
Basic code reference
Simple math functions
MIDI Bus Support
File I/O and Serialization
User defined functions and namespace pseudo-objects
This is a reference guide to programming audio-oriented effects
for REAPER using JS. JS is a scripting language which is compiled
on the fly and allows you to modify and/or generate audio and MIDI,
as well as draw custom vector based UI and analysis displays.
JS effects are simple text files, which when loaded in REAPER become
full featured plug-ins. You can try loading existing JS effects and
since they are distributed in source form, you can also edit existing
effects to suit your needs (we recommend if editing an existing effect
you save it as something with a new name--if you do not you may lose
your changes when upgrading REAPER).
This guide will offer an outline of the structure of the text file
used by JS, the syntax for writing code, as well as a list of all
functions and special variables available for use.
top JSFX file structure
JS Effects are text files that are composed of some description lines followed by one or more code sections.
The description lines that can be specified are:
Following the description lines, there should be code sections. All of the code sections are optional (though an effect without any would likely have limited use). Code sections are declared by a single line, then followed by as much code as needed until the end of the file, or until the next code section. Each code section can only be defined once. The following code sections are currently used:
- desc:Effect Description
This line should be specified once and only once, and defines the name of the effect which will be displayed to the user.
Ideally this line should be the first line of the file, so that it can be quickly identified as a JS file.
- slider1:5<0,10,1>slider description
You can specify multiple of these lines (from 1-64 currently) to specify parameters that the user can control using standard
UI controls (typically a fader and text input, but this can vary, see below). These parameters are also automatable from REAPER.
In the above example, the first 1 specifies the first parameter, 5 is the default value of the parameter, 0 is
the minimum value, 10 is the maximum value, and 1 is the change increment. slider description
is what is displayed to the user.
There are additional extended slider syntaxes. One is:
This will show this parameter with a list of options from "zerolabel" to "fivelabel". Note that these parameters should be set to
start at 0 and have a change increment of 1, as shown above.
Another extended syntax is:
In the above example, the /some_path specifies a subdirectory of the REAPER\Data path, which will be scanned for .wav, .txt, .ogg, or .raw files. default_value defines a default filename. If this is used, the script will generally use file_open(slider1) in the @serialize code section to read the contents of the selected file.
You can also hide sliders by prefixing their names with "-":
Such parameters will not be visible in the plug-in UI but still be active, automatable, etc.
These optional lines export names for each of the JS pins (effect channels), for display in REAPER's plug-in pin connector dialog.
If the only named in_pin or out_pin is labeled "none", REAPER will know that the effect has no audio inputs and/or outputs, which enables some processing optimizations. MIDI-only FX should specify in_pin:none and out_pin:none.
These lines can be used to specify filenames which can be used by code later.
These definitions include 0 (the index) and a filename. The indices must be listed in order without gaps -- i.e. the first should always be 0, the second (if any) always should be 1, and so on.
To use for generic data files, the files should be located in the REAPER\Data directory, and these can be opened with file_open(), passing the filename index.
You may also specify a PNG file. If you specify a file ending in .png, it will be opened from the same directory as the effect, and you can use the filename index as a parameter to gfx_blit(). -- REAPER 2.018+
This line can be used to specify JSFX options:
This option allows plugins to allocate their own global shared buffer, see gmem.
Enables the "Send all keyboard input to plug-in" option for new instances of the plug-in, see gfx_getchar().
- import filename -- REAPER v4.25+
You can specify a filename to import (this filename will be searched within the JS effect directory). Importing files via this directive will have any functions defined in their @init sections available to the local effect. Additionally, if the imported file implements other sections (such as @sample, etc), and the importing file does not implement those sections, the imported version of those sections will be used.
Note that files that are designed for import only (such as function libraries) should ideally be named xyz.jsfx-inc, as these will be ignored in the user FX list in REAPER.
The code in the @init section gets executed on effect load, on samplerate changes, and on start of playback. If you wish this code to not execute on start of playback, you can set ext_noinit to 1.0, and it will only execute on load or samplerate change (and not on playback start/stop).
All memory and variables are zero on load, and if no @serialize code section is defined, then all memory and variables will be re-zeroed before calling @init (on samplerate change, playback start/stop/etc).
The code in the @slider section gets executed following an @init, or when a parameter (slider) changes. Ideally code in here should detect when a slider has changed, and adapt to the new parameters (ideally avoiding clicks or glitches). The parameters defined with sliderX: can be read using the variables sliderX.
The code in the @block section is executed before processing each sample block. Typically a block is whatever length as defined by the audio hardware, or anywhere from 128-2048 samples. In this code section the samplesblock variable will be valid (and set to the size of the upcoming block).
The code in the @sample section is executed for every PCM audio sample. This code can analyze, process, or synthesize, by reading, modifying, or writing to the variables spl0, spl1, ... spl63.
The code in the @serialize section is executed when the plug-in needs to load or save some extended state. The sliderX parameters are saved automatically, but if there are internal state variables or memory that should be saved, they should be
saved/restored here using file_var() or file_mem() (passing an argument of 0 for the file handle). (If the code needs to detect whether it is saving or loading, it can do so with file_avail() (file_avail(0) will return <0 if it is writing).
Note when saving the state of variables or memory, they are stored in a more compact 32 bit representation, so a slight precision loss is possible. Note also that you should not clear any variables saved/loaded by @serialize in @init, as sometimes @init will be called following @serialize.
- @gfx [width] [height]
The @gfx section gets executed around 30 times a second when the plug-ins GUI is open. You can do whatever processing you like in this (Typically using gfx_*()). Note that this code runs in a separate thread from the audio processing, so you may have both running simultaneously which could leave certain variables/RAM in an unpredictable state.
The @gfx section has two optional parameters, which can specify the desired width/height of the graphics area. Set either of these to 0 (or omit them) to specify that the code doesn't care what size it gets. Note that these are simply
hints to request this size -- you may not always get the specified size. Your code in this section should use the gfx_w, gfx_h variables to actually determine drawing dimensions.