mirror of
https://github.com/ZDoom/fluidsynth.git
synced 2024-12-02 17:12:15 +00:00
Fix bad router behaviour. (#891)
Each input event has values (chan, par1, par2) that could be changed by a rule. After a rule had been applied on any value and the value is out of range, the event can be ignored or the value can be clamped depending of the type of the event: - To get full benefice of the rule the value is clamped and the event passed to the output. - To avoid MIDI messages conflicts at the output, the event is ignored (i.e not passed to the output). chan value: event is ignored regardless of the event type par1: event is ignored for PROG_CHANGE or CONTROL_CHANGE type, par1 is clamped otherwise. par2: par2 is clamped regardless of the event type.
This commit is contained in:
parent
bf884758cb
commit
eda2fb21b0
1 changed files with 70 additions and 31 deletions
|
@ -536,7 +536,10 @@ fluid_midi_router_rule_set_param2(fluid_midi_router_rule_t *rule, int min, int m
|
|||
* this function can be used as a callback for other subsystems
|
||||
* (new_fluid_midi_driver() for example).
|
||||
* @param event MIDI event to handle
|
||||
* @return #FLUID_OK on success, #FLUID_FAILED otherwise
|
||||
* @return #FLUID_OK if all rules were applied successfully, #FLUID_FAILED if
|
||||
* an error occurred while applying a rule or (since 2.2.2) the event was
|
||||
* ignored because a parameter was out-of-range after the rule had been applied.
|
||||
* See the note below.
|
||||
*
|
||||
* Purpose: The midi router is called for each event, that is received
|
||||
* via the 'physical' midi input. Each event can trigger an arbitrary number
|
||||
|
@ -554,6 +557,17 @@ fluid_midi_router_rule_set_param2(fluid_midi_router_rule_t *rule, int min, int m
|
|||
* - velocity switching ("v <=100: Angel Choir; V > 100: Hell's Bells")
|
||||
* - get rid of aftertouch
|
||||
* - ...
|
||||
*
|
||||
* @note Each input event has values (ch, par1, par2) that could be changed by a rule.
|
||||
* After a rule has been applied on any value and the value is out of range, the event
|
||||
* can be either ignored or the value can be clamped depending on the type of the event:
|
||||
* - To get full benefice of the rule the value is clamped and the event passed to the output.
|
||||
* - To avoid MIDI messages conflicts at the output, the event is ignored
|
||||
* (i.e not passed to the output).
|
||||
* - ch out of range: event is ignored regardless of the event type.
|
||||
* - par1 out of range: event is ignored for PROG_CHANGE or CONTROL_CHANGE type,
|
||||
* par1 is clamped otherwise.
|
||||
* - par2 out of range: par2 is clamped regardless of the event type.
|
||||
*/
|
||||
int
|
||||
fluid_midi_router_handle_midi_event(void *data, fluid_midi_event_t *event)
|
||||
|
@ -561,6 +575,9 @@ fluid_midi_router_handle_midi_event(void *data, fluid_midi_event_t *event)
|
|||
fluid_midi_router_t *router = (fluid_midi_router_t *)data;
|
||||
fluid_midi_router_rule_t **rulep, *rule, *next_rule, *prev_rule = NULL;
|
||||
int event_has_par2 = 0; /* Flag, indicates that current event needs two parameters */
|
||||
int is_par1_ignored = 0; /* Flag, indicates that current event should be
|
||||
ignored/clamped when par1 is getting out of range
|
||||
value after the rule had been applied:1:ignored, 0:clamped */
|
||||
int par1_max = 127; /* Range limit for par1 */
|
||||
int par2_max = 127; /* Range limit for par2 */
|
||||
int ret_val = FLUID_OK;
|
||||
|
@ -585,34 +602,50 @@ fluid_midi_router_handle_midi_event(void *data, fluid_midi_event_t *event)
|
|||
/* Depending on the event type, choose the correct list of rules. */
|
||||
switch(event->type)
|
||||
{
|
||||
/* For NOTE_ON event, par1(pitch) and par2(velocity) will be clamped if
|
||||
they are out of range after the rule had been applied */
|
||||
case NOTE_ON:
|
||||
rulep = &router->rules[FLUID_MIDI_ROUTER_RULE_NOTE];
|
||||
event_has_par2 = 1;
|
||||
break;
|
||||
|
||||
/* For NOTE_OFF event, par1(pitch) and par2(velocity) will be clamped if
|
||||
they are out of range after the rule had been applied */
|
||||
case NOTE_OFF:
|
||||
rulep = &router->rules[FLUID_MIDI_ROUTER_RULE_NOTE];
|
||||
event_has_par2 = 1;
|
||||
break;
|
||||
|
||||
/* CONTROL_CHANGE event will be ignored if par1 (ctrl num) is out
|
||||
of range after the rule had been applied */
|
||||
case CONTROL_CHANGE:
|
||||
rulep = &router->rules[FLUID_MIDI_ROUTER_RULE_CC];
|
||||
event_has_par2 = 1;
|
||||
is_par1_ignored = 1;
|
||||
break;
|
||||
|
||||
/* PROGRAM_CHANGE event will be ignored if par1 (program num) is out
|
||||
of range after the rule had been applied */
|
||||
case PROGRAM_CHANGE:
|
||||
rulep = &router->rules[FLUID_MIDI_ROUTER_RULE_PROG_CHANGE];
|
||||
is_par1_ignored = 1;
|
||||
break;
|
||||
|
||||
/* For PITCH_BEND event, par1(bend value) will be clamped if
|
||||
it is out of range after the rule had been applied */
|
||||
case PITCH_BEND:
|
||||
rulep = &router->rules[FLUID_MIDI_ROUTER_RULE_PITCH_BEND];
|
||||
par1_max = 16383;
|
||||
break;
|
||||
|
||||
/* For CHANNEL_PRESSURE event, par1(pressure value) will be clamped if
|
||||
it is out of range after the rule had been applied */
|
||||
case CHANNEL_PRESSURE:
|
||||
rulep = &router->rules[FLUID_MIDI_ROUTER_RULE_CHANNEL_PRESSURE];
|
||||
break;
|
||||
|
||||
/* For KEY_PRESSURE event, par1(pitch) and par2(pressure value) will be
|
||||
clamped if they are out of range after the rule had been applied */
|
||||
case KEY_PRESSURE:
|
||||
rulep = &router->rules[FLUID_MIDI_ROUTER_RULE_KEY_PRESSURE];
|
||||
event_has_par2 = 1;
|
||||
|
@ -700,44 +733,46 @@ fluid_midi_router_handle_midi_event(void *data, fluid_midi_event_t *event)
|
|||
chan = rule->chan_add + (int)((fluid_real_t)event->channel * rule->chan_mul
|
||||
+ (fluid_real_t)0.5);
|
||||
|
||||
/* Par 1 scaling / offset */
|
||||
/* We ignore the event if chan is out of range */
|
||||
if((chan < 0) || (chan >= router->nr_midi_channels))
|
||||
{
|
||||
ret_val = FLUID_FAILED;
|
||||
continue; /* go to next rule */
|
||||
}
|
||||
|
||||
/* par 1 scaling / offset */
|
||||
par1 = rule->par1_add + (int)((fluid_real_t)event_par1 * rule->par1_mul
|
||||
+ (fluid_real_t)0.5);
|
||||
|
||||
/* Par 2 scaling / offset, if applicable */
|
||||
if(is_par1_ignored)
|
||||
{
|
||||
/* We ignore the event if par1 is out of range */
|
||||
if((par1 < 0) || (par1 > par1_max))
|
||||
{
|
||||
ret_val = FLUID_FAILED;
|
||||
continue; /* go to next rule */
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* par1 range clamping */
|
||||
if(par1 < 0)
|
||||
{
|
||||
par1 = 0;
|
||||
}
|
||||
else if(par1 > par1_max)
|
||||
{
|
||||
par1 = par1_max;
|
||||
}
|
||||
}
|
||||
|
||||
/* par 2 scaling / offset, if applicable */
|
||||
if(event_has_par2)
|
||||
{
|
||||
par2 = rule->par2_add + (int)((fluid_real_t)event_par2 * rule->par2_mul
|
||||
+ (fluid_real_t)0.5);
|
||||
}
|
||||
else
|
||||
{
|
||||
par2 = 0;
|
||||
}
|
||||
|
||||
/* Channel range limiting */
|
||||
if(chan < 0)
|
||||
{
|
||||
chan = 0;
|
||||
}
|
||||
else if(chan >= router->nr_midi_channels)
|
||||
{
|
||||
chan = router->nr_midi_channels - 1;
|
||||
}
|
||||
|
||||
/* Par1 range limiting */
|
||||
if(par1 < 0)
|
||||
{
|
||||
par1 = 0;
|
||||
}
|
||||
else if(par1 > par1_max)
|
||||
{
|
||||
par1 = par1_max;
|
||||
}
|
||||
|
||||
/* Par2 range limiting */
|
||||
if(event_has_par2)
|
||||
{
|
||||
/* par2 range clamping */
|
||||
if(par2 < 0)
|
||||
{
|
||||
par2 = 0;
|
||||
|
@ -747,6 +782,10 @@ fluid_midi_router_handle_midi_event(void *data, fluid_midi_event_t *event)
|
|||
par2 = par2_max;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
par2 = 0;
|
||||
}
|
||||
|
||||
/* At this point we have to create an event of event->type on 'chan' with par1 (maybe par2).
|
||||
* We keep track on the state of noteon and sustain pedal events. If the application tries
|
||||
|
|
Loading…
Reference in a new issue