Cockos Incorporated Forums JS function alternatives and useful snippets of code.
 Register Track Bugs/Feature Requests Search Today's Posts Mark Forums Read

 07-22-2009, 09:06 AM #1 liteon Human being with feelings     Join Date: Apr 2008 Posts: 510 JS function alternatives and useful snippets of code. this is a thread in which you can contribute: - alternatives to the default functions in jesusonic - approximations or simply "cheaper" algorithms, but less cpu extensive. share your methods in js code plus any links to original references. the default functions should be considered as the optimal base of comparison, regarding the quality / cpu trade-off. - other code optimization techniques. - what is faster? - any snippets of code, that may be useful to future coders. - "dsp explained" notes - how does a filter work? how to do convolution? - any interesting dsp related articles, books and lectures. lubomir __________________ Blog / Articles / Music / Reaper DJ tutorial JS plugin pack/ JS Wiki / JS tips / JSfxGen Holos / GitHub / GoogleCode / G+ Last edited by liteon; 07-22-2009 at 09:40 AM.
 07-22-2009, 09:07 AM #2 liteon Human being with feelings     Join Date: Apr 2008 Posts: 510 fast park–miller random number generator a fast linear congruential generator (or specifically the park-miller variation) is described below. basic algorithm: Code: ```@init rnd=1; @sample rnd=rnd*a%m;``` but the main problem is the range in our case, since with some of the common lcg parameters we go out of range: Code: ```@init rnd=1; @sample rnd=rnd*16807%2147483647; // call 0 // 1*16807%2147483647=16807 // call 1 // 16807*16807%2147483647=2824275249 // call 2 // 2824275249*16807%2147483647=1 -> out of range prevention``` therefore a larger modulus cannot be used, such as the 2^31-1 -> 'marsenne prime' so here are some parameters i've calculated based on the "zx-spectrum" multiplier,(77) but with much larger modulus. Code: ```//all with initial seed 1 rnd0*=77; //\$x4D rnd0%=16777219; //\$x1000003=2^24+3 rnd1*=76; //\$x4C rnd1%=16777221; //\$x1000005=2^24+5 rnd2*=77; //\$x4D rnd2%=8388609; //\$x800001=2^23+1``` so basically all that is needed is a scaling factor in the end: Code: ```//full code @init rnd=1; @sample rnd*=77; rnd%=16777219; spl0=rnd*0.0000000593; //scale down to 0-1 range``` comparison with the marsenne twister implementation in rand(). 100 executions of rand() = 61% cpu 100 executions of one recursion lane lcg = 26% cpu @gfx plots (ermm...30sec freerun) two rand() x,y: [img]http://img195.**************/img195/7922/mtwister.png[/img] two recursions lanes lcg for x,y: [img]http://img195.**************/img195/5992/gauss.png[/img] the more expensive gaussian noise version as a bonus: Code: ```//gaussian version @init rnd0=rnd1=rnd2=1; @sample rnd0*=77; rnd0%=16777219; rnd1*=76; rnd1%=16777221; rnd2*=77; rnd2%=8388609; spl0=(rnd0+rnd1+rnd2)*0.00000002403333333333333; //.... *k //k=(1/3*0.0000000721)``` ---- lubomir __________________ Blog / Articles / Music / Reaper DJ tutorial JS plugin pack/ JS Wiki / JS tips / JSfxGen Holos / GitHub / GoogleCode / G+ Last edited by liteon; 07-25-2009 at 07:44 AM.
 07-22-2009, 12:45 PM #3 liteon Human being with feelings     Join Date: Apr 2008 Posts: 510 fast integer conversations fast fractional to integer conversation for negative or positive input (x): floor: Code: `x|=0;` ceil: Code: ```x+=0.9999999999999999*sign(x); x|=0;``` round: Code: ```x+=0.5*sign(x); x|=0;``` --- lubomir __________________ Blog / Articles / Music / Reaper DJ tutorial JS plugin pack/ JS Wiki / JS tips / JSfxGen Holos / GitHub / GoogleCode / G+ Last edited by liteon; 07-25-2009 at 04:15 AM.
 07-22-2009, 12:50 PM #4 liteon Human being with feelings     Join Date: Apr 2008 Posts: 510 video lectures on dsp Prof. S.C Dutta Roy, Department of Electrical Engineering, IIT Delhi 43 - 1 hour lectures on DSP at: https://www.youtube.com/view_play_lis...67DFCA3A66F299 ---- lubomir __________________ Blog / Articles / Music / Reaper DJ tutorial JS plugin pack/ JS Wiki / JS tips / JSfxGen Holos / GitHub / GoogleCode / G+
 07-22-2009, 01:23 PM #5 liteon Human being with feelings     Join Date: Apr 2008 Posts: 510 exponential frequency mapping y range: 20-20000hz --- x range: 0-127 Code: `y=(exp((16+x*0.945699)*0.0573250666192694)*8.17742)|0;` x range: 0-100 Code: `y=(exp((16+x*1.20103)*0.0573250666192694)*8.17742)|0;` x range: 0-1 Code: ```//y=exp(x*log(20000/20)+log(20)); y=exp(x*6.90775527898214+2.99573227355399); y|=0;``` graphic: http://img188.**************/img188/6396/expplot.png ---- lubomir __________________ Blog / Articles / Music / Reaper DJ tutorial JS plugin pack/ JS Wiki / JS tips / JSfxGen Holos / GitHub / GoogleCode / G+ Last edited by liteon; 08-13-2009 at 07:43 PM.
 07-22-2009, 02:28 PM #6 cern.th.skei Human being with feelings     Join Date: Sep 2007 Location: trondheim, norway Posts: 316 a really cool initiative! here's some snippets i've used in a few plugins: a sin() approxamation for an oscillators, lfo, etc.. Code: ```desc:sinusoid (approximation) slider1: 55 < 1, 44100 > freq left - sinusoid slider2: 55 < 1, 44100 > freq right - sin() @init p0 = 0; p1 = 0; @slider r0 = (slider1/srate)*4; r1 = (slider2/srate); @sample // sinusoid p0+=r0; p0>2 ? p0-=4; s0 = p0*(2-abs(p0)); // sin() p1+=r1; p1>=1 ? p1-=1; s1 = sin(p1*(\$pi*2)); // spl0 = s0; spl1 = s1;``` another random/noise thing Code: ```desc:noise/random @init value = 19; // initialize b_noise = 19.1919191919191919191919191919191919191919; @sample // -1..1 b_noise = b_noise * b_noise; i_noise = floor(b_noise); // |0; b_noise = b_noise - i_noise; r0 = b_noise - 0.5; b_noise = b_noise + value; // 0..1 b_noiselast = b_noise; b_noise = b_noise + value; b_noise = b_noise * b_noise; b_noise = (b_noise+b_noiselast) * 0.5; i_noise = floor(b_noise); b_noise = b_noise - i_noise; r1 = b_noise; // spl0 = r0; spl1 = r1;``` and some filtering Code: ```desc:lowpass / weighted average slider1:0.5<0,1,0.001>weight @init n0 = 0; n1 = 0; @slider weight = slider1*slider1; // ??? @sample spl0 = (n0+=((spl0-n0)*weight)); // lowpass spl1 -= (n1+=((spl1-n1)*weight)); // highpass``` perhaps not scientifically correct, but useful when cpu and simplicity is important. the noise and sine things are around twice as fast as the builtin rand() and sin() functions. __________________ later..
