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: 310 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. __________________ :: blog :: github :: skei.audio :: ccernn.audio :: lethe :: manes :: manii ::
07-22-2009, 03:06 PM   #7
Mich
Human being with feelings

Join Date: May 2009
Posts: 1,265

Quote:
 Originally Posted by cern.th.skei 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 low/highpass is a perfectly correct RC filter as far as I can tell.

The formula to calculate the "weight" from frequency is:
weight = 1-exp(-2*\$pi*fc/srate);
and for time (that is RC time constant) it is:
weight = 1-exp(-1/t); where t is the time it takes the filter to decay to 36.8% of its initial input or reach 63.2% of its final output.

P.S. liteon you accidentally have a seed of 0 in one of your examples.

Last edited by Mich; 07-22-2009 at 03:15 PM. Reason: I'm an idiot! :(

 07-22-2009, 10:07 PM #8 dub3000 Human being with feelings     Join Date: Mar 2008 Location: Sydney, Australia Posts: 3,813 great thread, thanks!
 07-23-2009, 02:24 AM #9 cern.th.skei Human being with feelings     Join Date: Sep 2007 Location: trondheim, norway Posts: 310 sample accuracy another two snippets or examples, related to sample accuracy. you might need to tweak these to make them work in your own code.. if you want somethig to happen every x samples, for timing or sync, you can do something like this: Code: ```desc:sample accurate timing @block size = beats * srate / (tempo/60); // transport change play_state != prevstate ? ( play_state&1 ? countdown=0;//speed; prevstate = play_state; ); // timing offset = 0; block = samplesblock; while( countdown>=block ? ( countdown-=block; block=0; ) : ( offset += countdown; block-=countdown; // ...do stuff here... // ...or set some flags/variables... // ...offset = offset within current block (for midi out, etc) countdown=size; ); block>0; );``` and, one for handling midi events.. only one event per sample/offset here, but if you need more (notes?), you can stuff the _number_ of events per sample into the EVENTS buffer, and have another buffer where the actual events or data is stored, or have a 2d buffer and some indexing (offset*max_events_per_offset): Code: ```desc:sample accurate midi events slider1: 60 <0,127,1> midi cc num @init EVENTS = \$x10000; i127 = 1/127; i256 = 1/256; @slider midicc = slider1; @block memset(EVENTS,-1,samplesblock); // ??? while( midirecv(ofs,msg1,msg23) ? ( msg = msg1 & 240; msg == (11*16) ? ( cc = msg23 & 127; cc==midicc ? ( val = (msg23*i256) & 127; EVENTS[ofs] = val*i127; // -> 0..1 ); ); //midisend(ofs,msg1,msg23); ); ); offset = 0; @sample EVENTS[offset]>=0 ? ( our_value = EVENTS[offset]; ); EVENTS[offset] = -1; offset += 1; // ...use our_value for something``` (let's hope my cut'n'paste didn't introduce too many errors or incompabilities) - ccernn __________________ :: blog :: github :: skei.audio :: ccernn.audio :: lethe :: manes :: manii ::
