diff options
Diffstat (limited to 'libs/fluidsynth/src/fluid_conv.c')
-rw-r--r-- | libs/fluidsynth/src/fluid_conv.c | 463 |
1 files changed, 276 insertions, 187 deletions
diff --git a/libs/fluidsynth/src/fluid_conv.c b/libs/fluidsynth/src/fluid_conv.c index 1a790cfbfb..555dd61367 100644 --- a/libs/fluidsynth/src/fluid_conv.c +++ b/libs/fluidsynth/src/fluid_conv.c @@ -3,16 +3,16 @@ * Copyright (C) 2003 Peter Hanappe and others. * * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public License - * as published by the Free Software Foundation; either version 2 of + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. + * Lesser General Public License for more details. * - * You should have received a copy of the GNU Library General Public + * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA @@ -20,15 +20,17 @@ #include "fluid_conv.h" +#define FLUID_CENTS_HZ_SIZE 1200 +#define FLUID_VEL_CB_SIZE 128 +#define FLUID_CB_AMP_SIZE 1441 +#define FLUID_PAN_SIZE 1002 /* conversion tables */ -fluid_real_t fluid_ct2hz_tab[FLUID_CENTS_HZ_SIZE]; -fluid_real_t fluid_cb2amp_tab[FLUID_CB_AMP_SIZE]; -fluid_real_t fluid_atten2amp_tab[FLUID_ATTEN_AMP_SIZE]; -fluid_real_t fluid_posbp_tab[128]; -fluid_real_t fluid_concave_tab[128]; -fluid_real_t fluid_convex_tab[128]; -fluid_real_t fluid_pan_tab[FLUID_PAN_SIZE]; +static fluid_real_t fluid_ct2hz_tab[FLUID_CENTS_HZ_SIZE]; +static fluid_real_t fluid_cb2amp_tab[FLUID_CB_AMP_SIZE]; +static fluid_real_t fluid_concave_tab[FLUID_VEL_CB_SIZE]; +static fluid_real_t fluid_convex_tab[FLUID_VEL_CB_SIZE]; +static fluid_real_t fluid_pan_tab[FLUID_PAN_SIZE]; /* * void fluid_synth_init @@ -38,58 +40,52 @@ fluid_real_t fluid_pan_tab[FLUID_PAN_SIZE]; void fluid_conversion_config(void) { - int i; - double x; - - for (i = 0; i < FLUID_CENTS_HZ_SIZE; i++) { - fluid_ct2hz_tab[i] = (fluid_real_t) pow(2.0, (double) i / 1200.0); - } - - /* centibels to amplitude conversion - * Note: SF2.01 section 8.1.3: Initial attenuation range is - * between 0 and 144 dB. Therefore a negative attenuation is - * not allowed. - */ - for (i = 0; i < FLUID_CB_AMP_SIZE; i++) { - fluid_cb2amp_tab[i] = (fluid_real_t) pow(10.0, (double) i / -200.0); - } - - /* NOTE: EMU8k and EMU10k devices don't conform to the SoundFont - * specification in regards to volume attenuation. The below calculation - * is an approx. equation for generating a table equivelant to the - * cb_to_amp_table[] in tables.c of the TiMidity++ source, which I'm told - * was generated from device testing. By the spec this should be centibels. - */ - for (i = 0; i < FLUID_ATTEN_AMP_SIZE; i++) { - fluid_atten2amp_tab[i] = (fluid_real_t) pow(10.0, (double) i / FLUID_ATTEN_POWER_FACTOR); - } - - /* initialize the conversion tables (see fluid_mod.c - fluid_mod_get_value cases 4 and 8) */ - - /* concave unipolar positive transform curve */ - fluid_concave_tab[0] = 0.0; - fluid_concave_tab[127] = 1.0; - - /* convex unipolar positive transform curve */ - fluid_convex_tab[0] = 0; - fluid_convex_tab[127] = 1.0; - x = log10(128.0 / 127.0); - - /* There seems to be an error in the specs. The equations are - implemented according to the pictures on SF2.01 page 73. */ - - for (i = 1; i < 127; i++) { - x = -20.0 / 96.0 * log((i * i) / (127.0 * 127.0)) / log(10.0); - fluid_convex_tab[i] = (fluid_real_t) (1.0 - x); - fluid_concave_tab[127 - i] = (fluid_real_t) x; - } - - /* initialize the pan conversion table */ - x = PI / 2.0 / (FLUID_PAN_SIZE - 1.0); - for (i = 0; i < FLUID_PAN_SIZE; i++) { - fluid_pan_tab[i] = (fluid_real_t) sin(i * x); - } + int i; + double x; + + for(i = 0; i < FLUID_CENTS_HZ_SIZE; i++) + { + fluid_ct2hz_tab[i] = (fluid_real_t) pow(2.0, (double) i / 1200.0); + } + + /* centibels to amplitude conversion + * Note: SF2.01 section 8.1.3: Initial attenuation range is + * between 0 and 144 dB. Therefore a negative attenuation is + * not allowed. + */ + for(i = 0; i < FLUID_CB_AMP_SIZE; i++) + { + fluid_cb2amp_tab[i] = (fluid_real_t) pow(10.0, (double) i / -200.0); + } + + /* initialize the conversion tables (see fluid_mod.c + fluid_mod_get_value cases 4 and 8) */ + + /* concave unipolar positive transform curve */ + fluid_concave_tab[0] = 0.0; + fluid_concave_tab[FLUID_VEL_CB_SIZE - 1] = 1.0; + + /* convex unipolar positive transform curve */ + fluid_convex_tab[0] = 0; + fluid_convex_tab[FLUID_VEL_CB_SIZE - 1] = 1.0; + + /* There seems to be an error in the specs. The equations are + implemented according to the pictures on SF2.01 page 73. */ + + for(i = 1; i < FLUID_VEL_CB_SIZE - 1; i++) + { + x = (-200.0 / FLUID_PEAK_ATTENUATION) * log((i * i) / (fluid_real_t)((FLUID_VEL_CB_SIZE - 1) * (FLUID_VEL_CB_SIZE - 1))) / M_LN10; + fluid_convex_tab[i] = (fluid_real_t)(1.0 - x); + fluid_concave_tab[(FLUID_VEL_CB_SIZE - 1) - i] = (fluid_real_t) x; + } + + /* initialize the pan conversion table */ + x = M_PI / 2.0 / (FLUID_PAN_SIZE - 1.0); + + for(i = 0; i < FLUID_PAN_SIZE; i++) + { + fluid_pan_tab[i] = (fluid_real_t) sin(i * x); + } } /* @@ -98,35 +94,62 @@ fluid_conversion_config(void) fluid_real_t fluid_ct2hz_real(fluid_real_t cents) { - if (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 */ - } + if(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 */ + } } /* @@ -135,55 +158,46 @@ fluid_ct2hz_real(fluid_real_t cents) fluid_real_t fluid_ct2hz(fluid_real_t cents) { - /* Filter fc limit: SF2.01 page 48 # 8 */ - if (cents >= 13500){ - cents = 13500; /* 20 kHz */ - } else if (cents < 1500){ - cents = 1500; /* 20 Hz */ - } - return fluid_ct2hz_real(cents); + /* Filter fc limit: SF2.01 page 48 # 8 */ + if(cents >= 13500) + { + cents = 13500; /* 20 kHz */ + } + else if(cents < 1500) + { + cents = 1500; /* 20 Hz */ + } + + return fluid_ct2hz_real(cents); } /* * fluid_cb2amp * - * in: a value between 0 and 960, 0 is no attenuation + * in: a value between 0 and 1440, 0 is no attenuation * out: a value between 1 and 0 */ fluid_real_t fluid_cb2amp(fluid_real_t cb) { - /* - * cb: an attenuation in 'centibels' (1/10 dB) - * SF2.01 page 49 # 48 limits it to 144 dB. - * 96 dB is reasonable for 16 bit systems, 144 would make sense for 24 bit. - */ - - /* minimum attenuation: 0 dB */ - if (cb < 0) { - return 1.0; - } - if (cb >= FLUID_CB_AMP_SIZE) { - return 0.0; - } - return fluid_cb2amp_tab[(int) cb]; -} + /* + * cb: an attenuation in 'centibels' (1/10 dB) + * SF2.01 page 49 # 48 limits it to 144 dB. + * 96 dB is reasonable for 16 bit systems, 144 would make sense for 24 bit. + */ -/* - * fluid_atten2amp - * - * in: a value between 0 and 1440, 0 is no attenuation - * out: a value between 1 and 0 - * - * Note: Volume attenuation is supposed to be centibels but EMU8k/10k don't - * follow this. Thats the reason for separate fluid_cb2amp and fluid_atten2amp. - */ -fluid_real_t -fluid_atten2amp(fluid_real_t atten) -{ - if (atten < 0) return 1.0; - else if (atten >= FLUID_ATTEN_AMP_SIZE) return 0.0; - else return fluid_atten2amp_tab[(int) atten]; + /* minimum attenuation: 0 dB */ + if(cb < 0) + { + return 1.0; + } + + if(cb >= FLUID_CB_AMP_SIZE) + { + return 0.0; + } + + return fluid_cb2amp_tab[(int) cb]; } /* @@ -192,21 +206,27 @@ fluid_atten2amp(fluid_real_t atten) fluid_real_t fluid_tc2sec_delay(fluid_real_t tc) { - /* SF2.01 section 8.1.2 items 21, 23, 25, 33 - * SF2.01 section 8.1.3 items 21, 23, 25, 33 - * - * The most negative number indicates a delay of 0. Range is limited - * from -12000 to 5000 */ - if (tc <= -32768.0f) { - return (fluid_real_t) 0.0f; - }; - if (tc < -12000.) { - tc = (fluid_real_t) -12000.0f; - } - if (tc > 5000.0f) { - tc = (fluid_real_t) 5000.0f; - } - return (fluid_real_t) pow(2.0, (double) tc / 1200.0); + /* SF2.01 section 8.1.2 items 21, 23, 25, 33 + * SF2.01 section 8.1.3 items 21, 23, 25, 33 + * + * The most negative number indicates a delay of 0. Range is limited + * from -12000 to 5000 */ + if(tc <= -32768.0f) + { + return (fluid_real_t) 0.0f; + }; + + if(tc < -12000.) + { + tc = (fluid_real_t) -12000.0f; + } + + if(tc > 5000.0f) + { + tc = (fluid_real_t) 5000.0f; + } + + return (fluid_real_t) pow(2.0, (double) tc / 1200.0); } /* @@ -215,14 +235,26 @@ fluid_tc2sec_delay(fluid_real_t tc) fluid_real_t fluid_tc2sec_attack(fluid_real_t tc) { - /* SF2.01 section 8.1.2 items 26, 34 - * SF2.01 section 8.1.3 items 26, 34 - * The most negative number indicates a delay of 0 - * Range is limited from -12000 to 8000 */ - if (tc<=-32768.){return (fluid_real_t) 0.0;}; - if (tc<-12000.){tc=(fluid_real_t) -12000.0;}; - if (tc>8000.){tc=(fluid_real_t) 8000.0;}; - return (fluid_real_t) pow(2.0, (double) tc / 1200.0); + /* SF2.01 section 8.1.2 items 26, 34 + * SF2.01 section 8.1.3 items 26, 34 + * The most negative number indicates a delay of 0 + * Range is limited from -12000 to 8000 */ + if(tc <= -32768.) + { + return (fluid_real_t) 0.0; + }; + + if(tc < -12000.) + { + tc = (fluid_real_t) -12000.0; + }; + + if(tc > 8000.) + { + tc = (fluid_real_t) 8000.0; + }; + + return (fluid_real_t) pow(2.0, (double) tc / 1200.0); } /* @@ -231,8 +263,8 @@ fluid_tc2sec_attack(fluid_real_t tc) fluid_real_t fluid_tc2sec(fluid_real_t tc) { - /* No range checking here! */ - return (fluid_real_t) pow(2.0, (double) tc / 1200.0); + /* No range checking here! */ + return (fluid_real_t) pow(2.0, (double) tc / 1200.0); } /* @@ -241,14 +273,26 @@ fluid_tc2sec(fluid_real_t tc) fluid_real_t fluid_tc2sec_release(fluid_real_t tc) { - /* SF2.01 section 8.1.2 items 30, 38 - * SF2.01 section 8.1.3 items 30, 38 - * No 'most negative number' rule here! - * Range is limited from -12000 to 8000 */ - if (tc<=-32768.){return (fluid_real_t) 0.0;}; - if (tc<-12000.){tc=(fluid_real_t) -12000.0;}; - if (tc>8000.){tc=(fluid_real_t) 8000.0;}; - return (fluid_real_t) pow(2.0, (double) tc / 1200.0); + /* SF2.01 section 8.1.2 items 30, 38 + * SF2.01 section 8.1.3 items 30, 38 + * No 'most negative number' rule here! + * Range is limited from -12000 to 8000 */ + if(tc <= -32768.) + { + return (fluid_real_t) 0.0; + }; + + if(tc < -12000.) + { + tc = (fluid_real_t) -12000.0; + }; + + if(tc > 8000.) + { + tc = (fluid_real_t) 8000.0; + }; + + return (fluid_real_t) pow(2.0, (double) tc / 1200.0); } /* @@ -259,7 +303,7 @@ fluid_tc2sec_release(fluid_real_t tc) fluid_real_t fluid_act2hz(fluid_real_t c) { - return (fluid_real_t) (8.176 * pow(2.0, (double) c / 1200.0)); + return (fluid_real_t)(8.176 * pow(2.0, (double) c / 1200.0)); } /* @@ -270,7 +314,7 @@ fluid_act2hz(fluid_real_t c) fluid_real_t fluid_hz2ct(fluid_real_t f) { - return (fluid_real_t) (6900 + 1200 * log(f / 440.0) / log(2.0)); + return (fluid_real_t)(6900 + 1200 * log(f / 440.0) / M_LN2); } /* @@ -279,16 +323,53 @@ fluid_hz2ct(fluid_real_t f) fluid_real_t fluid_pan(fluid_real_t c, int left) { - if (left) { - c = -c; - } - if (c < -500) { - return (fluid_real_t) 0.0; - } else if (c > 500) { - return (fluid_real_t) 1.0; - } else { - return fluid_pan_tab[(int) (c + 500)]; - } + if(left) + { + c = -c; + } + + if(c <= -500) + { + return (fluid_real_t) 0.0; + } + else if(c >= 500) + { + return (fluid_real_t) 1.0; + } + else + { + return fluid_pan_tab[(int)(c + 500)]; + } +} + +/* + * Return the amount of attenuation based on the balance for the specified + * channel. If balance is negative (turned toward left channel, only the right + * channel is attenuated. If balance is positive, only the left channel is + * attenuated. + * + * @params balance left/right balance, range [-960;960] in absolute centibels + * @return amount of attenuation [0.0;1.0] + */ +fluid_real_t fluid_balance(fluid_real_t balance, int left) +{ + /* This is the most common case */ + if(balance == 0) + { + return 1.0f; + } + + if((left && balance < 0) || (!left && balance > 0)) + { + return 1.0f; + } + + if(balance < 0) + { + balance = -balance; + } + + return fluid_cb2amp(balance); } /* @@ -297,12 +378,16 @@ fluid_pan(fluid_real_t c, int left) fluid_real_t fluid_concave(fluid_real_t val) { - if (val < 0) { - return 0; - } else if (val > 127) { - return 1; - } - return fluid_concave_tab[(int) val]; + if(val < 0) + { + return 0; + } + else if(val >= FLUID_VEL_CB_SIZE) + { + return 1; + } + + return fluid_concave_tab[(int) val]; } /* @@ -311,10 +396,14 @@ fluid_concave(fluid_real_t val) fluid_real_t fluid_convex(fluid_real_t val) { - if (val < 0) { - return 0; - } else if (val > 127) { - return 1; - } - return fluid_convex_tab[(int) val]; + if(val < 0) + { + return 0; + } + else if(val >= FLUID_VEL_CB_SIZE) + { + return 1; + } + + return fluid_convex_tab[(int) val]; } |