10-17-2013, 01:15 PM   #7
reapercurious
Human being with feelings

Join Date: Jul 2007
Posts: 1,667

Quote:
 Originally Posted by liteon a fast linear congruential generator (or specifically the park-miller variation) is described below. basic algorithm: Code: ```@init rnd=1; @sample rnd=rnd*a%m;``` but the main problem is the range in our case, since with some of the common lcg parameters we go out of range: Code: ```@init rnd=1; @sample rnd=rnd*16807%2147483647; // call 0 // 1*16807%2147483647=16807 // call 1 // 16807*16807%2147483647=2824275249 // call 2 // 2824275249*16807%2147483647=1 -> out of range prevention``` therefore a larger modulus cannot be used, such as the 2^31-1 -> 'marsenne prime' so here are some parameters i've calculated based on the "zx-spectrum" multiplier,(77) but with much larger modulus. Code: ```//all with initial seed 1 rnd0*=77; //\$x4D rnd0%=16777219; //\$x1000003=2^24+3 rnd1*=76; //\$x4C rnd1%=16777221; //\$x1000005=2^24+5 rnd2*=77; //\$x4D rnd2%=8388609; //\$x800001=2^23+1``` so basically all that is needed is a scaling factor in the end: Code: ```//full code @init rnd=1; @sample rnd*=77; rnd%=16777219; spl0=rnd*0.0000000593; //scale down to 0-1 range``` comparison with the marsenne twister implementation in rand(). 100 executions of rand() = 61% cpu 100 executions of one recursion lane lcg = 26% cpu @gfx plots (ermm...30sec freerun) two rand() x,y: [img]http://img195.**************/img195/7922/mtwister.png[/img] two recursions lanes lcg for x,y: [img]http://img195.**************/img195/5992/gauss.png[/img] the more expensive gaussian noise version as a bonus: Code: ```//gaussian version @init rnd0=rnd1=rnd2=1; @sample rnd0*=77; rnd0%=16777219; rnd1*=76; rnd1%=16777221; rnd2*=77; rnd2%=8388609; spl0=(rnd0+rnd1+rnd2)*0.00000002403333333333333; //.... *k //k=(1/3*0.0000000721)``` ---- lubomir
real world user-understandable application would be appreciated on these snippets, otherwise they are only useful to people who understand terms and concepts that are four orders elevated in mean sophistication.

 10-20-2013, 04:46 AM #8 chilledpanda Human being with feelings     Join Date: Jan 2013 Location: United Kingdom Posts: 28 Here's a technique I found useful for debugging, by watching local memory akin to memory watch widows in professional debuggers. First set up a slider (I use 64 as it's he last one), This slider allows you to view local 0-to 2048, slider64:0<0,2048,16>MEMWATCH LOC Then change/add @slider to read the slider and set the memwatchvariable @slider //debugging code memwatch = floor(slider64); Add the follow to the @gfx uppdate block this constantly updates so allows us to constantly update the mem watch variables @gfx //debug code memwatch_00 = memwatch[0]; memwatch_01 = memwatch[1]; memwatch_02 = memwatch[2]; memwatch_03 = memwatch[3]; memwatch_04 = memwatch[4]; memwatch_05 = memwatch[5]; memwatch_06 = memwatch[6]; memwatch_07 = memwatch[7]; memwatch_08 = memwatch[8]; memwatch_09 = memwatch[9]; memwatch_10 = memwatch[10]; memwatch_11 = memwatch[11]; memwatch_12 = memwatch[12]; memwatch_13 = memwatch[13]; memwatch_14 = memwatch[14]; memwatch_15 = memwatch[15]; Then in the JS development environment editor make sure the auto refresh is ticked under the left window and then locate the memwatch variables. Move the slider and see the memory locations update in steps of 16 values. __________________ ------------------------------------------------------------------------------- http://soundcloud.com/chilled-panda
 02-04-2014, 11:09 AM #9 Argitoth Human being with feelings     Join Date: Feb 2008 Location: Phoenix, AZ Posts: 2,055 this page: https://ccrma.stanford.edu/~craig/ar...essenmidi.html seems to have some explanation on midi messages, but does not exactly correlate to JS explanation: http://www.reaper.fm/sdk/js/midi.php#js_midi Is there a comprehensive list of midi messages/parameters? Like note on/off, channel pressure, midi cc, etc. __________________ Soundemote - Home of the chaosfly and pretty oscilloscope. MyReaperPlugin - Easy-to-use cross-platform C++ REAPER extension template