07-23-2009, 02:50 AM   #10
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 #11 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 #12 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 #13 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 #14 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.
 07-24-2009, 12:55 PM #15 liteon Human being with feelings     Join Date: Apr 2008 Posts: 510 using lookup tables for expensive functions, lookup tables (lut) can be used, so that the values are pre-computed in indexes (@init section) and only certain indexes are called in realtime (@sample section). results from using lut - are great accuracy and fast execution times. here is an example with the log() function: Code: ```@init //set depth of 256 indexes depth=2^8; i=0; loop(depth, //add value ln[i]=log(i/depth); i+=1; ); @sample //possible x range in this case [0,1] x=0.5; //multiply input to depth. x=ln[x*depth]; // <-- the fractional part is discarded by the compiler``` some outputs for the above: Code: ``` depth is: 256 --- input is: 0.1 >> call index: 25 >> log(x): -2.30258509299405 >> from lut: -2.32630161961136 --- input is: 0.5 >> call index: 128 >> log(x): -0.693147180559945 >> from lut: -0.693147180559945 --- input is: 1 >> call index: 256 >> log(x): 0 >> from lut: 0 ``` performance: - in the form of: Code: ```x=0.5; y=x; y*=depth; loop(100, y=ln[y]; );``` cpu usage is 35% compared to 57% for 100 calls of x=log(x) notes: - bigger accuracy is achieved with bigger scaling factor 'depth' (and more indexes accordingly). - if not enough accuracy - lower index is returned. example: Code: ``` depth is: 256 --- input is: 0.01 >> call index: 2 >> log(x): -4.60517018598809 >> from lut: -4.85203026391962 --- input is: 0.001 >> call index: 0 >> log(x): -6.90775527898214 >> from lut: -Infinity ``` - a simple modification is required for negative inputs values (as there are no negative indexes) or different ranges other than [0,1]. in the case of ln[] negative indexes will return 0, which is acceptable. - this method can be used for many functions, such as exp(), rand(), sin(), b^x and etcetera. --- lubomir __________________ Blog / Articles / Music / Reaper DJ tutorial JS plugin pack/ JS Wiki / JS tips / JSfxGen Holos / GitHub / GoogleCode / G+ Last edited by liteon; 08-22-2009 at 04:17 PM.
 07-28-2009, 04:48 AM #16 liteon Human being with feelings     Join Date: Apr 2008 Posts: 510 oversampling with "zero-stuffing" method "oversampling" in dsp therms is "processing at a higher sample rate, then restoring to the original sample rate" or related to a dsp effect which is "oversampled". The most common use is in cases, where effects produce the reflection like artifact of "aliasing" (or static distortion). Nx oversampling requires execution of the same process Nx times. a 4x os scheme for a non-recursive [fx]: usf - up-sample dsf - down-sample bl - band-limit (aliasing reduction or anti-aliasing) Code: ``` -->- [fx0] [bl] -->- / \ [usf] [dsf] / \ / \ / -->- [fx1] [bl] -->- \ / \ [usf] [dsf] \ / \ -->- [fx2] [bl] -->- / \ / \ / [usf] [dsf] \ / -->- [fx3] [bl] -->-``` the above scheme is only for a non-recursive fx (not using previous sample values) in the lines of y(n)=sin(x(n)). for a recursive fx in the lines of y(n)=sin((x(n-1)+x(n))*0.5), the following must be done: one should think of the two outputs of an up-sample filter as a sequence in a discrete signal: out0 is followed by out1, but to make an recursive fx work, you should feed the result of processing of out0 into fx1, since out0 is previous to out1. and then for the next call the processed output of out1 should be fed into fx0. if we block-diagram this: Code: ``` --[out0] ->--------- [fx0] -- [result0] ->- ... / ...(result1) ->----/ [usf] \ --[out1] ->--------- [fx1] -- [result1] ->- ... ...(result0) ->----/``` a triangular window filter as an example: Code: ```//usf usout0=(usout1+input)*0.5; usout1=input; //fxout0 = process -> usout0; //fxout1 = process -> usout1; //bandlimit -> fxout0; //bandlimit -> fxout1; //dsf output=0.25*(dsmem0+2*dsmem1+fxout1); dsmem0=fxout0; dsmem1=fxout1;``` notes: - up/down sampling introduces aliasing of its own. - the quality of the up/down sample and band-limit filters is of great importance (high order filters required). the above triangular filter requires "signal restoration" in the form of high-shelf boost or similar since it also affects the audible range. - oversampling ends up as a resource expensive process, so it is best to be avoided, unless more resources are available. extended information: http://ccrma.stanford.edu/~jos/resample/resample.html (by jos - ccrma @ stanford) http://synthmaker.co.uk/dokuwiki/dok...s:oversampling (by andrew j - sm) --- lubomir __________________ Blog / Articles / Music / Reaper DJ tutorial JS plugin pack/ JS Wiki / JS tips / JSfxGen Holos / GitHub / GoogleCode / G+ Last edited by liteon; 08-01-2009 at 08:09 PM.
 08-20-2009, 07:12 AM #17 Fabian Human being with feelings     Join Date: Sep 2008 Location: Sweden Posts: 5,252 MIDI-only FX, in/out_pin:none This is from JS:MIDI/midi_transpose. I had no idea, but it seems to make sense. Code: ```// these lines tell Reaper the effect has no audio input/output, // which enables processing optimizations. // MIDI-only FX should always have these lines. in_pin:none out_pin:none``` __________________ // MVHMF I never always did the right thing, but all I did wasn't wrong...
