diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index ae729f70..cf8f3369 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -360,3 +360,13 @@ else ( MACOSX_FRAMEWORK ) install ( FILES ${public_main_HEADER} DESTINATION ${INCLUDE_INSTALL_DIR} ) endif ( MACOSX_FRAMEWORK ) +# ******* Auto Generated Lookup Tables ****** + +include(ExternalProject) +ExternalProject_Add(gentables + DOWNLOAD_COMMAND "" + SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/gentables + BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/gentables + INSTALL_COMMAND ${CMAKE_CURRENT_BINARY_DIR}/gentables/make_tables${CMAKE_EXECUTABLE_SUFFIX} "${CMAKE_BINARY_DIR}/" +) +add_dependencies(libfluidsynth-OBJ gentables) diff --git a/src/gentables/CMakeLists.txt b/src/gentables/CMakeLists.txt new file mode 100644 index 00000000..437027ae --- /dev/null +++ b/src/gentables/CMakeLists.txt @@ -0,0 +1,27 @@ +cmake_minimum_required(VERSION 3.1) + +# remove $CC from the current environment and by that force cmake to look for a (working) C compiler, +# which hopefully will be the host compiler +unset(ENV{CC}) + +project (gentables C) + +set ( CMAKE_BUILD_TYPE Debug ) + +set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}) +set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_DEBUG ${CMAKE_BINARY_DIR}) +set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_RELEASE ${CMAKE_BINARY_DIR}) + +include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../) + +# Add the executable that generates the table +add_executable( make_tables + make_tables.c + gen_conv.c + gen_rvoice_dsp.c) + +if ( WIN32 ) + add_definitions ( -D_USE_MATH_DEFINES -D_CRT_SECURE_NO_WARNINGS ) +else ( WIN32 ) + target_link_libraries (make_tables "m") +endif () diff --git a/src/gentables/gen_conv.c b/src/gentables/gen_conv.c new file mode 100644 index 00000000..86b119d5 --- /dev/null +++ b/src/gentables/gen_conv.c @@ -0,0 +1,81 @@ + +#include "utils/fluid_conv_tables.h" +#include "make_tables.h" + + +/* conversion tables */ +static double fluid_ct2hz_tab[FLUID_CENTS_HZ_SIZE]; +static double fluid_cb2amp_tab[FLUID_CB_AMP_SIZE]; +static double fluid_concave_tab[FLUID_VEL_CB_SIZE]; +static double fluid_convex_tab[FLUID_VEL_CB_SIZE]; +static double fluid_pan_tab[FLUID_PAN_SIZE]; + +/* + * void fluid_synth_init + * + * Does all the initialization for this module. + */ +static void fluid_conversion_config(void) +{ + int i; + double x; + + for(i = 0; i < FLUID_CENTS_HZ_SIZE; i++) + { + fluid_ct2hz_tab[i] = 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] = 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((double)(i * i) / ((FLUID_VEL_CB_SIZE - 1) * (FLUID_VEL_CB_SIZE - 1))) / M_LN10; + fluid_convex_tab[i] = (1.0 - x); + fluid_concave_tab[(FLUID_VEL_CB_SIZE - 1) - i] = 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] = sin(i * x); + } +} + + +void gen_conv_table(FILE *fp) +{ + /* Calculate the values */ + fluid_conversion_config(); + + /* fluid_ct2hz_tab */ + EMIT_ARRAY(fp, fluid_ct2hz_tab); + EMIT_ARRAY(fp, fluid_cb2amp_tab); + EMIT_ARRAY(fp, fluid_concave_tab); + EMIT_ARRAY(fp, fluid_convex_tab); + EMIT_ARRAY(fp, fluid_pan_tab); +} + diff --git a/src/gentables/gen_rvoice_dsp.c b/src/gentables/gen_rvoice_dsp.c new file mode 100644 index 00000000..0d326236 --- /dev/null +++ b/src/gentables/gen_rvoice_dsp.c @@ -0,0 +1,81 @@ + +#include "rvoice/fluid_rvoice_dsp_tables.h" +#include "make_tables.h" + +/* Linear interpolation table (2 coefficients centered on 1st) */ +static double interp_coeff_linear[FLUID_INTERP_MAX][2]; + +/* 4th order (cubic) interpolation table (4 coefficients centered on 2nd) */ +static double interp_coeff[FLUID_INTERP_MAX][4]; + +/* 7th order interpolation (7 coefficients centered on 3rd) */ +static double sinc_table7[FLUID_INTERP_MAX][SINC_INTERP_ORDER]; + +static double cb_interp_coeff_linear(int y, int x) { return interp_coeff_linear[y][x]; } +static double cb_interp_coeff (int y, int x) { return interp_coeff[y][x]; } +static double cb_sinc_table7 (int y, int x) { return sinc_table7[y][x]; } + +/* Initializes interpolation tables */ +void fluid_rvoice_dsp_config(void) +{ + int i, i2; + double x, v; + double i_shifted; + + /* Initialize the coefficients for the interpolation. The math comes + * from a mail, posted by Olli Niemitalo to the music-dsp mailing + * list (I found it in the music-dsp archives + * http://www.smartelectronix.com/musicdsp/). */ + + for(i = 0; i < FLUID_INTERP_MAX; i++) + { + x = (double) i / (double) FLUID_INTERP_MAX; + + interp_coeff[i][0] = (x * (-0.5 + x * (1 - 0.5 * x))); + interp_coeff[i][1] = (1.0 + x * x * (1.5 * x - 2.5)); + interp_coeff[i][2] = (x * (0.5 + x * (2.0 - 1.5 * x))); + interp_coeff[i][3] = (0.5 * x * x * (x - 1.0)); + + interp_coeff_linear[i][0] = (1.0 - x); + interp_coeff_linear[i][1] = x; + } + + /* i: Offset in terms of whole samples */ + for(i = 0; i < SINC_INTERP_ORDER; i++) + { + /* i2: Offset in terms of fractional samples ('subsamples') */ + for(i2 = 0; i2 < FLUID_INTERP_MAX; i2++) + { + /* center on middle of table */ + i_shifted = (double)i - ((double)SINC_INTERP_ORDER / 2.0) + + (double)i2 / (double)FLUID_INTERP_MAX; + + /* sinc(0) cannot be calculated straightforward (limit needed for 0/0) */ + if(fabs(i_shifted) > 0.000001) + { + double arg = M_PI * i_shifted; + v = sin(arg) / (arg); + /* Hanning window */ + v *= 0.5 * (1.0 + cos(2.0 * arg / (double)SINC_INTERP_ORDER)); + } + else + { + v = 1.0; + } + + sinc_table7[FLUID_INTERP_MAX - i2 - 1][i] = v; + } + } +} + + +void gen_rvoice_table_dsp (FILE *fp) +{ + /* Calculate the values */ + fluid_rvoice_dsp_config(); + + /* Emit the matrices */ + emit_matrix(fp, "interp_coeff_linear", cb_interp_coeff_linear, FLUID_INTERP_MAX, 2); + emit_matrix(fp, "interp_coeff", cb_interp_coeff, FLUID_INTERP_MAX, 4); + emit_matrix(fp, "sinc_table7", cb_sinc_table7, FLUID_INTERP_MAX, 7); +} diff --git a/src/gentables/make_tables.c b/src/gentables/make_tables.c new file mode 100644 index 00000000..b1e4dbb2 --- /dev/null +++ b/src/gentables/make_tables.c @@ -0,0 +1,84 @@ + +#include "make_tables.h" + +static void write_value(FILE *fp, double val, int i) +{ + fprintf(fp, " %.15e%c /* %d */\n", + val, + ',', + i + ); +} + +/* Emit an array of real numbers */ +void emit_array(FILE *fp, const char *tblname, const double *tbl, int size) +{ + int i; + + fprintf(fp, "static const fluid_real_t %s[%d] = {\n", tblname, size); + + for (i = 0; i < size; i++) + { + write_value(fp, tbl[i], i); + } + fprintf(fp, "};\n\n"); +} + +/* Emit a matrix of real numbers */ +void emit_matrix(FILE *fp, const char *tblname, emit_matrix_cb tbl_cb, int sizeh, int sizel) +{ + int i, j; + + fprintf(fp, "static const fluid_real_t %s[%d][%d] = {\n {\n", tblname, sizeh, sizel); + + for (i = 0; i < sizeh; i++) + { + for (j = 0; j < sizel; j++) + { + write_value(fp, tbl_cb(i, j), i*sizel+j); + } + + + if (i < (sizeh-1)) + fprintf(fp, " }, {\n"); + else + fprintf(fp, " }\n};\n\n"); + } +} + +static void open_table(FILE**fp, const char* dir, const char* file) +{ + char buf[2048] = {0}; + + strcat(buf, dir); + strcat(buf, file); + + /* open the output file */ + *fp = fopen(buf, "w"); + if (*fp == NULL) + { + exit(-2); + } + + /* Emit warning header */ + fprintf(*fp, "/* THIS FILE HAS BEEN AUTOMATICALLY GENERATED. DO NOT EDIT. */\n\n"); +} + +int main (int argc, char *argv[]) +{ + FILE *fp; + + // make sure we have enough arguments + if (argc < 2) + return -1; + + open_table(&fp, argv[1], "fluid_conv_tables.c"); + gen_conv_table(fp); + fclose(fp); + + open_table(&fp, argv[1], "fluid_rvoice_dsp_tables.c"); + gen_rvoice_table_dsp(fp); + fclose(fp); + + return 0; +} diff --git a/src/gentables/make_tables.h b/src/gentables/make_tables.h new file mode 100644 index 00000000..95972e06 --- /dev/null +++ b/src/gentables/make_tables.h @@ -0,0 +1,21 @@ +#include +#include +#include +#include + + +#define EMIT_ARRAY(__fp__, __arr__) emit_array(__fp__, #__arr__, __arr__, sizeof(__arr__)/sizeof(*__arr__)) + +/* callback for general access to matrices */ +typedef double (*emit_matrix_cb)(int y, int x); + +/* Generators */ +void gen_rvoice_table_dsp(FILE *fp); +void gen_conv_table(FILE *fp); + +/* Emit an array of real numbers */ +void emit_array(FILE *fp, const char *tblname, const double *tbl, int size); + +/* Emit a matrix of real numbers */ +void emit_matrix(FILE *fp, const char *tblname, emit_matrix_cb tbl_cb, int sizeh, int sizel); + diff --git a/src/rvoice/fluid_phase.h b/src/rvoice/fluid_phase.h index 08975cbb..44df6b24 100644 --- a/src/rvoice/fluid_phase.h +++ b/src/rvoice/fluid_phase.h @@ -22,8 +22,6 @@ #ifndef _FLUID_PHASE_H #define _FLUID_PHASE_H -#include "config.h" - /* * phase */ @@ -31,7 +29,7 @@ #define FLUID_INTERP_BITS 8 #define FLUID_INTERP_BITS_MASK 0xff000000 #define FLUID_INTERP_BITS_SHIFT 24 -#define FLUID_INTERP_MAX 256 + #define FLUID_FRACT_MAX ((double)4294967296.0) diff --git a/src/rvoice/fluid_rvoice_dsp.c b/src/rvoice/fluid_rvoice_dsp.c index cc162829..25f4a4b8 100644 --- a/src/rvoice/fluid_rvoice_dsp.c +++ b/src/rvoice/fluid_rvoice_dsp.c @@ -22,6 +22,7 @@ #include "fluid_phase.h" #include "fluid_rvoice.h" #include "fluid_sys.h" +#include "fluid_rvoice_dsp_tables.c" /* Purpose: * @@ -47,85 +48,6 @@ /* Interpolation (find a value between two samples of the original waveform) */ -/* Linear interpolation table (2 coefficients centered on 1st) */ -static fluid_real_t interp_coeff_linear[FLUID_INTERP_MAX][2]; - -/* 4th order (cubic) interpolation table (4 coefficients centered on 2nd) */ -static fluid_real_t interp_coeff[FLUID_INTERP_MAX][4]; - -/* 7th order interpolation (7 coefficients centered on 3rd) */ -static fluid_real_t sinc_table7[FLUID_INTERP_MAX][7]; - - -#define SINC_INTERP_ORDER 7 /* 7th order constant */ - - -/* Initializes interpolation tables */ -void fluid_rvoice_dsp_config(void) -{ - int i, i2; - double x, v; - double i_shifted; - - /* Initialize the coefficients for the interpolation. The math comes - * from a mail, posted by Olli Niemitalo to the music-dsp mailing - * list (I found it in the music-dsp archives - * http://www.smartelectronix.com/musicdsp/). */ - - for(i = 0; i < FLUID_INTERP_MAX; i++) - { - x = (double) i / (double) FLUID_INTERP_MAX; - - interp_coeff[i][0] = (fluid_real_t)(x * (-0.5 + x * (1 - 0.5 * x))); - interp_coeff[i][1] = (fluid_real_t)(1.0 + x * x * (1.5 * x - 2.5)); - interp_coeff[i][2] = (fluid_real_t)(x * (0.5 + x * (2.0 - 1.5 * x))); - interp_coeff[i][3] = (fluid_real_t)(0.5 * x * x * (x - 1.0)); - - interp_coeff_linear[i][0] = (fluid_real_t)(1.0 - x); - interp_coeff_linear[i][1] = (fluid_real_t)x; - } - - /* i: Offset in terms of whole samples */ - for(i = 0; i < SINC_INTERP_ORDER; i++) - { - /* i2: Offset in terms of fractional samples ('subsamples') */ - for(i2 = 0; i2 < FLUID_INTERP_MAX; i2++) - { - /* center on middle of table */ - i_shifted = (double)i - ((double)SINC_INTERP_ORDER / 2.0) - + (double)i2 / (double)FLUID_INTERP_MAX; - - /* sinc(0) cannot be calculated straightforward (limit needed for 0/0) */ - if(fabs(i_shifted) > 0.000001) - { - double arg = M_PI * i_shifted; - v = (fluid_real_t)sin(arg) / (arg); - /* Hanning window */ - v *= (fluid_real_t)0.5 * (1.0 + cos(2.0 * arg / (fluid_real_t)SINC_INTERP_ORDER)); - } - else - { - v = 1.0; - } - - sinc_table7[FLUID_INTERP_MAX - i2 - 1][i] = v; - } - } - -#if 0 - - for(i = 0; i < FLUID_INTERP_MAX; i++) - { - printf("%d %0.3f %0.3f %0.3f %0.3f %0.3f %0.3f %0.3f\n", - i, sinc_table7[0][i], sinc_table7[1][i], sinc_table7[2][i], - sinc_table7[3][i], sinc_table7[4][i], sinc_table7[5][i], sinc_table7[6][i]); - } - -#endif - - fluid_check_fpe("interpolation table calculation"); -} - static FLUID_INLINE fluid_real_t fluid_rvoice_get_float_sample(const short int *dsp_msb, const char *dsp_lsb, unsigned int idx) { diff --git a/src/rvoice/fluid_rvoice_dsp_tables.h b/src/rvoice/fluid_rvoice_dsp_tables.h new file mode 100644 index 00000000..befc9faf --- /dev/null +++ b/src/rvoice/fluid_rvoice_dsp_tables.h @@ -0,0 +1,8 @@ + +#ifndef _FLUID_RVOICE_DSP_TABLES_H +#define _FLUID_RVOICE_DSP_TABLES_H + +#define FLUID_INTERP_MAX 256 +#define SINC_INTERP_ORDER 7 /* 7th order constant */ + +#endif diff --git a/src/synth/fluid_synth.c b/src/synth/fluid_synth.c index 078911f1..0f0cf7a8 100644 --- a/src/synth/fluid_synth.c +++ b/src/synth/fluid_synth.c @@ -285,10 +285,6 @@ fluid_synth_init(void) feenableexcept(FE_DIVBYZERO | FE_UNDERFLOW | FE_OVERFLOW | FE_INVALID); #endif - fluid_conversion_config(); - - fluid_rvoice_dsp_config(); - init_dither(); /* custom_breath2att_mod is not a default modulator specified in SF2.01. diff --git a/src/utils/fluid_conv.c b/src/utils/fluid_conv.c index 2c46062d..483b371d 100644 --- a/src/utils/fluid_conv.c +++ b/src/utils/fluid_conv.c @@ -19,74 +19,7 @@ */ #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 */ -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 - * - * Does all the initialization for this module. - */ -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); - } - - /* 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); - } -} +#include "fluid_conv_tables.c" /* * fluid_ct2hz @@ -403,3 +336,4 @@ fluid_convex(fluid_real_t val) return fluid_convex_tab[(int) val]; } + diff --git a/src/utils/fluid_conv.h b/src/utils/fluid_conv.h index aa3ea895..60f441c4 100644 --- a/src/utils/fluid_conv.h +++ b/src/utils/fluid_conv.h @@ -22,39 +22,7 @@ #define _FLUID_CONV_H #include "fluidsynth_priv.h" - -/* - Attenuation range in centibels. - Attenuation range is the dynamic range of the volume envelope generator - from 0 to the end of attack segment. - fluidsynth is a 24 bit synth, it could (should??) be 144 dB of attenuation. - However the spec makes no distinction between 16 or 24 bit synths, so use - 96 dB here. - - Note about usefulness of 24 bits: - 1)Even fluidsynth is a 24 bit synth, this format is only relevant if - the sample format coming from the soundfont is 24 bits and the audio sample format - choosen by the application (audio.sample.format) is not 16 bits. - - 2)When the sample soundfont is 16 bits, the internal 24 bits number have - 16 bits msb and lsb to 0. Consequently, at the DAC output, the dynamic range of - this 24 bit sample is reduced to the the dynamic of a 16 bits sample (ie 90 db) - even if this sample is produced by the audio driver using an audio sample format - compatible for a 24 bit DAC. - - 3)When the audio sample format settings is 16 bits (audio.sample.format), the - audio driver will make use of a 16 bit DAC, and the dynamic will be reduced to 96 dB - even if the initial sample comes from a 24 bits soundfont. - - In both cases (2) or (3), the real dynamic range is only 96 dB. - - Other consideration for FLUID_NOISE_FLOOR related to case (1),(2,3): - - for case (1), FLUID_NOISE_FLOOR should be the noise floor for 24 bits (i.e -138 dB). - - for case (2) or (3), FLUID_NOISE_FLOOR should be the noise floor for 16 bits (i.e -90 dB). - */ -#define FLUID_PEAK_ATTENUATION 960.0f - -void fluid_conversion_config(void); +#include "utils/fluid_conv_tables.h" fluid_real_t fluid_ct2hz_real(fluid_real_t cents); fluid_real_t fluid_ct2hz(fluid_real_t cents); diff --git a/src/utils/fluid_conv_tables.h b/src/utils/fluid_conv_tables.h new file mode 100644 index 00000000..744733b4 --- /dev/null +++ b/src/utils/fluid_conv_tables.h @@ -0,0 +1,41 @@ + +#ifndef _FLUID_CONV_TABLES_H +#define _FLUID_CONV_TABLES_H + +/* + Attenuation range in centibels. + Attenuation range is the dynamic range of the volume envelope generator + from 0 to the end of attack segment. + fluidsynth is a 24 bit synth, it could (should??) be 144 dB of attenuation. + However the spec makes no distinction between 16 or 24 bit synths, so use + 96 dB here. + + Note about usefulness of 24 bits: + 1)Even fluidsynth is a 24 bit synth, this format is only relevant if + the sample format coming from the soundfont is 24 bits and the audio sample format + choosen by the application (audio.sample.format) is not 16 bits. + + 2)When the sample soundfont is 16 bits, the internal 24 bits number have + 16 bits msb and lsb to 0. Consequently, at the DAC output, the dynamic range of + this 24 bit sample is reduced to the the dynamic of a 16 bits sample (ie 90 db) + even if this sample is produced by the audio driver using an audio sample format + compatible for a 24 bit DAC. + + 3)When the audio sample format settings is 16 bits (audio.sample.format), the + audio driver will make use of a 16 bit DAC, and the dynamic will be reduced to 96 dB + even if the initial sample comes from a 24 bits soundfont. + + In both cases (2) or (3), the real dynamic range is only 96 dB. + + Other consideration for FLUID_NOISE_FLOOR related to case (1),(2,3): + - for case (1), FLUID_NOISE_FLOOR should be the noise floor for 24 bits (i.e -138 dB). + - for case (2) or (3), FLUID_NOISE_FLOOR should be the noise floor for 16 bits (i.e -90 dB). + */ +#define FLUID_PEAK_ATTENUATION 960.0f + +#define FLUID_CENTS_HZ_SIZE 1200 +#define FLUID_VEL_CB_SIZE 128 +#define FLUID_CB_AMP_SIZE 1441 +#define FLUID_PAN_SIZE 1002 + +#endif