02-04-2014, 11:25 AM   #10
James HE
Human being with feelings

Join Date: Mar 2007
Location: I'm in a barn
Posts: 4,415

Quote:
 Originally Posted by Argitoth Is there a comprehensive list of midi messages/parameters? Like note on/off, channel pressure, midi cc, etc.
here.

http://www.midi.org/techspecs/midimessages.php

07-23-2009, 02:50 AM   #11
Jeffos
Mortal

Join Date: Dec 2008
Location: France
Posts: 1,969

Yes, great tips here!
So here are some (more basic :-) things I have noted. HTH... Here I focus on:
Quote:
 Originally Posted by liteon - other code optimization techniques. - what is faster?
How to know what is faster (i.e. how to monitor the CPU) ?
We cannot trust Reaper's performance meter (it seems it does not take some things into account, such as the @gfx thread). So, what I do: I set up a test project, I clean it as much as possible (usually one media item + the js). Then, I monitor reaper with Win's performance meter (cool for threads but I also simply use the task manager when I'm in an rush) with DISABLED JS, then I just enable it. The CPU use is the diff (note: diff done in the same conditions - just enabling the JS - as play/routing/etc.. have an impact), dif made with hidden and shown GUI.
I'd like to know how other js coders monitor CPU/RAM !?

Where to code ?
This one is really basic - I know - but it must be said! I often see that and it leads to the best optimizations => put the maximum of code in the @block part (as far as possible: typically periodic processing NOT needed for each sample), and, of course, the less in the @sample.
Then, you can even lower the processing frequency, e.g.:
Code:
```@block
cpt+=samplesblock;
(cpt - lastCpt) > updatefreq ?
(
lastCpt=cpt;
// do some heavy stuff
);```
where "updatefreq" is in samples *
 *if computed: only when needed! i.e. in the @init or @slider parts.

Branching
Huge impact on CPU.
=> avoid them as far as possible!

=> use logical operator precedence
Code:
```cond2 = cond1 || (floor(rand(spl0) * \$pi * 1000) % 2);
cond2 = cond1 && (floor(rand(spl0) * \$pi * 1000) % 2);```
will be faster than:
Code:
```cond2 = (floor(rand(spl0) * \$pi * 1000) % 2) || cond1;
cond2 = (floor(rand(spl0) * \$pi * 1000) % 2) && cond1;```
here, floor() & rand() are used for test purpose only

=> some code branching tips
The 2 following code lines do the same thing (where "cond1" is a "boolean"):
Code:
```//1)
spi1 = condi1 * slider1 * spl0;
//2)
condi1 ? spi1 = slider1 * spl0 : spi1 = 0;```
According to some (old) Justin's post, I was thinking that 1) was the fastest one. In fact, CPU monitoring shows that that fastest one is 2) (Reaper v3.06pre7).
I really don't understand why! If a dev read this post, can he just confirm/say why (very briefly) ?

=> setting a default STATIC value according to a condition
Code:
`a=0; cond1 ? a = floor(rand(spl0) * \$pi * 1000);`
is faster than:
Code:
`cond1 ? a = floor(rand(spl0) * \$pi * 1000) : a=0;`
Midi processing
=> counting samples (basic thing, but I've also seen this possible optimization in a bunch of JS!). We often have to evaluate time elapsed between midi events, for this we have to count samples.
Code:
```@block
cpt+=samplesblock; // +use midircv()'s 1st param for sample accurate processing```
is faster than:
Code:
```@sample
cpt+=1;```
 even more true since v3.06!

coming back later...

Last edited by Jeffos; 07-23-2009 at 01:33 PM. Reason: english wording + better with "compilable" code !

 07-24-2009, 05:44 AM #12 liteon Human being with feelings     Join Date: Apr 2008 Posts: 510 fast polynomial approximations of exp() fast approximations of exp() with lagrange polynomials: Code: ```//stable range for x is [-1.5, 1.5] //3 points polynomial //y=x*(x*0.601+1.42)+1; y=x; y*=0.601; y+=1.42; y*=x; y+=1; //4 points polynomial //y=x*(x*(x*0.189+0.612)+0.995)+0.975; y=x; y*=0.189; y+=0.612; y*=x; y+=0.995; y*=x; y+=0.975; //5 points polynomial //y=x*(x*(x*(x*0.046+0.191)+0.498)+0.989)+1; y=x; y*=0.046; y+=0.191; y*=x; y+=0.498; y*=x; y+=0.989; y*=x; y+=1;``` plot comparisons with exp(): [img]http://img233.**************/img233/4125/explagrangen.gif[/img] performance test - 100 executions per sample: 4 point -> 26% cpu exp(x) -> 56% cpu example: Code: ```//omega=2*\$pi*fc=2*\$pi*2000=12566.370614 //x=-omega/srate=-omega/44100= x=-0.284951; y0=exp(x); //0.7205110 y1=x*(x*(x*0.189+0.612)+0.995)+0.975; //0.7367934``` --- lubomir __________________ Blog / Articles / Music / Reaper DJ tutorial JS plugin pack/ JS Wiki / JS tips / JSfxGen Holos / GitHub / GoogleCode / G+
 07-24-2009, 06:08 AM #13 liteon Human being with feelings     Join Date: Apr 2008 Posts: 510 fast pow() from identity using the above approximation of exp() and the identity: Code: `2^x=exp(x*log(2));` it is possible to get a fixed base approximation of b^x: Code: ```@init //base 2 b=log(2); @sample //example with 4 point polynomial: x*=b; y=x; y*=0.189; y+=0.612; y*=x; y+=0.995; y*=x; y+=0.975; //x=1 -> y=2.02166035; //x=2 -> y=4.03404514;``` stable within x range [-2, 2,5] [img]http://img233.**************/img233/9909/powlagrange.gif[/img] performance test (100 executions per sample): 4point approximation (2^x) - 33% inline 2^x - 75% --- lubomir __________________ Blog / Articles / Music / Reaper DJ tutorial JS plugin pack/ JS Wiki / JS tips / JSfxGen Holos / GitHub / GoogleCode / G+
 07-24-2009, 07:40 AM #14 liteon Human being with feelings     Join Date: Apr 2008 Posts: 510 fractional delay approximation with an allpass filter fractional delay approximation with an allpass filter: Code: ```//code here @init k=0.5; @sample y0=spl0-k*(y=y0+k*spl0); spl0=y;``` quick explanation: the above is a basic one pole allpass filter. in one sentence - allpass filters affect only the phase of the signal while preserving the energy (magnitude) of the signal. this way it is possible to get relative group delay, the amount of which is dependent from a pole position (k). note that group delay value does not correspond directly to the pole i.e. k=0.5 != gd=0.5 samples. this requires extra mapping for user controlled amounts. [img]http://img233.**************/img233/6681/gdmapping.gif[/img] example for parameter mapping with an exponent: Code: ```//error is minimized but k should be limited to [0,1] for slider values [0,1]: slider1:0<0,1,0.01>d @slider x=slider1; k=exp(x*1.29)/\$e-0.356;``` various fractional delay methods described here: http://sal.shs.arizona.edu/~smathur/.../MathurCh3.pdf http://www.acoustics.hut.fi/~vpv/pub...cassp00-fd.pdf --- lubomir __________________ Blog / Articles / Music / Reaper DJ tutorial JS plugin pack/ JS Wiki / JS tips / JSfxGen Holos / GitHub / GoogleCode / G+ Last edited by liteon; 07-25-2009 at 02:54 AM.
 07-24-2009, 09:48 AM #15 liteon Human being with feelings     Join Date: Apr 2008 Posts: 510 code optimizations this syntax is troublesome for the given function due to the 'pow' operator: Code: `y=7*x^4+5*x^3-3*x^2+2*x-1;` this is better: Code: `y=7*x*x*x*x+5*x*x*x-3*x*x+2*x-1;` even better: Code: ```y=x; y*=7; y+=5; y*=x; y-=3; y*=x; y+=2; y*=x; y-=1;``` best: Code: `y=x*(x*(x*(7*x+5)-3)+2)-1;` ----------------------------------------------- however it is slightly faster to execute: Code: ```x=6.28; x*=2; x|=0; x%=3;``` over: Code: ```x=6.28; x=((2*x)|0)%3;``` ----------------------------------------------- if there are more variables and recursion: Code: ```@sample y=y0+k*spl0; y0=spl0-k*y; spl0=y;``` could be optimized to: Code: ```y0=spl0-k*(y=y0+k*spl0); spl0=y;``` ----------------------------------------------- loops: loop() - 73% cpu Code: ```i=0; loop(100, mem[i]=exp(i); i+1; );``` while() - 76% cpu Code: ```i=0; while( mem[i]=exp(i); i+=1; i<100; //<- inlined cmp - eventual cause for 76% );``` ----------------------------------------------- min() / max() or inline cmp: Code: ```x=0.9; //this call x<1?x=1; //is slower than x=max(x,1);``` ----------------------------------------------- abs() and sign() are both quite fast: correction here: Code: ```//alternative to abs() x=-0.5; x*=sign(x); //700 iterations, x=-0.5, x=abs(x) -> 82.6% cpu, x*=sign(x) -> 84.5% cpu //700 iterations, x=0.5, x=abs(x) -> 80.1% cpu, x*=sign(x) -> 76.5% cpu //-- //if input values are mostly with negative sign use abs(x)``` --- lubomir __________________ Blog / Articles / Music / Reaper DJ tutorial JS plugin pack/ JS Wiki / JS tips / JSfxGen Holos / GitHub / GoogleCode / G+ Last edited by liteon; 03-28-2011 at 10:40 PM.
08-20-2009, 08:16 AM   #16
Justin

Join Date: Jan 2005
Location: NYC
Posts: 12,567

Quote:
 Originally Posted by Jeffos => some code branching tips The 2 following code lines do the same thing (where "cond1" is a "boolean"): Code: ```//1) spi1 = condi1 * slider1 * spl0; //2) condi1 ? spi1 = slider1 * spl0 : spi1 = 0;``` According to some (old) Justin's post, I was thinking that 1) was the fastest one. In fact, CPU monitoring shows that that fastest one is 2) (Reaper v3.06pre7). I really don't understand why! If a dev read this post, can he just confirm/say why (very briefly) ?
I think it depends on what condi1 refers to.. If it's mostly 0, then 2) should be faster. Other cases, the difference becomes less I'd think.

 08-27-2009, 08:34 AM #17 IXix Human being with feelings   Join Date: Jan 2007 Location: mcr:uk Posts: 3,386 Debugging Aid Great thread! I can't contribute much but I'll re-post this (slightly improved) snippet here where more people might find it. Just paste this at the bottom of your @gfx section to display a chunk of memory buffer and six general purpose debugging variables. You can set various parameters in the options bit at the top. Code: ```/******************************************************************************* General purpose debugging aid. Paste into the gfx section of your code. Variables: debug1...debug6 - Displayed at the top of the debug area. dOffset - Index of first item of buffer data to display. *******************************************************************************/ SHOWDEBUG = 1; //Set non-zero to enable the debug view SHOWDEBUG ? ( //Options dPrecision = 2; //Decimal places for numbers dLeft = 5; //Debug window position in pixels dTop = 5; //Debug window position in pixels dRows = 5; //Row count for buffer data dCols = 6; //Column count for buffer data dRowHeight = 20; //Row height offset for buffer data dColWidth = 80; //Column width offset for buffer data dMarginX = 5; //Left margin in pixels dMarginY = 5; //Top margin in pixels dBufferY = 30; //Vertical offset for buffer data display /* ------------------------------------------------------------- */ dOld_x = gfx_x; dOld_y = gfx_y; dOld_a = gfx_a; dOld_r = gfx_r; dOld_g = gfx_g; dOld_b = gfx_b; dOld_mode = gfx_mode; gfx_a = 1; gfx_mode = 0; //Calculate debug window size dWidth = dCols * dColWidth + dMarginX; dHeight = dRows * dRowHeight + dBufferY; //Set background colour gfx_r=1;gfx_g=1;gfx_b=1;gfx_a=1; //Erase gfx_x = dLeft; gfx_y = dTop; gfx_rectto(dLeft + dWidth, dTop + dHeight); //Set text colour gfx_r=.7;gfx_g=0;gfx_b=.3; //Draw debug vars gfx_x = dLeft + dMarginX; gfx_y = dTop + dMarginY; gfx_drawNumber(debug1, dPrecision); gfx_x = dLeft + dMarginX + dColWidth; gfx_y = dTop + dMarginY; gfx_drawNumber(debug2, dPrecision); gfx_x = dLeft + dMarginX + dColWidth * 2; gfx_y = dTop + dMarginY; gfx_drawNumber(debug3, dPrecision); gfx_x = dLeft + dMarginX + dColWidth * 3; gfx_y = dTop + dMarginY; gfx_drawNumber(debug4, dPrecision); gfx_x = dLeft + dMarginX + dColWidth * 4; gfx_y = dTop + dMarginY; gfx_drawNumber(debug5, dPrecision); gfx_x = dLeft + dMarginX + dColWidth * 5; gfx_y = dTop + dMarginY; gfx_drawNumber(debug6, dPrecision); //Draw separator gfx_x = dLeft + dMarginX; gfx_y = dTop + dBufferY - dMarginY; gfx_lineto(dLeft + dWidth - dMarginX, gfx_y, 1); //Draw buffer data di = 0; dRow = 0; loop ( dRows, dCol = 0; loop ( dCols, gfx_x = dLeft + dMarginX + dCol * dColWidth; gfx_y = dTop + dMarginY + dBufferY + dRow * dRowHeight; gfx_drawNumber(dOffset[di], dPrecision); di += 1; dCol += 1; ); dRow += 1; ); //Restore previous state gfx_x = dOld_x; gfx_y = dOld_y; gfx_a = dOld_a; gfx_r = dOld_r; gfx_g = dOld_g; gfx_b = dOld_b; gfx_mode = dOld_mode; );``` You can use debug1...debug6 to report the value of a variable at specific points in your code, or they can be handy for tracing which parts of a conditional block are being executed. To use the buffer viewer, just set dOffset to the memory index you're interested in. I've found it very helpful for dealing with my typically over-complicated scripts. Last edited by IXix; 08-27-2009 at 08:45 AM. Reason: Added code to restore gfx variables to their original state after debug drawing is completed
08-28-2009, 09:35 AM   #18
Jeffos
Mortal

Join Date: Dec 2008
Location: France
Posts: 1,969

Hey! IXix! I use it, I forget to thank you for that in the other thread! Very handy especially in comparison with how I was debugging arrays before

Quote:
 Originally Posted by Justin I think it depends on what condi1 refers to.. If it's mostly 0, then 2) should be faster. Other cases, the difference becomes less I'd think.
Thanks for the feedback, Mr Frankel! The "boolean" "cond" meant a variable that's either 0 or 1 and nothing else. So, in both cases, I was hoping some stuff not to be evaluated in "cond * something_else" as the result is either 0 or something_else.
Here's the not-good-for-speakers code I used to test that (where "cond" is often updated as you can see):
Code:
```desc:Jeff test 27
slider1:0<0,1,1{1,2}>Mode
@init
cond=0;

@sample
cond = !cond;

!slider1 ?
// 1)
(spl0 = cond * floor(rand(spl0) * \$pi * 100);)
// 2)
: (cond ? spl0 = floor(rand(spl0) * \$pi * 100) : spl0 = 0;);```
As logical operations use operator precedence, I also tried "spl0 = cond && (floor(rand(spl0) * \$pi * 100))" that is to say "&&" instead of "*" but it's ko: logical operations clamp results to 0 or 1 (edit: and that's fine)

Last edited by Jeffos; 08-28-2009 at 12:17 PM.

 08-28-2009, 05:22 PM #19 Tale Human being with feelings     Join Date: Jul 2008 Location: The Netherlands Posts: 3,005 General JS synth implementation I don't have any general optimizations, nor any ingenius DSP code snippets, but I do have a polyphone JS synth implementation. It receives MIDI notes in full polyphony (within the chosen note range), stores the notes in a buffer, and then caches this buffer for optimal speed. In this case sound is generated using a bunch of sinuses (with the frequencies for each note pre-calculated to speed up things a litle more), but you could easily replace that with any other sound generating code snippet. Code: ```// Sinas v0.0.1 // (c) 2009 Theo Niessink // License: GPL desc:Simple stacked sine synth in_pin:none out_pin:Mono out_pin:Mono @init bot_key = 36; // C2 top_key = 96; // C7 num_key = top_key - bot_key + 1; // Pre-calculate the frequency for each key. //freq_buf = 0; key = 69 - bot_key; // A @ 440 Hz // Calculate the top octave. i = num_key; loop(12, freq_buf[i -= 1] = 440.0 * 2 ^ ((i - key) / 12)); // Caclulate the lower octaves by dividing down the top octave. loop(i, freq_buf[i -= 1] = 0.5 * freq_buf[i + 12]); key_buf = freq_buf + num_key; //memset(key_buf, 0, num_key); cache_buf = key_buf + num_key; //num_cache = 0; pi2 = \$pi * 2; speriod = 1/srate * pi2; //position = 0.0; @block while( midirecv(ofs, msg1, msg23) ? ( event = msg1&\$xF0; velocity = msg23&\$x7F00; // Note On event == \$x90 && velocity ? ( key = msg23&\$x007F; key >= bot_key && key <= top_key ? ( key -= bot_key; // Add the key to the cache. key_buf[key] == 0 ? ( cache_buf[num_cache] = key; num_cache += 1; ); // Set the velocity value / (127 * 256) in the keyboard buffer. key_buf[key] = 0.000030757874015748031496062992125984 * velocity; ); ) : // Note Off (event == \$x80 || (event == \$x90 && !velocity)) ? ( key = msg23&\$x007F; key >= bot_key && key <= top_key ? ( key -= bot_key; // Remove the key from the cache. loop(i = num_cache, cache_buf[i -= 1] == key ? ( num_cache -= 1; i < num_cache ? memcpy(cache_buf + i, cache_buf + i + 1, num_cache - i); ); ); // Clear the velocity value in the keyboard buffer. key_buf[key] = 0; ); ) : // Control Change event == \$xB0 ? ( cc = msg23&\$x007F; // All Notes Off cc >= 123 && (num_cache > 0 || position > 0.0) ? ( memset(key_buf, 0, num_key); num_cache = 0; position = 0.0; ); ); midisend(ofs, msg1, msg23); 1; // Loop ); ); @sample spl0 = 0.0; // Calculate a sample for each of the keys in the cache. loop(i = num_cache, key = cache_buf[i -= 1]; f = position * freq_buf[key]; spl0 += key_buf[key] * (sin(f) + sin(2 * f) + sin(3 * f) + sin(4 * f) + sin(5 * f)); ); spl0 *= 0.1; spl1 = spl0; position += speriod; num_cache == 0 && position >= pi2 ? position -= pi2;``` Without the cache the sound generating loop in the @sample section would look something like this: Code: ```loop(key = num_key, velocity = key_buf[key -= 1]; velocity > 0 ? ( f = position * freq_buf[key]; spl0 += velocity * (sin(f) + sin(2 * f) + sin(3 * f) + sin(4 * f) + sin(5 * f)); ); );``` This would make the @sample section considerably slower, especially in idle or with only a few keys playing. On my system the cached version takes 0.3% CPU time in idle, and 3.3% with 3 keys playing. The non-cached version takes 6.4% in idle, and 9.0% with 3 keys playing. __________________ Martinic Kee Bass - Scanner Vibrato - Elka Panther - Tale's JSFX Pack
 09-01-2009, 06:30 PM #20 liteon Human being with feelings     Join Date: Apr 2008 Posts: 510 methods of pseudo-random number generation with non-uniform distribution explained below is a method for generating white noise with non-uniform distribution. unlike the gaussian function for white gaussian noise this method uses trigonometric functions and in general can be tweaked to produce quick variations in regard of probability density with relatively fast execution times. you may have stumbled on this before doing a simple oscillator: Code: ```//full code @init x=y=1; @sample y=sin((x+=1)*y);``` this recursion algorithm is a prng with non-uniform (trigonometric) distribution which outputs in the [-1,+1] range for y using sin(), previous value y[n-1] and an 'index' variable x. probability density function: sin() will result in a 'negative' pdf function (less density in center ), while tan() in positive. execution times: -slower than the above park–miller and faster than rand() (but both implementations are uniform). -using tan() is slower than sin(), and tan() requires limiting and some tweaks. use of approximations: -example link with some approximations for trigonometric functions at musicdsp - http://musicdsp.org/files/approx.h plot for tan() - scaled: vid: https://stash.reaper.fm/oldsb/618700/...tribution0.gif extra points for guessing why the @gfx sections outputs the exponential grid. plotter algorithm: https://stash.reaper.fm/oldsb/618769/prngplot short read on trigonometry in non-uniform distributions: http://www.stat.wisc.edu/~larget/math496/random2.html ------ lubomir __________________ Blog / Articles / Music / Reaper DJ tutorial JS plugin pack/ JS Wiki / JS tips / JSfxGen Holos / GitHub / GoogleCode / G+ Last edited by liteon; 09-01-2009 at 07:30 PM.
09-03-2009, 05:13 PM   #21
whatsup
Human being with feelings

Join Date: Aug 2008
Posts: 1,144

Quote:
 Originally Posted by Justin I think it depends on what condi1 refers to.. If it's mostly 0, then 2) should be faster. Other cases, the difference becomes less I'd think.
or maybe it because, it take less time to compare, than to mul ?

EDIT: reffers to that:

cond1 = 0 or 1

Quote:
 Code: //1) spi1 = condi1 * slider1 * spl0; //2) condi1 ? spi1 = slider1 * spl0 : spi1 = 0;
__________________
you can contack me on
whatsup@inn.co.il

Last edited by whatsup; 09-03-2009 at 05:15 PM.

09-09-2009, 12:25 PM   #22
liteon
Human being with feelings

Join Date: Apr 2008
Posts: 510
precision

for evaluation there are 5 decimal places of precision.
Code:
```@sample
a = 5*10^-5; //0.00005
b = 4*10^-5; //0.00004
//(a == b) = 1;
a = 5*10^-4; //0.0005
b = 4*10^-4; //0.0004
//(a == b) = 0;```
justin suggests:
Quote:
 Originally Posted by Justin Note (for the docs), if you need more accuracy, you could do a*1000000 == b*1000000
-----
normally the accuracy of mathematical identities is dependent from the implemented functions (if are based on standards such as IEEE) and also very importantly the precision of the format.

evaluating the identity x=exp(log(x)) in c:
Code:
```x is 5 (single or double)
y=exp(log(x))
* for single precision:
x=5.0, y=5.000000000000000000000
(x==y)=true
* for double precision:
x=5.0, y=4.999999999999999100000
(x==y)=false```
in js (double precision):
Code:
```x=5;
y=exp(log(x));
//x 5.000000...
//y 5.000000... <- js debugger rounds value
x*=10^7;
y*=10^7;
//x 50000000.000000...
//y 49999999.999999...```
assuming that the used mathematical functions are standardized this a trick that can be used to determine the precision in programming languages with less strict variable type definitions.

---
lubomir

 12-01-2009, 09:21 PM #23 liteon Human being with feelings     Join Date: Apr 2008 Posts: 510 jsfxgen spamming a little.. JSfxGEN is a modular ide for jesusonic: http://forum.cockos.com/showthread.php?t=46286 -- __________________ Blog / Articles / Music / Reaper DJ tutorial JS plugin pack/ JS Wiki / JS tips / JSfxGen Holos / GitHub / GoogleCode / G+
 04-25-2013, 11:40 PM #24 bang Human being with feelings     Join Date: Jul 2006 Posts: 554 newJs pseudo-object parameters hello all! seems that the main limitation of newJs pseudo-objects is that inside a function "this.foo" is all there is. there's no inbuilt way to refer to "that.foo". here's my current workaround technique: Code: ```function rgbapush() instance( r, g, b, a ) ( stack_push( a ); stack_push( b ); stack_push( g ); stack_push( r ); ); function rgbapop() instance( r, g, b, a ) ( stack_pop( r ); stack_pop( g ); stack_pop( b ); stack_pop( a ); ); // a.rgbapush(); b.rgbapush(); function rgbamix( mix ) // thread safe instance( r, g, b, a ) local( mix1 ) ( mix1= 1-mix; this.rgbapop(); // this= b.rgbapush(); // keep in sync w/ rgbapop() r= stack_pop() * mix1 + r * mix; //stack_pop( a.r ); g= stack_pop() * mix1 + g * mix; //stack_pop( a.g ); b= stack_pop() * mix1 + b * mix; //stack_pop( a.b ); a= stack_pop() * mix1 + a * mix; //stack_pop( a.a ); ); /*** alas, doesn't work: // a.rgbapush(); b.rgbapush(); function rgbamix2( mix ) instance( r, g, b, a ) local(a1, b1) ( mix1= 1-mix; b1.rgbapop(); a1.rgbapop(); r= a1.r * mix1 + b1.r * mix; g= a1.g * mix1 + b1.g * mix; b= a1.b * mix1 + b1.b * mix; a= a1.a * mix1 + b1.a * mix; ); ***/``` anyone have anything better than this? enjoy! /dan
05-26-2013, 12:32 PM   #25
Justin

Join Date: Jan 2005
Location: NYC
Posts: 12,567

Quote:
 Originally Posted by bang Code: ```/*** alas, doesn't work: // a.rgbapush(); b.rgbapush(); function rgbamix2( mix ) instance( r, g, b, a ) local(a1, b1) ( mix1= 1-mix; b1.rgbapop(); a1.rgbapop(); r= a1.r * mix1 + b1.r * mix; g= a1.g * mix1 + b1.g * mix; b= a1.b * mix1 + b1.b * mix; a= a1.a * mix1 + b1.a * mix; ); ***/``` anyone have anything better than this?
If you changed local(a1,b1) to instance(a1,b1), I believe this might work! local namespace support would be nice, too, but it isn't currently supported.

05-26-2013, 01:30 PM   #26
bang
Human being with feelings

Join Date: Jul 2006
Posts: 554

Quote:
 Originally Posted by Justin If you changed local(a1,b1) to instance(a1,b1), I believe this might work! local namespace support would be nice, too, but it isn't currently supported.
yes. but won't we end up with <psuedo-object>.a1.r/g/b/a and <psuedo-object>.b1.r/g/b/a for every psuedo-object which uses rgbamix2()? i guess i haven't wanted to load up the Js namespace any more than i need to. it already gets to be a pretty massive variables list in the debug window. :^)

