Note: the most recent updated JSFX documentation is available here: REAPER/JS Programming Reference.

The old, outdated version follows:

JSFX Coding Documentation HTML Dump

Version 1.0, Copyright (C) 2004-2007, Cockos Incorporated

editor keys, effect format, code format, reference

Editor Controls

JSFX Editor Controls The text editor is similar to most standard text editors. Here is a list of some of the less obvious controls: ESC, Ctrl+Q: quit the editor (prompt for save) Ctrl+S: save (and recompile) effect Ctrl+N: save as new effect Ctrl+R: toggle auto recompiling (recompile on edit) Ctrl+Z: undo Ctrl+Y: redo Ctrl+F: find string Ctrl+G: find next Ctrl+K: look up symbol (can use to debug the value of a variable) Insert: toggle overwrite mode Text selection / copy / paste: Ctrl+E: select text (once in select mode, use arrow keys) Ctrl+C: copy text Ctrl+X: cut text Ctrl+V: paste text Ctrl+A: select all

Effect Format

JSFX Effect Format -------------------------------------------------------------------------------- Using the effect editor, you may modify existing effects as well as create new effects. Effects are composed of eight parts: 1. User readable description of the effect desc:effect description This provides a user-readable description of the effect. For example, you may wish to describe what it does, i.e. 'Reverb' or 'Delay', etc. 2. 'Slider' definition(s) slider1:5<0,10,1>slider description ... You may specify as few as none and as many as eight of these, ranging from slider1 to slider8. The first value in the above definition (5) specifies the default value of the slider. The second value (0) specifies the minimum extent of the slider, and the third value (10) specifies the maximum extent. Finally, the fourth value (1), which is optional, specifies the increment of the slider when using the knobs/arrow keys. If not specified this defaults to 1/100th of the slider range. There are also some extended slider syntaxes. One is to have name aliases for positive integer values of the slider. Here is an example: slider1:0<0,2,1{off,on,really really on}>my option This will allow the user to switch between off, on and really really on which corresponds to 0, 1 and 2. The other extended slider syntax allows the user to select files in a particular directory, and then code in @slider can open and read the selected file. For example: slider1:/my_directory:default_value:slider name This will look in data/my_directory for all files of .wav, .txt, or .raw. Later, in the @slider section, you can have code: lastslider1 != (slider1|0) ? ( lastslider1=slider1|0; myfile = file_open(slider1); myfile > 0 ? ( file_var(myfile,somevar); file_close(myfile); ) ); 3. Data filename definition(s) (optional) filename:0,filename.raw filename:1,somefile.wav Specify a list of filenames which can be opened with file_open() in user code. This is list of files must be in order and not skip any values, starting with 0. To open the files in your code, use file_open(index). See file_open() for more information. 4. Initialization code @init myvar=0; somevar=32; ... Initialization code is specified by @init on a line by itself, followed by any number of lines of code (see the Code Format page for code format). Initialization code is executed on the first load of an effect. Use this to initialize any variables that only need to be initialized once, i.e. constants. 5. Slider change code @slider myvar=slider1; ... Slider change code is specified by @slider on a line by itself, followed by any number of lines of code (see the Code Format page for code format). Slider change code is executed both on the first load of an effect, and at any subsequent slider change (knob movement, keyboard change, etc). Use this to modify any variables that need to be modified when the parameters of your effect change, or to validate the changes to the effect (if you modify the contents of slider1-slider8 in this code, the values shown by the slider in the UI will be updated). 6. On-block code @block myvar+=samplesblock; ... On-block code is specified by @block on a line by itself, followed by any number of lines of code (see the Code Format page for code format). On-block code is executed prior to processing every block of samples (which is usually around 128-1024 samples), and allows code to execute very often (many times per second), but not at every sample. This is often good for checking or setting triggers (see the trigger section on the reference page) 7. Per-sample code @sample spl0 *= 2; spl1 *= 2; ... Per-sample code is specified by @sample on a line by itself, followed by any number of lines of code (see the Code Format page for code format). Per-sample code is executed for every sample processed, and allows for direct manipulation of each sample (the variables spl0 and spl1, for left and right channels, respectively). 8. Serialization code (optional) @serialize file_var(0,mystatevar); file_var(0,myotherstatevar); file_mem(0,offset,length); ... Serialization code is specified by @serialize on a line by itself, followed by any number of lines of code (see the Code Format page for code format). This code is executed when the user loads a preset, or saves a preset. It should only really call the special serialization functions, whose function depends on whether it is a load or save operation (your calling code can also query the mode, if desired, using file_avail(). if file_avail(0) returns >= 0, it is read, otherwise it is a write)). For the file handle for all file functions, just use 0, rather than calling file_open(). For more information on defining the code sections, hit the right arrow to go to the 'Code Format' page. <end>