08-20-2009, 08:16 AM   #18
Justin

Join Date: Jan 2005
Location: NYC
Posts: 11,863

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 #19 IXix Human being with feelings   Join Date: Jan 2007 Location: mcr:uk Posts: 3,354 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   #20
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 #21 Tale Human being with feelings     Join Date: Jul 2008 Location: Holland Posts: 2,926 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 Scanner Vibrato - Tale's JSFX Pack - WDL.git
 09-01-2009, 06:30 PM #22 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, 03:43 PM #23 liteon Human being with feelings     Join Date: Apr 2008 Posts: 510 fm/rm/am a post which summarizes some modulation methods (fm, rm, am), can be found here: http://forum.cockos.com/showpost.php...34&postcount=7 (also an optimized square wave is included.) -- lubomir __________________ Blog / Articles / Music / Reaper DJ tutorial JS plugin pack/ JS Wiki / JS tips / JSfxGen Holos / GitHub / GoogleCode / G+
09-03-2009, 05:13 PM   #24
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   #25
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 #26 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+
 12-12-2009, 03:01 AM #27 liteon Human being with feelings     Join Date: Apr 2008 Posts: 510 using memory slots __________________ Blog / Articles / Music / Reaper DJ tutorial JS plugin pack/ JS Wiki / JS tips / JSfxGen Holos / GitHub / GoogleCode / G+
 02-11-2010, 07:49 PM #28 liteon Human being with feelings     Join Date: Apr 2008 Posts: 510 calculating RMS for continous waveforms some info here: http://forum.cockos.com/showthread.php?t=51621 make sure you check the provided JesuSonic plugins (names) for code examples. -- __________________ Blog / Articles / Music / Reaper DJ tutorial JS plugin pack/ JS Wiki / JS tips / JSfxGen Holos / GitHub / GoogleCode / G+ Last edited by liteon; 02-11-2010 at 07:57 PM.
 02-11-2010, 08:59 PM #29 dub3000 Human being with feelings     Join Date: Mar 2008 Location: Sydney, Australia Posts: 3,813 thanks again, liteon. these posts are really useful. still love your JS plugins as well, the moog filter and waveshaper end up on everything!
 03-07-2010, 03:34 AM #30 zorn Human being with feelings   Join Date: Feb 2008 Location: france Posts: 230 not a useful snippet, here's just a JS language file for Notepad++. could be improved, the main interest is being able to fold text ( /* or //@ starts a a block of text and */ or //- closes it ) how to install : http://notepad-plus.sourceforge.net/uk/download.php https://stash.reaper.fm/oldsb/814716/...nguageFile.txt Last edited by zorn; 03-07-2010 at 04:56 AM.
06-12-2010, 09:38 AM   #31
magnus0re
Human being with feelings

Join Date: Jan 2010
Location: Bergen, Norway.
Posts: 78

Quote:
 Originally Posted by zorn not a useful snippet, here's just a JS language file for Notepad++. could be improved, the main interest is being able to fold text ( /* or //@ starts a a block of text and */ or //- closes it ) how to install : http://notepad-plus.sourceforge.net/uk/download.php https://stash.reaper.fm/oldsb/814716/...nguageFile.txt
Awesome, but how do i add the custom language to notepad++ ?

06-12-2010, 11:48 AM   #32
Fabian
Human being with feelings

Join Date: Sep 2008
Location: Sweden
Posts: 5,252

Quote:
 Originally Posted by magnus0re Awesome, but how do i add the custom language to notepad++ ?
You could start by googeling.
http://sourceforge.net/apps/mediawik...ghting_Sharing
http://sourceforge.net/apps/mediawik...ined_Languages
etc...
__________________
// MVHMF
I never always did the right thing, but all I did wasn't wrong...

