From: Jacek Caban <jacek@codeweavers.com> --- configure | 1 + configure.ac | 2 + dlls/dmsynth/Makefile.in | 2 +- libs/fluidsynth/Makefile.in | 2 +- libs/fluidsynth/glib.h | 2 +- libs/fluidsynth/src/rvoice/fluid_adsr_env.h | 14 +- libs/fluidsynth/src/rvoice/fluid_iir_filter.c | 222 +------- libs/fluidsynth/src/rvoice/fluid_iir_filter.h | 231 +++++++- libs/fluidsynth/src/rvoice/fluid_lfo.h | 6 + libs/fluidsynth/src/rvoice/fluid_phase.h | 6 + libs/fluidsynth/src/rvoice/fluid_rev.c | 3 +- libs/fluidsynth/src/rvoice/fluid_rvoice.c | 2 +- libs/fluidsynth/src/rvoice/fluid_rvoice.h | 39 +- ...luid_rvoice_dsp.c => fluid_rvoice_dsp.cpp} | 492 +++++++++++++----- libs/fluidsynth/src/sfloader/fluid_sfont.h | 6 + libs/fluidsynth/src/synth/fluid_synth.c | 31 +- libs/fluidsynth/src/synth/fluid_synth.h | 11 +- libs/fluidsynth/src/synth/fluid_voice.c | 11 +- libs/fluidsynth/src/utils/fluid_conv.c | 2 +- libs/fluidsynth/src/utils/fluid_conv.h | 6 + libs/fluidsynth/src/utils/fluid_sys.h | 7 + 21 files changed, 703 insertions(+), 395 deletions(-) rename libs/fluidsynth/src/rvoice/{fluid_rvoice_dsp.c => fluid_rvoice_dsp.cpp} (60%) diff --git a/configure b/configure index b117be9e756..8da3b5206fc 100755 --- a/configure +++ b/configure @@ -23270,6 +23270,7 @@ else enable_wow64cpu=${enable_wow64cpu:-no} enable_xtajit64=${enable_xtajit64:-no} enable_compiler_rt=${enable_compiler_rt:-no} + enable_dmsynth=${enable_dmsynth:-no} fi enable_conhost=${enable_conhost:-$HOST_ARCH} diff --git a/configure.ac b/configure.ac index 40d6d8140a1..a9343ca191e 100644 --- a/configure.ac +++ b/configure.ac @@ -2446,6 +2446,8 @@ else enable_wow64cpu=${enable_wow64cpu:-no} enable_xtajit64=${enable_xtajit64:-no} enable_compiler_rt=${enable_compiler_rt:-no} + dnl Disable modules that need C++ + enable_dmsynth=${enable_dmsynth:-no} fi dnl Disable some programs for other PE archs diff --git a/dlls/dmsynth/Makefile.in b/dlls/dmsynth/Makefile.in index 11bd107f37f..5ba5fdd1a64 100644 --- a/dlls/dmsynth/Makefile.in +++ b/dlls/dmsynth/Makefile.in @@ -1,5 +1,5 @@ MODULE = dmsynth.dll -IMPORTS = $(FLUIDSYNTH_PE_LIBS) dxguid uuid ole32 advapi32 user32 +IMPORTS = $(FLUIDSYNTH_PE_LIBS) $(CXX_PE_LIBS) dxguid uuid ole32 advapi32 user32 EXTRAINCL = $(FLUIDSYNTH_PE_CFLAGS) PARENTSRC = ../dmusic diff --git a/libs/fluidsynth/Makefile.in b/libs/fluidsynth/Makefile.in index 1383ed82c9f..0620725b8ee 100644 --- a/libs/fluidsynth/Makefile.in +++ b/libs/fluidsynth/Makefile.in @@ -20,7 +20,7 @@ SOURCES = \ src/rvoice/fluid_lfo.c \ src/rvoice/fluid_rev.c \ src/rvoice/fluid_rvoice.c \ - src/rvoice/fluid_rvoice_dsp.c \ + src/rvoice/fluid_rvoice_dsp.cpp \ src/rvoice/fluid_rvoice_event.c \ src/rvoice/fluid_rvoice_mixer.c \ src/sfloader/fluid_defsfont.c \ diff --git a/libs/fluidsynth/glib.h b/libs/fluidsynth/glib.h index 466a2644d98..54436d3dfef 100644 --- a/libs/fluidsynth/glib.h +++ b/libs/fluidsynth/glib.h @@ -78,7 +78,7 @@ extern void g_clear_error( GError **error ); extern int g_file_test( const char *path, int test ); -#define g_new( type, count ) calloc( (count), sizeof(type) ) +#define g_new( type, count ) ((type *)calloc( (count), sizeof(type) )) static inline void g_free( void *ptr ) { free( ptr ); } typedef SRWLOCK GMutex; diff --git a/libs/fluidsynth/src/rvoice/fluid_adsr_env.h b/libs/fluidsynth/src/rvoice/fluid_adsr_env.h index 92c8fcd24c0..ca3351b5632 100644 --- a/libs/fluidsynth/src/rvoice/fluid_adsr_env.h +++ b/libs/fluidsynth/src/rvoice/fluid_adsr_env.h @@ -24,6 +24,9 @@ #include "fluidsynth_priv.h" #include "fluid_sys.h" +#ifdef __cplusplus +extern "C" { +#endif /* * envelope data */ @@ -39,7 +42,7 @@ struct _fluid_env_data_t /* Indices for envelope tables */ enum fluid_voice_envelope_index { - FLUID_VOICE_ENVDELAY, + FLUID_VOICE_ENVDELAY=0, FLUID_VOICE_ENVATTACK, FLUID_VOICE_ENVHOLD, FLUID_VOICE_ENVDECAY, @@ -56,9 +59,9 @@ typedef struct _fluid_adsr_env_t fluid_adsr_env_t; struct _fluid_adsr_env_t { fluid_env_data_t data[FLUID_VOICE_ENVLAST]; + unsigned int section; // type fluid_adsr_env_section_t, but declare it unsigned to make C++ happy unsigned int count; fluid_real_t val; /* the current value of the envelope */ - fluid_adsr_env_section_t section; }; /* For performance, all functions are inlined */ @@ -136,14 +139,14 @@ fluid_adsr_env_set_val(fluid_adsr_env_t *env, fluid_real_t val) static FLUID_INLINE fluid_adsr_env_section_t fluid_adsr_env_get_section(fluid_adsr_env_t *env) { - return env->section; + return (fluid_adsr_env_section_t)env->section; } static FLUID_INLINE void fluid_adsr_env_set_section(fluid_adsr_env_t *env, fluid_adsr_env_section_t section) { - env->section = section; + env->section = (unsigned int)section; env->count = 0; } @@ -163,4 +166,7 @@ fluid_adsr_env_get_max_val(fluid_adsr_env_t *env) } } +#ifdef __cplusplus +} +#endif #endif diff --git a/libs/fluidsynth/src/rvoice/fluid_iir_filter.c b/libs/fluidsynth/src/rvoice/fluid_iir_filter.c index ba8d5a9603f..81b279e61c2 100644 --- a/libs/fluidsynth/src/rvoice/fluid_iir_filter.c +++ b/libs/fluidsynth/src/rvoice/fluid_iir_filter.c @@ -23,121 +23,6 @@ #include "fluid_conv.h" -static FLUID_INLINE void -fluid_iir_filter_calculate_coefficients(fluid_iir_filter_t *iir_filter, fluid_real_t output_rate, - fluid_real_t *a1_out, fluid_real_t *a2_out, - fluid_real_t *b02_out, fluid_real_t *b1_out); - - -/** - * Applies a low- or high-pass filter with variable cutoff frequency and quality factor - * for a given biquad transfer function: - * b0 + b1*z^-1 + b2*z^-2 - * H(z) = ------------------------ - * a0 + a1*z^-1 + a2*z^-2 - * - * Also modifies filter state accordingly. - * @param iir_filter Filter parameter - * @param dsp_buf Pointer to the synthesized audio data - * @param count Count of samples in dsp_buf - */ -/* - * Variable description: - * - dsp_a1, dsp_a2: Filter coefficients for the the previously filtered output signal - * - dsp_b0, dsp_b1, dsp_b2: Filter coefficients for input signal - * - coefficients normalized to a0 - * - * A couple of variables are used internally, their results are discarded: - * - dsp_i: Index through the output buffer - * - dsp_centernode: delay line for the IIR filter - * - dsp_hist1: same - * - dsp_hist2: same - */ -void -fluid_iir_filter_apply(fluid_iir_filter_t *iir_filter, - fluid_real_t *dsp_buf, int count, fluid_real_t output_rate) -{ - if(iir_filter->type == FLUID_IIR_DISABLED || FLUID_FABS(iir_filter->last_q) <= 0.001) - { - return; - } - else - { - /* IIR filter sample history */ - fluid_real_t dsp_hist1 = iir_filter->hist1; - fluid_real_t dsp_hist2 = iir_filter->hist2; - - /* IIR filter coefficients */ - fluid_real_t dsp_a1 = iir_filter->a1; - fluid_real_t dsp_a2 = iir_filter->a2; - fluid_real_t dsp_b02 = iir_filter->b02; - fluid_real_t dsp_b1 = iir_filter->b1; - - int fres_incr_count = iir_filter->fres_incr_count; - int q_incr_count = iir_filter->q_incr_count; - - fluid_real_t dsp_centernode; - int dsp_i; - - /* filter (implement the voice filter according to SoundFont standard) */ - - /* Check for denormal number (too close to zero). */ - if(FLUID_FABS(dsp_hist1) < 1e-20f) - { - dsp_hist1 = 0.0f; /* FIXME JMG - Is this even needed? */ - } - - /* Two versions of the filter loop. One, while the filter is - * changing towards its new setting. The other, if the filter - * doesn't change. - */ - - for(dsp_i = 0; dsp_i < count; dsp_i++) - { - /* The filter is implemented in Direct-II form. */ - dsp_centernode = dsp_buf[dsp_i] - dsp_a1 * dsp_hist1 - dsp_a2 * dsp_hist2; - dsp_buf[dsp_i] = dsp_b02 * (dsp_centernode + dsp_hist2) + dsp_b1 * dsp_hist1; - dsp_hist2 = dsp_hist1; - dsp_hist1 = dsp_centernode; - /* Alternatively, it could be implemented in Transposed Direct Form II */ - // fluid_real_t dsp_input = dsp_buf[dsp_i]; - // dsp_buf[dsp_i] = dsp_b02 * dsp_input + dsp_hist1; - // dsp_hist1 = dsp_b1 * dsp_input - dsp_a1 * dsp_buf[dsp_i] + dsp_hist2; - // dsp_hist2 = dsp_b02 * dsp_input - dsp_a2 * dsp_buf[dsp_i]; - - if(fres_incr_count > 0 || q_incr_count > 0) - { - if(fres_incr_count > 0) - { - --fres_incr_count; - iir_filter->last_fres += iir_filter->fres_incr; - } - if(q_incr_count > 0) - { - --q_incr_count; - iir_filter->last_q += iir_filter->q_incr; - } - - LOG_FILTER("last_fres: %.2f Hz | target_fres: %.2f Hz |---| last_q: %.4f | target_q: %.4f", iir_filter->last_fres, iir_filter->target_fres, iir_filter->last_q, iir_filter->target_q); - - fluid_iir_filter_calculate_coefficients(iir_filter, output_rate, &dsp_a1, &dsp_a2, &dsp_b02, &dsp_b1); - } - } - - iir_filter->hist1 = dsp_hist1; - iir_filter->hist2 = dsp_hist2; - iir_filter->a1 = dsp_a1; - iir_filter->a2 = dsp_a2; - iir_filter->b02 = dsp_b02; - iir_filter->b1 = dsp_b1; - - iir_filter->fres_incr_count = fres_incr_count; - iir_filter->q_incr_count = q_incr_count; - - fluid_check_fpe("voice_filter"); - } -} - DECLARE_FLUID_RVOICE_FUNCTION(fluid_iir_filter_init) { fluid_iir_filter_t *iir_filter = obj; @@ -232,114 +117,25 @@ DECLARE_FLUID_RVOICE_FUNCTION(fluid_iir_filter_set_q) if(iir_filter->filter_startup) { iir_filter->last_q = q; + iir_filter->q_incr_count = 0; } else { static const fluid_real_t q_incr_count = FLUID_BUFSIZE; + // Q must be at least Q_MIN, otherwise fluid_iir_filter_apply would never be entered + if(q >= Q_MIN && iir_filter->last_q < Q_MIN) + { + iir_filter->last_q = Q_MIN; + } iir_filter->q_incr = (q - iir_filter->last_q) / (q_incr_count); iir_filter->q_incr_count = q_incr_count; + LOG_FILTER("%f - %f / %f = %f", q , iir_filter->last_q, q_incr_count, iir_filter->q_incr); } #ifdef DBG_FILTER iir_filter->target_q = q; #endif } -static FLUID_INLINE void -fluid_iir_filter_calculate_coefficients(fluid_iir_filter_t *iir_filter, - fluid_real_t output_rate, - fluid_real_t *a1_out, fluid_real_t *a2_out, - fluid_real_t *b02_out, fluid_real_t *b1_out) -{ - // FLUID_IIR_Q_LINEAR may switch the filter off by setting Q==0 - // Due to the linear smoothing, last_q may not exactly become zero. - if(FLUID_FABS(iir_filter->last_q) <= 0.001) - { - return; - } - else - { - int flags = iir_filter->flags; - fluid_real_t filter_gain = 1.0f; - - /* - * Those equations from Robert Bristow-Johnson's `Cookbook - * formulae for audio EQ biquad filter coefficients', obtained - * from Harmony-central.com / Computer / Programming. They are - * the result of the bilinear transform on an analogue filter - * prototype. To quote, `BLT frequency warping has been taken - * into account for both significant frequency relocation and for - * bandwidth readjustment'. */ - - fluid_real_t omega = (fluid_real_t)(2.0 * M_PI) * - (iir_filter->last_fres / output_rate); - fluid_real_t sin_coeff = FLUID_SIN(omega); - fluid_real_t cos_coeff = FLUID_COS(omega); - fluid_real_t alpha_coeff = sin_coeff / (2.0f * iir_filter->last_q); - fluid_real_t a0_inv = 1.0f / (1.0f + alpha_coeff); - - /* Calculate the filter coefficients. All coefficients are - * normalized by a0. Think of `a1' as `a1/a0'. - * - * Here a couple of multiplications are saved by reusing common expressions. - * The original equations should be: - * iir_filter->b0=(1.-cos_coeff)*a0_inv*0.5*filter_gain; - * iir_filter->b1=(1.-cos_coeff)*a0_inv*filter_gain; - * iir_filter->b2=(1.-cos_coeff)*a0_inv*0.5*filter_gain; */ - - /* "a" coeffs are same for all 3 available filter types */ - fluid_real_t a1_temp = -2.0f * cos_coeff * a0_inv; - fluid_real_t a2_temp = (1.0f - alpha_coeff) * a0_inv; - fluid_real_t b02_temp, b1_temp; - - if(!(flags & FLUID_IIR_NO_GAIN_AMP)) - { - /* SF 2.01 page 59: - * - * The SoundFont specs ask for a gain reduction equal to half the - * height of the resonance peak (Q). For example, for a 10 dB - * resonance peak, the gain is reduced by 5 dB. This is done by - * multiplying the total gain with sqrt(1/Q). `Sqrt' divides dB - * by 2 (100 lin = 40 dB, 10 lin = 20 dB, 3.16 lin = 10 dB etc) - * The gain is later factored into the 'b' coefficients - * (numerator of the filter equation). This gain factor depends - * only on Q, so this is the right place to calculate it. - */ - filter_gain /= FLUID_SQRT(iir_filter->last_q); - } - - switch(iir_filter->type) - { - case FLUID_IIR_HIGHPASS: - b1_temp = (1.0f + cos_coeff) * a0_inv * filter_gain; - - /* both b0 -and- b2 */ - b02_temp = b1_temp * 0.5f; - - b1_temp *= -1.0f; - break; - - case FLUID_IIR_LOWPASS: - b1_temp = (1.0f - cos_coeff) * a0_inv * filter_gain; - - /* both b0 -and- b2 */ - b02_temp = b1_temp * 0.5f; - break; - - default: - /* filter disabled, should never get here */ - return; - } - - *a1_out = a1_temp; - *a2_out = a2_temp; - *b02_out = b02_temp; - *b1_out = b1_temp; - - fluid_check_fpe("voice_write filter calculation"); - } -} - - void fluid_iir_filter_calc(fluid_iir_filter_t *iir_filter, fluid_real_t output_rate, fluid_real_t fres_mod) @@ -385,7 +181,7 @@ void fluid_iir_filter_calc(fluid_iir_filter_t *iir_filter, iir_filter->fres_incr_count = 0; iir_filter->last_fres = fres; - iir_filter->filter_startup = 0; + iir_filter->filter_startup = (FLUID_FABS(iir_filter->last_q) < Q_MIN); // filter coefficients will not be initialized when Q is small } else if(FLUID_FABS(fres_diff) > 0.01f) { @@ -411,7 +207,7 @@ void fluid_iir_filter_calc(fluid_iir_filter_t *iir_filter, // will be taken care of in fluid_iir_filter_apply(). } - if(calc_coeff_flag) + if (calc_coeff_flag && !iir_filter->filter_startup) { fluid_iir_filter_calculate_coefficients(iir_filter, output_rate, &iir_filter->a1, &iir_filter->a2, &iir_filter->b02, &iir_filter->b1); } diff --git a/libs/fluidsynth/src/rvoice/fluid_iir_filter.h b/libs/fluidsynth/src/rvoice/fluid_iir_filter.h index d47bf2073f5..c1916a729a3 100644 --- a/libs/fluidsynth/src/rvoice/fluid_iir_filter.h +++ b/libs/fluidsynth/src/rvoice/fluid_iir_filter.h @@ -22,6 +22,7 @@ #define _FLUID_IIR_FILTER_H #include "fluidsynth_priv.h" +#include "fluid_sys.h" // Uncomment to get debug logging for filter parameters // #define DBG_FILTER @@ -31,20 +32,9 @@ #define LOG_FILTER(...) #endif -typedef struct _fluid_iir_filter_t fluid_iir_filter_t; - -DECLARE_FLUID_RVOICE_FUNCTION(fluid_iir_filter_init); -DECLARE_FLUID_RVOICE_FUNCTION(fluid_iir_filter_set_fres); -DECLARE_FLUID_RVOICE_FUNCTION(fluid_iir_filter_set_q); - -void fluid_iir_filter_apply(fluid_iir_filter_t *iir_filter, - fluid_real_t *dsp_buf, int dsp_buf_count, fluid_real_t output_rate); - -void fluid_iir_filter_reset(fluid_iir_filter_t *iir_filter); - -void fluid_iir_filter_calc(fluid_iir_filter_t *iir_filter, - fluid_real_t output_rate, - fluid_real_t fres_mod); +#ifdef __cplusplus +extern "C" { +#endif /* We can't do information hiding here, as fluid_voice_t includes the struct without a pointer. */ @@ -78,4 +68,217 @@ struct _fluid_iir_filter_t #endif }; +typedef struct _fluid_iir_filter_t fluid_iir_filter_t; + +DECLARE_FLUID_RVOICE_FUNCTION(fluid_iir_filter_init); +DECLARE_FLUID_RVOICE_FUNCTION(fluid_iir_filter_set_fres); +DECLARE_FLUID_RVOICE_FUNCTION(fluid_iir_filter_set_q); + +#define Q_MIN ((fluid_real_t)0.001) + +static FLUID_INLINE void +fluid_iir_filter_calculate_coefficients(fluid_iir_filter_t *iir_filter, fluid_real_t output_rate, + fluid_real_t *a1_out, fluid_real_t *a2_out, + fluid_real_t *b02_out, fluid_real_t *b1_out) +{ + int flags = iir_filter->flags; + fluid_real_t filter_gain = 1.0f; + + /* + * Those equations from Robert Bristow-Johnson's `Cookbook + * formulae for audio EQ biquad filter coefficients', obtained + * from Harmony-central.com / Computer / Programming. They are + * the result of the bilinear transform on an analogue filter + * prototype. To quote, `BLT frequency warping has been taken + * into account for both significant frequency relocation and for + * bandwidth readjustment'. */ + + fluid_real_t omega = (fluid_real_t)(2.0 * M_PI) * + (iir_filter->last_fres / output_rate); + fluid_real_t sin_coeff = FLUID_SIN(omega); + fluid_real_t cos_coeff = FLUID_COS(omega); + fluid_real_t alpha_coeff = sin_coeff / (2.0f * iir_filter->last_q); + fluid_real_t a0_inv = 1.0f / (1.0f + alpha_coeff); + + /* Calculate the filter coefficients. All coefficients are + * normalized by a0. Think of `a1' as `a1/a0'. + * + * Here a couple of multiplications are saved by reusing common expressions. + * The original equations should be: + * iir_filter->b0=(1.-cos_coeff)*a0_inv*0.5*filter_gain; + * iir_filter->b1=(1.-cos_coeff)*a0_inv*filter_gain; + * iir_filter->b2=(1.-cos_coeff)*a0_inv*0.5*filter_gain; */ + + /* "a" coeffs are same for all 3 available filter types */ + fluid_real_t a1_temp = -2.0f * cos_coeff * a0_inv; + fluid_real_t a2_temp = (1.0f - alpha_coeff) * a0_inv; + fluid_real_t b02_temp, b1_temp; + + if(!(flags & FLUID_IIR_NO_GAIN_AMP)) + { + /* SF 2.01 page 59: + * + * The SoundFont specs ask for a gain reduction equal to half the + * height of the resonance peak (Q). For example, for a 10 dB + * resonance peak, the gain is reduced by 5 dB. This is done by + * multiplying the total gain with sqrt(1/Q). `Sqrt' divides dB + * by 2 (100 lin = 40 dB, 10 lin = 20 dB, 3.16 lin = 10 dB etc) + * The gain is later factored into the 'b' coefficients + * (numerator of the filter equation). This gain factor depends + * only on Q, so this is the right place to calculate it. + */ + filter_gain /= FLUID_SQRT(iir_filter->last_q); + } + + switch(iir_filter->type) + { + case FLUID_IIR_HIGHPASS: + b1_temp = (1.0f + cos_coeff) * a0_inv * filter_gain; + + /* both b0 -and- b2 */ + b02_temp = b1_temp * 0.5f; + + b1_temp *= -1.0f; + break; + + case FLUID_IIR_LOWPASS: + b1_temp = (1.0f - cos_coeff) * a0_inv * filter_gain; + + /* both b0 -and- b2 */ + b02_temp = b1_temp * 0.5f; + break; + + default: + /* filter disabled, should never get here */ + return; + } + + *a1_out = a1_temp; + *a2_out = a2_temp; + *b02_out = b02_temp; + *b1_out = b1_temp; + + fluid_check_fpe("voice_write filter calculation"); +} + +/** + * Applies a low- or high-pass filter with variable cutoff frequency and quality factor + * for a given biquad transfer function: + * b0 + b1*z^-1 + b2*z^-2 + * H(z) = ------------------------ + * a0 + a1*z^-1 + a2*z^-2 + * + * Also modifies filter state accordingly. + * @param iir_filter Filter parameter + * @param dsp_buf Pointer to the synthesized audio data + * @param count Count of samples in dsp_buf + */ +/* + * Variable description: + * - dsp_a1, dsp_a2: Filter coefficients for the the previously filtered output signal + * - dsp_b0, dsp_b1, dsp_b2: Filter coefficients for input signal + * - coefficients normalized to a0 + * + * A couple of variables are used internally, their results are discarded: + * - dsp_i: Index through the output buffer + * - dsp_centernode: delay line for the IIR filter + * - dsp_hist1: same + * - dsp_hist2: same + */ +static FLUID_INLINE void +fluid_iir_filter_apply(fluid_iir_filter_t *iir_filter, + fluid_real_t *dsp_buf, int count, fluid_real_t output_rate) +{ + // FLUID_IIR_Q_LINEAR may switch the filter off by setting Q==0 + // Due to the linear smoothing, last_q may not exactly become zero. + if (iir_filter->type == FLUID_IIR_DISABLED || FLUID_FABS(iir_filter->last_q) < Q_MIN) + { + return; + } + else + { + /* IIR filter sample history */ + fluid_real_t dsp_hist1 = iir_filter->hist1; + fluid_real_t dsp_hist2 = iir_filter->hist2; + + /* IIR filter coefficients */ + fluid_real_t dsp_a1 = iir_filter->a1; + fluid_real_t dsp_a2 = iir_filter->a2; + fluid_real_t dsp_b02 = iir_filter->b02; + fluid_real_t dsp_b1 = iir_filter->b1; + + int fres_incr_count = iir_filter->fres_incr_count; + int q_incr_count = iir_filter->q_incr_count; + + fluid_real_t dsp_centernode; + int dsp_i; + + /* filter (implement the voice filter according to SoundFont standard) */ + + /* Check for denormal number (too close to zero). */ + if(FLUID_FABS(dsp_hist1) < 1e-20f) + { + dsp_hist1 = 0.0f; /* FIXME JMG - Is this even needed? */ + } + + /* Two versions of the filter loop. One, while the filter is + * changing towards its new setting. The other, if the filter + * doesn't change. + */ + + for(dsp_i = 0; dsp_i < count; dsp_i++) + { + /* The filter is implemented in Direct-II form. */ + dsp_centernode = dsp_buf[dsp_i] - dsp_a1 * dsp_hist1 - dsp_a2 * dsp_hist2; + dsp_buf[dsp_i] = dsp_b02 * (dsp_centernode + dsp_hist2) + dsp_b1 * dsp_hist1; + dsp_hist2 = dsp_hist1; + dsp_hist1 = dsp_centernode; + /* Alternatively, it could be implemented in Transposed Direct Form II */ + // fluid_real_t dsp_input = dsp_buf[dsp_i]; + // dsp_buf[dsp_i] = dsp_b02 * dsp_input + dsp_hist1; + // dsp_hist1 = dsp_b1 * dsp_input - dsp_a1 * dsp_buf[dsp_i] + dsp_hist2; + // dsp_hist2 = dsp_b02 * dsp_input - dsp_a2 * dsp_buf[dsp_i]; + + if(fres_incr_count > 0 || q_incr_count > 0) + { + if(fres_incr_count > 0) + { + --fres_incr_count; + iir_filter->last_fres += iir_filter->fres_incr; + } + if(q_incr_count > 0) + { + --q_incr_count; + iir_filter->last_q += iir_filter->q_incr; + } + + LOG_FILTER("last_fres: %.2f Hz | target_fres: %.2f Hz |---| last_q: %.4f | target_q: %.4f", iir_filter->last_fres, iir_filter->target_fres, iir_filter->last_q, iir_filter->target_q); + + fluid_iir_filter_calculate_coefficients(iir_filter, output_rate, &dsp_a1, &dsp_a2, &dsp_b02, &dsp_b1); + } + } + + iir_filter->hist1 = dsp_hist1; + iir_filter->hist2 = dsp_hist2; + iir_filter->a1 = dsp_a1; + iir_filter->a2 = dsp_a2; + iir_filter->b02 = dsp_b02; + iir_filter->b1 = dsp_b1; + + iir_filter->fres_incr_count = fres_incr_count; + iir_filter->q_incr_count = q_incr_count; + + fluid_check_fpe("voice_filter"); + } +} + +void fluid_iir_filter_reset(fluid_iir_filter_t *iir_filter); + +void fluid_iir_filter_calc(fluid_iir_filter_t *iir_filter, + fluid_real_t output_rate, + fluid_real_t fres_mod); + +#ifdef __cplusplus +} +#endif #endif diff --git a/libs/fluidsynth/src/rvoice/fluid_lfo.h b/libs/fluidsynth/src/rvoice/fluid_lfo.h index 9a439498213..d7c3564dc83 100644 --- a/libs/fluidsynth/src/rvoice/fluid_lfo.h +++ b/libs/fluidsynth/src/rvoice/fluid_lfo.h @@ -23,6 +23,9 @@ #include "fluid_sys.h" +#ifdef __cplusplus +extern "C" { +#endif typedef struct _fluid_lfo_t fluid_lfo_t; struct _fluid_lfo_t @@ -71,4 +74,7 @@ fluid_lfo_calc(fluid_lfo_t *lfo, unsigned int cur_delay) } +#ifdef __cplusplus +} +#endif #endif diff --git a/libs/fluidsynth/src/rvoice/fluid_phase.h b/libs/fluidsynth/src/rvoice/fluid_phase.h index 44df6b249fc..abd5d7bbda0 100644 --- a/libs/fluidsynth/src/rvoice/fluid_phase.h +++ b/libs/fluidsynth/src/rvoice/fluid_phase.h @@ -22,6 +22,9 @@ #ifndef _FLUID_PHASE_H #define _FLUID_PHASE_H +#ifdef __cplusplus +extern "C" { +#endif /* * phase */ @@ -110,4 +113,7 @@ typedef uint64_t fluid_phase_t; * Creates the expression a.index++. */ #define fluid_phase_index_plusplus(a) (((a) += 0x100000000LL) +#ifdef __cplusplus +} +#endif #endif /* _FLUID_PHASE_H */ diff --git a/libs/fluidsynth/src/rvoice/fluid_rev.c b/libs/fluidsynth/src/rvoice/fluid_rev.c index 11bc760832a..727567a8410 100644 --- a/libs/fluidsynth/src/rvoice/fluid_rev.c +++ b/libs/fluidsynth/src/rvoice/fluid_rev.c @@ -66,7 +66,8 @@ * - width (0 to 100): controls the left/right output separation. * When 0, there are no separation and the signal on left and right. * output is the same. This sounds like a monophonic signal. - * When 100, the separation between left and right is maximum. + * When 1, the separation between left and right is maximum. + * When 100 the perception of this separation is further "exaggerated". * * - level (0 to 1), controls the output level reverberation. * diff --git a/libs/fluidsynth/src/rvoice/fluid_rvoice.c b/libs/fluidsynth/src/rvoice/fluid_rvoice.c index e07896fea01..8c4cf9c3b4d 100644 --- a/libs/fluidsynth/src/rvoice/fluid_rvoice.c +++ b/libs/fluidsynth/src/rvoice/fluid_rvoice.c @@ -465,7 +465,7 @@ fluid_rvoice_write(fluid_rvoice_t *voice, fluid_real_t *dsp_buf) // // Currently, this does access the sample buffers, which is redundant and could be optimized away. // On the other hand, entering this if-clause is not supposed to happen often. - return fluid_rvoice_dsp_interpolate_none(voice, dsp_buf, is_looping); + return fluid_rvoice_dsp_silence(voice, dsp_buf, is_looping); } switch(voice->dsp.interp_method) diff --git a/libs/fluidsynth/src/rvoice/fluid_rvoice.h b/libs/fluidsynth/src/rvoice/fluid_rvoice.h index 9c8788decc7..a2521b30837 100644 --- a/libs/fluidsynth/src/rvoice/fluid_rvoice.h +++ b/libs/fluidsynth/src/rvoice/fluid_rvoice.h @@ -29,6 +29,9 @@ #include "fluid_phase.h" #include "fluid_sfont.h" +#ifdef __cplusplus +extern "C" { +#endif typedef struct _fluid_rvoice_envlfo_t fluid_rvoice_envlfo_t; typedef struct _fluid_rvoice_dsp_t fluid_rvoice_dsp_t; typedef struct _fluid_rvoice_buffers_t fluid_rvoice_buffers_t; @@ -200,6 +203,7 @@ DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_set_sample); /* defined in fluid_rvoice_dsp.c */ void fluid_rvoice_dsp_config(void); +int fluid_rvoice_dsp_silence(fluid_rvoice_t *rvoice, fluid_real_t *FLUID_RESTRICT dsp_buf, int looping); int fluid_rvoice_dsp_interpolate_none(fluid_rvoice_t *voice, fluid_real_t *FLUID_RESTRICT dsp_buf, int is_looping); int fluid_rvoice_dsp_interpolate_linear(fluid_rvoice_t *voice, fluid_real_t *FLUID_RESTRICT dsp_buf, int is_looping); int fluid_rvoice_dsp_interpolate_4th_order(fluid_rvoice_t *voice, fluid_real_t *FLUID_RESTRICT dsp_buf, int is_looping); @@ -211,21 +215,40 @@ int fluid_rvoice_dsp_interpolate_7th_order(fluid_rvoice_t *voice, fluid_real_t * * least sig. 8 bit part in order to create a 24 bit sample. */ static FLUID_INLINE int32_t -fluid_rvoice_get_sample(const short int *dsp_msb, const char *dsp_lsb, unsigned int idx) +fluid_rvoice_get_sample24(const short int *FLUID_RESTRICT dsp_msb, const char *FLUID_RESTRICT dsp_lsb, unsigned int idx) +{ + /* cast sample to unsigned type, so we can safely shift and bitwise or + * without relying on undefined behaviour (should never happen anyway ofc...) */ + uint32_t msb = (uint32_t)dsp_msb[idx]; + uint8_t lsb = (uint8_t)dsp_lsb[idx]; + + return (int32_t)((msb << 8) | lsb); +} + +static FLUID_INLINE int32_t +fluid_rvoice_get_sample16(const short int *FLUID_RESTRICT dsp_msb, unsigned int idx) { /* cast sample to unsigned type, so we can safely shift and bitwise or * without relying on undefined behaviour (should never happen anyway ofc...) */ uint32_t msb = (uint32_t)dsp_msb[idx]; - uint8_t lsb = 0U; - /* most soundfonts have 16 bit samples, assume that it's unlikely we - * experience 24 bit samples here */ - if(FLUID_UNLIKELY(dsp_lsb != NULL)) + return (int32_t)((msb << 8) | 0); +} + +static FLUID_INLINE int32_t +fluid_rvoice_get_sample(const short int *FLUID_RESTRICT dsp_msb, const char *FLUID_RESTRICT dsp_lsb, unsigned int idx) +{ + if (dsp_lsb != NULL) { - lsb = (uint8_t)dsp_lsb[idx]; + return fluid_rvoice_get_sample24(dsp_msb, dsp_lsb, idx); + } + else + { + return fluid_rvoice_get_sample16(dsp_msb, idx); } - - return (int32_t)((msb << 8) | lsb); } +#ifdef __cplusplus +} +#endif #endif diff --git a/libs/fluidsynth/src/rvoice/fluid_rvoice_dsp.c b/libs/fluidsynth/src/rvoice/fluid_rvoice_dsp.cpp similarity index 60% rename from libs/fluidsynth/src/rvoice/fluid_rvoice_dsp.c rename to libs/fluidsynth/src/rvoice/fluid_rvoice_dsp.cpp index 210ed93dfdc..4888a56ef18 100644 --- a/libs/fluidsynth/src/rvoice/fluid_rvoice_dsp.c +++ b/libs/fluidsynth/src/rvoice/fluid_rvoice_dsp.cpp @@ -47,34 +47,103 @@ /* Interpolation (find a value between two samples of the original waveform) */ +template<bool IS_24BIT> static FLUID_INLINE fluid_real_t -fluid_rvoice_get_float_sample(const short int *dsp_msb, const char *dsp_lsb, unsigned int idx) +fluid_rvoice_get_float_sample(const short int *FLUID_RESTRICT dsp_msb, const char *FLUID_RESTRICT dsp_lsb, unsigned int idx) { - int32_t sample = fluid_rvoice_get_sample(dsp_msb, dsp_lsb, idx); + int32_t sample; + if (IS_24BIT) + { + sample = fluid_rvoice_get_sample24(dsp_msb, dsp_lsb, idx); + } + else + { + sample = fluid_rvoice_get_sample16(dsp_msb, idx); + } + return (fluid_real_t)sample; } +/* Special case of interpolate_none for rendering silent voices, i.e. in delay phase or zero volume */ +template<bool LOOPING> +static int fluid_rvoice_dsp_silence_local(fluid_rvoice_t *rvoice, fluid_real_t *FLUID_RESTRICT dsp_buf) +{ + fluid_rvoice_dsp_t *voice = &rvoice->dsp; + fluid_phase_t dsp_phase = voice->phase; + fluid_phase_t dsp_phase_incr; + unsigned short dsp_i = 0; + unsigned int dsp_phase_index; + unsigned int end_index; + + /* Convert playback "speed" floating point value to phase index/fract */ + fluid_phase_set_float(dsp_phase_incr, voice->phase_incr); + + end_index = LOOPING ? voice->loopend - 1 : voice->end; + + while (1) + { + dsp_phase_index = fluid_phase_index_round(dsp_phase); /* round to nearest point */ + + /* interpolate sequence of sample points */ + for (; dsp_i < FLUID_BUFSIZE && dsp_phase_index <= end_index; dsp_i++) + { + fluid_real_t sample = 0; + dsp_buf[dsp_i] = sample; + + /* increment phase and amplitude */ + fluid_phase_incr(dsp_phase, dsp_phase_incr); + } + + /* break out if not looping (buffer may not be full) */ + if (!LOOPING) + { + break; + } + + dsp_phase_index = fluid_phase_index_round(dsp_phase); /* round to nearest point */ + /* go back to loop start */ + if (dsp_phase_index > end_index) + { + fluid_phase_sub_int(dsp_phase, voice->loopend - voice->loopstart); + voice->has_looped = 1; + } + + /* break out if filled buffer */ + if (dsp_i >= FLUID_BUFSIZE) + { + break; + } + } + + voice->phase = dsp_phase; + // Note, there is no need to update the amplitude here. When the voice becomes audible again, the amp will be updated anyway in fluid_rvoice_calc_amp(). + // voice->amp = dsp_amp; + + return (dsp_i); +} + /* No interpolation. Just take the sample, which is closest to * the playback pointer. Questionable quality, but very * efficient. */ -int -fluid_rvoice_dsp_interpolate_none(fluid_rvoice_t *rvoice, fluid_real_t *FLUID_RESTRICT dsp_buf, int looping) +template<bool ENABLE_CUSTOM_FILTER, bool IS_24BIT, bool LOOPING> +static int +fluid_rvoice_dsp_interpolate_none_local(fluid_rvoice_t *rvoice, fluid_real_t *FLUID_RESTRICT dsp_buf) { fluid_rvoice_dsp_t *voice = &rvoice->dsp; fluid_phase_t dsp_phase = voice->phase; fluid_phase_t dsp_phase_incr; - short int *dsp_data = voice->sample->data; - char *dsp_data24 = voice->sample->data24; + const short int *FLUID_RESTRICT dsp_data = voice->sample->data; + const char *FLUID_RESTRICT dsp_data24 = voice->sample->data24; fluid_real_t dsp_amp = voice->amp; fluid_real_t dsp_amp_incr = voice->amp_incr; - unsigned int dsp_i = 0; + unsigned short dsp_i = 0; unsigned int dsp_phase_index; unsigned int end_index; /* Convert playback "speed" floating point value to phase index/fract */ fluid_phase_set_float(dsp_phase_incr, voice->phase_incr); - end_index = looping ? voice->loopend - 1 : voice->end; + end_index = LOOPING ? voice->loopend - 1 : voice->end; while(1) { @@ -83,10 +152,13 @@ fluid_rvoice_dsp_interpolate_none(fluid_rvoice_t *rvoice, fluid_real_t *FLUID_RE /* interpolate sequence of sample points */ for(; dsp_i < FLUID_BUFSIZE && dsp_phase_index <= end_index; dsp_i++) { - fluid_real_t sample = fluid_rvoice_get_float_sample(dsp_data, dsp_data24, dsp_phase_index); + fluid_real_t sample = fluid_rvoice_get_float_sample<IS_24BIT>(dsp_data, dsp_data24, dsp_phase_index); fluid_iir_filter_apply(&rvoice->resonant_filter, &sample, 1, voice->output_rate); - fluid_iir_filter_apply(&rvoice->resonant_custom_filter, &sample, 1, voice->output_rate); + if (ENABLE_CUSTOM_FILTER) + { + fluid_iir_filter_apply(&rvoice->resonant_custom_filter, &sample, 1, voice->output_rate); + } dsp_buf[dsp_i] = dsp_amp * sample; @@ -97,7 +169,7 @@ fluid_rvoice_dsp_interpolate_none(fluid_rvoice_t *rvoice, fluid_real_t *FLUID_RE } /* break out if not looping (buffer may not be full) */ - if(!looping) + if(!LOOPING) { break; } @@ -126,17 +198,18 @@ fluid_rvoice_dsp_interpolate_none(fluid_rvoice_t *rvoice, fluid_real_t *FLUID_RE * Returns number of samples processed (usually FLUID_BUFSIZE but could be * smaller if end of sample occurs). */ -int -fluid_rvoice_dsp_interpolate_linear(fluid_rvoice_t *rvoice, fluid_real_t *FLUID_RESTRICT dsp_buf, int looping) +template<bool ENABLE_CUSTOM_FILTER, bool IS_24BIT, bool LOOPING> +static int +fluid_rvoice_dsp_interpolate_linear_local(fluid_rvoice_t *rvoice, fluid_real_t *FLUID_RESTRICT dsp_buf) { fluid_rvoice_dsp_t *voice = &rvoice->dsp; fluid_phase_t dsp_phase = voice->phase; fluid_phase_t dsp_phase_incr; - short int *dsp_data = voice->sample->data; - char *dsp_data24 = voice->sample->data24; + const short int *FLUID_RESTRICT dsp_data = voice->sample->data; + const char *FLUID_RESTRICT dsp_data24 = voice->sample->data24; fluid_real_t dsp_amp = voice->amp; fluid_real_t dsp_amp_incr = voice->amp_incr; - unsigned int dsp_i = 0; + unsigned short dsp_i = 0; unsigned int dsp_phase_index; unsigned int end_index; fluid_real_t point; @@ -146,16 +219,16 @@ fluid_rvoice_dsp_interpolate_linear(fluid_rvoice_t *rvoice, fluid_real_t *FLUID_ fluid_phase_set_float(dsp_phase_incr, voice->phase_incr); /* last index before 2nd interpolation point must be specially handled */ - end_index = (looping ? voice->loopend - 1 : voice->end) - 1; + end_index = (LOOPING ? voice->loopend - 1 : voice->end) - 1; /* 2nd interpolation point to use at end of loop or sample */ - if(looping) + if(LOOPING) { - point = fluid_rvoice_get_float_sample(dsp_data, dsp_data24, voice->loopstart); /* loop start */ + point = fluid_rvoice_get_float_sample<IS_24BIT>(dsp_data, dsp_data24, voice->loopstart); /* loop start */ } else { - point = fluid_rvoice_get_float_sample(dsp_data, dsp_data24, voice->end); /* duplicate end for samples no longer looping */ + point = fluid_rvoice_get_float_sample<IS_24BIT>(dsp_data, dsp_data24, voice->end); /* duplicate end for samples no longer looping */ } while(1) @@ -168,11 +241,14 @@ fluid_rvoice_dsp_interpolate_linear(fluid_rvoice_t *rvoice, fluid_real_t *FLUID_ fluid_real_t sample; coeffs = interp_coeff_linear[fluid_phase_fract_to_tablerow(dsp_phase)]; - sample = (coeffs[0] * fluid_rvoice_get_float_sample(dsp_data, dsp_data24, dsp_phase_index) - + coeffs[1] * fluid_rvoice_get_float_sample(dsp_data, dsp_data24, dsp_phase_index + 1)); + sample = (coeffs[0] * fluid_rvoice_get_float_sample<IS_24BIT>(dsp_data, dsp_data24, dsp_phase_index) + + coeffs[1] * fluid_rvoice_get_float_sample<IS_24BIT>(dsp_data, dsp_data24, dsp_phase_index + 1)); fluid_iir_filter_apply(&rvoice->resonant_filter, &sample, 1, voice->output_rate); - fluid_iir_filter_apply(&rvoice->resonant_custom_filter, &sample, 1, voice->output_rate); + if (ENABLE_CUSTOM_FILTER) + { + fluid_iir_filter_apply(&rvoice->resonant_custom_filter, &sample, 1, voice->output_rate); + } dsp_buf[dsp_i] = dsp_amp * sample; @@ -196,11 +272,14 @@ fluid_rvoice_dsp_interpolate_linear(fluid_rvoice_t *rvoice, fluid_real_t *FLUID_ fluid_real_t sample; coeffs = interp_coeff_linear[fluid_phase_fract_to_tablerow(dsp_phase)]; - sample = (coeffs[0] * fluid_rvoice_get_float_sample(dsp_data, dsp_data24, dsp_phase_index) + sample = (coeffs[0] * fluid_rvoice_get_float_sample<IS_24BIT>(dsp_data, dsp_data24, dsp_phase_index) + coeffs[1] * point); fluid_iir_filter_apply(&rvoice->resonant_filter, &sample, 1, voice->output_rate); - fluid_iir_filter_apply(&rvoice->resonant_custom_filter, &sample, 1, voice->output_rate); + if (ENABLE_CUSTOM_FILTER) + { + fluid_iir_filter_apply(&rvoice->resonant_custom_filter, &sample, 1, voice->output_rate); + } dsp_buf[dsp_i] = dsp_amp * sample; @@ -210,7 +289,7 @@ fluid_rvoice_dsp_interpolate_linear(fluid_rvoice_t *rvoice, fluid_real_t *FLUID_ dsp_amp += dsp_amp_incr; /* increment amplitude */ } - if(!looping) + if(!LOOPING) { break; /* break out if not looping (end of sample) */ } @@ -241,17 +320,18 @@ fluid_rvoice_dsp_interpolate_linear(fluid_rvoice_t *rvoice, fluid_real_t *FLUID_ * Returns number of samples processed (usually FLUID_BUFSIZE but could be * smaller if end of sample occurs). */ -int -fluid_rvoice_dsp_interpolate_4th_order(fluid_rvoice_t *rvoice, fluid_real_t *FLUID_RESTRICT dsp_buf, int looping) +template<bool ENABLE_CUSTOM_FILTER, bool IS_24BIT, bool LOOPING> +static int +fluid_rvoice_dsp_interpolate_4th_order_local(fluid_rvoice_t *rvoice, fluid_real_t *FLUID_RESTRICT dsp_buf) { fluid_rvoice_dsp_t *voice = &rvoice->dsp; fluid_phase_t dsp_phase = voice->phase; fluid_phase_t dsp_phase_incr; - short int *dsp_data = voice->sample->data; - char *dsp_data24 = voice->sample->data24; + const short int *FLUID_RESTRICT dsp_data = voice->sample->data; + const char *FLUID_RESTRICT dsp_data24 = voice->sample->data24; fluid_real_t dsp_amp = voice->amp; fluid_real_t dsp_amp_incr = voice->amp_incr; - unsigned int dsp_i = 0; + unsigned short dsp_i = 0; unsigned int dsp_phase_index; unsigned int start_index, end_index; fluid_real_t start_point, end_point1, end_point2; @@ -261,28 +341,28 @@ fluid_rvoice_dsp_interpolate_4th_order(fluid_rvoice_t *rvoice, fluid_real_t *FLU fluid_phase_set_float(dsp_phase_incr, voice->phase_incr); /* last index before 4th interpolation point must be specially handled */ - end_index = (looping ? voice->loopend - 1 : voice->end) - 2; + end_index = (LOOPING ? voice->loopend - 1 : voice->end) - 2; if(voice->has_looped) /* set start_index and start point if looped or not */ { start_index = voice->loopstart; - start_point = fluid_rvoice_get_float_sample(dsp_data, dsp_data24, voice->loopend - 1); /* last point in loop (wrap around) */ + start_point = fluid_rvoice_get_float_sample<IS_24BIT>(dsp_data, dsp_data24, voice->loopend - 1); /* last point in loop (wrap around) */ } else { start_index = voice->start; - start_point = fluid_rvoice_get_float_sample(dsp_data, dsp_data24, voice->start); /* just duplicate the point */ + start_point = fluid_rvoice_get_float_sample<IS_24BIT>(dsp_data, dsp_data24, voice->start); /* just duplicate the point */ } /* get points off the end (loop start if looping, duplicate point if end) */ - if(looping) + if(LOOPING) { - end_point1 = fluid_rvoice_get_float_sample(dsp_data, dsp_data24, voice->loopstart); - end_point2 = fluid_rvoice_get_float_sample(dsp_data, dsp_data24, voice->loopstart + 1); + end_point1 = fluid_rvoice_get_float_sample<IS_24BIT>(dsp_data, dsp_data24, voice->loopstart); + end_point2 = fluid_rvoice_get_float_sample<IS_24BIT>(dsp_data, dsp_data24, voice->loopstart + 1); } else { - end_point1 = fluid_rvoice_get_float_sample(dsp_data, dsp_data24, voice->end); + end_point1 = fluid_rvoice_get_float_sample<IS_24BIT>(dsp_data, dsp_data24, voice->end); end_point2 = end_point1; } @@ -297,12 +377,15 @@ fluid_rvoice_dsp_interpolate_4th_order(fluid_rvoice_t *rvoice, fluid_real_t *FLU coeffs = interp_coeff[fluid_phase_fract_to_tablerow(dsp_phase)]; sample = (coeffs[0] * start_point - + coeffs[1] * fluid_rvoice_get_float_sample(dsp_data, dsp_data24, dsp_phase_index) - + coeffs[2] * fluid_rvoice_get_float_sample(dsp_data, dsp_data24, dsp_phase_index + 1) - + coeffs[3] * fluid_rvoice_get_float_sample(dsp_data, dsp_data24, dsp_phase_index + 2)); + + coeffs[1] * fluid_rvoice_get_float_sample<IS_24BIT>(dsp_data, dsp_data24, dsp_phase_index) + + coeffs[2] * fluid_rvoice_get_float_sample<IS_24BIT>(dsp_data, dsp_data24, dsp_phase_index + 1) + + coeffs[3] * fluid_rvoice_get_float_sample<IS_24BIT>(dsp_data, dsp_data24, dsp_phase_index + 2)); fluid_iir_filter_apply(&rvoice->resonant_filter, &sample, 1, voice->output_rate); - fluid_iir_filter_apply(&rvoice->resonant_custom_filter, &sample, 1, voice->output_rate); + if (ENABLE_CUSTOM_FILTER) + { + fluid_iir_filter_apply(&rvoice->resonant_custom_filter, &sample, 1, voice->output_rate); + } dsp_buf[dsp_i] = dsp_amp * sample; @@ -318,13 +401,16 @@ fluid_rvoice_dsp_interpolate_4th_order(fluid_rvoice_t *rvoice, fluid_real_t *FLU fluid_real_t sample; coeffs = interp_coeff[fluid_phase_fract_to_tablerow(dsp_phase)]; - sample = (coeffs[0] * fluid_rvoice_get_float_sample(dsp_data, dsp_data24, dsp_phase_index - 1) - + coeffs[1] * fluid_rvoice_get_float_sample(dsp_data, dsp_data24, dsp_phase_index) - + coeffs[2] * fluid_rvoice_get_float_sample(dsp_data, dsp_data24, dsp_phase_index + 1) - + coeffs[3] * fluid_rvoice_get_float_sample(dsp_data, dsp_data24, dsp_phase_index + 2)); + sample = (coeffs[0] * fluid_rvoice_get_float_sample<IS_24BIT>(dsp_data, dsp_data24, dsp_phase_index - 1) + + coeffs[1] * fluid_rvoice_get_float_sample<IS_24BIT>(dsp_data, dsp_data24, dsp_phase_index) + + coeffs[2] * fluid_rvoice_get_float_sample<IS_24BIT>(dsp_data, dsp_data24, dsp_phase_index + 1) + + coeffs[3] * fluid_rvoice_get_float_sample<IS_24BIT>(dsp_data, dsp_data24, dsp_phase_index + 2)); fluid_iir_filter_apply(&rvoice->resonant_filter, &sample, 1, voice->output_rate); - fluid_iir_filter_apply(&rvoice->resonant_custom_filter, &sample, 1, voice->output_rate); + if (ENABLE_CUSTOM_FILTER) + { + fluid_iir_filter_apply(&rvoice->resonant_custom_filter, &sample, 1, voice->output_rate); + } dsp_buf[dsp_i] = dsp_amp * sample; @@ -348,13 +434,16 @@ fluid_rvoice_dsp_interpolate_4th_order(fluid_rvoice_t *rvoice, fluid_real_t *FLU fluid_real_t sample; coeffs = interp_coeff[fluid_phase_fract_to_tablerow(dsp_phase)]; - sample = (coeffs[0] * fluid_rvoice_get_float_sample(dsp_data, dsp_data24, dsp_phase_index - 1) - + coeffs[1] * fluid_rvoice_get_float_sample(dsp_data, dsp_data24, dsp_phase_index) - + coeffs[2] * fluid_rvoice_get_float_sample(dsp_data, dsp_data24, dsp_phase_index + 1) + sample = (coeffs[0] * fluid_rvoice_get_float_sample<IS_24BIT>(dsp_data, dsp_data24, dsp_phase_index - 1) + + coeffs[1] * fluid_rvoice_get_float_sample<IS_24BIT>(dsp_data, dsp_data24, dsp_phase_index) + + coeffs[2] * fluid_rvoice_get_float_sample<IS_24BIT>(dsp_data, dsp_data24, dsp_phase_index + 1) + coeffs[3] * end_point1); fluid_iir_filter_apply(&rvoice->resonant_filter, &sample, 1, voice->output_rate); - fluid_iir_filter_apply(&rvoice->resonant_custom_filter, &sample, 1, voice->output_rate); + if (ENABLE_CUSTOM_FILTER) + { + fluid_iir_filter_apply(&rvoice->resonant_custom_filter, &sample, 1, voice->output_rate); + } dsp_buf[dsp_i] = dsp_amp * sample; @@ -373,13 +462,16 @@ fluid_rvoice_dsp_interpolate_4th_order(fluid_rvoice_t *rvoice, fluid_real_t *FLU coeffs = interp_coeff[fluid_phase_fract_to_tablerow(dsp_phase)]; - sample = (coeffs[0] * fluid_rvoice_get_float_sample(dsp_data, dsp_data24, dsp_phase_index - 1) - + coeffs[1] * fluid_rvoice_get_float_sample(dsp_data, dsp_data24, dsp_phase_index) + sample = (coeffs[0] * fluid_rvoice_get_float_sample<IS_24BIT>(dsp_data, dsp_data24, dsp_phase_index - 1) + + coeffs[1] * fluid_rvoice_get_float_sample<IS_24BIT>(dsp_data, dsp_data24, dsp_phase_index) + coeffs[2] * end_point1 + coeffs[3] * end_point2); fluid_iir_filter_apply(&rvoice->resonant_filter, &sample, 1, voice->output_rate); - fluid_iir_filter_apply(&rvoice->resonant_custom_filter, &sample, 1, voice->output_rate); + if (ENABLE_CUSTOM_FILTER) + { + fluid_iir_filter_apply(&rvoice->resonant_custom_filter, &sample, 1, voice->output_rate); + } dsp_buf[dsp_i] = dsp_amp * sample; @@ -389,7 +481,7 @@ fluid_rvoice_dsp_interpolate_4th_order(fluid_rvoice_t *rvoice, fluid_real_t *FLU dsp_amp += dsp_amp_incr; } - if(!looping) + if(!LOOPING) { break; /* break out if not looping (end of sample) */ } @@ -403,7 +495,7 @@ fluid_rvoice_dsp_interpolate_4th_order(fluid_rvoice_t *rvoice, fluid_real_t *FLU { voice->has_looped = 1; start_index = voice->loopstart; - start_point = fluid_rvoice_get_float_sample(dsp_data, dsp_data24, voice->loopend - 1); + start_point = fluid_rvoice_get_float_sample<IS_24BIT>(dsp_data, dsp_data24, voice->loopend - 1); } } @@ -426,17 +518,18 @@ fluid_rvoice_dsp_interpolate_4th_order(fluid_rvoice_t *rvoice, fluid_real_t *FLU * Returns number of samples processed (usually FLUID_BUFSIZE but could be * smaller if end of sample occurs). */ -int -fluid_rvoice_dsp_interpolate_7th_order(fluid_rvoice_t *rvoice, fluid_real_t *FLUID_RESTRICT dsp_buf, int looping) +template<bool ENABLE_CUSTOM_FILTER, bool IS_24BIT, bool LOOPING> +static int +fluid_rvoice_dsp_interpolate_7th_order_local(fluid_rvoice_t *rvoice, fluid_real_t *FLUID_RESTRICT dsp_buf) { fluid_rvoice_dsp_t *voice = &rvoice->dsp; fluid_phase_t dsp_phase = voice->phase; fluid_phase_t dsp_phase_incr; - short int *dsp_data = voice->sample->data; - char *dsp_data24 = voice->sample->data24; + const short int *FLUID_RESTRICT dsp_data = voice->sample->data; + const char *FLUID_RESTRICT dsp_data24 = voice->sample->data24; fluid_real_t dsp_amp = voice->amp; fluid_real_t dsp_amp_incr = voice->amp_incr; - unsigned int dsp_i = 0; + unsigned short dsp_i = 0; unsigned int dsp_phase_index; unsigned int start_index, end_index; fluid_real_t start_points[3], end_points[3]; @@ -450,33 +543,33 @@ fluid_rvoice_dsp_interpolate_7th_order(fluid_rvoice_t *rvoice, fluid_real_t *FLU fluid_phase_incr(dsp_phase, (fluid_phase_t)0x80000000); /* last index before 7th interpolation point must be specially handled */ - end_index = (looping ? voice->loopend - 1 : voice->end) - 3; + end_index = (LOOPING ? voice->loopend - 1 : voice->end) - 3; if(voice->has_looped) /* set start_index and start point if looped or not */ { start_index = voice->loopstart; - start_points[0] = fluid_rvoice_get_float_sample(dsp_data, dsp_data24, voice->loopend - 1); - start_points[1] = fluid_rvoice_get_float_sample(dsp_data, dsp_data24, voice->loopend - 2); - start_points[2] = fluid_rvoice_get_float_sample(dsp_data, dsp_data24, voice->loopend - 3); + start_points[0] = fluid_rvoice_get_float_sample<IS_24BIT>(dsp_data, dsp_data24, voice->loopend - 1); + start_points[1] = fluid_rvoice_get_float_sample<IS_24BIT>(dsp_data, dsp_data24, voice->loopend - 2); + start_points[2] = fluid_rvoice_get_float_sample<IS_24BIT>(dsp_data, dsp_data24, voice->loopend - 3); } else { start_index = voice->start; - start_points[0] = fluid_rvoice_get_float_sample(dsp_data, dsp_data24, voice->start); /* just duplicate the start point */ + start_points[0] = fluid_rvoice_get_float_sample<IS_24BIT>(dsp_data, dsp_data24, voice->start); /* just duplicate the start point */ start_points[1] = start_points[0]; start_points[2] = start_points[0]; } /* get the 3 points off the end (loop start if looping, duplicate point if end) */ - if(looping) + if(LOOPING) { - end_points[0] = fluid_rvoice_get_float_sample(dsp_data, dsp_data24, voice->loopstart); - end_points[1] = fluid_rvoice_get_float_sample(dsp_data, dsp_data24, voice->loopstart + 1); - end_points[2] = fluid_rvoice_get_float_sample(dsp_data, dsp_data24, voice->loopstart + 2); + end_points[0] = fluid_rvoice_get_float_sample<IS_24BIT>(dsp_data, dsp_data24, voice->loopstart); + end_points[1] = fluid_rvoice_get_float_sample<IS_24BIT>(dsp_data, dsp_data24, voice->loopstart + 1); + end_points[2] = fluid_rvoice_get_float_sample<IS_24BIT>(dsp_data, dsp_data24, voice->loopstart + 2); } else { - end_points[0] = fluid_rvoice_get_float_sample(dsp_data, dsp_data24, voice->end); + end_points[0] = fluid_rvoice_get_float_sample<IS_24BIT>(dsp_data, dsp_data24, voice->end); end_points[1] = end_points[0]; end_points[2] = end_points[0]; } @@ -494,14 +587,16 @@ fluid_rvoice_dsp_interpolate_7th_order(fluid_rvoice_t *rvoice, fluid_real_t *FLU sample = (coeffs[0] * start_points[2] + coeffs[1] * start_points[1] + coeffs[2] * start_points[0] - + coeffs[3] * fluid_rvoice_get_float_sample(dsp_data, dsp_data24, dsp_phase_index) - + coeffs[4] * fluid_rvoice_get_float_sample(dsp_data, dsp_data24, dsp_phase_index + 1) - + coeffs[5] * fluid_rvoice_get_float_sample(dsp_data, dsp_data24, dsp_phase_index + 2) - + coeffs[6] * fluid_rvoice_get_float_sample(dsp_data, dsp_data24, dsp_phase_index + 3)); + + coeffs[3] * fluid_rvoice_get_float_sample<IS_24BIT>(dsp_data, dsp_data24, dsp_phase_index) + + coeffs[4] * fluid_rvoice_get_float_sample<IS_24BIT>(dsp_data, dsp_data24, dsp_phase_index + 1) + + coeffs[5] * fluid_rvoice_get_float_sample<IS_24BIT>(dsp_data, dsp_data24, dsp_phase_index + 2) + + coeffs[6] * fluid_rvoice_get_float_sample<IS_24BIT>(dsp_data, dsp_data24, dsp_phase_index + 3)); fluid_iir_filter_apply(&rvoice->resonant_filter, &sample, 1, voice->output_rate); - fluid_iir_filter_apply(&rvoice->resonant_custom_filter, &sample, 1, voice->output_rate); - + if (ENABLE_CUSTOM_FILTER) + { + fluid_iir_filter_apply(&rvoice->resonant_custom_filter, &sample, 1, voice->output_rate); + } dsp_buf[dsp_i] = dsp_amp * sample; /* increment phase and amplitude */ @@ -520,15 +615,17 @@ fluid_rvoice_dsp_interpolate_7th_order(fluid_rvoice_t *rvoice, fluid_real_t *FLU sample = (coeffs[0] * start_points[1] + coeffs[1] * start_points[0] - + coeffs[2] * fluid_rvoice_get_float_sample(dsp_data, dsp_data24, dsp_phase_index - 1) - + coeffs[3] * fluid_rvoice_get_float_sample(dsp_data, dsp_data24, dsp_phase_index) - + coeffs[4] * fluid_rvoice_get_float_sample(dsp_data, dsp_data24, dsp_phase_index + 1) - + coeffs[5] * fluid_rvoice_get_float_sample(dsp_data, dsp_data24, dsp_phase_index + 2) - + coeffs[6] * fluid_rvoice_get_float_sample(dsp_data, dsp_data24, dsp_phase_index + 3)); + + coeffs[2] * fluid_rvoice_get_float_sample<IS_24BIT>(dsp_data, dsp_data24, dsp_phase_index - 1) + + coeffs[3] * fluid_rvoice_get_float_sample<IS_24BIT>(dsp_data, dsp_data24, dsp_phase_index) + + coeffs[4] * fluid_rvoice_get_float_sample<IS_24BIT>(dsp_data, dsp_data24, dsp_phase_index + 1) + + coeffs[5] * fluid_rvoice_get_float_sample<IS_24BIT>(dsp_data, dsp_data24, dsp_phase_index + 2) + + coeffs[6] * fluid_rvoice_get_float_sample<IS_24BIT>(dsp_data, dsp_data24, dsp_phase_index + 3)); fluid_iir_filter_apply(&rvoice->resonant_filter, &sample, 1, voice->output_rate); - fluid_iir_filter_apply(&rvoice->resonant_custom_filter, &sample, 1, voice->output_rate); - + if (ENABLE_CUSTOM_FILTER) + { + fluid_iir_filter_apply(&rvoice->resonant_custom_filter, &sample, 1, voice->output_rate); + } dsp_buf[dsp_i] = dsp_amp * sample; /* increment phase and amplitude */ @@ -546,16 +643,18 @@ fluid_rvoice_dsp_interpolate_7th_order(fluid_rvoice_t *rvoice, fluid_real_t *FLU coeffs = sinc_table7[fluid_phase_fract_to_tablerow(dsp_phase)]; sample = (coeffs[0] * start_points[0] - + coeffs[1] * fluid_rvoice_get_float_sample(dsp_data, dsp_data24, dsp_phase_index - 2) - + coeffs[2] * fluid_rvoice_get_float_sample(dsp_data, dsp_data24, dsp_phase_index - 1) - + coeffs[3] * fluid_rvoice_get_float_sample(dsp_data, dsp_data24, dsp_phase_index) - + coeffs[4] * fluid_rvoice_get_float_sample(dsp_data, dsp_data24, dsp_phase_index + 1) - + coeffs[5] * fluid_rvoice_get_float_sample(dsp_data, dsp_data24, dsp_phase_index + 2) - + coeffs[6] * fluid_rvoice_get_float_sample(dsp_data, dsp_data24, dsp_phase_index + 3)); + + coeffs[1] * fluid_rvoice_get_float_sample<IS_24BIT>(dsp_data, dsp_data24, dsp_phase_index - 2) + + coeffs[2] * fluid_rvoice_get_float_sample<IS_24BIT>(dsp_data, dsp_data24, dsp_phase_index - 1) + + coeffs[3] * fluid_rvoice_get_float_sample<IS_24BIT>(dsp_data, dsp_data24, dsp_phase_index) + + coeffs[4] * fluid_rvoice_get_float_sample<IS_24BIT>(dsp_data, dsp_data24, dsp_phase_index + 1) + + coeffs[5] * fluid_rvoice_get_float_sample<IS_24BIT>(dsp_data, dsp_data24, dsp_phase_index + 2) + + coeffs[6] * fluid_rvoice_get_float_sample<IS_24BIT>(dsp_data, dsp_data24, dsp_phase_index + 3)); fluid_iir_filter_apply(&rvoice->resonant_filter, &sample, 1, voice->output_rate); - fluid_iir_filter_apply(&rvoice->resonant_custom_filter, &sample, 1, voice->output_rate); - + if (ENABLE_CUSTOM_FILTER) + { + fluid_iir_filter_apply(&rvoice->resonant_custom_filter, &sample, 1, voice->output_rate); + } dsp_buf[dsp_i] = dsp_amp * sample; /* increment phase and amplitude */ @@ -573,17 +672,19 @@ fluid_rvoice_dsp_interpolate_7th_order(fluid_rvoice_t *rvoice, fluid_real_t *FLU fluid_real_t sample; coeffs = sinc_table7[fluid_phase_fract_to_tablerow(dsp_phase)]; - sample = (coeffs[0] * fluid_rvoice_get_float_sample(dsp_data, dsp_data24, dsp_phase_index - 3) - + coeffs[1] * fluid_rvoice_get_float_sample(dsp_data, dsp_data24, dsp_phase_index - 2) - + coeffs[2] * fluid_rvoice_get_float_sample(dsp_data, dsp_data24, dsp_phase_index - 1) - + coeffs[3] * fluid_rvoice_get_float_sample(dsp_data, dsp_data24, dsp_phase_index) - + coeffs[4] * fluid_rvoice_get_float_sample(dsp_data, dsp_data24, dsp_phase_index + 1) - + coeffs[5] * fluid_rvoice_get_float_sample(dsp_data, dsp_data24, dsp_phase_index + 2) - + coeffs[6] * fluid_rvoice_get_float_sample(dsp_data, dsp_data24, dsp_phase_index + 3)); + sample = (coeffs[0] * fluid_rvoice_get_float_sample<IS_24BIT>(dsp_data, dsp_data24, dsp_phase_index - 3) + + coeffs[1] * fluid_rvoice_get_float_sample<IS_24BIT>(dsp_data, dsp_data24, dsp_phase_index - 2) + + coeffs[2] * fluid_rvoice_get_float_sample<IS_24BIT>(dsp_data, dsp_data24, dsp_phase_index - 1) + + coeffs[3] * fluid_rvoice_get_float_sample<IS_24BIT>(dsp_data, dsp_data24, dsp_phase_index) + + coeffs[4] * fluid_rvoice_get_float_sample<IS_24BIT>(dsp_data, dsp_data24, dsp_phase_index + 1) + + coeffs[5] * fluid_rvoice_get_float_sample<IS_24BIT>(dsp_data, dsp_data24, dsp_phase_index + 2) + + coeffs[6] * fluid_rvoice_get_float_sample<IS_24BIT>(dsp_data, dsp_data24, dsp_phase_index + 3)); fluid_iir_filter_apply(&rvoice->resonant_filter, &sample, 1, voice->output_rate); - fluid_iir_filter_apply(&rvoice->resonant_custom_filter, &sample, 1, voice->output_rate); - + if (ENABLE_CUSTOM_FILTER) + { + fluid_iir_filter_apply(&rvoice->resonant_custom_filter, &sample, 1, voice->output_rate); + } dsp_buf[dsp_i] = dsp_amp * sample; /* increment phase and amplitude */ @@ -606,17 +707,19 @@ fluid_rvoice_dsp_interpolate_7th_order(fluid_rvoice_t *rvoice, fluid_real_t *FLU fluid_real_t sample; coeffs = sinc_table7[fluid_phase_fract_to_tablerow(dsp_phase)]; - sample = (coeffs[0] * fluid_rvoice_get_float_sample(dsp_data, dsp_data24, dsp_phase_index - 3) - + coeffs[1] * fluid_rvoice_get_float_sample(dsp_data, dsp_data24, dsp_phase_index - 2) - + coeffs[2] * fluid_rvoice_get_float_sample(dsp_data, dsp_data24, dsp_phase_index - 1) - + coeffs[3] * fluid_rvoice_get_float_sample(dsp_data, dsp_data24, dsp_phase_index) - + coeffs[4] * fluid_rvoice_get_float_sample(dsp_data, dsp_data24, dsp_phase_index + 1) - + coeffs[5] * fluid_rvoice_get_float_sample(dsp_data, dsp_data24, dsp_phase_index + 2) + sample = (coeffs[0] * fluid_rvoice_get_float_sample<IS_24BIT>(dsp_data, dsp_data24, dsp_phase_index - 3) + + coeffs[1] * fluid_rvoice_get_float_sample<IS_24BIT>(dsp_data, dsp_data24, dsp_phase_index - 2) + + coeffs[2] * fluid_rvoice_get_float_sample<IS_24BIT>(dsp_data, dsp_data24, dsp_phase_index - 1) + + coeffs[3] * fluid_rvoice_get_float_sample<IS_24BIT>(dsp_data, dsp_data24, dsp_phase_index) + + coeffs[4] * fluid_rvoice_get_float_sample<IS_24BIT>(dsp_data, dsp_data24, dsp_phase_index + 1) + + coeffs[5] * fluid_rvoice_get_float_sample<IS_24BIT>(dsp_data, dsp_data24, dsp_phase_index + 2) + coeffs[6] * end_points[0]); fluid_iir_filter_apply(&rvoice->resonant_filter, &sample, 1, voice->output_rate); - fluid_iir_filter_apply(&rvoice->resonant_custom_filter, &sample, 1, voice->output_rate); - + if (ENABLE_CUSTOM_FILTER) + { + fluid_iir_filter_apply(&rvoice->resonant_custom_filter, &sample, 1, voice->output_rate); + } dsp_buf[dsp_i] = dsp_amp * sample; /* increment phase and amplitude */ @@ -633,17 +736,19 @@ fluid_rvoice_dsp_interpolate_7th_order(fluid_rvoice_t *rvoice, fluid_real_t *FLU fluid_real_t sample; coeffs = sinc_table7[fluid_phase_fract_to_tablerow(dsp_phase)]; - sample = (coeffs[0] * fluid_rvoice_get_float_sample(dsp_data, dsp_data24, dsp_phase_index - 3) - + coeffs[1] * fluid_rvoice_get_float_sample(dsp_data, dsp_data24, dsp_phase_index - 2) - + coeffs[2] * fluid_rvoice_get_float_sample(dsp_data, dsp_data24, dsp_phase_index - 1) - + coeffs[3] * fluid_rvoice_get_float_sample(dsp_data, dsp_data24, dsp_phase_index) - + coeffs[4] * fluid_rvoice_get_float_sample(dsp_data, dsp_data24, dsp_phase_index + 1) + sample = (coeffs[0] * fluid_rvoice_get_float_sample<IS_24BIT>(dsp_data, dsp_data24, dsp_phase_index - 3) + + coeffs[1] * fluid_rvoice_get_float_sample<IS_24BIT>(dsp_data, dsp_data24, dsp_phase_index - 2) + + coeffs[2] * fluid_rvoice_get_float_sample<IS_24BIT>(dsp_data, dsp_data24, dsp_phase_index - 1) + + coeffs[3] * fluid_rvoice_get_float_sample<IS_24BIT>(dsp_data, dsp_data24, dsp_phase_index) + + coeffs[4] * fluid_rvoice_get_float_sample<IS_24BIT>(dsp_data, dsp_data24, dsp_phase_index + 1) + coeffs[5] * end_points[0] + coeffs[6] * end_points[1]); fluid_iir_filter_apply(&rvoice->resonant_filter, &sample, 1, voice->output_rate); - fluid_iir_filter_apply(&rvoice->resonant_custom_filter, &sample, 1, voice->output_rate); - + if (ENABLE_CUSTOM_FILTER) + { + fluid_iir_filter_apply(&rvoice->resonant_custom_filter, &sample, 1, voice->output_rate); + } dsp_buf[dsp_i] = dsp_amp * sample; /* increment phase and amplitude */ @@ -660,17 +765,19 @@ fluid_rvoice_dsp_interpolate_7th_order(fluid_rvoice_t *rvoice, fluid_real_t *FLU fluid_real_t sample; coeffs = sinc_table7[fluid_phase_fract_to_tablerow(dsp_phase)]; - sample = (coeffs[0] * fluid_rvoice_get_float_sample(dsp_data, dsp_data24, dsp_phase_index - 3) - + coeffs[1] * fluid_rvoice_get_float_sample(dsp_data, dsp_data24, dsp_phase_index - 2) - + coeffs[2] * fluid_rvoice_get_float_sample(dsp_data, dsp_data24, dsp_phase_index - 1) - + coeffs[3] * fluid_rvoice_get_float_sample(dsp_data, dsp_data24, dsp_phase_index) + sample = (coeffs[0] * fluid_rvoice_get_float_sample<IS_24BIT>(dsp_data, dsp_data24, dsp_phase_index - 3) + + coeffs[1] * fluid_rvoice_get_float_sample<IS_24BIT>(dsp_data, dsp_data24, dsp_phase_index - 2) + + coeffs[2] * fluid_rvoice_get_float_sample<IS_24BIT>(dsp_data, dsp_data24, dsp_phase_index - 1) + + coeffs[3] * fluid_rvoice_get_float_sample<IS_24BIT>(dsp_data, dsp_data24, dsp_phase_index) + coeffs[4] * end_points[0] + coeffs[5] * end_points[1] + coeffs[6] * end_points[2]); fluid_iir_filter_apply(&rvoice->resonant_filter, &sample, 1, voice->output_rate); - fluid_iir_filter_apply(&rvoice->resonant_custom_filter, &sample, 1, voice->output_rate); - + if (ENABLE_CUSTOM_FILTER) + { + fluid_iir_filter_apply(&rvoice->resonant_custom_filter, &sample, 1, voice->output_rate); + } dsp_buf[dsp_i] = dsp_amp * sample; /* increment phase and amplitude */ @@ -679,7 +786,7 @@ fluid_rvoice_dsp_interpolate_7th_order(fluid_rvoice_t *rvoice, fluid_real_t *FLU dsp_amp += dsp_amp_incr; } - if(!looping) + if(!LOOPING) { break; /* break out if not looping (end of sample) */ } @@ -693,9 +800,9 @@ fluid_rvoice_dsp_interpolate_7th_order(fluid_rvoice_t *rvoice, fluid_real_t *FLU { voice->has_looped = 1; start_index = voice->loopstart; - start_points[0] = fluid_rvoice_get_float_sample(dsp_data, dsp_data24, voice->loopend - 1); - start_points[1] = fluid_rvoice_get_float_sample(dsp_data, dsp_data24, voice->loopend - 2); - start_points[2] = fluid_rvoice_get_float_sample(dsp_data, dsp_data24, voice->loopend - 3); + start_points[0] = fluid_rvoice_get_float_sample<IS_24BIT>(dsp_data, dsp_data24, voice->loopend - 1); + start_points[1] = fluid_rvoice_get_float_sample<IS_24BIT>(dsp_data, dsp_data24, voice->loopend - 2); + start_points[2] = fluid_rvoice_get_float_sample<IS_24BIT>(dsp_data, dsp_data24, voice->loopend - 3); } } @@ -717,3 +824,136 @@ fluid_rvoice_dsp_interpolate_7th_order(fluid_rvoice_t *rvoice, fluid_real_t *FLU return (dsp_i); } + +struct ProcessSilence +{ + template<bool ENABLE_CUSTOM_FILTER, bool IS_24BIT, bool LOOPING> + int operator()(fluid_rvoice_t *rvoice, fluid_real_t *FLUID_RESTRICT dsp_buf) const + { + return fluid_rvoice_dsp_silence_local<LOOPING>(rvoice, dsp_buf); + } +}; + +struct InterpolateNone +{ + template<bool ENABLE_CUSTOM_FILTER, bool IS_24BIT, bool LOOPING> + int operator()(fluid_rvoice_t *rvoice, fluid_real_t *FLUID_RESTRICT dsp_buf) const + { + return fluid_rvoice_dsp_interpolate_none_local<ENABLE_CUSTOM_FILTER, IS_24BIT, LOOPING>(rvoice, dsp_buf); + } +}; + +struct InterpolateLinear +{ + template<bool ENABLE_CUSTOM_FILTER, bool IS_24BIT, bool LOOPING> + int operator()(fluid_rvoice_t *rvoice, fluid_real_t *FLUID_RESTRICT dsp_buf) const + { + return fluid_rvoice_dsp_interpolate_linear_local<ENABLE_CUSTOM_FILTER, IS_24BIT, LOOPING>(rvoice, dsp_buf); + } +}; + +struct Interpolate4thOrder +{ + template<bool ENABLE_CUSTOM_FILTER, bool IS_24BIT, bool LOOPING> + int operator()(fluid_rvoice_t *rvoice, fluid_real_t *FLUID_RESTRICT dsp_buf) const + { + return fluid_rvoice_dsp_interpolate_4th_order_local<ENABLE_CUSTOM_FILTER, IS_24BIT, LOOPING>(rvoice, dsp_buf); + } +}; + +struct Interpolate7thOrder +{ + template<bool ENABLE_CUSTOM_FILTER, bool IS_24BIT, bool LOOPING> + int operator()(fluid_rvoice_t *rvoice, fluid_real_t *FLUID_RESTRICT dsp_buf) const + { + return fluid_rvoice_dsp_interpolate_7th_order_local<ENABLE_CUSTOM_FILTER, IS_24BIT, LOOPING>(rvoice, dsp_buf); + } +}; + +template<typename T> +int dsp_invoker(fluid_rvoice_t *rvoice, fluid_real_t *FLUID_RESTRICT dsp_buf, int looping) +{ + T func; + bool is_24bit = rvoice->dsp.sample->data24 != NULL; + + if (rvoice->resonant_custom_filter.flags & FLUID_IIR_DISABLED) + { + if (is_24bit) + { + if(looping) + { + return func.template operator()<false, true, true>(rvoice, dsp_buf); + } + else + { + return func.template operator()<false, true, false>(rvoice, dsp_buf); + } + } + else + { + // This case is most common, thanks to templating it will also become the fastest one + if (looping) + { + return func.template operator()<false, false, true>(rvoice, dsp_buf); + } + else + { + return func.template operator()<false, false, false>(rvoice, dsp_buf); + } + } + } + else + { + if (is_24bit) + { + if (looping) + { + return func.template operator()<true, true, true>(rvoice, dsp_buf); + } + else + { + return func.template operator()<true, true, false>(rvoice, dsp_buf); + } + } + else + { + if (looping) + { + return func.template operator()<true, false, true>(rvoice, dsp_buf); + } + else + { + return func.template operator()<true, false, false>(rvoice, dsp_buf); + } + } + } +} + +extern "C" int +fluid_rvoice_dsp_silence(fluid_rvoice_t *rvoice, fluid_real_t *FLUID_RESTRICT dsp_buf, int looping) +{ + return dsp_invoker<ProcessSilence>(rvoice, dsp_buf, looping); +} + +extern "C" int +fluid_rvoice_dsp_interpolate_none(fluid_rvoice_t *rvoice, fluid_real_t *FLUID_RESTRICT dsp_buf, int looping) +{ + return dsp_invoker<InterpolateNone>(rvoice, dsp_buf, looping); +} + +extern "C" int +fluid_rvoice_dsp_interpolate_linear(fluid_rvoice_t *rvoice, fluid_real_t *FLUID_RESTRICT dsp_buf, int looping) +{ + return dsp_invoker<InterpolateLinear>(rvoice, dsp_buf, looping); +} + +extern "C" int +fluid_rvoice_dsp_interpolate_4th_order(fluid_rvoice_t *rvoice, fluid_real_t *FLUID_RESTRICT dsp_buf, int looping) +{ + return dsp_invoker<Interpolate4thOrder>(rvoice, dsp_buf, looping); +} + +extern "C" int fluid_rvoice_dsp_interpolate_7th_order(fluid_rvoice_t *rvoice, fluid_real_t *FLUID_RESTRICT dsp_buf, int looping) +{ + return dsp_invoker<Interpolate7thOrder>(rvoice, dsp_buf, looping); +} diff --git a/libs/fluidsynth/src/sfloader/fluid_sfont.h b/libs/fluidsynth/src/sfloader/fluid_sfont.h index 9a42c02eb19..855adee1b6c 100644 --- a/libs/fluidsynth/src/sfloader/fluid_sfont.h +++ b/libs/fluidsynth/src/sfloader/fluid_sfont.h @@ -24,6 +24,9 @@ #include "fluidsynth.h" +#ifdef __cplusplus +extern "C" { +#endif int fluid_sample_validate(fluid_sample_t *sample, unsigned int max_end); int fluid_sample_sanitize_loop(fluid_sample_t *sample, unsigned int max_end); @@ -186,4 +189,7 @@ struct _fluid_sample_t }; +#ifdef __cplusplus +} +#endif #endif /* _PRIV_FLUID_SFONT_H */ diff --git a/libs/fluidsynth/src/synth/fluid_synth.c b/libs/fluidsynth/src/synth/fluid_synth.c index 1c4d1977d75..d1cc33f6f6d 100644 --- a/libs/fluidsynth/src/synth/fluid_synth.c +++ b/libs/fluidsynth/src/synth/fluid_synth.c @@ -256,6 +256,7 @@ void fluid_synth_settings(fluid_settings_t *settings) fluid_settings_add_option(settings, "synth.midi-bank-select", "mma"); fluid_settings_register_int(settings, "synth.dynamic-sample-loading", 0, 0, 1, FLUID_HINT_TOGGLED); + fluid_settings_register_int(settings, "synth.note-cut", 0, 0, 2, 0); } /** @@ -690,6 +691,9 @@ new_fluid_synth(fluid_settings_t *settings) fluid_settings_getnum_float(settings, "synth.overflow.age", &synth->overflow.age); fluid_settings_getnum_float(settings, "synth.overflow.important", &synth->overflow.important); + fluid_settings_getint(settings, "synth.note-cut", &i); + synth->msgs_note_cut_mode = i; + /* register the callbacks */ fluid_settings_callback_num(settings, "synth.gain", fluid_synth_handle_gain, synth); @@ -5213,7 +5217,7 @@ fluid_synth_alloc_voice_LOCAL(fluid_synth_t *synth, fluid_sample_t *sample, int FLUID_LOG(FLUID_INFO, "noteon\t%d\t%d\t%d\t%05d\t%.3f\t%.3f\t%.3f\t%d", chan, key, vel, synth->storeid, - (float) ticks / 44100.0f, + (float) ticks / synth->sample_rate, (fluid_curtime() - synth->start) / 1000.0f, 0.0f, k); @@ -6880,6 +6884,7 @@ fluid_synth_release_voice_on_same_note_LOCAL(fluid_synth_t *synth, int chan, && (fluid_voice_get_id(voice) != synth->noteid)) { enum fluid_midi_channel_type type = synth->channel[chan]->channel_type; + enum fluid_msgs_note_cut note_cut_mode = synth->msgs_note_cut_mode; /* Id of voices that was sustained by sostenuto */ if(fluid_voice_is_sostenuto(voice)) @@ -6887,21 +6892,17 @@ fluid_synth_release_voice_on_same_note_LOCAL(fluid_synth_t *synth, int chan, synth->storeid = fluid_voice_get_id(voice); } - switch(type) + if(note_cut_mode == FLUID_MSGS_DISABLED || (note_cut_mode == FLUID_MSGS_DRUM_CUT && type == CHANNEL_TYPE_MELODIC)) + { + /* Force the voice into release stage except if pedaling (sostenuto or sustain) is active. + * This gives a more realistic sound to pianos and possibly other instruments (see PR #905). */ + fluid_voice_noteoff(voice); + } + else // i.e. if((note_cut_mode == FLUID_MSGS_ALL_CUT) || (note_cut_mode == FLUID_MSGS_DRUM_CUT && type == CHANNEL_TYPE_DRUM)) { - case CHANNEL_TYPE_DRUM: - /* release the voice, this should make riding hi-hats or snares sound more - * realistic (Discussion #1196) */ - fluid_voice_off(voice); - break; - case CHANNEL_TYPE_MELODIC: - /* Force the voice into release stage except if pedaling (sostenuto or sustain) is active. - * This gives a more realistic sound to pianos and possibly other instruments (see PR #905). */ - fluid_voice_noteoff(voice); - break; - default: - FLUID_LOG(FLUID_ERR, "This should never happen: unknown channel type %d", (int)type); - break; + /* release the voice, this should make riding hi-hats or snares sound more realistic (Discussion #1196) + * Note however, that this is not a SF2 compliant behavior, see #1466 */ + fluid_voice_off(voice); } } } diff --git a/libs/fluidsynth/src/synth/fluid_synth.h b/libs/fluidsynth/src/synth/fluid_synth.h index 48ab8ac43d2..3958f93c1db 100644 --- a/libs/fluidsynth/src/synth/fluid_synth.h +++ b/libs/fluidsynth/src/synth/fluid_synth.h @@ -81,6 +81,13 @@ enum fluid_synth_status FLUID_SYNTH_STOPPED }; +enum fluid_msgs_note_cut +{ + FLUID_MSGS_DISABLED = 0, + FLUID_MSGS_DRUM_CUT = 1, + FLUID_MSGS_ALL_CUT = 2 +}; + #define SYNTH_REVERB_CHANNEL 0 #define SYNTH_CHORUS_CHANNEL 1 @@ -115,8 +122,7 @@ struct _fluid_synth_t int midi_channels; /**< the number of MIDI channels (>= 16) */ int bank_select; /**< the style of Bank Select MIDI messages */ int audio_channels; /**< the number of audio channels (1 channel=left+right) */ - int audio_groups; /**< the number of (stereo) 'sub'groups from the synth. - Typically equal to audio_channels. */ + int audio_groups; /**< the number of (stereo) 'sub'groups from the synth. Typically equal to audio_channels. */ int effects_channels; /**< the number of effects channels (>= 2) */ int effects_groups; /**< the number of effects units (>= 1) */ int state; /**< the synthesizer state */ @@ -164,6 +170,7 @@ struct _fluid_synth_t fluid_ladspa_fx_t *ladspa_fx; /**< Effects unit for LADSPA support */ enum fluid_iir_filter_type custom_filter_type; /**< filter type of the user-defined filter currently used for all voices */ enum fluid_iir_filter_flags custom_filter_flags; /**< filter type of the user-defined filter currently used for all voices */ + enum fluid_msgs_note_cut msgs_note_cut_mode; }; /** diff --git a/libs/fluidsynth/src/synth/fluid_voice.c b/libs/fluidsynth/src/synth/fluid_voice.c index c1daf3d316d..6652ccf99af 100644 --- a/libs/fluidsynth/src/synth/fluid_voice.c +++ b/libs/fluidsynth/src/synth/fluid_voice.c @@ -1400,14 +1400,11 @@ fluid_voice_kill_excl(fluid_voice_t *voice) #if 0 /* unused in Wine */ /* Speed up the volume envelope */ - /* The value was found through listening tests with hi-hat samples. */ - fluid_voice_gen_set(voice, GEN_VOLENVRELEASE, -200); + /* The previously-used value of "-200" was found through listening tests + with hi-hat samples. This was changed to "-2000" after "-200" was shown + to cause too long cut times in most cases. */ + fluid_voice_gen_set(voice, GEN_VOLENVRELEASE, -2000); fluid_voice_update_param(voice, GEN_VOLENVRELEASE); - - /* Speed up the modulation envelope */ - fluid_voice_gen_set(voice, GEN_MODENVRELEASE, -200); - fluid_voice_update_param(voice, GEN_MODENVRELEASE); - gen[i].val = fluid_gen_info[i].def; #else /* Speed up the volume envelope */ fluid_voice_gen_set(voice, GEN_VOLENVRELEASE, -32768); diff --git a/libs/fluidsynth/src/utils/fluid_conv.c b/libs/fluidsynth/src/utils/fluid_conv.c index 690cc0526ef..9aad62acce7 100644 --- a/libs/fluidsynth/src/utils/fluid_conv.c +++ b/libs/fluidsynth/src/utils/fluid_conv.c @@ -211,7 +211,7 @@ fluid_real_t fluid_sec2tc(fluid_real_t sec) { fluid_real_t res; - if(sec < 0) + if(sec <= 0) { // would require a complex solution of fluid_tc2sec(), but this is real-only return -32768.f; diff --git a/libs/fluidsynth/src/utils/fluid_conv.h b/libs/fluidsynth/src/utils/fluid_conv.h index bd1edb94f6e..801afc4c33c 100644 --- a/libs/fluidsynth/src/utils/fluid_conv.h +++ b/libs/fluidsynth/src/utils/fluid_conv.h @@ -24,6 +24,9 @@ #include "fluidsynth_priv.h" #include "utils/fluid_conv_tables.h" +#ifdef __cplusplus +extern "C" { +#endif fluid_real_t fluid_ct2hz_real(fluid_real_t cents); fluid_real_t fluid_ct2hz(fluid_real_t cents); fluid_real_t fluid_cb2amp(fluid_real_t cb); @@ -39,4 +42,7 @@ fluid_real_t fluid_balance(fluid_real_t balance, int left); fluid_real_t fluid_concave(fluid_real_t val); fluid_real_t fluid_convex(fluid_real_t val); +#ifdef __cplusplus +} +#endif #endif /* _FLUID_CONV_H */ diff --git a/libs/fluidsynth/src/utils/fluid_sys.h b/libs/fluidsynth/src/utils/fluid_sys.h index 79aeef0fb90..753347d596f 100644 --- a/libs/fluidsynth/src/utils/fluid_sys.h +++ b/libs/fluidsynth/src/utils/fluid_sys.h @@ -177,6 +177,10 @@ typedef gintptr intptr_t; /* #include <glib/gstdio.h> */ +#ifdef __cplusplus +extern "C" { +#endif + /** * Macro used for safely accessing a message from a GError and using a default * message if it is NULL. @@ -798,4 +802,7 @@ static FLUID_INLINE void *fluid_align_ptr(const void *ptr, unsigned int alignmen #define FLUID_DEFAULT_ALIGNMENT (64U) +#ifdef __cplusplus +} +#endif #endif /* _FLUID_SYS_H */ -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10299