[gen~] additive synthesis efficiency problem
A student used an LLM to populate a gen~ with an additive approach to plucked string synthesis.
It's a bit CPU-heavier than I'd like (well, kind of a lot CPU heavier, particularly if the goal is to introduce polyphony later).
An "elapsed" counter is initialized when a trigger signal is received ("prev <= 0 && now > 0"); otherwise, it's incremented by 1/sr. Then a loop drives it:
limit = min(20000, f1*256);
i = 1;
for (fn = f1; fn < limit; fn += f1) {
i += 1;
// Modal force amplitude
an = sign * K * sin(i * 3.14159265359 * p) / i;
// Individual decay time
dn = tau0 * pitchDecay / pow(i, alpha);
// Modal oscillation and exponential decay
sn = an * exp(-elapsed / dn)
* cos(6.28318530718 * fn * elapsed);
// Accumulate
sum = sum + sn;
}I'm leaving out a few details that are not relevant to the code structure.
I'm not sure of the relationship between the code box contents and the eventual llvm stuff, so I'm at a bit of a loss to suggest how to make it more efficient. If it were standard imperative code, I would perhaps cache the 'an' values and not do sin() every time, and replace the pow and exp with cascaded multiplications. Not sure how gen~ handles those.
Any ideas?
hjh
sin() ist very cheap on modern processors, given that the poor thing might end up in a [poly~ foo up 16] i don´t think a lookuptable will be any better.
Computers really don't like division. I would see if you can replace them with multipliers especially when used in heavy math functions such as here. If you know the limit its 1/n before your loop and just multiply it by i*1/n within the loop itself.
Source:
https://cycling74.com/forums/need-help-cleaning-up-a-gen-patch
At one point in the thread here i removed 8-ish divi...ders? and got a performance increase of 10% in that case so that was pretty convincing of the benefit of doing so