and fwiw... what i'd really love to see someday is a way to alias psuedo-object namespaces inside functions. something like:
Code:
```// rgbamix2( mix, a, b )
function rgbamix2( mix, @a1, @b1 )
instance( r, g, b, a )
(
mix1= 1-mix;
r= a1.r * mix1 + b1.r * mix; // r= a.r * mix1 + b.r * mix
g= a1.g * mix1 + b1.g * mix;
b= a1.b * mix1 + b1.b * mix;
a= a1.a * mix1 + b1.a * mix;
);```
just sayin'... :^)

enjoy! /dan

ps- also fwiw, stack_push()/pop() are awesomely useful generally. thanks so much for those.

Last edited by bang; 05-26-2013 at 01:35 PM. Reason: ps

 10-10-2013, 11:49 PM #27 Hubi Human being with feelings   Join Date: Oct 2010 Posts: 75 A simple button maker function: Code: ```function button(state x1 y1 x2 y2 r g b) ( gfx_x = x1; gfx_y = y1; gfx_r =r;gfx_b=b;gfx_g=g; (mouse_x > x1 && mouse_x < x1+x2 && mouse_y > y1 && mouse_y < y1+y2) ? ( gfx_r =r+0.05;gfx_b=b+0.05;gfx_g=g+0.05; mouse_cap == 1 ? ( state = 1; gfx_r =r+0.2;gfx_b=b+0.2;gfx_g=g+0.2; ); ) : ( state = 0; ); gfx_rectto(gfx_x+x2,gfx_y+y2); state; );``` Code: `button_clicked = button(state,20,20,40,20,0.6,0.6,0.6);` state returns "1" if the button is clicked, otherwise it is "0" x1 and y1 are the position of the left top corner x2 and y2 are the size of the button r,g,b color it shows if the mouse hovers over the button and if it is clicked regards Hubi __________________ Switcher, tool for switching articulations
 11-05-2015, 09:54 AM #28 mrlimbic Human being with feelings     Join Date: Nov 2009 Location: UK Posts: 598 Anyone know the maths to calculate a rolling value for the width of the stereo field? __________________ Convert NLE XMLs to RPP. http://vordio.net
