This introduction will largely pick apart a few very simple JSFX scripts to see how they work.
My comments are preceded by a lot of slashes, e.g. ///////
Volume
// This effect Copyright (C) 2004 and later Cockos Incorporated
// License: LGPL - http://www.gnu.org/licenses/lgpl.html
////// the desc: line is what defines the name that appears in Reaper's FX browser
desc: Volume Adjustment
//tags: utility gain
//author: Cockos
/////// slider format:
// sliderN:defaultValue<minValue,maxValue,step>Name
// see below how to use a slider
slider1:6<-150,150,0.1>Adjustment (dB)
slider2:0<-150,150,0.1>Max Volume (dB)
/////// input configuration for 2-in 2-out
in_pin:left input
in_pin:right input
out_pin:left output
out_pin:right output
////// @init section is run once when plugin is loaded
@init
//// use varName = value; to set a value
//// note that all statements end with a semicolon
ext_tail_size = -2;
////// the @slider section is run whenever a slider is moved
@slider
///// ^ is used for exponention, this converts from dB to linear values
adj1=2 ^ (slider1/6);
adj2=2 ^ (slider2/6);
doseek < 0 ? doseek = 1; //// this is so that changes aren't abrupt
////// @block is run once per block of samples (e.g. 256 samples at a time)
////// you'll tend to do MIDI processing here
@block
///// if/else takes the form (inspired by C's ternary operator)
///// condition ? what-to-do-if-true : what-to-do-if-false ;
///// statements are grouped with brackets
doseek > 0 ? (
dadj=(adj1-adj1_s)/samplesblock;
):(
dadj=0;
adj1_s=adj1;
);
doseek = -1;
////// @sample is run once per sample, DSP goes here
@sample
////// the min(max(...)) is used to clamp the values to a max amplitude
spl0=min(max(spl0*adj1_s,-adj2),adj2);
spl1=min(max(spl1*adj1_s,-adj2),adj2);
adj1_s+=dadj;
Functions
See the docs
function getSampleRate()
(
srate; // return srate
);
function mySine(x)
(
// taylor approximation
x - (x^3)/(3*2) + (x^5)/(5*4*3*2) - (x^7)/(7*6*5*4*3*2) + (x^9)/(9*8*7*6*5*4*3*2);
);
function calculateSomething(x y)
(
x += mySine(y);
x/y;
);
MPE Example
This allocates notes to the first available channel. This will probably fail if more than 15 simultaneous notes are played.
desc: JDA Midi Mpe Allocator 1
@init
alloc_base = 100; // channel => pitch
alloc_chan = 200; // pitch => channel
alloc_i = 0;
loop(i=0;16,alloc_base[i]=-1;i+=1);
function off(offset,nch,p,v) (
alloc_chan[p] = 0;
alloc_base[nch] = -1;
midisend(offset,0x80|nch,p,v);
);
@block
while(midirecv(offset,m1,m2,m3)) (
cmd = m1 >> 4;
ch = m1 & 0xF;
( cmd == 0x8 || ( cmd == 90 && m3 == 0 ) ) ? (
nch = alloc_chan[m2];
off(offset,nch,m2,( cmd == 0x80 ? v : 0));
) : ( cmd == 0x9 ) ? (
nch = alloc_chan[m2];
nch > 0 ? (
off(offset,nch,m2,0);
);
fch = 0;
i=1;
while(i<16 && fch == 0) (
( alloc_base[i] == -1 ) ? ( fch = i; tmx1 = i; );
i += 1;
);
alloc_chan[m2] = fch;
alloc_base[fch] = m2;
midisend(offset,0x90|fch,m2,m3);
) : (
midisend(offset,m1,m2,m3);
)
);