Code format

Writing code with JSFX -------------------------------------------------------------------------------- JSFX lets you create effects with a simple language that has many similarities to C. For example, to assign a value to a variable, you can do: x = 5; Note that variables do not need to be declared--by simply using a variable, it is declared. Variable names are not case sensitive, so using x is the same as as using X. All variables are numbers. Comments can be specified by using // to comment until end of line: x = 5; // set x to equal 5 Comments can also be specified by beginning with /* and ending with */: x = 5; /* this is a multi-line comment */ or, x = 5; /* bla bla */ y=5; There are a plethora of built-in operators, most of which behave very much like their C counterparts: x = 5*y; x = 5 * y + 4; x = y + z; For a full list of the available operators, see the Reference Page. There are built-in functions, many of which may be familiar: x = pow(2,y); // raise 2 to the Yth power x = sin($pi * 1.5); // get SINE of 1.5 * PI x = min(y,z); // get minimum of Y or Z For a full list of the available functions, see the Reference Page. Each effect has its own limited amount of memory that it can use for temporary storage. The syntax to access the private memory is as follows: buffer = 1024; // set buffer to reference the local memory starting at 1024 x=buffer[0]; // read first item in buffer buffer[1]=x; // write to second item in buffer buffer[n]=x; // write to n'th item in buffer Each effect has 1,048,576 slots of storage, so you may partition your memory use however you desire. There are logic operators available, to allow for conditional code, for example: x == 5 ? y = 3; // if x is equal to 5, then set y to 3. x == 5 ? y = 3 : z += 1; /* if x is equal to 5, then set y to 3, otherwise add one to Z */ x == 5 ? ( y = 3; // if x is equal to 5, do all of this. x = cos(z); z += 5; ); x == 5 ? ( foo=1; // if x==5 ) : ( foo=2; // if x!=5 ); The operators || (logical or) and && (logical and) can also be used for this purpose: x == 5 && z=y; // if x is equal to 5, set z to y <end>

Reference

