about: Poly-Ana

DSP, Plugin and Host development discussion.
RELATED
PRODUCTS

Post

OK, I've had several of you knowledgeable types ask me very good questions in the Poly-Ana announcement thread http://www.kvraudio.com/forum/viewtopic.php?t=153748 . So rather than get too into technical stuff there, you guys can go ahead and question me, and HELP me, here in this thread.

You've all already been a great help. As I've already stated, it would be unlikey that this synth would exist if not for KVR and all the great people on it.

So... to get things started... what IS the transfer function to correct for an IIR's cutoff curve, anyway? :D It's 2:1 at the low end... but it gets curvier towards the top. If I could correct for this, then filter tracking wouldn't change when my users select different oversample rates.

??? :help:

Post

I'm not saying what you should do or what anyone else should do, but in situations like the filter cutoff changes between oversampling settings, I always try to find a way to make the computer do the work.

In this case, if you're happy with the 8x oversampling, I'd set up the synth to switch between 8x and 4x, for example, and do FFTs on the output until it comes up with a good match.

Stupid, I know, but I prefer the computer staying up all night working on the program while I sleep. When I was doing videogames, I often had AI bots fight it out all night to get them as good as possible.

Post

mistertoast wrote:I'm not saying what you should do or what anyone else should do, but in situations like the filter cutoff changes between oversampling settings, I always try to find a way to make the computer do the work.

In this case, if you're happy with the 8x oversampling, I'd set up the synth to switch between 8x and 4x, for example, and do FFTs on the output until it comes up with a good match.

Stupid, I know, but I prefer the computer staying up all night working on the program while I sleep. When I was doing videogames, I often had AI bots fight it out all night to get them as good as possible.
Yes, the empirical approach again. And you're right, I could just create a giant lookup table to do that. But that would add CPU cost that we all already understand, where instead I think a simple formula with only a few factors will do.

Now, that data WILL be valuable in figuring out what that formula is... but I can't help but think that there's somebody else out there who already knows this, and who'd like a free copy. :hihi:

Post

>>Now, that data WILL be valuable in figuring out what that formula is...

That's exactly what I was thinking. But yeah, if someone already knows the answer...

Post

Congratulations on your release AQ, Did you find an efficient method to calculate the Pitch to Frequency curve relation? I managed to improve the accuracy of the fast power method I was suggesting a while back if you are interested...

For the IIR, whats the relation between the frequency and the coefficients and what do you use for an approximation? If the algebraic relation involves sines or cosines, just replace these with chebyshev polynomials, you can always improve accuracy by adding more terms..

Sam

Post

sambean wrote:Congratulations on your release AQ, Did you find an efficient method to calculate the Pitch to Frequency curve relation? I managed to improve the accuracy of the fast power method I was suggesting a while back if you are interested...

For the IIR, whats the relation between the frequency and the coefficients and what do you use for an approximation? If the algebraic relation involves sines or cosines, just replace these with chebyshev polynomials, you can always improve accuracy by adding more terms..

Sam
Nope, it's still powf. Per-sample. (It should really be per-subsample but it's taking enough time as it is.)

And again, the relation between real sample rate and cutoff for the filter coeff's is 2:1. Crazy, eh? :) This works perfectly when oversampling is high, and not well at all when there's no oversampling. Like I said in the other thread... the curve is mostly flat at the low end, and only get's curvy towards the top. This is why oversampling (and reality) work to fix these non-linearities. I'm sure if you sampled a real analog LPF up into the gigahertz, you'd find the exact same curve at some point.

Post

I think mistertoast was on the mark to get the data. I actually did what he suggested *manually* (yes it was mad but it was a learning type of thing that I never have to do again).

giant lookup tables? but couldn't you easily omit values from those. Just use the points that matter. As far as I understood you would only ever need 128 max (number of midi notes), and I'm sure not all of them are significant when smoothed out with the right polynomial. It might end up as something surprisingly simple and "cost effective".

