 
            From: Anton Baskanov baskanov@gmail.com
This is the last release we can import, as in 2.4.3 the DSP code has been converted to C++. --- libs/fluidsynth/config.h | 1 + libs/fluidsynth/include/fluidsynth/types.h | 2 - libs/fluidsynth/include/fluidsynth/version.h | 6 +- libs/fluidsynth/src/rvoice/fluid_iir_filter.c | 184 +++++++++---- libs/fluidsynth/src/rvoice/fluid_iir_filter.h | 31 ++- libs/fluidsynth/src/rvoice/fluid_rvoice.c | 40 +-- libs/fluidsynth/src/rvoice/fluid_rvoice.h | 8 +- libs/fluidsynth/src/rvoice/fluid_rvoice_dsp.c | 253 ++++++++++++------ libs/fluidsynth/src/sfloader/fluid_sffile.c | 35 ++- libs/fluidsynth/src/synth/fluid_synth.c | 29 +- libs/fluidsynth/src/synth/fluid_synth.h | 2 +- libs/fluidsynth/src/synth/fluid_voice.c | 5 - libs/fluidsynth/src/utils/fluid_sys.c | 13 +- libs/fluidsynth/src/utils/fluid_sys.h | 7 + 14 files changed, 409 insertions(+), 207 deletions(-)
diff --git a/libs/fluidsynth/config.h b/libs/fluidsynth/config.h index 2170ad098ed..0d6d99c1709 100644 --- a/libs/fluidsynth/config.h +++ b/libs/fluidsynth/config.h @@ -218,6 +218,7 @@ /* #undef TEST_SOUNDFONT_UTF8_1 */ /* #undef TEST_SOUNDFONT_UTF8_2 */ /* #undef TEST_MIDI_UTF8 */ +/* #undef TEST_WAV_UTF8 */
/* SF3 Soundfont to load for unit testing */ /* #undef TEST_SOUNDFONT_SF3 */ diff --git a/libs/fluidsynth/include/fluidsynth/types.h b/libs/fluidsynth/include/fluidsynth/types.h index 9c2aaadacaa..09a8509697b 100644 --- a/libs/fluidsynth/include/fluidsynth/types.h +++ b/libs/fluidsynth/include/fluidsynth/types.h @@ -55,8 +55,6 @@ typedef struct _fluid_shell_t fluid_shell_t; /**< Command she typedef struct _fluid_server_t fluid_server_t; /**< TCP/IP shell server instance */ typedef struct _fluid_event_t fluid_event_t; /**< Sequencer event */ typedef struct _fluid_sequencer_t fluid_sequencer_t; /**< Sequencer instance */ -typedef struct _fluid_ramsfont_t fluid_ramsfont_t; /**< RAM SoundFont */ -typedef struct _fluid_rampreset_t fluid_rampreset_t; /**< RAM SoundFont preset */ typedef struct _fluid_cmd_handler_t fluid_cmd_handler_t; /**< Shell Command Handler */ typedef struct _fluid_ladspa_fx_t fluid_ladspa_fx_t; /**< LADSPA effects instance */ typedef struct _fluid_file_callbacks_t fluid_file_callbacks_t; /**< Callback struct to perform custom file loading of soundfonts */ diff --git a/libs/fluidsynth/include/fluidsynth/version.h b/libs/fluidsynth/include/fluidsynth/version.h index b1dcf349ba6..f15b9b2b680 100644 --- a/libs/fluidsynth/include/fluidsynth/version.h +++ b/libs/fluidsynth/include/fluidsynth/version.h @@ -31,10 +31,10 @@ extern "C" { * * @{ */ -#define FLUIDSYNTH_VERSION "2.3.6" /**< String constant of libfluidsynth version. */ +#define FLUIDSYNTH_VERSION "2.4.2" /**< String constant of libfluidsynth version. */ #define FLUIDSYNTH_VERSION_MAJOR 2 /**< libfluidsynth major version integer constant. */ -#define FLUIDSYNTH_VERSION_MINOR 3 /**< libfluidsynth minor version integer constant. */ -#define FLUIDSYNTH_VERSION_MICRO 6 /**< libfluidsynth micro version integer constant. */ +#define FLUIDSYNTH_VERSION_MINOR 4 /**< libfluidsynth minor version integer constant. */ +#define FLUIDSYNTH_VERSION_MICRO 2 /**< libfluidsynth micro version integer constant. */
FLUIDSYNTH_API void fluid_version(int *major, int *minor, int *micro); FLUIDSYNTH_API char* fluid_version_str(void); diff --git a/libs/fluidsynth/src/rvoice/fluid_iir_filter.c b/libs/fluidsynth/src/rvoice/fluid_iir_filter.c index fcea1793d50..ba8d5a9603f 100644 --- a/libs/fluidsynth/src/rvoice/fluid_iir_filter.c +++ b/libs/fluidsynth/src/rvoice/fluid_iir_filter.c @@ -22,6 +22,13 @@ #include "fluid_sys.h" #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: @@ -48,9 +55,9 @@ */ void fluid_iir_filter_apply(fluid_iir_filter_t *iir_filter, - fluid_real_t *dsp_buf, int count) + fluid_real_t *dsp_buf, int count, fluid_real_t output_rate) { - if(iir_filter->type == FLUID_IIR_DISABLED || iir_filter->q_lin == 0) + if(iir_filter->type == FLUID_IIR_DISABLED || FLUID_FABS(iir_filter->last_q) <= 0.001) { return; } @@ -66,6 +73,9 @@ fluid_iir_filter_apply(fluid_iir_filter_t *iir_filter, 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;
@@ -94,6 +104,24 @@ fluid_iir_filter_apply(fluid_iir_filter_t *iir_filter, // 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; @@ -103,11 +131,13 @@ fluid_iir_filter_apply(fluid_iir_filter_t *iir_filter, 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; @@ -129,7 +159,7 @@ fluid_iir_filter_reset(fluid_iir_filter_t *iir_filter) iir_filter->hist1 = 0; iir_filter->hist2 = 0; iir_filter->last_fres = -1.; - iir_filter->q_lin = 0; + iir_filter->last_q = 0; iir_filter->filter_startup = 1; }
@@ -139,7 +169,8 @@ DECLARE_FLUID_RVOICE_FUNCTION(fluid_iir_filter_set_fres) fluid_real_t fres = param[0].real;
iir_filter->fres = fres; - iir_filter->last_fres = -1.; + + LOG_FILTER("fluid_iir_filter_set_fres: fres= %f [acents]",fres); }
static fluid_real_t fluid_iir_filter_q_from_dB(fluid_real_t q_dB) @@ -181,58 +212,55 @@ DECLARE_FLUID_RVOICE_FUNCTION(fluid_iir_filter_set_q) fluid_real_t q = param[0].real; int flags = iir_filter->flags;
+ LOG_FILTER("fluid_iir_filter_set_q: Q= %f [dB]",q); + if(flags & FLUID_IIR_Q_ZERO_OFF && q <= 0.0) { q = 0; } else if(flags & FLUID_IIR_Q_LINEAR) { - /* q is linear (only for user-defined filter) - * increase to avoid Q being somewhere between zero and one, - * which results in some strange amplified lowpass signal - */ - q++; + /* q is linear (only for user-defined filter) */ } else { q = fluid_iir_filter_q_from_dB(q); }
- iir_filter->q_lin = q; - iir_filter->filter_gain = 1.0; + LOG_FILTER("fluid_iir_filter_set_q: Q= %f [linear]",q);
- if(!(flags & FLUID_IIR_NO_GAIN_AMP)) + if(iir_filter->filter_startup) { - /* 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. - */ - iir_filter->filter_gain /= FLUID_SQRT(q); + iir_filter->last_q = q; } - - /* The synthesis loop will have to recalculate the filter coefficients. */ - iir_filter->last_fres = -1.; + else + { + static const fluid_real_t q_incr_count = FLUID_BUFSIZE; + iir_filter->q_incr = (q - iir_filter->last_q) / (q_incr_count); + iir_filter->q_incr_count = q_incr_count; + } +#ifdef DBG_FILTER + iir_filter->target_q = q; +#endif }
static FLUID_INLINE void fluid_iir_filter_calculate_coefficients(fluid_iir_filter_t *iir_filter, - int transition_samples, - fluid_real_t output_rate) + 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 */ - if(iir_filter->q_lin == 0) + // 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 @@ -246,7 +274,7 @@ fluid_iir_filter_calculate_coefficients(fluid_iir_filter_t *iir_filter, (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->q_lin); + 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 @@ -254,20 +282,35 @@ fluid_iir_filter_calculate_coefficients(fluid_iir_filter_t *iir_filter, * * 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*iir_filter->filter_gain; - * iir_filter->b1=(1.-cos_coeff)*a0_inv*iir_filter->filter_gain; - * iir_filter->b2=(1.-cos_coeff)*a0_inv*0.5*iir_filter->filter_gain; */ + * 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 * iir_filter->filter_gain; + b1_temp = (1.0f + cos_coeff) * a0_inv * filter_gain;
/* both b0 -and- b2 */ b02_temp = b1_temp * 0.5f; @@ -276,7 +319,7 @@ fluid_iir_filter_calculate_coefficients(fluid_iir_filter_t *iir_filter, break;
case FLUID_IIR_LOWPASS: - b1_temp = (1.0f - cos_coeff) * a0_inv * iir_filter->filter_gain; + b1_temp = (1.0f - cos_coeff) * a0_inv * filter_gain;
/* both b0 -and- b2 */ b02_temp = b1_temp * 0.5f; @@ -287,11 +330,10 @@ fluid_iir_filter_calculate_coefficients(fluid_iir_filter_t *iir_filter, return; }
- iir_filter->a1 = a1_temp; - iir_filter->a2 = a2_temp; - iir_filter->b02 = b02_temp; - iir_filter->b1 = b1_temp; - iir_filter->filter_startup = 0; + *a1_out = a1_temp; + *a2_out = a2_temp; + *b02_out = b02_temp; + *b1_out = b1_temp;
fluid_check_fpe("voice_write filter calculation"); } @@ -302,7 +344,13 @@ void fluid_iir_filter_calc(fluid_iir_filter_t *iir_filter, fluid_real_t output_rate, fluid_real_t fres_mod) { - fluid_real_t fres; + unsigned int calc_coeff_flag = FALSE; + fluid_real_t fres, fres_diff; + + if(iir_filter->type == FLUID_IIR_DISABLED) + { + return; + }
/* calculate the frequency of the resonant filter in Hz */ fres = fluid_ct2hz(iir_filter->fres + fres_mod); @@ -326,21 +374,47 @@ void fluid_iir_filter_calc(fluid_iir_filter_t *iir_filter, fres = 5.f; }
- // FLUID_LOG(FLUID_INFO, "%f + %f cents = %f cents = %f Hz | Q: %f", iir_filter->fres, fres_mod, iir_filter->fres + fres_mod, fres, iir_filter->q_lin); + LOG_FILTER("%f + %f = %f cents = %f Hz | Q: %f", iir_filter->fres, fres_mod, iir_filter->fres + fres_mod, fres, iir_filter->last_q); + /* if filter enabled and there is a significant frequency change.. */ - if(iir_filter->type != FLUID_IIR_DISABLED && FLUID_FABS(fres - iir_filter->last_fres) > 0.01f) + fres_diff = fres - iir_filter->last_fres; + if(iir_filter->filter_startup) { - /* The filter coefficients have to be recalculated (filter - * parameters have changed). Recalculation for various reasons is - * forced by setting last_fres to -1. The flag filter_startup - * indicates, that the DSP loop runs for the first time, in this - * case, the filter is set directly, instead of smoothly fading - * between old and new settings. */ + // The filer was just starting up, make sure to calculate initial coefficients for the initial Q value, even though the fres may not have changed + calc_coeff_flag = TRUE; + + iir_filter->fres_incr_count = 0; iir_filter->last_fres = fres; - fluid_iir_filter_calculate_coefficients(iir_filter, FLUID_BUFSIZE, - output_rate); + iir_filter->filter_startup = 0; + } + else if(FLUID_FABS(fres_diff) > 0.01f) + { + fluid_real_t fres_incr_count = FLUID_BUFSIZE; + fluid_real_t num_buffers = iir_filter->last_q; + fluid_clip(num_buffers, 1, 5); + // For high values of Q, the phase gets really steep. To prevent clicks when quickly modulating fres in this case, we need to smooth out "slower". + // This is done by simply using Q times FLUID_BUFSIZE samples for the interpolation to complete, capped at 5. + // 5 was chosen because the phase doesn't really get any steeper when continuing to increase Q. + fres_incr_count *= num_buffers; + iir_filter->fres_incr = fres_diff / (fres_incr_count); + iir_filter->fres_incr_count = fres_incr_count; +#ifdef DBG_FILTER + iir_filter->target_fres = fres; +#endif + + // The filter coefficients have to be recalculated (filter cutoff has changed). + calc_coeff_flag = TRUE; + } + else + { + // We do not account for any change of Q here - if it was changed q_incro_count will be non-zero and recalculating the coeffs + // will be taken care of in fluid_iir_filter_apply(). }
+ if(calc_coeff_flag) + { + fluid_iir_filter_calculate_coefficients(iir_filter, output_rate, &iir_filter->a1, &iir_filter->a2, &iir_filter->b02, &iir_filter->b1); + }
fluid_check_fpe("voice_write DSP coefficients");
diff --git a/libs/fluidsynth/src/rvoice/fluid_iir_filter.h b/libs/fluidsynth/src/rvoice/fluid_iir_filter.h index 422059c5ddc..d47bf2073f5 100644 --- a/libs/fluidsynth/src/rvoice/fluid_iir_filter.h +++ b/libs/fluidsynth/src/rvoice/fluid_iir_filter.h @@ -23,6 +23,14 @@
#include "fluidsynth_priv.h"
+// Uncomment to get debug logging for filter parameters +// #define DBG_FILTER +#ifdef DBG_FILTER +#define LOG_FILTER(...) FLUID_LOG(FLUID_DBG, __VA_ARGS__) +#else +#define LOG_FILTER(...) +#endif + typedef struct _fluid_iir_filter_t fluid_iir_filter_t;
DECLARE_FLUID_RVOICE_FUNCTION(fluid_iir_filter_init); @@ -30,7 +38,7 @@ 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 *dsp_buf, int dsp_buf_count, fluid_real_t output_rate);
void fluid_iir_filter_reset(fluid_iir_filter_t *iir_filter);
@@ -54,15 +62,20 @@ struct _fluid_iir_filter_t fluid_real_t a2; /* a1 / a0 */
fluid_real_t hist1, hist2; /* Sample history for the IIR filter */ - int filter_startup; /* Flag: If set, the filter will be set directly. - Else it changes smoothly. */ + int filter_startup; /* Flag: If set, the filter parameters will be set directly. Else it changes smoothly. */
- fluid_real_t fres; /* the resonance frequency, in cents (not absolute cents) */ - fluid_real_t last_fres; /* Current resonance frequency of the IIR filter */ - /* Serves as a flag: A deviation between fres and last_fres */ - /* indicates, that the filter has to be recalculated. */ - fluid_real_t q_lin; /* the q-factor on a linear scale */ - fluid_real_t filter_gain; /* Gain correction factor, depends on q */ + fluid_real_t fres; /* The desired resonance frequency, in absolute cents, this filter is currently set to */ + fluid_real_t last_fres; /* The filter's current (smoothed out) resonance frequency in Hz, which will converge towards its target fres once fres_incr_count has become zero */ + fluid_real_t fres_incr; /* The linear increment of fres each sample */ + int fres_incr_count; /* The number of samples left for the smoothed last_fres adjustment to complete */ + + fluid_real_t last_q; /* The filter's current (smoothed) Q-factor (or "bandwidth", or "resonance-friendlyness") on a linear scale. Just like fres, this will converge towards its target Q once q_incr_count has become zero. */ + fluid_real_t q_incr; /* The linear increment of q each sample */ + int q_incr_count; /* The number of samples left for the smoothed Q adjustment to complete */ +#ifdef DBG_FILTER + fluid_real_t target_fres; /* The filter's target fres, that last_fres should converge towards - for debugging only */ + fluid_real_t target_q; /* The filter's target Q - for debugging only */ +#endif };
#endif diff --git a/libs/fluidsynth/src/rvoice/fluid_rvoice.c b/libs/fluidsynth/src/rvoice/fluid_rvoice.c index 3db52b60fb7..e07896fea01 100644 --- a/libs/fluidsynth/src/rvoice/fluid_rvoice.c +++ b/libs/fluidsynth/src/rvoice/fluid_rvoice.c @@ -435,6 +435,22 @@ fluid_rvoice_write(fluid_rvoice_t *voice, fluid_real_t *dsp_buf) || (voice->dsp.samplemode == FLUID_LOOP_UNTIL_RELEASE && fluid_adsr_env_get_section(&voice->envlfo.volenv) < FLUID_VOICE_ENVRELEASE);
+ /*************** resonant filter ******************/ + // Only "prepare" the filter here, the filter itself will be applied in the dsp_interpolation routines below. + // This is to satisfy SF2 Section 9.1.8, particularly, the filtered output must be gain-adjusted by the volEnv. + // Applying the filter after applying the gain from the volEnv might cause audible clicks for when turning off + // voices that are filtered by a high Q, see https://github.com/FluidSynth/fluidsynth/issues/1427 + // + // Note that at this point we are using voice->dsp.output_rate which is set to the synth's output rate, because + // the filter will receive the interpolated waveform. + + fluid_iir_filter_calc(&voice->resonant_filter, voice->dsp.output_rate, + fluid_lfo_get_val(&voice->envlfo.modlfo) * voice->envlfo.modlfo_to_fc + + modenv_val * voice->envlfo.modenv_to_fc); + + /* additional custom filter - only uses the fixed modulator, no lfos... */ + fluid_iir_filter_calc(&voice->resonant_custom_filter, voice->dsp.output_rate, 0); + /*********************** run the dsp chain ************************ * The sample is mixed with the output buffer. * The buffer has to be filled from 0 to FLUID_BUFSIZE-1. @@ -449,28 +465,26 @@ 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. - // - // Also note, that we're returning directly without running the IIR filter below. - return fluid_rvoice_dsp_interpolate_none(&voice->dsp, dsp_buf, is_looping); + return fluid_rvoice_dsp_interpolate_none(voice, dsp_buf, is_looping); }
switch(voice->dsp.interp_method) { case FLUID_INTERP_NONE: - count = fluid_rvoice_dsp_interpolate_none(&voice->dsp, dsp_buf, is_looping); + count = fluid_rvoice_dsp_interpolate_none(voice, dsp_buf, is_looping); break;
case FLUID_INTERP_LINEAR: - count = fluid_rvoice_dsp_interpolate_linear(&voice->dsp, dsp_buf, is_looping); + count = fluid_rvoice_dsp_interpolate_linear(voice, dsp_buf, is_looping); break;
case FLUID_INTERP_4THORDER: default: - count = fluid_rvoice_dsp_interpolate_4th_order(&voice->dsp, dsp_buf, is_looping); + count = fluid_rvoice_dsp_interpolate_4th_order(voice, dsp_buf, is_looping); break;
case FLUID_INTERP_7THORDER: - count = fluid_rvoice_dsp_interpolate_7th_order(&voice->dsp, dsp_buf, is_looping); + count = fluid_rvoice_dsp_interpolate_7th_order(voice, dsp_buf, is_looping); break; }
@@ -482,18 +496,6 @@ fluid_rvoice_write(fluid_rvoice_t *voice, fluid_real_t *dsp_buf) return count; }
- /*************** resonant filter ******************/ - - fluid_iir_filter_calc(&voice->resonant_filter, voice->dsp.output_rate, - fluid_lfo_get_val(&voice->envlfo.modlfo) * voice->envlfo.modlfo_to_fc + - modenv_val * voice->envlfo.modenv_to_fc); - - fluid_iir_filter_apply(&voice->resonant_filter, dsp_buf, count); - - /* additional custom filter - only uses the fixed modulator, no lfos... */ - fluid_iir_filter_calc(&voice->resonant_custom_filter, voice->dsp.output_rate, 0); - fluid_iir_filter_apply(&voice->resonant_custom_filter, dsp_buf, count); - return count; }
diff --git a/libs/fluidsynth/src/rvoice/fluid_rvoice.h b/libs/fluidsynth/src/rvoice/fluid_rvoice.h index 229e8833780..9c8788decc7 100644 --- a/libs/fluidsynth/src/rvoice/fluid_rvoice.h +++ b/libs/fluidsynth/src/rvoice/fluid_rvoice.h @@ -200,10 +200,10 @@ DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_set_sample);
/* defined in fluid_rvoice_dsp.c */ void fluid_rvoice_dsp_config(void); -int fluid_rvoice_dsp_interpolate_none(fluid_rvoice_dsp_t *voice, fluid_real_t *FLUID_RESTRICT dsp_buf, int is_looping); -int fluid_rvoice_dsp_interpolate_linear(fluid_rvoice_dsp_t *voice, fluid_real_t *FLUID_RESTRICT dsp_buf, int is_looping); -int fluid_rvoice_dsp_interpolate_4th_order(fluid_rvoice_dsp_t *voice, fluid_real_t *FLUID_RESTRICT dsp_buf, int is_looping); -int fluid_rvoice_dsp_interpolate_7th_order(fluid_rvoice_dsp_t *voice, fluid_real_t *FLUID_RESTRICT dsp_buf, int is_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); +int fluid_rvoice_dsp_interpolate_7th_order(fluid_rvoice_t *voice, fluid_real_t *FLUID_RESTRICT dsp_buf, int is_looping);
/* diff --git a/libs/fluidsynth/src/rvoice/fluid_rvoice_dsp.c b/libs/fluidsynth/src/rvoice/fluid_rvoice_dsp.c index b43a0f19077..210ed93dfdc 100644 --- a/libs/fluidsynth/src/rvoice/fluid_rvoice_dsp.c +++ b/libs/fluidsynth/src/rvoice/fluid_rvoice_dsp.c @@ -58,8 +58,9 @@ fluid_rvoice_get_float_sample(const short int *dsp_msb, const char *dsp_lsb, uns * the playback pointer. Questionable quality, but very * efficient. */ int -fluid_rvoice_dsp_interpolate_none(fluid_rvoice_dsp_t *voice, fluid_real_t *FLUID_RESTRICT dsp_buf, int looping) +fluid_rvoice_dsp_interpolate_none(fluid_rvoice_t *rvoice, fluid_real_t *FLUID_RESTRICT dsp_buf, int looping) { + 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; @@ -82,7 +83,12 @@ fluid_rvoice_dsp_interpolate_none(fluid_rvoice_dsp_t *voice, fluid_real_t *FLUID /* interpolate sequence of sample points */ for(; dsp_i < FLUID_BUFSIZE && dsp_phase_index <= end_index; dsp_i++) { - dsp_buf[dsp_i] = dsp_amp * fluid_rvoice_get_float_sample(dsp_data, dsp_data24, dsp_phase_index); + fluid_real_t sample = fluid_rvoice_get_float_sample(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); + + dsp_buf[dsp_i] = dsp_amp * sample;
/* increment phase and amplitude */ fluid_phase_incr(dsp_phase, dsp_phase_incr); @@ -121,8 +127,9 @@ fluid_rvoice_dsp_interpolate_none(fluid_rvoice_dsp_t *voice, fluid_real_t *FLUID * smaller if end of sample occurs). */ int -fluid_rvoice_dsp_interpolate_linear(fluid_rvoice_dsp_t *voice, fluid_real_t *FLUID_RESTRICT dsp_buf, int looping) +fluid_rvoice_dsp_interpolate_linear(fluid_rvoice_t *rvoice, fluid_real_t *FLUID_RESTRICT dsp_buf, int looping) { + 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; @@ -158,9 +165,16 @@ fluid_rvoice_dsp_interpolate_linear(fluid_rvoice_dsp_t *voice, fluid_real_t *FLU /* interpolate the sequence of sample points */ for(; dsp_i < FLUID_BUFSIZE && dsp_phase_index <= end_index; dsp_i++) { + fluid_real_t sample; coeffs = interp_coeff_linear[fluid_phase_fract_to_tablerow(dsp_phase)]; - dsp_buf[dsp_i] = dsp_amp * (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(dsp_data, dsp_data24, dsp_phase_index) + + coeffs[1] * fluid_rvoice_get_float_sample(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); + + dsp_buf[dsp_i] = dsp_amp * sample;
/* increment phase and amplitude */ fluid_phase_incr(dsp_phase, dsp_phase_incr); @@ -179,9 +193,16 @@ fluid_rvoice_dsp_interpolate_linear(fluid_rvoice_dsp_t *voice, fluid_real_t *FLU /* interpolate within last point */ for(; dsp_phase_index <= end_index && dsp_i < FLUID_BUFSIZE; dsp_i++) { + fluid_real_t sample; coeffs = interp_coeff_linear[fluid_phase_fract_to_tablerow(dsp_phase)]; - dsp_buf[dsp_i] = dsp_amp * (coeffs[0] * fluid_rvoice_get_float_sample(dsp_data, dsp_data24, dsp_phase_index) - + coeffs[1] * point); + + sample = (coeffs[0] * fluid_rvoice_get_float_sample(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); + + dsp_buf[dsp_i] = dsp_amp * sample;
/* increment phase and amplitude */ fluid_phase_incr(dsp_phase, dsp_phase_incr); @@ -221,8 +242,9 @@ fluid_rvoice_dsp_interpolate_linear(fluid_rvoice_dsp_t *voice, fluid_real_t *FLU * smaller if end of sample occurs). */ int -fluid_rvoice_dsp_interpolate_4th_order(fluid_rvoice_dsp_t *voice, fluid_real_t *FLUID_RESTRICT dsp_buf, int looping) +fluid_rvoice_dsp_interpolate_4th_order(fluid_rvoice_t *rvoice, fluid_real_t *FLUID_RESTRICT dsp_buf, int looping) { + 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; @@ -271,12 +293,18 @@ fluid_rvoice_dsp_interpolate_4th_order(fluid_rvoice_dsp_t *voice, fluid_real_t * /* interpolate first sample point (start or loop start) if needed */ for(; dsp_phase_index == start_index && dsp_i < FLUID_BUFSIZE; dsp_i++) { + fluid_real_t sample; coeffs = interp_coeff[fluid_phase_fract_to_tablerow(dsp_phase)]; - dsp_buf[dsp_i] = dsp_amp * - (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)); + + 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)); + + 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); + + dsp_buf[dsp_i] = dsp_amp * sample;
/* increment phase and amplitude */ fluid_phase_incr(dsp_phase, dsp_phase_incr); @@ -287,12 +315,18 @@ fluid_rvoice_dsp_interpolate_4th_order(fluid_rvoice_dsp_t *voice, fluid_real_t * /* interpolate the sequence of sample points */ for(; dsp_i < FLUID_BUFSIZE && dsp_phase_index <= end_index; dsp_i++) { + fluid_real_t sample; coeffs = interp_coeff[fluid_phase_fract_to_tablerow(dsp_phase)]; - dsp_buf[dsp_i] = dsp_amp * - (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(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)); + + 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); + + dsp_buf[dsp_i] = dsp_amp * sample;
/* increment phase and amplitude */ fluid_phase_incr(dsp_phase, dsp_phase_incr); @@ -311,12 +345,18 @@ fluid_rvoice_dsp_interpolate_4th_order(fluid_rvoice_dsp_t *voice, fluid_real_t * /* interpolate within 2nd to last point */ for(; dsp_phase_index <= end_index && dsp_i < FLUID_BUFSIZE; dsp_i++) { + fluid_real_t sample; coeffs = interp_coeff[fluid_phase_fract_to_tablerow(dsp_phase)]; - dsp_buf[dsp_i] = dsp_amp * - (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] * end_point1); + + 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] * 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); + + dsp_buf[dsp_i] = dsp_amp * sample;
/* increment phase and amplitude */ fluid_phase_incr(dsp_phase, dsp_phase_incr); @@ -329,12 +369,19 @@ fluid_rvoice_dsp_interpolate_4th_order(fluid_rvoice_dsp_t *voice, fluid_real_t * /* interpolate within the last point */ for(; dsp_phase_index <= end_index && dsp_i < FLUID_BUFSIZE; dsp_i++) { + fluid_real_t sample; coeffs = interp_coeff[fluid_phase_fract_to_tablerow(dsp_phase)]; - dsp_buf[dsp_i] = dsp_amp * - (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] * end_point1 - + coeffs[3] * end_point2); + + + 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] * 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); + + dsp_buf[dsp_i] = dsp_amp * sample;
/* increment phase and amplitude */ fluid_phase_incr(dsp_phase, dsp_phase_incr); @@ -380,8 +427,9 @@ fluid_rvoice_dsp_interpolate_4th_order(fluid_rvoice_dsp_t *voice, fluid_real_t * * smaller if end of sample occurs). */ int -fluid_rvoice_dsp_interpolate_7th_order(fluid_rvoice_dsp_t *voice, fluid_real_t *FLUID_RESTRICT dsp_buf, int looping) +fluid_rvoice_dsp_interpolate_7th_order(fluid_rvoice_t *rvoice, fluid_real_t *FLUID_RESTRICT dsp_buf, int looping) { + 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; @@ -440,16 +488,21 @@ fluid_rvoice_dsp_interpolate_7th_order(fluid_rvoice_dsp_t *voice, fluid_real_t * /* interpolate first sample point (start or loop start) if needed */ for(; dsp_phase_index == start_index && dsp_i < FLUID_BUFSIZE; dsp_i++) { + fluid_real_t sample; coeffs = sinc_table7[fluid_phase_fract_to_tablerow(dsp_phase)];
- dsp_buf[dsp_i] = dsp_amp - * (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)); + 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)); + + 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); + + dsp_buf[dsp_i] = dsp_amp * sample;
/* increment phase and amplitude */ fluid_phase_incr(dsp_phase, dsp_phase_incr); @@ -462,16 +515,21 @@ fluid_rvoice_dsp_interpolate_7th_order(fluid_rvoice_dsp_t *voice, fluid_real_t * /* interpolate 2nd to first sample point (start or loop start) if needed */ for(; dsp_phase_index == start_index && dsp_i < FLUID_BUFSIZE; dsp_i++) { + fluid_real_t sample; coeffs = sinc_table7[fluid_phase_fract_to_tablerow(dsp_phase)];
- dsp_buf[dsp_i] = dsp_amp - * (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)); + 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)); + + 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); + + dsp_buf[dsp_i] = dsp_amp * sample;
/* increment phase and amplitude */ fluid_phase_incr(dsp_phase, dsp_phase_incr); @@ -484,16 +542,21 @@ fluid_rvoice_dsp_interpolate_7th_order(fluid_rvoice_dsp_t *voice, fluid_real_t * /* interpolate 3rd to first sample point (start or loop start) if needed */ for(; dsp_phase_index == start_index && dsp_i < FLUID_BUFSIZE; dsp_i++) { + fluid_real_t sample; coeffs = sinc_table7[fluid_phase_fract_to_tablerow(dsp_phase)];
- dsp_buf[dsp_i] = dsp_amp - * (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)); + 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)); + + 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); + + dsp_buf[dsp_i] = dsp_amp * sample;
/* increment phase and amplitude */ fluid_phase_incr(dsp_phase, dsp_phase_incr); @@ -507,16 +570,21 @@ fluid_rvoice_dsp_interpolate_7th_order(fluid_rvoice_dsp_t *voice, fluid_real_t * /* interpolate the sequence of sample points */ for(; dsp_i < FLUID_BUFSIZE && dsp_phase_index <= end_index; dsp_i++) { + fluid_real_t sample; coeffs = sinc_table7[fluid_phase_fract_to_tablerow(dsp_phase)];
- dsp_buf[dsp_i] = dsp_amp - * (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(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)); + + 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); + + dsp_buf[dsp_i] = dsp_amp * sample;
/* increment phase and amplitude */ fluid_phase_incr(dsp_phase, dsp_phase_incr); @@ -535,16 +603,21 @@ fluid_rvoice_dsp_interpolate_7th_order(fluid_rvoice_dsp_t *voice, fluid_real_t * /* interpolate within 3rd to last point */ for(; dsp_phase_index <= end_index && dsp_i < FLUID_BUFSIZE; dsp_i++) { + fluid_real_t sample; coeffs = sinc_table7[fluid_phase_fract_to_tablerow(dsp_phase)];
- dsp_buf[dsp_i] = dsp_amp - * (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] * end_points[0]); + 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] * 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); + + dsp_buf[dsp_i] = dsp_amp * sample;
/* increment phase and amplitude */ fluid_phase_incr(dsp_phase, dsp_phase_incr); @@ -557,16 +630,21 @@ fluid_rvoice_dsp_interpolate_7th_order(fluid_rvoice_dsp_t *voice, fluid_real_t * /* interpolate within 2nd to last point */ for(; dsp_phase_index <= end_index && dsp_i < FLUID_BUFSIZE; dsp_i++) { + fluid_real_t sample; coeffs = sinc_table7[fluid_phase_fract_to_tablerow(dsp_phase)];
- dsp_buf[dsp_i] = dsp_amp - * (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] * end_points[0] - + coeffs[6] * end_points[1]); + 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] * 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); + + dsp_buf[dsp_i] = dsp_amp * sample;
/* increment phase and amplitude */ fluid_phase_incr(dsp_phase, dsp_phase_incr); @@ -579,16 +657,21 @@ fluid_rvoice_dsp_interpolate_7th_order(fluid_rvoice_dsp_t *voice, fluid_real_t * /* interpolate within last point */ for(; dsp_phase_index <= end_index && dsp_i < FLUID_BUFSIZE; dsp_i++) { + fluid_real_t sample; coeffs = sinc_table7[fluid_phase_fract_to_tablerow(dsp_phase)];
- dsp_buf[dsp_i] = dsp_amp - * (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] * end_points[0] - + coeffs[5] * end_points[1] - + coeffs[6] * end_points[2]); + 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] * 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); + + dsp_buf[dsp_i] = dsp_amp * sample;
/* increment phase and amplitude */ fluid_phase_incr(dsp_phase, dsp_phase_incr); diff --git a/libs/fluidsynth/src/sfloader/fluid_sffile.c b/libs/fluidsynth/src/sfloader/fluid_sffile.c index 83594246dfd..21535c91c6b 100644 --- a/libs/fluidsynth/src/sfloader/fluid_sffile.c +++ b/libs/fluidsynth/src/sfloader/fluid_sffile.c @@ -669,6 +669,7 @@ static int process_info(SFData *sf, int size) sf->version.major = ver; READW(sf, ver); sf->version.minor = ver; + FLUID_LOG(FLUID_DBG, "SF Version: %hu.%hu", sf->version.major, sf->version.minor);
if(sf->version.major < 2) { @@ -710,6 +711,7 @@ static int process_info(SFData *sf, int size) sf->romver.major = ver; READW(sf, ver); sf->romver.minor = ver; + FLUID_LOG(FLUID_DBG, "ROM Version: %hu.%hu", sf->version.major, sf->version.minor); } else if(chunkid(chunk.id) != UNKN_ID) { @@ -2219,21 +2221,23 @@ static int fluid_sffile_read_wav(SFData *sf, unsigned int start, unsigned int en goto error_exit; }
+ fluid_rec_mutex_lock(sf->mtx); + /* Load 16-bit sample data */ if(sf->fcbs->fseek(sf->sffd, sf->samplepos + (start * sizeof(short)), SEEK_SET) == FLUID_FAILED) { FLUID_LOG(FLUID_ERR, "Failed to seek to sample position"); - goto error_exit; + goto error_exit_unlock; }
loaded_data = FLUID_ARRAY(short, num_samples); - if(loaded_data == NULL) { FLUID_LOG(FLUID_ERR, "Out of memory"); - goto error_exit; + goto error_exit_unlock; }
+ FLUID_LOG(FLUID_DBG, "ftell(): %llu, fread(): %ld bytes", sf->fcbs->ftell(sf->sffd), num_samples*sizeof(short)); if(sf->fcbs->fread(loaded_data, num_samples * sizeof(short), sf->sffd) == FLUID_FAILED) { #if FLUID_VERSION_CHECK(FLUIDSYNTH_VERSION_MAJOR, FLUIDSYNTH_VERSION_MINOR, FLUIDSYNTH_VERSION_MICRO) < FLUID_VERSION_CHECK(2,2,0) @@ -2245,9 +2249,11 @@ static int fluid_sffile_read_wav(SFData *sf, unsigned int start, unsigned int en } #endif FLUID_LOG(FLUID_ERR, "Failed to read sample data"); - goto error_exit; + goto error_exit_unlock; }
+ fluid_rec_mutex_unlock(sf->mtx); + /* If this machine is big endian, byte swap the 16 bit samples */ if(FLUID_IS_BIG_ENDIAN) { @@ -2272,37 +2278,44 @@ static int fluid_sffile_read_wav(SFData *sf, unsigned int start, unsigned int en goto error24_exit; }
- if(sf->fcbs->fseek(sf->sffd, sf->sample24pos + start, SEEK_SET) == FLUID_FAILED) + loaded_data24 = FLUID_ARRAY(char, num_samples); + if(loaded_data24 == NULL) { - FLUID_LOG(FLUID_ERR, "Failed to seek position for 24-bit sample data in data file"); + FLUID_LOG(FLUID_ERR, "Out of memory reading 24-bit sample data"); goto error24_exit; }
- loaded_data24 = FLUID_ARRAY(char, num_samples); + fluid_rec_mutex_lock(sf->mtx);
- if(loaded_data24 == NULL) + if(sf->fcbs->fseek(sf->sffd, sf->sample24pos + start, SEEK_SET) == FLUID_FAILED) { - FLUID_LOG(FLUID_ERR, "Out of memory reading 24-bit sample data"); - goto error24_exit; + FLUID_LOG(FLUID_ERR, "Failed to seek position for 24-bit sample data in data file"); + goto error24_exit_unlock; }
if(sf->fcbs->fread(loaded_data24, num_samples, sf->sffd) == FLUID_FAILED) { FLUID_LOG(FLUID_ERR, "Failed to read 24-bit sample data"); - goto error24_exit; + goto error24_exit_unlock; } + + fluid_rec_mutex_unlock(sf->mtx); }
*data24 = loaded_data24;
return num_samples;
+error24_exit_unlock: + fluid_rec_mutex_unlock(sf->mtx); error24_exit: FLUID_LOG(FLUID_WARN, "Ignoring 24-bit sample data, sound quality might suffer"); FLUID_FREE(loaded_data24); *data24 = NULL; return num_samples;
+error_exit_unlock: + fluid_rec_mutex_unlock(sf->mtx); error_exit: FLUID_FREE(loaded_data); FLUID_FREE(loaded_data24); diff --git a/libs/fluidsynth/src/synth/fluid_synth.c b/libs/fluidsynth/src/synth/fluid_synth.c index 545a4e08cd4..c0b3b3293a1 100644 --- a/libs/fluidsynth/src/synth/fluid_synth.c +++ b/libs/fluidsynth/src/synth/fluid_synth.c @@ -1736,7 +1736,7 @@ fluid_synth_cc_LOCAL(fluid_synth_t *synth, int channum, int num) basic channel minus 1 (if any) or to MIDI channel count minus 1. However, if value is > 0 (e.g. 4), the group of channels will be be limited to 4. - value is ignored for #FLUID_CHANNEL_MODE_OMNIOFF_POLY as this mode + value is ignored for #FLUID_CHANNEL_MODE_OMNIOFF_POLY as this mode implies a group of only one channel. */ /* Checks value range and changes this existing basic channel group */ @@ -1747,9 +1747,15 @@ fluid_synth_cc_LOCAL(fluid_synth_t *synth, int channum, int num) /* reset the current basic channel before changing it */ fluid_synth_reset_basic_channel_LOCAL(synth, channum, chan->mode_val); fluid_synth_set_basic_channel_LOCAL(synth, channum, new_mode, value); + FLUID_LOG(FLUID_INFO, "Successfully configured channel group, from channel %d up to including chan %d to mode 0x%X", channum, channum + value, new_mode); break; /* FLUID_OK */ } } + else + { + static const char* poly_mono_str[] = {"OMNI_OFF","OMNI_ON","POLY_OFF","POLY_ON"}; + FLUID_LOG(FLUID_WARN, "Failed to set channel %d to %s: Operation illegal, because channel is currently no basic channel.", channum, poly_mono_str[num - OMNI_OFF]); + }
return FLUID_FAILED;
@@ -2130,7 +2136,7 @@ fluid_synth_sysex_midi_tuning(fluid_synth_t *synth, const char *data, int len, uint8_t chksum; int i, count, index; const char *dataptr; - char *resptr; + char *resptr;;
realtime = data[0] == MIDI_SYSEX_UNIV_REALTIME; msgid = data[3]; @@ -7711,7 +7717,7 @@ static void fluid_synth_process_awe32_nrpn_LOCAL(fluid_synth_t *synth, int chan, };
enum fluid_gen_type sf2_gen = awe32_to_sf2_gen[gen]; - int is_realtime = FALSE, i, coef; + int is_realtime = FALSE, i; fluid_real_t converted_sf2_generator_value, q;
// The AWE32 NRPN docs say that a value of 8192 is considered to be the middle, i.e. zero. @@ -7786,7 +7792,7 @@ static void fluid_synth_process_awe32_nrpn_LOCAL(fluid_synth_t *synth, int chan,
case GEN_FILTERFC: fluid_clip(data_lsb, 0, 127); - // Yes, DO NOT use data here, Uplift.mid doesn't set MSB=64, therefore we would always get a negative value after subtracting 8192. + // Yes, DO NOT use data here, Uplift.mid doesn't set DATA_MSB=64, therefore we would always get a negative value after subtracting 8192. // Since Uplift.mid sounds fine on hardware though, it seems like AWE32 only inspects DATA_LSB in this case. // conversion continues below! converted_sf2_generator_value = (data_lsb * 62 /* Hz */); @@ -7799,20 +7805,25 @@ static void fluid_synth_process_awe32_nrpn_LOCAL(fluid_synth_t *synth, int chan, synth->channel[chan]->awe32_filter_coeff = data_lsb; return;
+ // Note: The description in the official "SB AWE32 Developer's Information Pack" is probably wrong. + // There it says: "Positive data value causes a positive phase (from 0 to maximum) filter modulation + // [...] negative data value causes a negative phase [...]" + // That doesn't make sense. A filter is a causual system - you cannot change its phase independently + // of the rest. The text a few section above has it correct, there they speak of the filter's + // cutoff frequency. In that sense, this is probably intended to behave similar to the logic in SF2. + // PS: Same applies to the GEN_MODENVTOFILTERFC below! case GEN_MODLFOTOFILTERFC: fluid_clip(data, -64, 63); converted_sf2_generator_value = data * (fluid_real_t)56.25 /* cents */; FLUID_LOG(FLUID_DBG, "AWE32 MOD LFO TO FILTER Fc: %f cents", converted_sf2_generator_value); is_realtime = TRUE; - // not supported, as this modulates the "phase" rather than the filters cutoff frequency - return; + break;
case GEN_MODENVTOFILTERFC: fluid_clip(data, -127, 127); converted_sf2_generator_value = data * (fluid_real_t)56.25 /* cents */; FLUID_LOG(FLUID_DBG, "AWE32 MOD ENV TO FILTER Fc: %f cents", converted_sf2_generator_value); - // not supported, as this modulates the "phase" rather than the filters cutoff frequency - return; + break;
case GEN_REVERBSEND: fluid_clip(data, 0, 255); @@ -7836,9 +7847,9 @@ static void fluid_synth_process_awe32_nrpn_LOCAL(fluid_synth_t *synth, int chan, return; }
- coef = synth->channel[chan]->awe32_filter_coeff; if(sf2_gen == GEN_FILTERFC) { + int coef = synth->channel[chan]->awe32_filter_coeff; // The cutoff at fc seems to be very steep for SoundBlaster! hardware. Listening tests have shown that lowering the cutoff frequency by 1000Hz gives a closer signal to the SB! hardware filter... converted_sf2_generator_value -= 1000; q = calc_awe32_filter_q(coef, &converted_sf2_generator_value); diff --git a/libs/fluidsynth/src/synth/fluid_synth.h b/libs/fluidsynth/src/synth/fluid_synth.h index 48ab8ac43d2..7dbcdc556a8 100644 --- a/libs/fluidsynth/src/synth/fluid_synth.h +++ b/libs/fluidsynth/src/synth/fluid_synth.h @@ -120,7 +120,7 @@ struct _fluid_synth_t int effects_channels; /**< the number of effects channels (>= 2) */ int effects_groups; /**< the number of effects units (>= 1) */ int state; /**< the synthesizer state */ - fluid_atomic_int_t ticks_since_start; /**< the number of audio samples since the start */ + fluid_atomic_uint_t ticks_since_start; /**< the number of audio samples since the start */ unsigned int start; /**< the start in msec, as returned by system clock */ fluid_overflow_prio_t overflow; /**< parameters for overflow priority (aka voice-stealing) */
diff --git a/libs/fluidsynth/src/synth/fluid_voice.c b/libs/fluidsynth/src/synth/fluid_voice.c index ca0bad05e9c..aadfc097895 100644 --- a/libs/fluidsynth/src/synth/fluid_voice.c +++ b/libs/fluidsynth/src/synth/fluid_voice.c @@ -859,11 +859,6 @@ fluid_voice_update_param(fluid_voice_t *voice, int gen) break;
case GEN_FILTERFC: - /* The resonance frequency is converted from absolute cents to - * midicents .val and .mod are both used, this permits real-time - * modulation. The allowed range is tested in the 'fluid_ct2hz' - * function [PH,20021214] - */ UPDATE_RVOICE_GENERIC_R1(fluid_iir_filter_set_fres, &voice->rvoice->resonant_filter, x); break;
diff --git a/libs/fluidsynth/src/utils/fluid_sys.c b/libs/fluidsynth/src/utils/fluid_sys.c index 8fc14cd5f5e..0964cb93d57 100644 --- a/libs/fluidsynth/src/utils/fluid_sys.c +++ b/libs/fluidsynth/src/utils/fluid_sys.c @@ -1660,7 +1660,7 @@ new_fluid_server_socket(int port, fluid_server_func_t func, void *data) return NULL; }
- if(bind(sock, addr, addr_size) == SOCKET_ERROR) + if(bind(sock, addr, (int) addr_size) == SOCKET_ERROR) { FLUID_LOG(FLUID_ERR, "Failed to bind server socket: %d", fluid_socket_get_error()); fluid_socket_close(sock); @@ -1787,9 +1787,16 @@ fluid_long_long_t fluid_file_tell(FILE* f)
#if defined(_WIN32) || defined(__CYGWIN__) // not thread-safe! +#define FLUID_WINDOWS_MEX_ERROR_LEN 1024 + char* fluid_get_windows_error(void) { - static TCHAR err[1024]; +#ifdef _UNICODE + TCHAR err[FLUID_WINDOWS_MEX_ERROR_LEN]; + static char ascii_err[FLUID_WINDOWS_MEX_ERROR_LEN]; +#else + static TCHAR err[FLUID_WINDOWS_MEX_ERROR_LEN]; +#endif
FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, @@ -1800,8 +1807,6 @@ char* fluid_get_windows_error(void) NULL);
#ifdef _UNICODE - static char ascii_err[sizeof(err)]; - WideCharToMultiByte(CP_UTF8, 0, err, -1, ascii_err, sizeof(ascii_err)/sizeof(ascii_err[0]), 0, 0); return ascii_err; #else diff --git a/libs/fluidsynth/src/utils/fluid_sys.h b/libs/fluidsynth/src/utils/fluid_sys.h index 15f3f57b756..79aeef0fb90 100644 --- a/libs/fluidsynth/src/utils/fluid_sys.h +++ b/libs/fluidsynth/src/utils/fluid_sys.h @@ -156,6 +156,13 @@ typedef gintptr intptr_t; #pragma warning(disable : 4996) #endif
+/* + * Required by Windows-specific sf_wchar_open() from old libsndfile + * versions before v1.1.0, that takes a UTF16_BE encoded filename. + * Note that FluidSynth needs libsndfile >= v1.2.1 anyway. + */ +#define ENABLE_SNDFILE_WINDOWS_PROTOTYPES 1 + #endif
/* Darwin special defines (taken from config_macosx.h) */