11-05-2015, 10:51 AM   #29
derek.john.evans
Human being with feelings

Join Date: Feb 2011
Posts: 217

Quote:
 Originally Posted by mrlimbic Anyone know the maths to calculate a rolling value for the width of the stereo field?
Mmm. This could be one of those deceptively simple questions.

Do you mean RMS or DB or peak levels over time? It should be the same as what is used in DB level displays or compressors, just with the side being used.

vumeter has code to calculate DB over time. dynamics_meter contains code for 3 types of levels over time. Depends on how complex or "accurate" you need it.

Here is some basic code using a decay style level. Or, you can implement a window style level, which is just calculating the level of the average over a time period (window).

Code:
```desc: Mid-Side Levels

@init

sc = 6 / log(2);
response = 0.5;

@sample

// Calculate the DB of mid/side
mid_db = max(log(abs(spl0 + spl1)) * sc, -80);
sid_db = max(log(abs(spl0 - spl1)) * sc, -80);

// Or, calculate the abs level of mid/side
mid_le1 = abs(spl0 + spl1);
sid_le1 = abs(spl0 - spl1);

// Or, calculate the sqrt of abs level of mid/side. (I think this might be RMS)
mid_le2 = sqrt(abs(spl0 + spl1));
sid_le2 = sqrt(abs(spl0 - spl1));

// You can then use a response formular to soften the level changes.
// This is the same type of code used in a compressor.
mid_level += (mid_db - mid_level) * response;
sid_level += (sid_db - sid_level) * response;

@gfx

// Some code to display two DB bars. Needs to be adjusted for other level types.
gfx_r = gfx_g = gfx_b = gfx_a = 1;
gfx_x = 0; gfx_y = 10; gfx_rectto(80 + mid_level, gfx_y + 16);
gfx_x = 0; gfx_y = 40; gfx_rectto(80 + sid_level, gfx_y + 16);```
__________________
http://wascal.net/music/

