diff --git a/fluidsynth/include/fluidsynth/event.h b/fluidsynth/include/fluidsynth/event.h index db76d2ba..f07fad26 100644 --- a/fluidsynth/include/fluidsynth/event.h +++ b/fluidsynth/include/fluidsynth/event.h @@ -45,7 +45,7 @@ enum fluid_seq_event_type { FLUID_SEQ_PROGRAMCHANGE, /**< Program change message */ FLUID_SEQ_PROGRAMSELECT, /**< Program select message (DOCME) */ FLUID_SEQ_PITCHBEND, /**< Pitch bend message */ - FLUID_SEQ_PITCHWHHELSENS, /**< Pitch wheel sensitivity set message */ + FLUID_SEQ_PITCHWHHELSENS, /**< Pitch wheel sensitivity set message TODO: Correct spelling of this event? */ FLUID_SEQ_MODULATION, /**< Modulation controller event */ FLUID_SEQ_SUSTAIN, /**< Sustain controller event */ FLUID_SEQ_CONTROLCHANGE, /**< MIDI control change event */ @@ -55,6 +55,8 @@ enum fluid_seq_event_type { FLUID_SEQ_CHORUSSEND, /**< Chorus send set event */ 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_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 */ }; @@ -71,7 +73,7 @@ FLUIDSYNTH_API void fluid_event_set_dest(fluid_event_t* evt, short dest); FLUIDSYNTH_API void fluid_event_timer(fluid_event_t* evt, void* data); /* Note events */ -FLUIDSYNTH_API void fluid_event_note(fluid_event_t* evt, int channel, +FLUIDSYNTH_API void fluid_event_nfluid_event_set_timeote(fluid_event_t* evt, int channel, short key, short vel, unsigned int duration); @@ -99,6 +101,10 @@ 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_channel_pressure(fluid_event_t* evt, int channel, short val); +FLUIDSYNTH_API void fluid_event_system_reset(fluid_event_t* evt); + + /* Only for removing events */ FLUIDSYNTH_API void fluid_event_any_control_change(fluid_event_t* evt, int channel); diff --git a/fluidsynth/include/fluidsynth/seqbind.h b/fluidsynth/include/fluidsynth/seqbind.h index 09fb46ac..18560e20 100644 --- a/fluidsynth/include/fluidsynth/seqbind.h +++ b/fluidsynth/include/fluidsynth/seqbind.h @@ -35,6 +35,8 @@ extern "C" { FLUIDSYNTH_API short fluid_sequencer_register_fluidsynth(fluid_sequencer_t* seq, fluid_synth_t* synth); +int +fluid_sequencer_add_midi_event_to_buffer(void* data, fluid_midi_event_t* event); #ifdef __cplusplus diff --git a/fluidsynth/include/fluidsynth/synth.h b/fluidsynth/include/fluidsynth/synth.h index 912e4c56..cd3fee33 100644 --- a/fluidsynth/include/fluidsynth/synth.h +++ b/fluidsynth/include/fluidsynth/synth.h @@ -107,6 +107,9 @@ FLUIDSYNTH_API int fluid_synth_get_pitch_wheel_sens(fluid_synth_t* synth, int ch /** Send a program change message. Returns 0 if no error occurred, -1 otherwise. */ FLUIDSYNTH_API int fluid_synth_program_change(fluid_synth_t* synth, int chan, int program); + /** Send a channel aftertouch message. Returns 0 if no error occurred, -1 otherwise. */ +FLUIDSYNTH_API int fluid_synth_channel_pressure(fluid_synth_t* synth, int chan, int val); + /** Select a bank. Returns 0 if no error occurred, -1 otherwise. */ FLUIDSYNTH_API int fluid_synth_bank_select(fluid_synth_t* synth, int chan, unsigned int bank); diff --git a/fluidsynth/src/fluid_event.c b/fluidsynth/src/fluid_event.c index 50c22922..05b370c0 100644 --- a/fluidsynth/src/fluid_event.c +++ b/fluidsynth/src/fluid_event.c @@ -38,6 +38,17 @@ /* Event alloc/free */ +void +fluid_event_clear(fluid_event_t* evt) +{ + FLUID_MEMSET(evt, 0, sizeof(fluid_event_t)); + + // by default, no type + evt->dest = -1; + evt->src = -1; + evt->type = -1; +} + /** * Create a new sequencer event structure. * @return New sequencer event structure or NULL if out of memory @@ -52,13 +63,7 @@ new_fluid_event() fluid_log(FLUID_PANIC, "event: Out of memory\n"); return NULL; } - - FLUID_MEMSET(evt, 0, sizeof(fluid_event_t)); - - // by default, no type - evt->dest = -1; - evt->src = -1; - evt->type = -1; + fluid_event_clear(evt); return(evt); } @@ -402,6 +407,7 @@ fluid_event_chorus_send(fluid_event_t* evt, int channel, short val) /** * Set a sequencer event to be an unregistering event. * @param evt Sequencer event structure + * @since 1.1.0 */ void fluid_event_unregistering(fluid_event_t* evt) @@ -409,6 +415,34 @@ fluid_event_unregistering(fluid_event_t* evt) evt->type = FLUID_SEQ_UNREGISTERING; } +/** + * Set a sequencer event to be a channel-wide aftertouch event. + * @param evt Sequencer event structure + * @param channel MIDI channel number + * @param val Aftertouch amount (0-127) + * @since 1.1.0 + */ +void +fluid_event_channel_pressure(fluid_event_t* evt, int channel, short val) +{ + evt->type = FLUID_SEQ_CHANNELPRESSURE; + evt->channel = channel; + if (val < 0) val = 0; + if (val > 127) val = 127; + evt->value = val; +} + +/** + * Set a sequencer event to be a midi system reset event. + * @param evt Sequencer event structure + * @since 1.1.0 + */ +void +fluid_event_system_reset(fluid_event_t* evt) +{ + evt->type = FLUID_SEQ_SYSTEMRESET; +} + /* diff --git a/fluidsynth/src/fluid_event_priv.h b/fluidsynth/src/fluid_event_priv.h index 619381c4..244ae1d3 100644 --- a/fluidsynth/src/fluid_event_priv.h +++ b/fluidsynth/src/fluid_event_priv.h @@ -46,6 +46,8 @@ struct _fluid_event_t { unsigned int fluid_event_get_time(fluid_event_t* evt); void fluid_event_set_time(fluid_event_t* evt, unsigned int time); +void fluid_event_clear(fluid_event_t* evt); + /* private data for sorter + heap */ enum fluid_evt_entry_type { FLUID_EVT_ENTRY_INSERT = 0, diff --git a/fluidsynth/src/fluid_seq.c b/fluidsynth/src/fluid_seq.c index c7c1ea7e..46a2019d 100644 --- a/fluidsynth/src/fluid_seq.c +++ b/fluidsynth/src/fluid_seq.c @@ -42,7 +42,7 @@ /* Private data for SEQUENCER */ struct _fluid_sequencer_t { unsigned int startMs; - unsigned int currentMs; + gint currentMs; gboolean useSystemTimer; double scale; // ticks per second fluid_list_t* clients; @@ -379,6 +379,7 @@ void fluid_sequencer_send_now(fluid_sequencer_t* seq, fluid_event_t* evt) } } + int fluid_sequencer_send_at(fluid_sequencer_t* seq, fluid_event_t* evt, unsigned int time, int absolute) { @@ -392,16 +393,17 @@ fluid_sequencer_send_at(fluid_sequencer_t* seq, fluid_event_t* evt, unsigned int fluid_event_set_time(evt, time); /* process late */ - if (time < now) { +/* Commented out for thread safety - send_at must go via the queue */ +/* if (time < now) { fluid_sequencer_send_now(seq, evt); return 0; - } + }*/ /* process now */ - if (time == now) { +/* if (time == now) { fluid_sequencer_send_now(seq, evt); return 0; - } + }*/ /* queue for processing later */ return _fluid_seq_queue_pre_insert(seq, evt); @@ -419,7 +421,7 @@ fluid_sequencer_remove_events(fluid_sequencer_t* seq, short source, short dest, **************************************/ unsigned int fluid_sequencer_get_tick(fluid_sequencer_t* seq) { - unsigned int absMs = seq->useSystemTimer ? fluid_curtime() : seq->currentMs; + unsigned int absMs = seq->useSystemTimer ? (int) fluid_curtime() : g_atomic_int_get(&seq->currentMs); double nowFloat; unsigned int now; nowFloat = ((double)(absMs - seq->startMs))*seq->scale/1000.0f; @@ -763,7 +765,7 @@ fluid_sequencer_process(fluid_sequencer_t* seq, unsigned int msec) } /* send queued events */ - seq->currentMs = msec; + g_atomic_int_set(&seq->currentMs, msec); _fluid_seq_queue_send_queued_events(seq); } diff --git a/fluidsynth/src/fluid_seqbind.c b/fluidsynth/src/fluid_seqbind.c index d19c5abd..a0dfbf24 100644 --- a/fluidsynth/src/fluid_seqbind.c +++ b/fluidsynth/src/fluid_seqbind.c @@ -29,6 +29,8 @@ #include "fluidsynth_priv.h" #include "fluid_synth.h" +#include "fluid_midi.h" +#include "fluid_event_priv.h" /*************************************************************** * @@ -229,6 +231,18 @@ fluid_seq_fluidsynth_callback(unsigned int time, fluid_event_t* evt, fluid_seque } break; + case FLUID_SEQ_CHANNELPRESSURE: + { + fluid_synth_channel_pressure(synth, fluid_event_get_channel(evt), fluid_event_get_value(evt)); + } + break; + + case FLUID_SEQ_SYSTEMRESET: + { + fluid_synth_system_reset(synth); + } + break; + case FLUID_SEQ_UNREGISTERING: /* free ourselves */ { seqbind->client_id = -1; /* avoid recursive call to fluid_sequencer_unregister_client */ @@ -245,4 +259,70 @@ fluid_seq_fluidsynth_callback(unsigned int time, fluid_event_t* evt, fluid_seque } } +static int get_fluidsynth_dest(fluid_sequencer_t* seq) +{ + int i, id; + char* name; + int j = fluid_sequencer_count_clients(seq); + for (i = 0; i < j; i++) { + id = fluid_sequencer_get_client_id(seq, i); + name = fluid_sequencer_get_client_name(seq, id); + if (strcmp(name, "fluidsynth") == 0) { + return id; + } + } + return -1; +} + +/** + * Transforms an incoming midi event (from a midi driver or midi router) to a + * sequencer event and adds it to the sequencer queue for sending as soon as possible. + * @param data the sequencer, must be a valid fluid_sequencer_t + * @param event midi event + * @return FLUID_OK or FLUID_FAILED + * @since 1.1.0 + */ +int +fluid_sequencer_add_midi_event_to_buffer(void* data, fluid_midi_event_t* event) +{ + fluid_event_t evt; + fluid_sequencer_t* seq = (fluid_sequencer_t*) data; + int chan = fluid_midi_event_get_channel(event); + + fluid_event_clear(&evt); + fluid_event_set_time(&evt, fluid_sequencer_get_tick(seq)); + fluid_event_set_dest(&evt, get_fluidsynth_dest(seq)); + + switch (fluid_midi_event_get_type(event)) { + case NOTE_OFF: + fluid_event_noteoff(&evt, chan, fluid_midi_event_get_key(event)); + break; + case NOTE_ON: + fluid_event_noteon(&evt, fluid_midi_event_get_channel(event), + fluid_midi_event_get_key(event), fluid_midi_event_get_velocity(event)); + break; + case CONTROL_CHANGE: + fluid_event_control_change(&evt, chan, fluid_midi_event_get_control(event), + fluid_midi_event_get_value(event)); + break; + case PROGRAM_CHANGE: + fluid_event_program_change(&evt, chan, fluid_midi_event_get_program(event)); + break; + case PITCH_BEND: + fluid_event_pitch_bend(&evt, chan, fluid_midi_event_get_pitch(event)); + break; + case CHANNEL_PRESSURE: + fluid_event_channel_pressure(&evt, chan, fluid_midi_event_get_program(event)); + break; + case MIDI_SYSTEM_RESET: + fluid_event_system_reset(&evt); + break; + default: /* Not yet implemented */ + return FLUID_FAILED; + } + + /* Schedule for sending at next call to fluid_sequencer_process */ + return fluid_sequencer_send_at(seq, &evt, 0, 0); +} +