diff --git a/AUTHORS b/AUTHORS index bbf8ce3d..a2a2c451 100644 --- a/AUTHORS +++ b/AUTHORS @@ -143,3 +143,4 @@ Nick Daly David Hilvert Bernat Arlandis i Mañó Sven Meier +Marcus Weseloh diff --git a/include/fluidsynth/event.h b/include/fluidsynth/event.h index ebf70c36..ae53c4e4 100644 --- a/include/fluidsynth/event.h +++ b/include/fluidsynth/event.h @@ -56,6 +56,7 @@ enum fluid_seq_event_type { FLUID_SEQ_TIMER, /**< Timer event (useful for giving a callback at a certain time) */ 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 @deprecated As of 1.1.7 this enum value is deprecated and will be removed in a future release, because it prevents adding new enum values without breaking ABI compatibility. */ @@ -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); diff --git a/include/fluidsynth/synth.h b/include/fluidsynth/synth.h index bee64d4c..86620808 100644 --- a/include/fluidsynth/synth.h +++ b/include/fluidsynth/synth.h @@ -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 diff --git a/src/midi/fluid_seqbind.c b/src/midi/fluid_seqbind.c index 4cead706..f456d7a7 100644 --- a/src/midi/fluid_seqbind.c +++ b/src/midi/fluid_seqbind.c @@ -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; diff --git a/src/synth/fluid_chan.c b/src/synth/fluid_chan.c index 82d8dbc9..418da1e2 100644 --- a/src/synth/fluid_chan.c +++ b/src/synth/fluid_chan.c @@ -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); diff --git a/src/synth/fluid_chan.h b/src/synth/fluid_chan.h index 06d6e674..bf3b5564 100644 --- a/src/synth/fluid_chan.h +++ b/src/synth/fluid_chan.h @@ -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 */ + char 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) \ diff --git a/src/synth/fluid_event.c b/src/synth/fluid_event.c index 3b27cb7b..e32ed614 100644 --- a/src/synth/fluid_event.c +++ b/src/synth/fluid_event.c @@ -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 diff --git a/src/synth/fluid_mod.c b/src/synth/fluid_mod.c index fb14cab6..eb9116c6 100644 --- a/src/synth/fluid_mod.c +++ b/src/synth/fluid_mod.c @@ -185,7 +185,7 @@ fluid_mod_get_source_value(const unsigned char mod_src, val = fluid_voice_get_actual_key(voice); break; case FLUID_MOD_KEYPRESSURE: - val = fluid_channel_get_key_pressure (chan); + val = fluid_channel_get_key_pressure(chan, voice->key); break; case FLUID_MOD_CHANNELPRESSURE: val = fluid_channel_get_channel_pressure (chan); diff --git a/src/synth/fluid_synth.c b/src/synth/fluid_synth.c index c44baf88..3207b53b 100644 --- a/src/synth/fluid_synth.c +++ b/src/synth/fluid_synth.c @@ -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, @@ -1724,6 +1725,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 @@ -4967,6 +5014,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));