diff --git a/src/midi/fluid_midi.h b/src/midi/fluid_midi.h index da5c4128..4b33383c 100644 --- a/src/midi/fluid_midi.h +++ b/src/midi/fluid_midi.h @@ -178,6 +178,7 @@ enum midi_meta_event enum midi_sysex_manuf { MIDI_SYSEX_MANUF_ROLAND = 0x41, /**< Roland manufacturer ID */ + MIDI_SYSEX_MANUF_YAMAHA = 0x43, MIDI_SYSEX_UNIV_NON_REALTIME = 0x7E, /**< Universal non realtime message */ MIDI_SYSEX_UNIV_REALTIME = 0x7F /**< Universal realtime message */ }; @@ -188,6 +189,7 @@ enum midi_sysex_manuf #define MIDI_SYSEX_MIDI_TUNING_ID 0x08 /**< Sysex sub-ID #1 for MIDI tuning messages */ #define MIDI_SYSEX_GM_ID 0x09 /**< Sysex sub-ID #1 for General MIDI messages */ #define MIDI_SYSEX_GS_ID 0x42 /**< Model ID (GS) serving as sub-ID #1 for GS messages*/ +#define MIDI_SYSEX_XG_ID 0x4C /**< Model ID (XG) serving as sub-ID #1 for XG messages*/ /** * SYSEX tuning message IDs. @@ -209,6 +211,7 @@ enum midi_sysex_tuning_msg_id /* General MIDI sub-ID #2 */ #define MIDI_SYSEX_GM_ON 0x01 /**< Enable GM mode */ #define MIDI_SYSEX_GM_OFF 0x02 /**< Disable GM mode */ +#define MIDI_SYSEX_GM2_ON 0x03 /**< Enable GM2 mode */ #define MIDI_SYSEX_GS_DT1 0x12 /**< GS DT1 command */ enum fluid_driver_status diff --git a/src/synth/fluid_synth.c b/src/synth/fluid_synth.c index 89def2fd..d9946317 100644 --- a/src/synth/fluid_synth.c +++ b/src/synth/fluid_synth.c @@ -70,6 +70,10 @@ static int fluid_synth_sysex_gs_dt1(fluid_synth_t *synth, const char *data, int len, char *response, int *response_len, int avail_response, int *handled, int dryrun); +static int fluid_synth_sysex_xg(fluid_synth_t *synth, const char *data, + int len, char *response, + int *response_len, int avail_response, + int *handled, int dryrun); int fluid_synth_all_notes_off_LOCAL(fluid_synth_t *synth, int chan); static int fluid_synth_all_sounds_off_LOCAL(fluid_synth_t *synth, int chan); static int fluid_synth_system_reset_LOCAL(fluid_synth_t *synth); @@ -2012,9 +2016,29 @@ fluid_synth_sysex(fluid_synth_t *synth, const char *data, int len, FLUID_API_RETURN(result); } + /* GM or GM2 system on */ + if(data[0] == MIDI_SYSEX_UNIV_NON_REALTIME + && (data[1] == synth->device_id || data[1] == MIDI_SYSEX_DEVICE_ID_ALL) + && data[2] == MIDI_SYSEX_GM_ID) + { + if(handled) + { + *handled = TRUE; + } + if(!dryrun && (data[3] == MIDI_SYSEX_GM_ON + || data[3] == MIDI_SYSEX_GM2_ON)) + { + int result; + synth->bank_select = FLUID_BANK_STYLE_GM; + fluid_synth_api_enter(synth); + result = fluid_synth_system_reset_LOCAL(synth); + FLUID_API_RETURN(result); + } + return FLUID_OK; + } + /* GS DT1 message */ - if((synth->bank_select == FLUID_BANK_STYLE_GS) - && data[0] == MIDI_SYSEX_MANUF_ROLAND + if(data[0] == MIDI_SYSEX_MANUF_ROLAND && (data[1] == synth->device_id || data[1] == MIDI_SYSEX_DEVICE_ID_ALL) && data[2] == MIDI_SYSEX_GS_ID && data[3] == MIDI_SYSEX_GS_DT1) @@ -2027,6 +2051,19 @@ fluid_synth_sysex(fluid_synth_t *synth, const char *data, int len, FLUID_API_RETURN(result); } + /* XG message */ + if(data[0] == MIDI_SYSEX_MANUF_YAMAHA + && (data[1] == synth->device_id || data[1] == MIDI_SYSEX_DEVICE_ID_ALL) + && data[2] == MIDI_SYSEX_XG_ID) + { + int result; + fluid_synth_api_enter(synth); + result = fluid_synth_sysex_xg(synth, data, len, response, + response_len, avail_response, + handled, dryrun); + FLUID_API_RETURN(result); + } + return FLUID_OK; } @@ -2348,6 +2385,36 @@ fluid_synth_sysex_gs_dt1(fluid_synth_t *synth, const char *data, int len, return FLUID_FAILED; } + if (addr == 0x40007F) // Mode set + { + if (len_data > 1 || (data[7] != 0 && data[7] != 0x7f)) + { + return FLUID_FAILED; + } + if (handled) + { + *handled = TRUE; + } + if (!dryrun) + { + if (data[7] == 0) + { + synth->bank_select = FLUID_BANK_STYLE_GS; + } + else + { + synth->bank_select = FLUID_BANK_STYLE_GM; + } + return fluid_synth_system_reset_LOCAL(synth); + } + return FLUID_OK; + } + + if (synth->bank_select != FLUID_BANK_STYLE_GS) + { + return FLUID_OK; // Silently ignore all other messages + } + if ((addr & 0xFFF0FF) == 0x401015) // Use for rhythm part { if (len_data > 1 || data[7] > 0x02) @@ -2377,6 +2444,51 @@ fluid_synth_sysex_gs_dt1(fluid_synth_t *synth, const char *data, int len, return FLUID_OK; } +/* Handler for XG messages */ +static int +fluid_synth_sysex_xg(fluid_synth_t *synth, const char *data, int len, + char *response, int *response_len, int avail_response, + int *handled, int dryrun) +{ + int addr; + int len_data; + + if(len < 7) // at least one byte of data should be transmitted + { + return FLUID_FAILED; + } + len_data = len - 6; + addr = (data[3] << 16) | (data[4] << 8) | data[5]; + + if (addr == 0x00007E // Reset + || addr == 0x00007F) // Reset to factory + { + if (len_data > 1 || data[6] != 0) + { + return FLUID_FAILED; + } + if (handled) + { + *handled = TRUE; + } + if (!dryrun) + { + synth->bank_select = FLUID_BANK_STYLE_XG; + return fluid_synth_system_reset_LOCAL(synth); + } + return FLUID_OK; + } + + /* No other messages handled yet + if (synth->bank_select != FLUID_BANK_STYLE_XG) + { + return FLUID_OK; // Silently ignore all other messages + }*/ + + //silently ignore + return FLUID_OK; +} + /** * Turn off all voices that are playing on the given MIDI channel, by putting them into release phase. * @param synth FluidSynth instance