Added fluid_synth_set_gen2(). Voices and channels can now handle

generators with absolute NRPN values. Added fluid_gen_info_t and a table of
information on all the standard generators.
This commit is contained in:
Peter Hanappe 2004-03-03 11:14:25 +00:00
parent 2aa2813083
commit ab066eb745
10 changed files with 238 additions and 174 deletions

View file

@ -17,24 +17,27 @@ already been done. - Josh Green 2003-08-25
- Windows DirectMusic component
- Multi-channel audio output
- fluid_synth_program_select() with name of soundfont instead of font_id
- set loop on/off on a sample (1 - with name sample, 2 - name sf and name preset)
- fluid_synth_program_select() with name of soundfont instead of font_id OK
- set loop on/off on a sample (1 - with name sample, 2 - name sf and name preset) Use set_gen?
set_gen: GEN_SAMPLEMODE (54):
Loop during release: 1,
Loop: 3
No loop: 0 and all other values,
- add function to get initial soundfont generator value
- add function to set generator value in absolute value (offset with
- add function to set generator value in absolute value (offset with testing
initial soundfont generator value)
- add function to set absolute and relative generator value on a scale
- add function to set absolute and relative generator value on a scale testing
of 0 to 1
inst zone
- attack (set to
- scale tune
- modLfoToPitch
- Write documention on tuning
- Remove dependency of settings on audio driver and other (see
fluid_settings_init())
Synthesis related
@ -58,7 +61,6 @@ Drivers
Fluid 1.0:
--------------------------------------------
- deb package
- Mac and Windows binaries
- Xtra binaries

View file

@ -113,7 +113,8 @@ typedef struct _fluid_gen_t
enum fluid_gen_flags
{
GEN_UNUSED,
GEN_SET
GEN_SET,
GEN_ABS_NRPN
};
/** Reset an array of generators to the SF2.01 default values */

View file

@ -73,6 +73,7 @@ fluid_channel_init_ctrl(fluid_channel_t* chan)
for (i = 0; i < GEN_LAST; i++) {
chan->gen[i] = 0.0f;
chan->gen_abs[i] = 0;
}
for (i = 0; i < 128; i++) {
@ -226,7 +227,7 @@ fluid_channel_cc(fluid_channel_t* chan, int num, int value)
/* SontFont 2.01 NRPN Message (Sect. 9.6, p. 74) */
if ((chan->cc[NRPN_MSB] == 120) && (chan->cc[NRPN_LSB] < 100)) {
float val = fluid_gen_map_nrpn(chan->nrpn_select, data);
float val = fluid_gen_scale_nrpn(chan->nrpn_select, data);
FLUID_LOG(FLUID_WARN, "%s: %d: Data = %d, value = %f", __FILE__, __LINE__, data, val);
fluid_synth_set_gen(chan->synth, chan->channum, chan->nrpn_select, val);
}

View file

@ -53,7 +53,24 @@ struct _fluid_channel_t
/* NRPN system */
short nrpn_select;
/* The values of the generators, set by NRPN messages, or by
* fluid_synth_set_gen(), are cached in the channel so they can be
* applied to future notes. They are copied to a voice's generators
* in fluid_voice_init(), wihich calls fluid_gen_init(). */
fluid_real_t gen[GEN_LAST];
/* By default, the NRPN values are relative to the values of the
* generators set in the SoundFont. For example, if the NRPN
* specifies an attack of 100 msec then 100 msec will be added to the
* combined attack time of the sound font and the modulators.
*
* However, it is useful to be able to specify the generator value
* absolutely, completely ignoring the generators of the sound font
* and the values of modulators. The gen_abs field, is a boolean
* flag indicating whether the NRPN value is absolute or not.
*/
char gen_abs[GEN_LAST];
};
fluid_channel_t* new_fluid_channel(fluid_synth_t* synth, int num);
@ -77,13 +94,12 @@ int fluid_channel_get_num(fluid_channel_t* chan);
void fluid_channel_set_interp_method(fluid_channel_t* chan, int new_method);
int fluid_channel_get_interp_method(fluid_channel_t* chan);
#define fluid_channel_set_tuning(_c, _t) { (_c)->tuning = _t; }
#define fluid_channel_has_tuning(_c) ((_c)->tuning != NULL)
#define fluid_channel_get_tuning(_c) ((_c)->tuning)
#define fluid_channel_sustained(_c) ((_c)->cc[SUSTAIN_SWITCH] >= 64)
#define fluid_channel_set_gen(_c, _n, _v) { (_c)->gen[_n] = _v; }
#define fluid_channel_get_gen(_c, _n) ((_c)->gen[_n])
#define fluid_channel_set_tuning(_c, _t) { (_c)->tuning = _t; }
#define fluid_channel_has_tuning(_c) ((_c)->tuning != NULL)
#define fluid_channel_get_tuning(_c) ((_c)->tuning)
#define fluid_channel_sustained(_c) ((_c)->cc[SUSTAIN_SWITCH] >= 64)
#define fluid_channel_set_gen(_c, _n, _v, _a) { (_c)->gen[_n] = _v; (_c)->gen_abs[_n] = _a; }
#define fluid_channel_get_gen(_c, _n) ((_c)->gen[_n])
#define fluid_channel_get_gen_abs(_c, _n) ((_c)->gen_abs[_n])
#endif /* _FLUID_CHAN_H */

View file

@ -647,7 +647,7 @@ fluid_defpreset_noteon(fluid_defpreset_t* preset, fluid_synth_t* synth, int chan
if (inst_zone->gen[i].flags){
fluid_voice_gen_set(voice, i, inst_zone->gen[i].val);
} else if (global_inst_zone != NULL && global_inst_zone->gen[i].flags){
} else if ((global_inst_zone != NULL) && (global_inst_zone->gen[i].flags)) {
fluid_voice_gen_set(voice, i, global_inst_zone->gen[i].val);
} else {
@ -733,9 +733,9 @@ fluid_defpreset_noteon(fluid_defpreset_t* preset, fluid_synth_t* synth, int chan
* generator. The effect is -added- to the destination
* summing node -> voice_gen_incr */
if (preset_zone->gen[i].flags){
if (preset_zone->gen[i].flags) {
fluid_voice_gen_incr(voice, i, preset_zone->gen[i].val);
} else if ((global_preset_zone != NULL) && global_preset_zone->gen[i].flags){
} else if ((global_preset_zone != NULL) && global_preset_zone->gen[i].flags) {
fluid_voice_gen_incr(voice, i, global_preset_zone->gen[i].val);
} else {
/* The generator has not been defined in this preset

View file

@ -22,6 +22,73 @@
#include "fluid_gen.h"
#include "fluid_chan.h"
/* See SFSpec21 $8.1.3 */
fluid_gen_info_t fluid_gen_info[] = {
/* number/name init scale min max def */
{ GEN_STARTADDROFS, 1, 1, 0.0f, 1e10f, 0.0f },
{ GEN_ENDADDROFS, 1, 1, -1e10f, 0.0f, 0.0f },
{ GEN_STARTLOOPADDROFS, 1, 1, -1e10f, 1e10f, 0.0f },
{ GEN_ENDLOOPADDROFS, 1, 1, -1e10f, 1e10f, 0.0f },
{ GEN_STARTADDRCOARSEOFS, 0, 1, 0.0f, 1e10f, 0.0f },
{ GEN_MODLFOTOPITCH, 1, 2, -12000.0f, 12000.0f, 0.0f },
{ GEN_VIBLFOTOPITCH, 1, 2, -12000.0f, 12000.0f, 0.0f },
{ GEN_MODENVTOPITCH, 1, 2, -12000.0f, 12000.0f, 0.0f },
{ GEN_FILTERFC, 1, 2, 1500.0f, 13500.0f, 13500.0f },
{ GEN_FILTERQ, 1, 1, 0.0f, 960.0f, 0.0f },
{ GEN_MODLFOTOFILTERFC, 1, 2, -12000.0f, 12000.0f, 0.0f },
{ GEN_MODENVTOFILTERFC, 1, 2, -12000.0f, 12000.0f, 0.0f },
{ GEN_ENDADDRCOARSEOFS, 0, 1, -1e10f, 0.0f, 0.0f },
{ GEN_MODLFOTOVOL, 1, 1, -960.0f, 960.0f, 0.0f },
{ GEN_UNUSED1, 0, 0, 0.0f, 0.0f, 0.0f },
{ GEN_CHORUSSEND, 1, 1, 0.0f, 1000.0f, 0.0f },
{ GEN_REVERBSEND, 1, 1, 0.0f, 1000.0f, 0.0f },
{ GEN_PAN, 1, 1, -500.0f, 500.0f, 0.0f },
{ GEN_UNUSED2, 0, 0, 0.0f, 0.0f, 0.0f },
{ GEN_UNUSED3, 0, 0, 0.0f, 0.0f, 0.0f },
{ GEN_UNUSED4, 0, 0, 0.0f, 0.0f, 0.0f },
{ GEN_MODLFODELAY, 1, 2, -12000.0f, 5000.0f, -12000.0f },
{ GEN_MODLFOFREQ, 1, 4, -16000.0f, 4500.0f, 0.0f },
{ GEN_VIBLFODELAY, 1, 2, -12000.0f, 5000.0f, -12000.0f },
{ GEN_VIBLFOFREQ, 1, 4, -16000.0f, 4500.0f, 0.0f },
{ GEN_MODENVDELAY, 1, 2, -12000.0f, 5000.0f, -12000.0f },
{ GEN_MODENVATTACK, 1, 2, -12000.0f, 8000.0f, -12000.0f },
{ GEN_MODENVHOLD, 1, 2, -12000.0f, 5000.0f, -12000.0f },
{ GEN_MODENVDECAY, 1, 2, -12000.0f, 8000.0f, -12000.0f },
{ GEN_MODENVSUSTAIN, 0, 1, 0.0f, 1000.0f, 0.0f },
{ GEN_MODENVRELEASE, 1, 2, -12000.0f, 8000.0f, -12000.0f },
{ GEN_KEYTOMODENVHOLD, 0, 1, -1200.0f, 1200.0f, 0.0f },
{ GEN_KEYTOMODENVDECAY, 0, 1, -1200.0f, 1200.0f, 0.0f },
{ GEN_VOLENVDELAY, 1, 2, -12000.0f, 5000.0f, -12000.0f },
{ GEN_VOLENVATTACK, 1, 2, -12000.0f, 8000.0f, -12000.0f },
{ GEN_VOLENVHOLD, 1, 2, -12000.0f, 5000.0f, -12000.0f },
{ GEN_VOLENVDECAY, 1, 2, -12000.0f, 8000.0f, -12000.0f },
{ GEN_VOLENVSUSTAIN, 0, 1, 0.0f, 1440.0f, 0.0f },
{ GEN_VOLENVRELEASE, 1, 2, -12000.0f, 8000.0f, -12000.0f },
{ GEN_KEYTOVOLENVHOLD, 0, 1, -1200.0f, 1200.0f, 0.0f },
{ GEN_KEYTOVOLENVDECAY, 0, 1, -1200.0f, 1200.0f, 0.0f },
{ GEN_INSTRUMENT, 0, 0, 0.0f, 0.0f, 0.0f },
{ GEN_RESERVED1, 0, 0, 0.0f, 0.0f, 0.0f },
{ GEN_KEYRANGE, 0, 0, 0.0f, 127.0f, 0.0f },
{ GEN_VELRANGE, 0, 0, 0.0f, 127.0f, 0.0f },
{ GEN_STARTLOOPADDRCOARSEOFS, 0, 1, -1e10f, 1e10f, 0.0f },
{ GEN_KEYNUM, 1, 0, 0.0f, 127.0f, -1.0f },
{ GEN_VELOCITY, 1, 1, 0.0f, 127.0f, -1.0f },
{ GEN_ATTENUATION, 1, 1, 0.0f, 1440.0f, 0.0f },
{ GEN_RESERVED2, 0, 0, 0.0f, 0.0f, 0.0f },
{ GEN_ENDLOOPADDRCOARSEOFS, 0, 1, -1e10f, 1e10f, 0.0f },
{ GEN_COARSETUNE, 0, 1, -120.0f, 120.0f, 0.0f },
{ GEN_FINETUNE, 0, 1, -99.0f, 99.0f, 0.0f },
{ GEN_SAMPLEID, 0, 0, 0.0f, 0.0f, 0.0f },
{ GEN_SAMPLEMODE, 0, 0, 0.0f, 0.0f, 0.0f },
{ GEN_RESERVED3, 0, 0, 0.0f, 0.0f, 0.0f },
{ GEN_SCALETUNE, 0, 1, 0.0f, 1200.0f, 100.0f },
{ GEN_EXCLUSIVECLASS, 0, 0, 0.0f, 0.0f, 0.0f },
{ GEN_OVERRIDEROOTKEY, 1, 0, 0.0f, 127.0f, -1.0f },
{ GEN_PITCH, 1, 0, 0.0f, 127.0f, 0.0f }
};
/* fluid_gen_set_default_values
*
* Set an array of generators to their initial value
@ -29,72 +96,16 @@
int
fluid_gen_set_default_values(fluid_gen_t* gen)
{
int i;
int i;
for (i = 0; i < GEN_LAST; i++) {
gen[i].flags = GEN_UNUSED;
gen[i].mod = 0.0;
gen[i].nrpn = 0.0;
}
for (i = 0; i < GEN_LAST; i++) {
gen[i].flags = GEN_UNUSED;
gen[i].mod = 0.0;
gen[i].nrpn = 0.0;
gen[i].val = fluid_gen_info[i].def;
}
gen[GEN_STARTADDROFS].val = (fluid_real_t) 0.0; /* SF2.01 section 8.1.3 #0 */
gen[GEN_ENDADDROFS].val = (fluid_real_t) 0.0f; /* # 1 */
gen[GEN_STARTLOOPADDROFS].val = (fluid_real_t) 0.0f; /* # 2 */
gen[GEN_ENDLOOPADDROFS].val = (fluid_real_t) 0.0f; /* # 3 */
gen[GEN_STARTADDRCOARSEOFS].val = (fluid_real_t) 0.0f; /* # 4 */
gen[GEN_MODLFOTOPITCH].val = (fluid_real_t) 0.0f; /* # 5 */
gen[GEN_VIBLFOTOPITCH].val = (fluid_real_t) 0.0f; /* # 6 */
gen[GEN_MODENVTOPITCH].val = (fluid_real_t) 0.0f; /* # 7 */
gen[GEN_FILTERFC].val = (fluid_real_t) 13500.0f; /* # 8 */
gen[GEN_FILTERQ].val = (fluid_real_t) 0.0f; /* # 9 */
gen[GEN_MODLFOTOFILTERFC].val = (fluid_real_t) 0.0f; /* # 10 */
gen[GEN_MODENVTOFILTERFC].val = (fluid_real_t) 0.0f; /* # 11 */
gen[GEN_ENDADDRCOARSEOFS].val = (fluid_real_t) 0.0f; /* # 12 */
gen[GEN_MODLFOTOVOL].val = (fluid_real_t) 0.0f; /* # 13 */
/* # 14 */
gen[GEN_CHORUSSEND].val = (fluid_real_t) 0.0f; /* # 15 */
gen[GEN_REVERBSEND].val = (fluid_real_t) 0.0f; /* # 16 */
gen[GEN_PAN].val = (fluid_real_t) 0.0f; /* # 17 */
/* # 18 - # 20 */
gen[GEN_MODLFODELAY].val = (fluid_real_t) -12000.0f; /* # 21 => instantaneous */
gen[GEN_MODLFOFREQ].val = (fluid_real_t) 0.0f; /* # 22 => 8.176 Hz */
gen[GEN_VIBLFODELAY].val = (fluid_real_t) -12000.0f; /* # 23 => instantaneous */
gen[GEN_VIBLFOFREQ].val = (fluid_real_t) 0.0f; /* # 24 => 8.176 Hz */
gen[GEN_MODENVDELAY].val = (fluid_real_t) -12000.0f; /* # 25 => instantaneous */
gen[GEN_MODENVATTACK].val = (fluid_real_t) -12000.0f; /* # 26 => instantaneous */
gen[GEN_MODENVHOLD].val = (fluid_real_t) -12000.0f; /* # 27 => instantaneous */
gen[GEN_MODENVDECAY].val = (fluid_real_t) -12000.0f; /* # 28 => instantaneous */
gen[GEN_MODENVSUSTAIN].val = (fluid_real_t) 0.0f; /* # 29 => 0 dB */
gen[GEN_MODENVRELEASE].val = (fluid_real_t) -12000.0f; /* # 30 => instantaneous */
gen[GEN_KEYTOMODENVHOLD].val = (fluid_real_t) 0.0f; /* # 31 */
gen[GEN_KEYTOMODENVDECAY].val = (fluid_real_t) 0.0f; /* # 32 */
gen[GEN_VOLENVDELAY].val = (fluid_real_t) -12000.0f; /* # 33 */
gen[GEN_VOLENVATTACK].val = (fluid_real_t) -12000.0f; /* # 34 */
gen[GEN_VOLENVHOLD].val = (fluid_real_t) -12000.0f; /* # 35 */
gen[GEN_VOLENVDECAY].val = (fluid_real_t) -12000.0f; /* # 36 */
gen[GEN_VOLENVSUSTAIN].val = (fluid_real_t) 0.0f; /* # 37 */
gen[GEN_VOLENVRELEASE].val = (fluid_real_t) -12000.0f; /* # 38 */
gen[GEN_KEYTOVOLENVHOLD].val = (fluid_real_t) 0.0f; /* # 39 */
gen[GEN_KEYTOVOLENVDECAY].val = (fluid_real_t) 0.0f; /* # 40 */
/* # 41 - # 42 */
/* GEN_KEYRANGE, GEN_VELRANGE are handled in fluid_defsfont.c # 43 - # 44 */
gen[GEN_STARTLOOPADDRCOARSEOFS].val = (fluid_real_t) 0.0f; /* # 45 */
gen[GEN_KEYNUM].val = (fluid_real_t) -1.0f; /* # 46 => disabled */
gen[GEN_VELOCITY].val = (fluid_real_t) -1.0f; /* # 47 => disabled */
gen[GEN_ATTENUATION].val = (fluid_real_t) 0.0f; /* # 48 => 0 dB */
/* # 49 */
gen[GEN_ENDLOOPADDRCOARSEOFS].val = (fluid_real_t) 0.0f; /* # 50 */
gen[GEN_COARSETUNE].val = (fluid_real_t) 0.0f; /* # 51 */
gen[GEN_FINETUNE].val = (fluid_real_t) 0.0f; /* # 52 */
gen[GEN_SAMPLEID].val = (fluid_real_t) 0.0f; /* # 53 ??? */
gen[GEN_SAMPLEMODE].val = (fluid_real_t) 0.0f; /* # 54 => no loop */
/* # 55 */
gen[GEN_SCALETUNE].val = (fluid_real_t) 100.0f; /* # 56 => 1 semitone / key */
gen[GEN_EXCLUSIVECLASS].val = (fluid_real_t) 0.0f; /* # 57 => no exclusive class */
gen[GEN_OVERRIDEROOTKEY].val = (fluid_real_t) -1.0f; /* # 58 => disabled */
gen[GEN_PITCH].val = 0.0f;
return FLUID_OK;
return FLUID_OK;
}
@ -105,87 +116,33 @@ fluid_gen_set_default_values(fluid_gen_t* gen)
int
fluid_gen_init(fluid_gen_t* gen, fluid_channel_t* channel)
{
int i;
int i;
fluid_gen_set_default_values(gen);
fluid_gen_set_default_values(gen);
for (i = 0; i < GEN_LAST; i++) {
gen[i].nrpn = fluid_channel_get_gen(channel, i);
}
for (i = 0; i < GEN_LAST; i++) {
gen[i].nrpn = fluid_channel_get_gen(channel, i);
return FLUID_OK;
/* This is an extension to the SoundFont standard. More
* documentation is available at the fluid_synth_set_gen2()
* function. */
if (fluid_channel_get_gen_abs(channel, i)) {
gen[i].flags = GEN_ABS_NRPN;
}
}
return FLUID_OK;
}
fluid_real_t fluid_gen_scale(int gen, float value)
{
return (fluid_gen_info[gen].min
+ value * (fluid_gen_info[gen].max - fluid_gen_info[gen].min));
}
fluid_real_t fluid_gen_map_nrpn(int gen, int data)
fluid_real_t fluid_gen_scale_nrpn(int gen, int data)
{
fluid_real_t value = (float) data - 8192.0f;
fluid_clip(value, -8192, 8192);
switch (gen) {
default:
case GEN_OVERRIDEROOTKEY:
case GEN_PITCH:
case GEN_KEYRANGE:
case GEN_VELRANGE:
case GEN_SAMPLEMODE:
case GEN_SAMPLEID:
case GEN_INSTRUMENT:
case GEN_KEYNUM:
case GEN_EXCLUSIVECLASS:
return 0.0;
case GEN_STARTADDROFS:
case GEN_ENDADDROFS:
case GEN_STARTLOOPADDROFS:
case GEN_ENDLOOPADDROFS:
case GEN_STARTADDRCOARSEOFS:
case GEN_FILTERQ:
case GEN_ENDADDRCOARSEOFS:
case GEN_MODLFOTOVOL:
case GEN_CHORUSSEND:
case GEN_REVERBSEND:
case GEN_PAN:
case GEN_KEYTOMODENVHOLD:
case GEN_KEYTOMODENVDECAY:
case GEN_MODENVSUSTAIN:
case GEN_VOLENVSUSTAIN:
case GEN_KEYTOVOLENVHOLD:
case GEN_KEYTOVOLENVDECAY:
case GEN_STARTLOOPADDRCOARSEOFS:
case GEN_ENDLOOPADDRCOARSEOFS:
case GEN_VELOCITY:
case GEN_ATTENUATION:
case GEN_COARSETUNE:
case GEN_FINETUNE:
case GEN_SCALETUNE:
return value;
case GEN_MODLFOTOPITCH:
case GEN_VIBLFOTOPITCH:
case GEN_MODENVTOPITCH:
case GEN_FILTERFC:
case GEN_MODLFOTOFILTERFC:
case GEN_MODENVTOFILTERFC:
case GEN_MODLFODELAY:
case GEN_VIBLFODELAY:
case GEN_MODENVDELAY:
case GEN_MODENVATTACK:
case GEN_MODENVHOLD:
case GEN_MODENVDECAY:
case GEN_MODENVRELEASE:
case GEN_VOLENVDELAY:
case GEN_VOLENVATTACK:
case GEN_VOLENVHOLD:
case GEN_VOLENVDECAY:
case GEN_VOLENVRELEASE:
return 2 * value;
case GEN_MODLFOFREQ:
case GEN_VIBLFOFREQ:
return 4 * value;
}
return 0.0f;
fluid_real_t value = (float) data - 8192.0f;
fluid_clip(value, -8192, 8192);
return value * (float) fluid_gen_info[gen].nrpn_scale;
}

View file

@ -24,11 +24,21 @@
#include "fluidsynth_priv.h"
typedef struct _fluid_gen_info_t {
char num; /* Generator number */
char init; /* Does the generator need to be initialized (cfr. fluid_voice_init()) */
char nrpn_scale; /* The scale to convert from NRPN (cfr. fluid_gen_map_nrpn()) */
float min; /* The minimum value */
float max; /* The maximum value */
float def; /* The default value (cfr. fluid_gen_set_default_values()) */
} fluid_gen_info_t;
#define fluid_gen_set_mod(_gen, _val) { (_gen)->mod = (double) (_val); }
#define fluid_gen_set_nrpn(_gen, _val) { (_gen)->nrpn = (double) (_val); }
fluid_real_t fluid_gen_map_nrpn(int gen, int nrpn);
fluid_real_t fluid_gen_scale(int gen, float value);
fluid_real_t fluid_gen_scale_nrpn(int gen, int nrpn);
int fluid_gen_init(fluid_gen_t* gen, fluid_channel_t* channel);
#endif /* _FLUID_GEN_H */

View file

@ -47,6 +47,10 @@ fluid_sfont_t* fluid_synth_get_sfont_by_name(fluid_synth_t* synth, char *name);
int fluid_synth_get_pitch_wheel_sens(fluid_synth_t* synth, int chan, int* pval);
int fluid_synth_set_gen2(fluid_synth_t* synth, int chan,
int param, float value,
int absolute, int normalized);
/***************************************************************
*
@ -2739,12 +2743,67 @@ fluid_synth_set_gen(fluid_synth_t* synth, int chan, int param, float value)
return FLUID_FAILED;
}
fluid_channel_set_gen(synth->channel[chan], param, value);
fluid_channel_set_gen(synth->channel[chan], param, value, 0);
for (i = 0; i < synth->nvoice; i++) {
voice = synth->voice[i];
if (voice->chan == chan) {
fluid_voice_set_param(voice, param, value);
fluid_voice_set_param(voice, param, value, 0);
}
}
return FLUID_OK;
}
/** Change the value of a generator. This function allows to control
all synthesis parameters in real-time. The changes are additive,
i.e. they add up to the existing parameter value. This function is
similar to sending an NRPN message to the synthesizer. The
function accepts a float as the value of the parameter. The
parameter numbers and ranges are described in the SoundFont 2.01
specification, paragraph 8.1.3, page 48. See also
'fluid_gen_type'.
Using the fluid_synth_set_gen2() function, it is possible to set
the absolute value of a generator. This is an extension to the
SoundFont standard. If 'absolute' is non-zero, the value of the
generator specified in the SoundFont is completely ignored and the
generator is fixed to the value passed as argument. To undo this
behavior, you must call fluid_synth_set_gen2 again, with
'absolute' set to 0 (and possibly 'value' set to zero).
If 'normalized' is non-zero, the value is supposed to be
normalized between 0 and 1. Before applying the value, it will be
scaled and shifted to the range defined in the SoundFont
specifications.
*/
int
fluid_synth_set_gen2(fluid_synth_t* synth, int chan, int param,
float value, int absolute, int normalized)
{
int i;
fluid_voice_t* voice;
float v;
if ((chan < 0) || (chan >= synth->midi_channels)) {
FLUID_LOG(FLUID_WARN, "Channel out of range");
return FLUID_FAILED;
}
if ((param < 0) || (param >= GEN_LAST)) {
FLUID_LOG(FLUID_WARN, "Parameter number out of range");
return FLUID_FAILED;
}
v = (normalized)? fluid_gen_scale(param, value) : value;
fluid_channel_set_gen(synth->channel[chan], param, v, absolute);
for (i = 0; i < synth->nvoice; i++) {
voice = synth->voice[i];
if (voice->chan == chan) {
fluid_voice_set_param(voice, param, v, absolute);
}
}

View file

@ -295,6 +295,18 @@ float fluid_voice_gen_get(fluid_voice_t* voice, int gen)
return voice->gen[gen].val;
}
fluid_real_t fluid_voice_gen_value(fluid_voice_t* voice, int num)
{
/* This is an extension to the SoundFont standard. More
* documentation is available at the fluid_synth_set_gen2()
* function. */
if (voice->gen[num].flags == GEN_ABS_NRPN) {
return (fluid_real_t) voice->gen[num].nrpn;
} else {
return (fluid_real_t) (voice->gen[num].val + voice->gen[num].mod + voice->gen[num].nrpn);
}
}
/*
* fluid_voice_write
@ -960,7 +972,7 @@ fluid_voice_calculate_runtime_synthesis_parameters(fluid_voice_t* voice)
* example, the pitch depends on GEN_COARSETUNE, GEN_FINETUNE and
* GEN_PITCH. voice->pitch. Unnecessary recalculation is avoided
* by removing all but one generator from the list of voice
* parameters. Same with GEN_XXX and GEN_XXXCOARSE: the
* parameters. Same with GEN_XXX and GEN_XXXCOARSE: the
* initialisation list contains only GEN_XXX.
*/
@ -1948,9 +1960,10 @@ void fluid_voice_check_sample_sanity(fluid_voice_t* voice)
}
int fluid_voice_set_param(fluid_voice_t* voice, int gen, fluid_real_t nrpn_value)
int fluid_voice_set_param(fluid_voice_t* voice, int gen, fluid_real_t nrpn_value, int abs)
{
voice->gen[gen].nrpn = nrpn_value;
voice->gen[gen].flags = (abs)? GEN_ABS_NRPN : GEN_SET;
fluid_voice_update_param(voice, gen);
return FLUID_OK;
}

View file

@ -208,7 +208,7 @@ int fluid_voice_modulate(fluid_voice_t* voice, int cc, int ctrl);
int fluid_voice_modulate_all(fluid_voice_t* voice);
/** Set the NRPN value of a generator. */
int fluid_voice_set_param(fluid_voice_t* voice, int gen, fluid_real_t value);
int fluid_voice_set_param(fluid_voice_t* voice, int gen, fluid_real_t value, int abs);
/** Set the gain. */
@ -239,13 +239,18 @@ void fluid_voice_check_sample_sanity(fluid_voice_t* voice);
#define _PLAYING(voice) (((voice)->status == FLUID_VOICE_ON) || ((voice)->status == FLUID_VOICE_SUSTAINED))
/* A voice is 'ON', if it has not yet received a noteoff event. Sending a noteoff event will advance the envelopes to section 5 (release). */
/* A voice is 'ON', if it has not yet received a noteoff
* event. Sending a noteoff event will advance the envelopes to
* section 5 (release). */
#define _ON(voice) ((voice)->status == FLUID_VOICE_ON && (voice)->volenv_section < FLUID_VOICE_ENVRELEASE)
#define _SUSTAINED(voice) ((voice)->status == FLUID_VOICE_SUSTAINED)
#define _AVAILABLE(voice) (((voice)->status == FLUID_VOICE_CLEAN) || ((voice)->status == FLUID_VOICE_OFF))
#define _RELEASED(voice) ((voice)->chan == NO_CHANNEL)
#define _SAMPLEMODE(voice) ((int)(voice)->gen[GEN_SAMPLEMODE].val)
fluid_real_t fluid_voice_gen_value(fluid_voice_t* voice, int num);
#define _GEN(_voice, _n) \
((fluid_real_t)(_voice)->gen[_n].val \
+ (fluid_real_t)(_voice)->gen[_n].mod \