JSFX Code Reference -------------------------------------------------------------------------------- Operators The following operators can be used within your code segments to make expressions: = Example: y = z; Assigns the value of 'z' to 'y'. 'z' can be a variable or an expression. * Example: y * z Multiplies two values and returns the product. / Example: y / z Divides two values and returns the quotient. % Example: y % z Divides two values and returns the remainder. ^ Example: y ^ z Returns the first parameter raised to the second parameter-th power. + Example: y + z Adds two values and returns the sum. - Example: y - z Subtracts two values and returns the difference. | Example: y | z Converts both values to integer, and returns bitwise OR of values. & Example: y & z Converts both values to integer, and returns bitwise AND of values. *= Example: y *= z Multiplies two values and stores the product back into 'y'. /= Example: y /= z Divides two values and stores the quotient back into 'y'. %= Example: y %= z Divides two values and stores the remainder back into 'y'. ^= Example: y ^= z Raises first parameter to the second parameter-th power, saves back to 'y'. += Example: y += z Adds two values and stores the sum back into 'y'. -= Example: y -= z Subtracts two values and stores the difference back into 'y'. |= Example: y |= z Converts both values to integer, and stores the bitwise OR into 'y' &= Example: y &= z Converts both values to integer, and stores the bitwise AND into 'y' || Example: y || z Returns logical OR of values. If y is nonzero, 'z' is not evaluated. && Example: y && z Returns logical AND of values. If y is zero, 'z' is not evaluated. == Example: y == z Compares two values, returns 1 if equal, 0 if not. != Example: y != z Compares two values, returns 0 if equal, 1 if not. < Example: y < z Compares two values, returns 1 if first parameter is less than second. > Example: y > z Compares two values, returns 1 if first parameter is greater than second. <= Example: y <= z Compares two values, returns 1 if first is less than or equal to second. >= Example: y >= z Compares two values, returns 1 if first is greater than or equal to second. ! Example: !z Returns the logical NOT of the parameter. ? Example: y ? z; Example: y ? z : x; Evaluates the first parameter 'y', and if nonzero, evaluates and returns the second parameter 'z'. If a third parameter 'x' is specified, and the first parameter is zero, evaluates and returns 'x'. The latter two expressions may often contain multiple statements seperated by semicolons, i.e. x % 5 ? ( f += 1; x *= 1.5; ) : ( f=max(3,f); x=0; ); [ ] Example: z=x[y]; or x[y]=z; Example: z=gmem[y]; or gmem[y]=z; In the first form, you may use brackets to index into memory that is local to your effect. Your effect has 1 million items of memory and you may access them either with fixed offsets (i.e. 16811[0]) or with variables (myBuffer[5]). If a value in the brackets is omitted then 0 is used instead. If 'gmem' is specified (the second form), then instead of local effect memory, the buffer is the global storage buffer, which is 1 million items that are shared across all effects. Simple Functions The following functions can be used within your code segments: sin(angle) Example: s = sin(theta); Returns the Sine of the angle specified (specified in radians). (To convert from degrees to radians, multiply by $pi/180, or 0.017453) cos(angle) Example: s = cos(theta); Returns the Cosine of the angle specified (specified in radians). tan(angle) Example: s = tan(theta); Returns the Tangent of the angle specified (specified in radians). asin(x) Example: theta = asin(s); Returns the Arc Sine of the value specified (return value is in radians). acos(x) Example: theta = acos(s); Returns the Arc Cosine of the value specified (return value is in radians). atan(x) Example: theta = atan(s); Returns the Arc Tangent of the value specified (return value is in radians). atan2(x,y) Example: theta = atan2(s,sd); Returns the Arc Tangent of s divided by sd (return value is in radians). sqr(x) Example: ss = sqr(s); Returns the square of the parameter (i.e. same as ss=s*s;). sqrt(x) Example: ss = sqrt(s); Returns the square root of the parameter. The parameter should be greater than or equal to zero. pow(x,y) Example: p = pow(s,y); Returns the first parameter raised to the second parameter-th power. This is exactly the same as the operator ^, and is provided for compatibility. exp(x) Example: ss = exp(s); Returns the number e (approx 2.718) raised to the parameter-th power. log(x) Example: ss = log(s); Returns the natural logarithm (base e) of the parameter. log10(x) Example: ss = log10(s); Returns the logarithm (base 10) of the parameter. abs(x) Example: ss = abs(s); Returns the absolute value of the parameter. min(x,y) Example: s = min(x,y); Returns the minimum value of the two parameters. max(x,y) Example: s = max(x,y); Returns the maximum value of the two parameters. sign(x) Example: s = sign(x); Returns the sign of the parameter (-1, 0, or 1). rand(x) Example: s = rand(x); Returns a psuedorandom number between 0 and the parameter. floor(x) Example: s = floor(x); Rounds the value to the lowest integer possible (i.e. 3.9 becomes 3). ceil(x) Example: s = ceil(x); Rounds the value to the highest integer possible (i.e. 3.1 becomes 4). invsqrt(x) Example: s = invsqrt(x); Returns an inverse square root (1/sqrt(x)) approximation of the parameter. Special Functions The following functions are more complex than the simple functions above: loop(count,code) Example: loop(32, r += b; b = buf * 1.5; ); Evaluates the second parameter a finite number of times, specified by the first parameter. If the first parameter is less than 1, the second parameter is not evaluated. Be careful with specifying large values for the first parameter -- it is possible to hang your effect for long periods of time doing so. The maximum for the first parameter is approximately 1 million. while(code) Example: while( a += b; b *= 1.5; a < 1000; // as long as a is below 1000, we go again. ); Evaluates the first parameter a finite number of times, until the last statement in the code block is zero. There is an artificial limit for number of executions of about 1 million. mdct(start_index, size), imdct(start_index, size) Example: mdct(0, 512); Performs a modified DCT (or inverse in the case of imdct()) on the data in the local memory buffer at the offset specified by the first parameter. The second parameter controls the size of the MDCT, and it MUST be one of the following: 64, 128, 256, 512, or 1024. The MDCT takes the number of inputs provided, and replaces the first half of them with the results. The IMDCT takes size/2 inputs, and gives size results. Note that the MDCT must NOT cross a 16,384 item boundary, so be sure to specify the offset accordingly. The MDCT/IMDCT provided also provide windowing, so your code is not required to window the overlapped results, but simply add them. See the example effects for more information. fft(start_index, size), ifft(start_index, size) fft_permute(index,size), fft_ipermute(index,size) Example: fft(0, 512); fft_permute(0, 512); 0[32]=0; fft_ipermute(0, 512); ifft(0, 512); // scale output by 1/512.0, too. Performs a FFT (or inverse in the case of ifft()) on the data in the local memory buffer at the offset specified by the first parameter. The size of the FFT is specified by the second parameter, which must be 32, 64, 128, 256, 512, 1024, 2048, or 4096. The outputs are permuted, so if you plan to use them in-order, call fft_permute(idx, size) before and fft_ipermute(idx,size) after your in-order use. Your inputs or outputs will need to be scaled down by 1/size, if used. Note that the FFT/IFFT require real/imaginary input pairs (so a 256 point FFT actually works with 512 items), while the real FFT/IFFT (rfft() and irfft(), below) provide a real-FFT. Note that the FFT/IFFT must NOT cross a 16,384 item boundary, so be sure to specify the offset accordingly. rfft(start_index, size), irfft(start_index, size) rfft_permute(index,size), rfft_ipermute(index, size) Example: rfft(0, 512); rfft_permute(0, 512); 0[16]=0; rfft_ipermute(0, 512); rifft(0, 512); // scale output by 1/512.0, too. Performs a real FFT (or inverse in the case of irfft()) on the data in the localmemory buffer at the offset specified by the first parameter. The size of the FFT is specified by the second parameter, which must be 32, 64, 128, 256, 512, 1024, 2048, or 4096. The outputs are permuted, so if you plan to use them in-order, call rfft_permute(idx, size) before and rfft_ipermute(idx, size) after your in-order use. Your inputs or outputs will need to be scaled down by 1/size, if used. rfft() and irfft() provide a real-FFT, which uses only a single value per point. Note that the FFT/IFFT must NOT cross a 16,384 item boundary, so be sure to specify the offset accordingly. convolve_c(dest,src,size), convolve_r(dest,src,size) Used to convolve two buffers, typically after FFTing them. convolve_c works with complex numbers, convolve_r works with real numbers. The sizes specify number of items (in the case of convolve_c, this signifies the number of complex number pairs). Note that the convolution must NOT cross a 16,384 item boundary, so be sure to specify the offset accordingly. freembuf(top) Example: freembuf(top); The freembuf() function provides a facility for you to notify the memory manager that you are no longer using a portion of the local memory buffer. For example, if the user changed a parameter on your effect halving your memory requirements, you should use the lowest indices possible, and call this function with the highest index you are using plus 1, i.e. if you are using 128,000 items, you should call freembuf(128001); If you are no longer using any memory, you should call freembuf(0); Note that calling this does not guarantee that the memory is freed or cleared, it just provides a hint that it is OK to free it. memcpy(dest,source,length) Example: memcpy(0,1024,1024); The memcpy() function provides the ability to quickly copy regions of the local memory buffer. The regions may overlap, but neither region may cross a 16,384 item boundary (they may be on different pages, however). memset(dest,value,length) Example: memset(0,0,1024); The memset() function provides the ability to quickly set a region of the local memory buffer to a particular value. Unlike memcpy(), this region may be of any length and cross any boundaries. sliderchange(mask) Example: sliderchange(slider4); or Example: sliderchange(2 ^ sliderindex); The sliderchange() function provides a facility for you to notify JSFX that you have changed a slider1-slider8 variable so that it can update the display. This function is not necessary to call from the @slider code segment, it is provided so that other code (i.e. @block or @sample) can update the sliders. The parameter can be the variables slider1-slider8, in which case that slider is refreshed. Otherwise, it can be a bitmask of which sliders have changed, where 1 would be the first slider, 2 would be the second, 4 would be the third, and so on (up to 128 being the 8th slider). set_slider(effect.slider,value) get_slider(effect.slider) Example: set_slider(1.3,get_slider(1.3)+1); Sets (or gets) the value of any effects' slider. The whole number of the first parameter is the index of the effect, starting at 1. The fractional part of the number specifies the slider index (1-8) of the slider. set_bypass(effect,value) get_bypass(effect) Example: set_bypass(1,!get_bypass(1)); Sets (or gets) the bypass state of any effect. Set to any positive nonzero value to bypass the effect, zero to have the effect be active. File Functions The following functions can be used in @serialize sections, @preload sections, and extended file-slider code sections. On @serialize sections, they can be for read or for write, but on all others they are for reading only. file_open(index or slider) Example: filename:0,myfile.wav handle = file_open(0); Example: slider1:/mydata:mydef.wav:WAV File handle = file_open(slider1); Opens a file from either the effect filename list or from a file slider. Once open, you may use all of the file functions available. Be sure to close the file handle when done with it, using file_close(). file_close(handle) Example: file_close(handle); Closes a file opened with file_open(). file_rewind(handle) Example: file_rewind(handle); You can use this to rewind the current file to the beginning, to re-read the file etc. file_var(handle,variable) Example: file_var(handle,myVar); This reads (or writes) the variable from(to) the current file. file_mem(handle,offset, length) Example: file_mem(handle,offset,len); This reads (or writes) the block of local memory from(to) the current file. Returns the actual number of items read (or written). file_avail(handle) Example: len=file_avail(handle); Returns the number of items remaining in the file, if it is in read mode. Returns < 0 if in write mode. If the file is in text mode (file_text(handle) returns TRUE), then the return value is simply 0 if EOF, 1 if not EOF. file_riff(handle,nch,samplrate) Example: file_riff(handle,nch,samplrate); nch ? file_mem(handle,0,file_avail(0)); If the file was a RIFF WAV file (and ended in .wav), this will set the first parameter to the number of channels, and the second to the samplerate. file_text(handle,istext) Example: istext=file_text(handle); istext ? use_diff_avail syntax; If the file was a text file (and ended in .txt), this will return 1. If you need to use different file_avail() logic for text files (you often will), you can query it this way. Text file notes Note that if in a extended file-slider code section or a @preload section, and the extension of the file is .txt, it will read one line at a time, ignoring non-number lines. Note that file_avail() should be called to check for EOF after each read, and if it returns 0, the last file_var() should be ignored. You can also use file_mem(offs,bignum) and it will read the maximum available. The format of each line in the text file can be either a floating point number, a binary number beginning with 'b', i.e. b0101010111, or a hexadecimal number beginning with 'x', i.e. xDEADF000. For more information on the format of the text file, view the help when editing a text file. MIDI Functions The following functions can be used in @block or @sample sections on supported platforms (currently only REAPER, but soon standalone). offset is offset from current block, in samples. msg1 is status byte, msg23 is second (and third if available) data bytes, second byte is low 8 bits (msg23&0xff), third byte is next 8 bits (msg23/256)&0xff. midisend(offset,msg1,msg23) Example: midisend(0,9*16 + 0,69|(127*256)); // send note 69 to channel 0 at velocity 127 (max) midirecv(offset,msg1,msg23) Example: midirecv(offset,msg1,msg23); (msg1&240)==9*16 ? ( /* note on! */ ) note: midirecv returns msg1 as a return value, as well. so you can do things like: while( midirecv(offs,msg1,msg23) ? ( midisend(offs,msg1,msg23); ); ); Special Variables The following variables are used by JSFX for special purposes: spl0, spl1 Context: @sample only Usage: read/write The variables spl0 and spl1 represent the current sample pair in the @sample code. Their values are meaningful from -1 to 1, and anything outside of this range will be clamped before playback. On a very basic level, their values represent the speaker position at that point in time. srate Context: available everywhere Usage: read-only The srate variable is set by the system to whatever the current sampling frequency is set to. In general this will never change, and is system specific. Usually it will be 48000 or 96000, represting 48khz or 96khz. samplesblock Context: @block only Usage: read-only The samplesblock variable can be used within the @block code to see how many samples will come before the next @block code. Useful for tracking time, etc. slider1-slider8 Context: @slider, @block, @sample Usage: read/write The variables slider1, slider2, ... slider8 allow interaction between the user and the effect, allowing the effect to be adjusted by the user and likewise allow the effect to show the user information (see the function sliderchange()). The values of these sliders are purely user-defined, and will be shown to the user, as well as tweaked by the user. If you modify one of these values in the @block or @sample code, it is recommended that you call the sliderchange() function. trigger Context: @block, @sample Usage: read/write The trigger variable provides a facility for triggering effects. Effects can be triggered by the user, or by other effects. The trigger variable is a bitmask, where each bit represents a unique trigger. For example, to check for trigger 5 (triggered also by the key '5' on the keyboard): isourtrig = trigger & (2^5); Conversely, to set trigger 5: trigger |= 2^5; Or, to clear trigger 5: trigger & (2^5) ? trigger -= 2^5; The trigger variable is preserved across effects, so that an effect higher on the effect list can control an effect that is lower. It is recommended that you use this variable in @block, but only sparingly in @sample. reg00-reg99 Context: available everywhere Usage: read/write The 100 variables reg00, reg01, reg02, .. reg99 are shared across all effects and can be used for inter-effect communication. Their use should be documented in the effect descriptions to avoid collisions with other effects. tempo Context: @block, @sample Usage: read-only The current project tempo, if supported (REAPER), or 120 on standalone. play_state Context: @block, @sample Usage: read-only The current playback state in REAPER (0=stopped, <0=error, 1=playing, 2=paused, 5=recording, 6=record paused. play_position Context: @block, @sample Usage: read-only The current playback position in REAPER (at last @block), in seconds. beat_position Context: @block, @sample Usage: read-only The current playback position (at last @block) in REAPER, in beats (beats usually = quarternotes). pdc_delay Context: @block, @slider Usage: read-write The current delay added by the plug-in, in samples. Note that you shouldnt change this too often. pdc_bot_ch, pdc_top_ch Context: @block, @slider Usage: read-write The channels that are delayed by pdc_delay. For example: pdc_bot_ch=0; pdc_top_ch=2; // delays the first two channels (spl0/spl1). pdc_bot_ch=2; pdc_top_ch=5; // delays channels spl2,spl3, and spl4. (this is provided so that channels you dont delay can be delayed properly by the host. <end>