mirror of
https://github.com/ZDoom/fluidsynth.git
synced 2025-04-22 23:50:53 +00:00
Apart from adding sostenuto pedal functionality, this also changes the behaviour of dampening currently sounding notes on the same key to ignore pedals. Signed-off-by: David Henningsson <diwic@ubuntu.com>
This commit is contained in:
parent
f11592a8a4
commit
048c51c4ab
5 changed files with 94 additions and 17 deletions
|
@ -67,6 +67,8 @@ fluid_channel_init(fluid_channel_t* chan)
|
|||
fluid_preset_t *newpreset;
|
||||
int prognum, banknum;
|
||||
|
||||
chan->sostenuto_orderid = 0;
|
||||
|
||||
chan->channel_type = (chan->channum == 9) ? CHANNEL_TYPE_DRUM : CHANNEL_TYPE_MELODIC;
|
||||
prognum = 0;
|
||||
banknum = (chan->channel_type == CHANNEL_TYPE_DRUM) ? DRUM_INST_BANK : 0;
|
||||
|
|
|
@ -48,6 +48,11 @@ struct _fluid_channel_t
|
|||
|
||||
int cc[128]; /**< MIDI controller values */
|
||||
|
||||
/* Sostenuto order id gives the order of SostenutoOn event.
|
||||
This value is useful to known when the sostenuto pedal is depressed
|
||||
(before or after a key note). We need to compare SostenutoOrderId with voice id.
|
||||
*/
|
||||
unsigned int sostenuto_orderid;
|
||||
int interp_method; /**< Interpolation method (enum fluid_interp) */
|
||||
fluid_tuning_t* tuning; /**< Micro tuning */
|
||||
int tuning_bank; /**< Current tuning bank number */
|
||||
|
@ -134,6 +139,7 @@ int fluid_channel_get_interp_method(fluid_channel_t* chan);
|
|||
#define fluid_channel_set_tuning_prog(chan, prog) \
|
||||
((chan)->tuning_prog = (prog))
|
||||
#define fluid_channel_sustained(_c) ((_c)->cc[SUSTAIN_SWITCH] >= 64)
|
||||
#define fluid_channel_sostenuto(_c) ((_c)->cc[SOSTENUTO_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])
|
||||
|
|
|
@ -42,7 +42,6 @@ static void fluid_synth_init(void);
|
|||
static int fluid_synth_noteon_LOCAL(fluid_synth_t* synth, int chan, int key,
|
||||
int vel);
|
||||
static int fluid_synth_noteoff_LOCAL(fluid_synth_t* synth, int chan, int key);
|
||||
static int fluid_synth_damp_voices_LOCAL(fluid_synth_t* synth, int chan);
|
||||
static int fluid_synth_cc_LOCAL(fluid_synth_t* synth, int channum, int num);
|
||||
static int fluid_synth_update_device_id (fluid_synth_t *synth, char *name,
|
||||
int value);
|
||||
|
@ -950,7 +949,6 @@ fluid_synth_noteon_LOCAL(fluid_synth_t* synth, int chan, int key, int vel)
|
|||
advance it to the release phase. */
|
||||
fluid_synth_release_voice_on_same_note_LOCAL(synth, chan, key);
|
||||
|
||||
synth->storeid = synth->noteid++;
|
||||
|
||||
return fluid_preset_noteon(channel->preset, synth, chan, key, vel);
|
||||
}
|
||||
|
@ -1007,9 +1005,10 @@ fluid_synth_noteoff_LOCAL(fluid_synth_t* synth, int chan, int key)
|
|||
return status;
|
||||
}
|
||||
|
||||
/* Damp all voices on a channel (turn notes off) */
|
||||
/* Damp voices on a channel (turn notes off), if they're sustained by
|
||||
sustain pedal */
|
||||
static int
|
||||
fluid_synth_damp_voices_LOCAL(fluid_synth_t* synth, int chan)
|
||||
fluid_synth_damp_voices_by_sustain_LOCAL(fluid_synth_t* synth, int chan)
|
||||
{
|
||||
fluid_voice_t* voice;
|
||||
int i;
|
||||
|
@ -1018,12 +1017,31 @@ fluid_synth_damp_voices_LOCAL(fluid_synth_t* synth, int chan)
|
|||
voice = synth->voice[i];
|
||||
|
||||
if ((voice->chan == chan) && _SUSTAINED(voice))
|
||||
fluid_voice_noteoff(voice);
|
||||
fluid_voice_release(voice);
|
||||
}
|
||||
|
||||
return FLUID_OK;
|
||||
}
|
||||
|
||||
/* Damp voices on a channel (turn notes off), if they're sustained by
|
||||
sostenuto pedal */
|
||||
static int
|
||||
fluid_synth_damp_voices_by_sostenuto_LOCAL(fluid_synth_t* synth, int chan)
|
||||
{
|
||||
fluid_voice_t* voice;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < synth->polyphony; i++) {
|
||||
voice = synth->voice[i];
|
||||
|
||||
if ((voice->chan == chan) && _HELD_BY_SOSTENUTO(voice))
|
||||
fluid_voice_release(voice);
|
||||
}
|
||||
|
||||
return FLUID_OK;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Send a MIDI controller event on a MIDI channel.
|
||||
* @param synth FluidSynth instance
|
||||
|
@ -1060,8 +1078,20 @@ fluid_synth_cc_LOCAL (fluid_synth_t* synth, int channum, int num)
|
|||
|
||||
switch (num) {
|
||||
case SUSTAIN_SWITCH:
|
||||
if (value < 64) fluid_synth_damp_voices_LOCAL (synth, channum);
|
||||
/* Release voices if Sustain switch is released */
|
||||
if (value < 64) /* Sustain is released */
|
||||
fluid_synth_damp_voices_by_sustain_LOCAL (synth, channum);
|
||||
break;
|
||||
|
||||
case SOSTENUTO_SWITCH:
|
||||
/* Release voices if Sostetuno switch is released */
|
||||
if (value < 64) /* Sostenuto is released */
|
||||
fluid_synth_damp_voices_by_sostenuto_LOCAL(synth, channum);
|
||||
else /* Sostenuto is depressed */
|
||||
/* Update sostenuto order id when pedaling on Sostenuto */
|
||||
chan->sostenuto_orderid = synth->noteid; /* future voice id value */
|
||||
break;
|
||||
|
||||
case BANK_SELECT_MSB:
|
||||
fluid_channel_set_bank_msb (chan, value & 0x7F);
|
||||
break;
|
||||
|
@ -3933,13 +3963,19 @@ fluid_synth_release_voice_on_same_note_LOCAL(fluid_synth_t* synth, int chan,
|
|||
int i;
|
||||
fluid_voice_t* voice;
|
||||
|
||||
synth->storeid = synth->noteid++;
|
||||
|
||||
for (i = 0; i < synth->polyphony; i++) {
|
||||
voice = synth->voice[i];
|
||||
if (_PLAYING(voice)
|
||||
&& (voice->chan == chan)
|
||||
&& (voice->key == key)
|
||||
&& (fluid_voice_get_id(voice) != synth->noteid)) {
|
||||
fluid_voice_noteoff(voice);
|
||||
/* Id of voices that was sustained by sostenuto */
|
||||
if(_HELD_BY_SOSTENUTO(voice))
|
||||
synth->storeid = voice->id;
|
||||
/* Force the voice into release stage (pedaling is ignored) */
|
||||
fluid_voice_release(voice);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1182,24 +1182,46 @@ int fluid_voice_modulate_all(fluid_voice_t* voice)
|
|||
return FLUID_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
Force the voice into release stage. Useful anywhere a voice
|
||||
needs to be damped even if pedals (sustain sostenuto) are depressed.
|
||||
See fluid_synth_damp_voices_by_sustain_LOCAL(),
|
||||
fluid_synth_damp_voices_by_sostenuto_LOCAL,
|
||||
fluid_voice_noteoff().
|
||||
*/
|
||||
void
|
||||
fluid_voice_release(fluid_voice_t* voice)
|
||||
{
|
||||
unsigned int at_tick = fluid_channel_get_min_note_length_ticks (voice->channel);
|
||||
UPDATE_RVOICE_I1(fluid_rvoice_noteoff, at_tick);
|
||||
voice->has_noteoff = 1; // voice is marked as noteoff occured
|
||||
}
|
||||
|
||||
/*
|
||||
* fluid_voice_noteoff
|
||||
*/
|
||||
int
|
||||
fluid_voice_noteoff(fluid_voice_t* voice)
|
||||
{
|
||||
unsigned int at_tick;
|
||||
fluid_channel_t* channel;
|
||||
|
||||
fluid_profile(FLUID_PROF_VOICE_NOTE, voice->ref);
|
||||
|
||||
channel = voice->channel;
|
||||
|
||||
if (voice->channel && fluid_channel_sustained(voice->channel)) {
|
||||
voice->status = FLUID_VOICE_SUSTAINED;
|
||||
} else {
|
||||
at_tick = fluid_channel_get_min_note_length_ticks (voice->channel);
|
||||
UPDATE_RVOICE_I1(fluid_rvoice_noteoff, at_tick);
|
||||
voice->has_noteoff = 1;
|
||||
/* Sustain a note under Sostenuto pedal */
|
||||
if (fluid_channel_sostenuto(channel) &&
|
||||
channel->sostenuto_orderid > voice->id)
|
||||
{ // Sostenuto depressed after note
|
||||
voice->status = FLUID_VOICE_HELD_BY_SOSTENUTO;
|
||||
}
|
||||
/* Or sustain a note under Sustain pedal */
|
||||
else if (fluid_channel_sustained(channel)) {
|
||||
voice->status = FLUID_VOICE_SUSTAINED;
|
||||
}
|
||||
/* Or force the voice to release stage */
|
||||
else
|
||||
fluid_voice_release(voice);
|
||||
|
||||
return FLUID_OK;
|
||||
}
|
||||
|
@ -1569,7 +1591,7 @@ fluid_voice_get_overflow_prio(fluid_voice_t* voice,
|
|||
else if (voice->has_noteoff) {
|
||||
/* Noteoff has */
|
||||
this_voice_prio += score->released;
|
||||
} else if (_SUSTAINED(voice)){
|
||||
} else if (_SUSTAINED(voice) || _HELD_BY_SOSTENUTO(voice)) {
|
||||
/* This voice is still active, since the sustain pedal is held down.
|
||||
* Consider it less important than non-sustained channels.
|
||||
* This decision is somehow subjective. But usually the sustain pedal
|
||||
|
|
|
@ -48,7 +48,8 @@ enum fluid_voice_status
|
|||
{
|
||||
FLUID_VOICE_CLEAN,
|
||||
FLUID_VOICE_ON,
|
||||
FLUID_VOICE_SUSTAINED,
|
||||
FLUID_VOICE_SUSTAINED, /* Sustained by Sustain pedal */
|
||||
FLUID_VOICE_HELD_BY_SOSTENUTO, /* Sustained by Sostenuto pedal */
|
||||
FLUID_VOICE_OFF
|
||||
};
|
||||
|
||||
|
@ -142,6 +143,13 @@ int fluid_voice_set_output_rate(fluid_voice_t* voice, fluid_real_t value);
|
|||
function.*/
|
||||
void fluid_voice_update_param(fluid_voice_t* voice, int gen);
|
||||
|
||||
/** fluid_voice_release
|
||||
Force the voice into release stage. Usefuf anywhere a voice
|
||||
needs to be damped even if pedals (sustain sostenuto) are depressed.
|
||||
See fluid_synth_damp_voices_LOCAL(), fluid_synth_damp_voices_by_sostenuto_LOCAL,
|
||||
fluid_voice_noteoff(), fluid_synth_stop_LOCAL().
|
||||
*/
|
||||
void fluid_voice_release(fluid_voice_t* voice);
|
||||
int fluid_voice_noteoff(fluid_voice_t* voice);
|
||||
int fluid_voice_off(fluid_voice_t* voice);
|
||||
void fluid_voice_overflow_rvoice_finished(fluid_voice_t* voice);
|
||||
|
@ -183,13 +191,16 @@ fluid_voice_unlock_rvoice(fluid_voice_t* voice)
|
|||
#define fluid_voice_get_chan(_voice) (_voice)->chan
|
||||
|
||||
|
||||
#define _PLAYING(voice) (((voice)->status == FLUID_VOICE_ON) || ((voice)->status == FLUID_VOICE_SUSTAINED))
|
||||
#define _PLAYING(voice) (((voice)->status == FLUID_VOICE_ON) || \
|
||||
_SUSTAINED(voice) || \
|
||||
_HELD_BY_SOSTENUTO(voice) )
|
||||
|
||||
/* 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->has_noteoff)
|
||||
#define _SUSTAINED(voice) ((voice)->status == FLUID_VOICE_SUSTAINED)
|
||||
#define _HELD_BY_SOSTENUTO(voice) ((voice)->status == FLUID_VOICE_HELD_BY_SOSTENUTO)
|
||||
#define _AVAILABLE(voice) ((voice)->can_access_rvoice && \
|
||||
(((voice)->status == FLUID_VOICE_CLEAN) || ((voice)->status == FLUID_VOICE_OFF)))
|
||||
//#define _RELEASED(voice) ((voice)->chan == NO_CHANNEL)
|
||||
|
|
Loading…
Reference in a new issue