mirror of
https://github.com/ZDoom/fluidsynth.git
synced 2025-02-21 19:31:40 +00:00
Cleanup initial attenuation generator value handling (#324)
The EMU8k/10k hardware applies a 0.4 factor to all initially set attenuation generator values. Do this once on soundfont load. Remove the invalid -531.509 power factor that was computed from Timidiy's non-standard conversion table. And remove the synth.volenv switch again, as the "compliant" setting wasn't compliant at all. This allows us to get rid of the atten2amp function and use cb2amp everywhere, with a range of 0 1440 centibels. Fixes #70 Supersedes #71 Supersedes #318
This commit is contained in:
parent
8c6d328cab
commit
aff8f0d458
8 changed files with 25 additions and 88 deletions
|
@ -258,15 +258,6 @@ https://stackoverflow.com/a/6251757
|
|||
When set to 1 (TRUE) the synthesizer will print out information about the received MIDI events to the stdout. This can be helpful for debugging. This setting cannot be changed after the synthesizer has started.
|
||||
</desc>
|
||||
</setting>
|
||||
<setting>
|
||||
<name>volenv</name>
|
||||
<type>str</type>
|
||||
<def>emu</def>
|
||||
<vals>compliant, emu</vals>
|
||||
<desc>
|
||||
Specifies the kind of volume envelope processing. This esp. influences the way fluidsynth responses to noteon velocity. The default setting 'emu' causes the envelope to be highly dynamic (i.e. compatible with the EMU10K1). Alternatively this may be set to 'compliant' for a less dynamic envelope, as it was done before fluidsynth 1.0.9. Note that this setting can only be changed until the first synth has been created. Changing it afterwards will have no effect for the rest of fluidsynths lifetime.
|
||||
</desc>
|
||||
</setting>
|
||||
</synth>
|
||||
|
||||
|
||||
|
|
|
@ -103,7 +103,6 @@ Changes in FluidSynth 2.0.0 concerning developers:
|
|||
- use unique device names for the "audio.portaudio.device" setting
|
||||
- rename fluid_mod_new() and fluid_mod_delete() to match naming conventions: new_fluid_mod() and delete_fluid_mod()
|
||||
<br /><br />
|
||||
- add <a href="fluidsettings.xml#synth.volenv">"synth.volenv"</a> a setting for volume envelope processing
|
||||
- add <a href="fluidsettings.xml#midi.autoconnect">"midi.autoconnect"</a> a setting for automatically connecting fluidsynth to available MIDI input ports
|
||||
- add <a href="fluidsettings.xml#synth.overflow.important">"synth.overflow.important"</a> and <a href="fluidsettings.xml#synth.overflow.important-channels">"synth.overflow.important-channels"</a> settings to take midi channels during overflow calculation into account that are considered to be "important"
|
||||
- add support for polyphonic key pressure events, see fluid_event_key_pressure() and fluid_synth_key_pressure()
|
||||
|
|
|
@ -38,7 +38,7 @@ fluid_rvoice_calc_amp(fluid_rvoice_t* voice)
|
|||
/* the envelope is in the attack section: ramp linearly to max value.
|
||||
* A positive modlfo_to_vol should increase volume (negative attenuation).
|
||||
*/
|
||||
target_amp = fluid_atten2amp (voice->dsp.attenuation)
|
||||
target_amp = fluid_cb2amp (voice->dsp.attenuation)
|
||||
* fluid_cb2amp (fluid_lfo_get_val(&voice->envlfo.modlfo) * -voice->envlfo.modlfo_to_vol)
|
||||
* fluid_adsr_env_get_val(&voice->envlfo.volenv);
|
||||
}
|
||||
|
@ -47,7 +47,7 @@ fluid_rvoice_calc_amp(fluid_rvoice_t* voice)
|
|||
fluid_real_t amplitude_that_reaches_noise_floor;
|
||||
fluid_real_t amp_max;
|
||||
|
||||
target_amp = fluid_atten2amp (voice->dsp.attenuation)
|
||||
target_amp = fluid_cb2amp (voice->dsp.attenuation)
|
||||
* fluid_cb2amp (960.0f * (1.0f - fluid_adsr_env_get_val(&voice->envlfo.volenv))
|
||||
+ fluid_lfo_get_val(&voice->envlfo.modlfo) * -voice->envlfo.modlfo_to_vol);
|
||||
|
||||
|
@ -74,7 +74,7 @@ fluid_rvoice_calc_amp(fluid_rvoice_t* voice)
|
|||
* volenv_val can only drop):
|
||||
*/
|
||||
|
||||
amp_max = fluid_atten2amp (voice->dsp.min_attenuation_cB) *
|
||||
amp_max = fluid_cb2amp (voice->dsp.min_attenuation_cB) *
|
||||
fluid_adsr_env_get_val(&voice->envlfo.volenv);
|
||||
|
||||
/* And if amp_max is already smaller than the known amplitude,
|
||||
|
|
|
@ -30,6 +30,13 @@
|
|||
#include <sndfile.h>
|
||||
#endif
|
||||
|
||||
|
||||
/* EMU8k/10k hardware applies this factor to initial attenuation generator values set at preset and
|
||||
* instrument level in a soundfont. We apply this factor when loading the generator values to stay
|
||||
* compatible as most existing soundfonts expect exactly this (strange, non-standard) behaviour. */
|
||||
#define EMU_ATTENUATION_FACTOR (0.4f)
|
||||
|
||||
|
||||
/***************************************************************
|
||||
*
|
||||
* SFONT LOADER
|
||||
|
@ -1289,6 +1296,12 @@ fluid_preset_zone_import_sfont(fluid_preset_zone_t* zone, SFZone *sfzone, fluid_
|
|||
zone->vello = (int) sfgen->amount.range.lo;
|
||||
zone->velhi = (int) sfgen->amount.range.hi;
|
||||
break;
|
||||
case GEN_ATTENUATION:
|
||||
/* EMU8k/10k hardware applies a scale factor to initial attenuation generator values set at
|
||||
* preset and instrument level */
|
||||
zone->gen[sfgen->id].val = (fluid_real_t) sfgen->amount.sword * EMU_ATTENUATION_FACTOR;
|
||||
zone->gen[sfgen->id].flags = GEN_SET;
|
||||
break;
|
||||
default:
|
||||
/* FIXME: some generators have an unsigne word amount value but i don't know which ones */
|
||||
zone->gen[sfgen->id].val = (fluid_real_t) sfgen->amount.sword;
|
||||
|
@ -1690,6 +1703,12 @@ fluid_inst_zone_import_sfont(fluid_inst_zone_t* zone, SFZone *sfzone, fluid_defs
|
|||
zone->vello = (int) sfgen->amount.range.lo;
|
||||
zone->velhi = (int) sfgen->amount.range.hi;
|
||||
break;
|
||||
case GEN_ATTENUATION:
|
||||
/* EMU8k/10k hardware applies a scale factor to initial attenuation generator values set at
|
||||
* preset and instrument level */
|
||||
zone->gen[sfgen->id].val = (fluid_real_t) sfgen->amount.sword * EMU_ATTENUATION_FACTOR;
|
||||
zone->gen[sfgen->id].flags = GEN_SET;
|
||||
break;
|
||||
default:
|
||||
/* FIXME: some generators have an unsigned word amount value but
|
||||
i don't know which ones */
|
||||
|
|
|
@ -196,10 +196,6 @@ void fluid_synth_settings(fluid_settings_t* settings)
|
|||
fluid_settings_add_option(settings, "synth.midi-bank-select", "gs");
|
||||
fluid_settings_add_option(settings, "synth.midi-bank-select", "xg");
|
||||
fluid_settings_add_option(settings, "synth.midi-bank-select", "mma");
|
||||
|
||||
fluid_settings_register_str(settings, "synth.volenv", "emu", 0);
|
||||
fluid_settings_add_option(settings, "synth.volenv", "emu");
|
||||
fluid_settings_add_option(settings, "synth.volenv", "compliant");
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -528,25 +524,6 @@ new_fluid_synth(fluid_settings_t *settings)
|
|||
/* initialize all the conversion tables and other stuff */
|
||||
if (fluid_atomic_int_compare_and_exchange(&fluid_synth_initialized, 0, 1))
|
||||
{
|
||||
char buf[64];
|
||||
if (fluid_settings_str_equal (settings, "synth.volenv", "compliant"))
|
||||
{
|
||||
fluid_conversion_set_atten_power(FLUID_ATTEN_POWER_DEFAULT_COMPLIANT);
|
||||
}
|
||||
else if (fluid_settings_str_equal (settings, "synth.volenv", "emu"))
|
||||
{
|
||||
fluid_conversion_set_atten_power(FLUID_ATTEN_POWER_DEFAULT_EMU);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (fluid_settings_copystr(settings, "synth.volenv", buf, sizeof(buf)) == FLUID_OK)
|
||||
{
|
||||
double atten = atof(buf);
|
||||
if(atten != 0.0)
|
||||
fluid_conversion_set_atten_power(atten);
|
||||
}
|
||||
}
|
||||
|
||||
fluid_synth_init();
|
||||
}
|
||||
|
||||
|
|
|
@ -681,8 +681,6 @@ calculate_hold_decay_buffers(fluid_voice_t* voice, int gen_base,
|
|||
void
|
||||
fluid_voice_update_param(fluid_voice_t* voice, int gen)
|
||||
{
|
||||
// Alternate attenuation scale used by EMU10K1 cards when setting the attenuation at the preset or instrument level within the SoundFont bank.
|
||||
static const float ALT_ATTENUATION_SCALE = 0.4f;
|
||||
unsigned int count, z;
|
||||
fluid_real_t q_dB;
|
||||
fluid_real_t x = fluid_voice_gen_value(voice, gen);
|
||||
|
@ -702,8 +700,7 @@ fluid_voice_update_param(fluid_voice_t* voice, int gen)
|
|||
break;
|
||||
|
||||
case GEN_ATTENUATION:
|
||||
voice->attenuation = ((fluid_real_t)(voice)->gen[GEN_ATTENUATION].val*ALT_ATTENUATION_SCALE) +
|
||||
(fluid_real_t)(voice)->gen[GEN_ATTENUATION].mod + (fluid_real_t)(voice)->gen[GEN_ATTENUATION].nrpn;
|
||||
voice->attenuation = x;
|
||||
|
||||
/* Range: SF2.01 section 8.1.3 # 48
|
||||
* Motivation for range checking:
|
||||
|
|
|
@ -21,17 +21,9 @@
|
|||
#include "fluid_conv.h"
|
||||
|
||||
|
||||
/* EMU 8k/10k don't follow spec in regards to volume attenuation.
|
||||
* This factor is used in the equation pow (10.0, cb / FLUID_ATTEN_POWER_FACTOR).
|
||||
* By the standard this should be -200.0. */
|
||||
/* 07/11/2008 modified by S. Christian Collins for increased velocity sensitivity.
|
||||
* Now it equals the response of EMU10K1 programming.*/
|
||||
static double FLUID_ATTEN_POWER_FACTOR = FLUID_ATTEN_POWER_DEFAULT_EMU; /* was (-531.509)*/
|
||||
|
||||
/* conversion tables */
|
||||
fluid_real_t fluid_ct2hz_tab[FLUID_CENTS_HZ_SIZE];
|
||||
fluid_real_t fluid_cb2amp_tab[FLUID_CB_AMP_SIZE];
|
||||
fluid_real_t fluid_atten2amp_tab[FLUID_ATTEN_AMP_SIZE];
|
||||
fluid_real_t fluid_concave_tab[128];
|
||||
fluid_real_t fluid_convex_tab[128];
|
||||
fluid_real_t fluid_pan_tab[FLUID_PAN_SIZE];
|
||||
|
@ -60,16 +52,6 @@ fluid_conversion_config(void)
|
|||
fluid_cb2amp_tab[i] = (fluid_real_t) pow(10.0, (double) i / -200.0);
|
||||
}
|
||||
|
||||
/* NOTE: EMU8k and EMU10k devices don't conform to the SoundFont
|
||||
* specification in regards to volume attenuation. The below calculation
|
||||
* is an approx. equation for generating a table equivelant to the
|
||||
* cb_to_amp_table[] in tables.c of the TiMidity++ source, which I'm told
|
||||
* was generated from device testing. By the spec this should be centibels.
|
||||
*/
|
||||
for (i = 0; i < FLUID_ATTEN_AMP_SIZE; i++) {
|
||||
fluid_atten2amp_tab[i] = (fluid_real_t) pow(10.0, (double) i / FLUID_ATTEN_POWER_FACTOR);
|
||||
}
|
||||
|
||||
/* initialize the conversion tables (see fluid_mod.c
|
||||
fluid_mod_get_value cases 4 and 8) */
|
||||
|
||||
|
@ -97,11 +79,6 @@ fluid_conversion_config(void)
|
|||
}
|
||||
}
|
||||
|
||||
void fluid_conversion_set_atten_power(double atten)
|
||||
{
|
||||
FLUID_ATTEN_POWER_FACTOR = atten;
|
||||
}
|
||||
|
||||
/*
|
||||
* fluid_ct2hz
|
||||
*/
|
||||
|
@ -157,7 +134,7 @@ fluid_ct2hz(fluid_real_t cents)
|
|||
/*
|
||||
* fluid_cb2amp
|
||||
*
|
||||
* in: a value between 0 and 960, 0 is no attenuation
|
||||
* in: a value between 0 and 1440, 0 is no attenuation
|
||||
* out: a value between 1 and 0
|
||||
*/
|
||||
fluid_real_t
|
||||
|
@ -179,23 +156,6 @@ fluid_cb2amp(fluid_real_t cb)
|
|||
return fluid_cb2amp_tab[(int) cb];
|
||||
}
|
||||
|
||||
/*
|
||||
* fluid_atten2amp
|
||||
*
|
||||
* in: a value between 0 and 1440, 0 is no attenuation
|
||||
* out: a value between 1 and 0
|
||||
*
|
||||
* Note: Volume attenuation is supposed to be centibels but EMU8k/10k don't
|
||||
* follow this. Thats the reason for separate fluid_cb2amp and fluid_atten2amp.
|
||||
*/
|
||||
fluid_real_t
|
||||
fluid_atten2amp(fluid_real_t atten)
|
||||
{
|
||||
if (atten < 0) return 1.0;
|
||||
else if (atten >= FLUID_ATTEN_AMP_SIZE) return 0.0;
|
||||
else return fluid_atten2amp_tab[(int) atten];
|
||||
}
|
||||
|
||||
/*
|
||||
* fluid_tc2sec_delay
|
||||
*/
|
||||
|
|
|
@ -25,20 +25,14 @@
|
|||
|
||||
#define FLUID_CENTS_HZ_SIZE 1200
|
||||
#define FLUID_VEL_CB_SIZE 128
|
||||
#define FLUID_CB_AMP_SIZE 961
|
||||
#define FLUID_ATTEN_AMP_SIZE 1441
|
||||
#define FLUID_CB_AMP_SIZE 1441
|
||||
#define FLUID_PAN_SIZE 1002
|
||||
|
||||
#define FLUID_ATTEN_POWER_DEFAULT_EMU (-200.0)
|
||||
#define FLUID_ATTEN_POWER_DEFAULT_COMPLIANT (-531.509)
|
||||
|
||||
void fluid_conversion_config(void);
|
||||
void fluid_conversion_set_atten_power(double atten);
|
||||
|
||||
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);
|
||||
fluid_real_t fluid_atten2amp(fluid_real_t atten);
|
||||
fluid_real_t fluid_tc2sec(fluid_real_t tc);
|
||||
fluid_real_t fluid_tc2sec_delay(fluid_real_t tc);
|
||||
fluid_real_t fluid_tc2sec_attack(fluid_real_t tc);
|
||||
|
|
Loading…
Reference in a new issue