06-12-2010, 03:49 PM   #33
magnus0re
Human being with feelings

Join Date: Jan 2010
Location: Bergen, Norway.
Posts: 78

Quote:
 Originally Posted by Fabian You could start by googeling.
Yeah, I tried to do that, and did that. does not work for me apparently.

 07-05-2010, 06:10 AM #34 IXix Human being with feelings   Join Date: Jan 2007 Location: mcr:uk Posts: 3,354 Synchronised MIDI generator template Thought I'd give my karma a boost by sharing this. It's well commented, easy to read and includes my graphical debugging aid, so it should be useful to beginners. IX MIDI Generator Template It's a sort of template for a host synchronised MIDI generator. You could probably use it to build something like a drum machine or it would be easy to strip out the MIDI parts and just use the underlying synchronisation. Not sure if it's sample accurate but the timing is solid. Edit: 2010.07.07 Oops, fixed incorrect slider definitions! Remember children, always test before you post. Last edited by IXix; 07-07-2010 at 07:20 AM.
 11-17-2010, 04:29 AM #35 IXix Human being with feelings   Join Date: Jan 2007 Location: mcr:uk Posts: 3,354 Made a slightly better version of the above. https://stash.reaper.fm/v/7106/IX%20M...plate%20II.zip Swingin'!
02-26-2011, 08:31 AM   #36
groundhum
Human being with feelings

Join Date: Jan 2011
Location: Finger Lakes, NY
Posts: 54

Quote:
 Originally Posted by IXix Made a slightly better version of the above. https://stash.reaper.fm/v/7106/IX%20M...plate%20II.zip
EDIT: Thanks, IXix, for the template. It saved me a great deal of wailing and gnashing of teeth. But the thrill of figuring out what stupid thing I'd done overwhelmed my sense of decency and good manners, and I forgot to note that originally.

Because I've been watching variables until my eyeballs are ready to bleed, might I suggest some small changes and/or additional commentary in lines 273-278 regarding dynamic note and velocity values?

If line 274 is changed to e.g.
Code:
`velocity = rand(90)+30;`
note is stomped upon.
Code:
`velocity = (rand(90)+30) & 127;`
avoids this unpleasant and time-consuming circumstance. And if the expression for note is likewise masked in line 273
Code:
`note = (rand(36)+36) & 127;`
for example, then lines 277 & 278 become redundant. Trust me; I know these things to be true. Now, at least…

Here's hoping this helps some other intrepid JS novice,
m.
__________________
Michael Rees, composer &c.
extraneous data

Last edited by groundhum; 02-26-2011 at 08:47 AM. Reason: bad manners

03-23-2011, 01:17 PM   #37
caseyjames
Human being with feelings

Join Date: Jul 2009
Posts: 627

Quote:
 Originally Posted by IXix Made a slightly better version of the above. https://stash.reaper.fm/v/7106/IX%20M...plate%20II.zip Swingin'!
How hard would it be to implement a function to read-in small midi files to use as sequences? Has anyone done anything like that with this yet?

This seems like a very useful template for future projects.

03-24-2011, 08:33 AM   #38
Mich
Human being with feelings

Join Date: May 2009
Posts: 1,265

Quote:
 Originally Posted by caseyjames How hard would it be to implement a function to read-in small midi files to use as sequences? Has anyone done anything like that with this yet? This seems like a very useful template for future projects.
Can't read MIDI files into JS AFAIK.

 03-24-2011, 01:43 PM #39 caseyjames Human being with feelings     Join Date: Jul 2009 Posts: 627 Not that I'd be able to write a handler for them, but is it not possible to write something within JS to read a midi file? Is it not able to load arbitrary files, even if it can't cope with them?
 03-24-2011, 01:59 PM #40 groundhum Human being with feelings     Join Date: Jan 2011 Location: Finger Lakes, NY Posts: 54 Yep. Pages 5 & 6 of the js sdk. IXix's MIDI_Velocifier II will show you how. __________________ Michael Rees, composer &c. extraneous data

 Thread Tools Display Modes Linear 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:12 AM.

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