11-05-2015, 11:01 AM   #30
mrlimbic
Human being with feelings

Join Date: Nov 2009
Location: UK
Posts: 598

Quote:
 Originally Posted by derek.john.evans Mmm. This could be one of those deceptively simple questions. Do you mean RMS or DB or peak levels over time? It should be the same as what is used in DB level displays or compressors, just with the side being used. vumeter has code to calculate DB over time. dynamics_meter contains code for 3 types of levels over time. Depends on how complex or "accurate" you need it. Here is some basic code using a decay style level. Or, you can implement a window style level, which is just calculating the level of the average over a time period (window).
Thanks. I suspect RMS will be more useful. The idea is to create an automation envelope from the stereo width of one audio item and apply that to pan on another item.
__________________
Convert NLE XMLs to RPP.
http://vordio.net

11-05-2015, 11:17 AM   #31
derek.john.evans
Human being with feelings

Join Date: Feb 2011
Posts: 217

Quote:
 Originally Posted by mrlimbic Thanks. I suspect RMS will be more useful. The idea is to create an automation envelope from the stereo width of one audio item and apply that to pan on another item.
Sounds interesting. Have you set up the effect using current JS/VST effects?

Sounds like some kinda stereo field ducking/dodging effect. Maybe start a new thread and document your idea.
__________________
http://wascal.net/music/

