17.01.2013 Views

musicdsp.org source code archive - WSInf

musicdsp.org source code archive - WSInf

musicdsp.org source code archive - WSInf

SHOW MORE
SHOW LESS

You also want an ePaper? Increase the reach of your titles

YUMPU automatically turns print PDFs into web optimized ePapers that Google loves.

samples at a time and then storing in memory the temp values for the next block. In this case you may see diferent results and a much bigger drift<br />

(that's my experience with the same algo).<br />

Anyway my algo is a bit diferent as it permits to change the curent type with a parameter, this makes the formula looks like<br />

value = value * coef + contant;<br />

May be this leads to more calculation errors :).<br />

from : schoenebeck ( at ) software ( minus ) engineering.<strong>org</strong><br />

comment : And again... no! :)<br />

Replace the C equation by:<br />

asm volatile (<br />

"movss %1,%%xmm0 # load coeff\n\t"<br />

"movss %2,%%xmm1 # load currentLevel\n\t"<br />

"mulss %%xmm1,%%xmm0 # coeff *= currentLevel\n\t"<br />

"addss %%xmm0,%%xmm1 # currentLevel += coeff * currentLevel\n\t"<br />

"movss %%xmm1,%0 # store currentLevel\n\t"<br />

: "=m" (currentLevel) /* %0 */<br />

: "m" (coeff), /* %1 */<br />

"m" (currentLevel) /* %2 */<br />

);<br />

This is a SSE1 assembly implementation. The SSE registers are only 32 bit<br />

large by guarantee. And this is the result I get:<br />

Calculated sample points: 5764845<br />

Demanded duration: 30.000000 s<br />

Actual duration: 30.025234 s<br />

So this result differs just 1 sample point from the x86 FPU solution! So<br />

believe me, this numerical solution is safe!<br />

(Of course the assembly <strong>code</strong> above is NOT meant as optimization, it's just<br />

to demonstrate the accuracy even for 32 bit / single precision FP<br />

calculation)<br />

from : m (at) mindplay (dot<br />

comment :<br />

from : m (at) mindplay (dot) dk<br />

comment : in my tests, the following <strong>code</strong> produced the exact same results, and saves one operation (the addition) per sample - so it should be<br />

faster:<br />

const float sampleRate = 44100;<br />

float coeff;<br />

float currentLevel;<br />

void init(float levelBegin, float levelEnd, float releaseTime) {<br />

currentLevel = levelBegin;<br />

coeff = exp(log(levelEnd)) /<br />

(releaseTime * sampleRate);<br />

}<br />

inline void calculateEnvelope(int samplePoints) {<br />

for (int i = 0; i < samplePoints; i++) {<br />

currentLevel *= coeff;<br />

// do something with 'currentLevel' here<br />

...<br />

}<br />

}<br />

...<br />

Also, assuming that your startLevel is 1.0, to calculate an appropriate endLevel, you can use something like:<br />

endLevel = 10 ^ dB/20;<br />

where dB is your endLevel in decibels (and must be a negative value of course) - for amplitude envelopes, -90 dB should be a suitable level for "near<br />

inaudible"...<br />

from : schoenebeck ( at ) software ( minus ) engineering.<strong>org</strong><br />

comment : Sorry, you are right of course; that simplification of the execution<br />

equation works here because we are calculating all points with linear<br />

discretization. But you will agree that your init() function is not good,<br />

because exp(log(x)) == x and it's not generalized at all. Usually you might<br />

have more than one exp segment in your EG and maybe even have an exp attack<br />

segment. So we arrive at the following solution:<br />

const float sampleRate = 44100;<br />

float coeff;<br />

float currentLevel;<br />

void init(float levelBegin, float levelEnd, float releaseTime) {<br />

currentLevel = levelBegin;

Hooray! Your file is uploaded and ready to be published.

Saved successfully!

Ooh no, something went wrong!