Post

Here's a fastish pitch to frequency converter, it's not super efficient, but probably a lot better than powf(). I've not benchmarked it but if somebody wants to that would be great..

It converts a delta-pitch measured in semi-tones to a frequency scale, so an input of zero gives 1, input of 12 gives 2, -12->0.5 etc etc.. The maximum error is < 0.02% across the octave, the error is the same for every octave so theres no drift for high/low values

Also, there's no exceptions so you may get silly results if you try to convert a delta pitch > 1000...

If you want it slightly faster use the second cheby approximation.

Code: Select all

#include <math.h>

float fastishP2F (float pitch)
{
long convert;
float *p=(float *)&convert;
float fl,fr,warp,out;

pitch *=0.0833333; //pitch scaling. remove this line for pow(2,a)
fl = floor(pitch);
fr = pitch - fl;
warp = fr*0.696 + fr*fr*0.225 + fr*fr*fr*0.079; // chebychev approx
//warp = fr*0.65 + fr*fr*0.35; // chebychev approx

out = fl+warp;
out *= 8388608.0; //2^23;
out += 127.0 * 8388608.0; //2^23;

convert = (long)out; //magic

return *p;
}
Let me know if it works...

Sam

Post

it certainly looks reasonably efficient. AQ's real problem seems to lie with the usual filter frequency nyquist wrap-around. I don't think it's actually non-linear (any further than simply polynomials anyway), and as I have fought with the exact same problem, I would be interested to know if there is an academic solution, some kludge of a coefficient calculator or somesuch.

(I still consider my forking method cheating, despite the fact it works)

Post

well the usual method is 2*sin((2/rate) * frequency)
i think..

Post

There is no pi in Poly-Ana! ;) (Well, except in the knob GUI code.)

I'll take a look at your algo sambean. Thanks. I COULD use a faster pitch to freq converter than powf. And if I can get it fast enough, then I can pull that calc into the subsample loop for improved FM accuracy (it's in the sample loop right now)

Post

for this:
sambean wrote:warp = fr*0.696 + fr*fr*0.225 + fr*fr*fr*0.079;
is this perhaps better?

warp = fr * (0.696 + fr * (0.225 + fr * 0.079);

Post

pj geerlings wrote:for this:
sambean wrote:warp = fr*0.696 + fr*fr*0.225 + fr*fr*fr*0.079;
is this perhaps better?

warp = fr * (0.696 + fr * (0.225 + fr * 0.079);
I havn't read the whole thread but a horner scheme isn't always better. Think of processors with more than one ALU. If it is the first version two (ore more) calculations can be done parallel.

But anyway modern compilers are usually able to 'unhorner' the code anyway.

Christian

Post

Yeah, it's not the best code, I didn't bother optimizing it for clarity, hence lines like:

Code: Select all

out += 127.0 * 8388608.0;
But as Christian says it shouldn't be a problem for a compiler...

For sub-sample accuracy, would it not be sufficient to linear interpolate the value between samples (or perhaps have the option?) It would certainally improve the performance...

For your curve, to know how to improve the accuracy at higher frequencies more information on the function would be needed. You could just use a table lookup, but you can probably get a pretty fast polynomial to be accurate enough..

Sam

Post

pj geerlings wrote:for this:
sambean wrote:warp = fr*0.696 + fr*fr*0.225 + fr*fr*fr*0.079;
is this perhaps better?

warp = fr * (0.696 + fr * (0.225 + fr * 0.079);
Thats the worst posible code for the cpu, every op is dependant on the result of the previous one, so it will be very slow.

Not so long ago I tested using Taylor exapansion for doing a fast exp, i think around 7 or 8 terms, and it ended up costing 90 cycles iirc. 7 for the muls and 3 for the adds, all dependant so they all took the full latency.

Im not sure if there is any faster way tbh.

chris

Post Reply

Return to “DSP and Plugin Development”