11-05-2015, 12:02 PM   #32
mrlimbic
Human being with feelings

Join Date: Nov 2009
Location: UK
Posts: 598

Quote:
 Originally Posted by derek.john.evans Sounds interesting. Have you set up the effect using current JS/VST effects? Sounds like some kinda stereo field ducking/dodging effect. Maybe start a new thread and document your idea.
Yes that's it. It is like ducking but for panning instead of volume (pucking?!!)

It seems I could do it as a multichannel effect (like ducking) or via envelope generation and stick the envelope to the pan parameter of another item.
__________________
Convert NLE XMLs to RPP.
http://vordio.net

 Thread Tools Display Modes Hybrid Mode

 Posting Rules You may not post new threads You may not post replies You may not post attachments You may not edit your posts BB code is On Smilies are On [IMG] code is On HTML code is Off Forum Rules
 Forum Jump User Control Panel Private Messages Subscriptions Who's Online Search Forums Forums Home General Discussion     General Discussion (aka spam trap) REAPER Forums     REAPER General Discussion Forum     newbieland     REAPER Q&A, Tips, Tricks and Howto     Recording Technologies and Techniques     REAPER Compatibility     REAPER Color Themes and Icon Sets     MIDI Hardware, Control Surfaces, and OSC     REAPER Non-English Speaking User Forums         Forum de REAPER en français         Foro de REAPER en Español         Fórum do REAPER em português         Forum di REAPER in italiano         Deutschsprachiges REAPER Userforum         Pyccкоязычный фopyм REAPER     REAPER Bug Reports     REAPER Feature Requests     Dstruct's Casa De Nitpicks     REAPER for Live Use     REAPER for Video Editing/Mangling     REAPER for Ambisonic and 3D positional audio uses     ReaScript, JSFX, REAPER Plug-in Extensions, Developer Forum     REAPER for macOS X     REAPER for Linux     REAPER Pre-Release Discussion     REAPER Music/Collaboration Discussion     REAPER lounge NINJAM Discussion     NINJAM User Discussion     NINJAM Developer Discussion Other Software Discussion     WDL users forum     LICEcap Discussion     OSCII-bot forum     Old Cockos Products Forum

All times are GMT -7. The time now is 01:40 AM.

 -- Cockos ---- REAPER 5 ---- Reaper 3 ---- Reaper 2 ---- Reaper 1 Contact Us - Çockos Incorporated - Archive - Top