diff options
Diffstat (limited to 'libs/fluidsynth/src/fluid_conv.c')
-rw-r--r-- | libs/fluidsynth/src/fluid_conv.c | 92 |
1 files changed, 41 insertions, 51 deletions
diff --git a/libs/fluidsynth/src/fluid_conv.c b/libs/fluidsynth/src/fluid_conv.c index a2ba770b35..5c055d2be9 100644 --- a/libs/fluidsynth/src/fluid_conv.c +++ b/libs/fluidsynth/src/fluid_conv.c @@ -23,66 +23,56 @@ #include "fluid_conv_tables.c" /* - * fluid_ct2hz + * Converts absolute cents to Hertz + * + * As per sfspec section 9.3: + * + * ABSOLUTE CENTS - An absolute logarithmic measure of frequency based on a + * reference of MIDI key number scaled by 100. + * A cent is 1/1200 of an octave [which is the twelve hundredth root of two], + * and value 6900 is 440 Hz (A-440). + * + * Implemented below basically is the following: + * 440 * 2^((cents-6900)/1200) + * = 440 * 2^((int)((cents-6900)/1200)) * 2^(((int)cents-6900)%1200)) + * = 2^((int)((cents-6900)/1200)) * (440 * 2^(((int)cents-6900)%1200))) + * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + * This second factor is stored in the lookup table. + * + * The first factor can be implemented with a fast shift when the exponent + * is always an int. This is the case when using 440/2^6 Hz rather than 440Hz + * reference. */ fluid_real_t fluid_ct2hz_real(fluid_real_t cents) { - if(cents < 0) + if(FLUID_UNLIKELY(cents < 0)) { return (fluid_real_t) 1.0; } - else if(cents < 900) - { - return (fluid_real_t) 6.875 * fluid_ct2hz_tab[(int)(cents + 300)]; - } - else if(cents < 2100) - { - return (fluid_real_t) 13.75 * fluid_ct2hz_tab[(int)(cents - 900)]; - } - else if(cents < 3300) - { - return (fluid_real_t) 27.5 * fluid_ct2hz_tab[(int)(cents - 2100)]; - } - else if(cents < 4500) - { - return (fluid_real_t) 55.0 * fluid_ct2hz_tab[(int)(cents - 3300)]; - } - else if(cents < 5700) - { - return (fluid_real_t) 110.0 * fluid_ct2hz_tab[(int)(cents - 4500)]; - } - else if(cents < 6900) - { - return (fluid_real_t) 220.0 * fluid_ct2hz_tab[(int)(cents - 5700)]; - } - else if(cents < 8100) - { - return (fluid_real_t) 440.0 * fluid_ct2hz_tab[(int)(cents - 6900)]; - } - else if(cents < 9300) - { - return (fluid_real_t) 880.0 * fluid_ct2hz_tab[(int)(cents - 8100)]; - } - else if(cents < 10500) - { - return (fluid_real_t) 1760.0 * fluid_ct2hz_tab[(int)(cents - 9300)]; - } - else if(cents < 11700) - { - return (fluid_real_t) 3520.0 * fluid_ct2hz_tab[(int)(cents - 10500)]; - } - else if(cents < 12900) - { - return (fluid_real_t) 7040.0 * fluid_ct2hz_tab[(int)(cents - 11700)]; - } - else if(cents < 14100) - { - return (fluid_real_t) 14080.0 * fluid_ct2hz_tab[(int)(cents - 12900)]; - } else { - return (fluid_real_t) 1.0; /* some loony trying to make you deaf */ + unsigned int mult, fac, rem; + unsigned int icents = (unsigned int)cents; + icents += 300u; + + // don't use stdlib div() here, it turned out have poor performance + fac = icents / 1200u; + rem = icents % 1200u; + + // Think of "mult" as the factor that we multiply (440/2^6)Hz with, + // or in other words mult is the "first factor" of the above + // functions comment. + // + // Assuming sizeof(uint)==4 this will give us a maximum range of + // 32 * 1200cents - 300cents == 38100 cents == 29,527,900,160 Hz + // which is much more than ever needed. For bigger values, just + // safely wrap around (the & is just a replacement for the quick + // modulo operation % 32). + mult = 1u << (fac & (sizeof(mult)*8u - 1u)); + + // don't use ldexp() either (poor performance) + return mult * fluid_ct2hz_tab[rem]; } } |