Implement polyphonic key pressure (aftertouch) handling

Signed-off-by: Marcus Weseloh <marcus@weseloh.cc>
This commit is contained in:
Marcus Weseloh 2017-08-03 16:50:08 +02:00
parent 25e7eb0c6b
commit a2951fc37d
9 changed files with 102 additions and 8 deletions

View file

@ -138,3 +138,4 @@ Nick Daly
David Hilvert
Bernat Arlandis i Mañó
Sven Meier
Marcus Weseloh

View file

@ -56,6 +56,7 @@ enum fluid_seq_event_type {
FLUID_SEQ_TIMER, /**< Timer event (DOCME) */
FLUID_SEQ_ANYCONTROLCHANGE, /**< DOCME (used for remove_events only) */
FLUID_SEQ_CHANNELPRESSURE, /**< Channel aftertouch event @since 1.1.0 */
FLUID_SEQ_KEYPRESSURE, /**< Polyphonic aftertouch event @since 1.1.7 */
FLUID_SEQ_SYSTEMRESET, /**< System reset event @since 1.1.0 */
FLUID_SEQ_UNREGISTERING, /**< Called when a sequencer client is being unregistered. @since 1.1.0 */
FLUID_SEQ_LASTEVENT /**< Defines the count of event enums */
@ -103,6 +104,7 @@ FLUIDSYNTH_API void fluid_event_volume(fluid_event_t* evt, int channel, short va
FLUIDSYNTH_API void fluid_event_reverb_send(fluid_event_t* evt, int channel, short val);
FLUIDSYNTH_API void fluid_event_chorus_send(fluid_event_t* evt, int channel, short val);
FLUIDSYNTH_API void fluid_event_key_pressure(fluid_event_t* evt, int channel, short key, short val);
FLUIDSYNTH_API void fluid_event_channel_pressure(fluid_event_t* evt, int channel, short val);
FLUIDSYNTH_API void fluid_event_system_reset(fluid_event_t* evt);

View file

@ -81,6 +81,7 @@ FLUIDSYNTH_API int fluid_synth_pitch_wheel_sens(fluid_synth_t* synth, int chan,
FLUIDSYNTH_API int fluid_synth_get_pitch_wheel_sens(fluid_synth_t* synth, int chan, int* pval);
FLUIDSYNTH_API int fluid_synth_program_change(fluid_synth_t* synth, int chan, int program);
FLUIDSYNTH_API int fluid_synth_channel_pressure(fluid_synth_t* synth, int chan, int val);
FLUIDSYNTH_API int fluid_synth_key_pressure(fluid_synth_t* synth, int chan, int key, int val);
FLUIDSYNTH_API int fluid_synth_bank_select(fluid_synth_t* synth, int chan, unsigned int bank);
FLUIDSYNTH_API int fluid_synth_sfont_select(fluid_synth_t* synth, int chan, unsigned int sfont_id);
FLUIDSYNTH_API

View file

@ -237,6 +237,14 @@ fluid_seq_fluidsynth_callback(unsigned int time, fluid_event_t* evt, fluid_seque
}
break;
case FLUID_SEQ_KEYPRESSURE:
{
fluid_synth_key_pressure(synth, fluid_event_get_channel(evt),
fluid_event_get_key(evt),
fluid_event_get_value(evt));
}
break;
case FLUID_SEQ_SYSTEMRESET:
{
fluid_synth_system_reset(synth);
@ -314,6 +322,11 @@ fluid_sequencer_add_midi_event_to_buffer(void* data, fluid_midi_event_t* event)
case CHANNEL_PRESSURE:
fluid_event_channel_pressure(&evt, chan, fluid_midi_event_get_program(event));
break;
case KEY_PRESSURE:
fluid_event_key_pressure(&evt, chan,
fluid_midi_event_get_key(event),
fluid_midi_event_get_value(event));
break;
case MIDI_SYSTEM_RESET:
fluid_event_system_reset(&evt);
break;

View file

@ -101,7 +101,6 @@ fluid_channel_init_ctrl(fluid_channel_t* chan, int is_all_ctrl_off)
{
int i;
chan->key_pressure = 0;
chan->channel_pressure = 0;
chan->pitch_bend = 0x2000; /* Range is 0x4000, pitch bend wheel starts in centered position */
@ -132,6 +131,11 @@ fluid_channel_init_ctrl(fluid_channel_t* chan, int is_all_ctrl_off)
}
}
/* Reset polyphonic key pressure on all voices */
for (i = 0; i < 128; i++) {
fluid_channel_set_key_pressure(chan, i, 0);
}
/* Set RPN controllers to NULL state */
fluid_channel_set_cc (chan, RPN_LSB, 127);
fluid_channel_set_cc (chan, RPN_MSB, 127);

View file

@ -41,7 +41,7 @@ struct _fluid_channel_t
int sfont_bank_prog; /**< SoundFont ID (bit 21-31), bank (bit 7-20), program (bit 0-6) */
fluid_preset_t* preset; /**< Selected preset */
int key_pressure; /**< MIDI key pressure */
int key_pressure[128]; /**< MIDI polyphonic key pressure */
int channel_pressure; /**< MIDI channel pressure */
int pitch_bend; /**< Current pitch bend value */
int pitch_wheel_sensitivity; /**< Current pitch wheel sensitivity */
@ -106,10 +106,10 @@ int fluid_channel_get_interp_method(fluid_channel_t* chan);
((chan)->cc[num] = (val))
#define fluid_channel_get_cc(chan, num) \
((chan)->cc[num])
#define fluid_channel_get_key_pressure(chan) \
((chan)->key_pressure)
#define fluid_channel_set_key_pressure(chan, val) \
((chan)->key_pressure = (val))
#define fluid_channel_get_key_pressure(chan, key) \
((chan)->key_pressure[key])
#define fluid_channel_set_key_pressure(chan, key, val) \
((chan)->key_pressure[key] = (val))
#define fluid_channel_get_channel_pressure(chan) \
((chan)->channel_pressure)
#define fluid_channel_set_channel_pressure(chan, val) \

View file

@ -432,6 +432,27 @@ fluid_event_channel_pressure(fluid_event_t* evt, int channel, short val)
evt->value = val;
}
/**
* Set a sequencer event to be a polyphonic aftertouch event.
* @param evt Sequencer event structure
* @param channel MIDI channel number
* @param key MIDI note number (0-127)
* @param val Aftertouch amount (0-127)
* @since 1.1.7
*/
void
fluid_event_key_pressure(fluid_event_t* evt, int channel, short key, short val)
{
evt->type = FLUID_SEQ_KEYPRESSURE;
evt->channel = channel;
if (key < 0) key = 0;
if (key > 127) key = 127;
if (val < 0) val = 0;
if (val > 127) val = 127;
evt->key = key;
evt->value = val;
}
/**
* Set a sequencer event to be a midi system reset event.
* @param evt Sequencer event structure

View file

@ -224,7 +224,7 @@ fluid_mod_get_value(fluid_mod_t* mod, fluid_channel_t* chan, fluid_voice_t* voic
v1 = voice->key;
break;
case FLUID_MOD_KEYPRESSURE:
v1 = fluid_channel_get_key_pressure (chan);
v1 = fluid_channel_get_key_pressure(chan, voice->key);
break;
case FLUID_MOD_CHANNELPRESSURE:
v1 = fluid_channel_get_channel_pressure (chan);
@ -317,7 +317,7 @@ fluid_mod_get_value(fluid_mod_t* mod, fluid_channel_t* chan, fluid_voice_t* voic
v2 = voice->key;
break;
case FLUID_MOD_KEYPRESSURE:
v2 = fluid_channel_get_key_pressure (chan);
v2 = fluid_channel_get_key_pressure(chan, voice->key);
break;
case FLUID_MOD_CHANNELPRESSURE:
v2 = fluid_channel_get_channel_pressure (chan);

View file

@ -58,6 +58,7 @@ static int fluid_synth_modulate_voices_LOCAL(fluid_synth_t* synth, int chan,
int is_cc, int ctrl);
static int fluid_synth_modulate_voices_all_LOCAL(fluid_synth_t* synth, int chan);
static int fluid_synth_update_channel_pressure_LOCAL(fluid_synth_t* synth, int channum);
static int fluid_synth_update_key_pressure_LOCAL(fluid_synth_t* synth, int chan, int key);
static int fluid_synth_update_pitch_bend_LOCAL(fluid_synth_t* synth, int chan);
static int fluid_synth_update_pitch_wheel_sens_LOCAL(fluid_synth_t* synth, int chan);
static int fluid_synth_set_preset (fluid_synth_t *synth, int chan,
@ -1717,6 +1718,52 @@ fluid_synth_update_channel_pressure_LOCAL(fluid_synth_t* synth, int chan)
return fluid_synth_modulate_voices_LOCAL (synth, chan, 0, FLUID_MOD_CHANNELPRESSURE);
}
/**
* Set the MIDI polyphonic key pressure controller value.
* @param synth FluidSynth instance
* @param chan MIDI channel number (0 to MIDI channel count - 1)
* @param key MIDI key number (0-127)
* @param val MIDI key pressure value (0-127)
* @return FLUID_OK on success, FLUID_FAILED otherwise
*/
int
fluid_synth_key_pressure(fluid_synth_t* synth, int chan, int key, int val)
{
int result;
fluid_return_val_if_fail (key >= 0 && key <= 127, FLUID_FAILED);
fluid_return_val_if_fail (val >= 0 && val <= 127, FLUID_FAILED);
FLUID_API_ENTRY_CHAN(FLUID_FAILED);
if (synth->verbose)
FLUID_LOG(FLUID_INFO, "keypressure\t%d\t%d\t%d", chan, key, val);
fluid_channel_set_key_pressure (synth->channel[chan], key, val);
result = fluid_synth_update_key_pressure_LOCAL (synth, chan, key);
FLUID_API_RETURN(result);
}
/* Updates key pressure from within synthesis thread */
static int
fluid_synth_update_key_pressure_LOCAL(fluid_synth_t* synth, int chan, int key)
{
fluid_voice_t* voice;
int i;
int result = FLUID_OK;
for (i = 0; i < synth->polyphony; i++) {
voice = synth->voice[i];
if (voice->chan == chan && voice->key == key) {
result = fluid_voice_modulate(voice, 0, FLUID_MOD_KEYPRESSURE);
if (result != FLUID_OK)
return result;
}
}
return result;
}
/**
* Set the MIDI pitch bend controller value on a MIDI channel.
* @param synth FluidSynth instance
@ -4957,6 +5004,11 @@ fluid_synth_handle_midi_event(void* data, fluid_midi_event_t* event)
case CHANNEL_PRESSURE:
return fluid_synth_channel_pressure(synth, chan, fluid_midi_event_get_program(event));
case KEY_PRESSURE:
return fluid_synth_key_pressure(synth, chan,
fluid_midi_event_get_key(event),
fluid_midi_event_get_value(event));
case PITCH_BEND:
return fluid_synth_pitch_bend(synth, chan, fluid_midi_event_get_pitch(event));