Added FLUID_EVENT_QUEUE_ELEM_MIDI_MODE event queue event.

Added handling of GM On/Off and GS reset SYSEX messages.
Added synth.midi-mode-lock parameter to prevent SYSEX messages from changing MIDI mode.
If MIDI mode is set to "gm" or "gs" then note-offs are ignored for percussion instruments (except Long Guiro and Long Whistle).
Split off MIDI Tuning Standard SYSEX messages into fluid_synth_sysex_midi_tuning.
This commit is contained in:
Josh Green 2009-10-08 05:31:11 +00:00
parent 422924ee45
commit 2579d853fb
4 changed files with 175 additions and 25 deletions

View file

@ -41,6 +41,7 @@ enum fluid_event_queue_elem
FLUID_EVENT_QUEUE_ELEM_SET_TUNING, /**< Set tuning event. Uses set_tuning field of event value */ FLUID_EVENT_QUEUE_ELEM_SET_TUNING, /**< Set tuning event. Uses set_tuning field of event value */
FLUID_EVENT_QUEUE_ELEM_REPL_TUNING, /**< Replace tuning event. Uses repl_tuning field of event value */ FLUID_EVENT_QUEUE_ELEM_REPL_TUNING, /**< Replace tuning event. Uses repl_tuning field of event value */
FLUID_EVENT_QUEUE_ELEM_UNREF_TUNING, /**< Unref tuning return event. Uses unref_tuning field of event value */ FLUID_EVENT_QUEUE_ELEM_UNREF_TUNING, /**< Unref tuning return event. Uses unref_tuning field of event value */
FLUID_EVENT_QUEUE_ELEM_MIDI_MODE /**< Set MIDI mode event. Uses ival field of event value */
}; };
/** /**

View file

@ -171,15 +171,20 @@ enum midi_meta_event {
/* MIDI SYSEX useful manufacturer values */ /* MIDI SYSEX useful manufacturer values */
enum midi_sysex_manuf { enum midi_sysex_manuf {
MIDI_SYSEX_MANUF_ROLAND = 0x41, /**< Roland manufacturer ID */
MIDI_SYSEX_UNIV_NON_REALTIME = 0x7E, /**< Universal non realtime message */ MIDI_SYSEX_UNIV_NON_REALTIME = 0x7E, /**< Universal non realtime message */
MIDI_SYSEX_UNIV_REALTIME = 0x7F /**< Universal realtime message */ MIDI_SYSEX_UNIV_REALTIME = 0x7F /**< Universal realtime message */
}; };
#define MIDI_SYSEX_DEVICE_ID_ALL 0x7F /**< Device ID used in SYSEX messages to indicate all devices */ #define MIDI_SYSEX_DEVICE_ID_ALL 0x7F /**< Device ID used in SYSEX messages to indicate all devices */
/* Sysex sub-ID #1 (following the device ID) for MIDI tuning messages */ /* SYSEX sub-ID #1 which follows device ID */
#define MIDI_SYSEX_MIDI_TUNING_ID 0x08 #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 */
/**
* SYSEX tuning message IDs.
*/
enum midi_sysex_tuning_msg_id { enum midi_sysex_tuning_msg_id {
MIDI_SYSEX_TUNING_BULK_DUMP_REQ = 0x00, /**< Bulk tuning dump request (non-realtime) */ MIDI_SYSEX_TUNING_BULK_DUMP_REQ = 0x00, /**< Bulk tuning dump request (non-realtime) */
MIDI_SYSEX_TUNING_BULK_DUMP = 0x01, /**< Bulk tuning dump response (non-realtime) */ MIDI_SYSEX_TUNING_BULK_DUMP = 0x01, /**< Bulk tuning dump response (non-realtime) */
@ -193,6 +198,10 @@ enum midi_sysex_tuning_msg_id {
MIDI_SYSEX_TUNING_OCTAVE_TUNE_2BYTE = 0x09 /**< Octave tuning message using 2 byte values (realtime/non-realtime) */ MIDI_SYSEX_TUNING_OCTAVE_TUNE_2BYTE = 0x09 /**< Octave tuning message using 2 byte values (realtime/non-realtime) */
}; };
/* General MIDI sub-ID #2 */
#define MIDI_SYSEX_GM_ON 0x01 /**< Enable GM mode */
#define MIDI_SYSEX_GM_OFF 0x02 /**< Disable GM mode */
enum fluid_driver_status enum fluid_driver_status
{ {
FLUID_MIDI_READY, FLUID_MIDI_READY,

View file

@ -61,6 +61,16 @@ static int fluid_synth_cc_real(fluid_synth_t* synth, int channum, int num,
int value, int noqueue); int value, int noqueue);
static int fluid_synth_update_device_id (fluid_synth_t *synth, char *name, static int fluid_synth_update_device_id (fluid_synth_t *synth, char *name,
int value); int value);
static int fluid_synth_update_midi_mode (fluid_synth_t *synth, char *name,
char *value);
static int fluid_synth_update_midi_mode_lock (fluid_synth_t *synth, char *name,
char *value);
static void fluid_synth_set_midi_mode_LOCAL (fluid_synth_t *synth,
fluid_synth_midi_mode_t mode);
static int fluid_synth_sysex_midi_tuning (fluid_synth_t *synth, char *data,
int len, char *response,
int *response_len, int avail_response,
int *handled, int dryrun);
static int fluid_synth_all_notes_off_LOCAL(fluid_synth_t* synth, int chan); static 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_all_sounds_off_LOCAL(fluid_synth_t* synth, int chan);
static int fluid_synth_system_reset_LOCAL(fluid_synth_t* synth); static int fluid_synth_system_reset_LOCAL(fluid_synth_t* synth);
@ -239,6 +249,10 @@ void fluid_synth_settings(fluid_settings_t* settings)
fluid_settings_add_option(settings, "synth.midi-mode", "normal"); fluid_settings_add_option(settings, "synth.midi-mode", "normal");
fluid_settings_add_option(settings, "synth.midi-mode", "gm"); fluid_settings_add_option(settings, "synth.midi-mode", "gm");
fluid_settings_add_option(settings, "synth.midi-mode", "gs"); fluid_settings_add_option(settings, "synth.midi-mode", "gs");
fluid_settings_register_str(settings, "synth.midi-mode-lock", "no", 0, NULL, NULL);
fluid_settings_add_option(settings, "synth.midi-mode-lock", "no");
fluid_settings_add_option(settings, "synth.midi-mode-lock", "yes");
} }
/* /*
@ -550,6 +564,7 @@ new_fluid_synth(fluid_settings_t *settings)
synth->with_chorus = fluid_settings_str_equal(settings, "synth.chorus.active", "yes"); synth->with_chorus = fluid_settings_str_equal(settings, "synth.chorus.active", "yes");
synth->verbose = fluid_settings_str_equal(settings, "synth.verbose", "yes"); synth->verbose = fluid_settings_str_equal(settings, "synth.verbose", "yes");
synth->dump = fluid_settings_str_equal(settings, "synth.dump", "yes"); synth->dump = fluid_settings_str_equal(settings, "synth.dump", "yes");
synth->midi_mode_lock = fluid_settings_str_equal(settings, "synth.midi-mode-lock", "yes");
fluid_settings_getint(settings, "synth.polyphony", &synth->polyphony); fluid_settings_getint(settings, "synth.polyphony", &synth->polyphony);
fluid_settings_getnum(settings, "synth.sample-rate", &synth->sample_rate); fluid_settings_getnum(settings, "synth.sample-rate", &synth->sample_rate);
@ -571,7 +586,11 @@ new_fluid_synth(fluid_settings_t *settings)
synth); synth);
fluid_settings_register_int(settings, "synth.device-id", fluid_settings_register_int(settings, "synth.device-id",
synth->device_id, 126, 0, 0, synth->device_id, 126, 0, 0,
(fluid_int_update_t) fluid_synth_update_device_id, NULL); (fluid_int_update_t) fluid_synth_update_device_id, synth);
fluid_settings_register_str(settings, "synth.midi-mode", "normal", 0,
(fluid_str_update_t) fluid_synth_update_midi_mode, synth);
fluid_settings_register_str(settings, "synth.midi-mode-lock", "no", 0,
(fluid_str_update_t) fluid_synth_update_midi_mode_lock, synth);
/* do some basic sanity checking on the settings */ /* do some basic sanity checking on the settings */
@ -1351,9 +1370,21 @@ fluid_synth_noteoff(fluid_synth_t* synth, int chan, int key)
static int static int
fluid_synth_noteoff_LOCAL(fluid_synth_t* synth, int chan, int key) fluid_synth_noteoff_LOCAL(fluid_synth_t* synth, int chan, int key)
{ {
int i;
fluid_voice_t* voice; fluid_voice_t* voice;
int status = FLUID_FAILED; int status = FLUID_FAILED;
int midi_mode;
int i;
/* We ignore percussion note offs in GM/GS for everything except
* Long Guiro and Long Whistle, as per GM revision 2 spec - JG */
if (chan == 9)
{
midi_mode = fluid_atomic_int_get (&synth->midi_mode);
if ((midi_mode == FLUID_SYNTH_MIDI_MODE_GM || midi_mode == FLUID_SYNTH_MIDI_MODE_GS)
&& key != 72 && key != 74)
return FLUID_OK;
}
for (i = 0; i < synth->polyphony; i++) { for (i = 0; i < synth->polyphony; i++) {
voice = synth->voice[i]; voice = synth->voice[i];
@ -1588,6 +1619,60 @@ fluid_synth_update_device_id (fluid_synth_t *synth, char *name, int value)
return 0; return 0;
} }
/* Handler for synth.midi-mode setting. */
static int
fluid_synth_update_midi_mode (fluid_synth_t *synth, char *name, char *value)
{
int mode = FLUID_SYNTH_MIDI_MODE_NORMAL;
if (FLUID_STRCMP (value, "gm") == 0)
mode = FLUID_SYNTH_MIDI_MODE_GM;
else if (FLUID_STRCMP (value, "gs") == 0)
mode = FLUID_SYNTH_MIDI_MODE_GS;
if (fluid_synth_should_queue (synth))
fluid_synth_queue_int_event (synth, FLUID_EVENT_QUEUE_ELEM_MIDI_MODE, mode);
else fluid_synth_set_midi_mode_LOCAL (synth, mode);
return 0;
}
/* Local synthesis context version of set MIDI mode */
static void
fluid_synth_set_midi_mode_LOCAL (fluid_synth_t *synth, fluid_synth_midi_mode_t mode)
{
char *modestr;
if (synth->verbose)
{
switch (mode)
{
case FLUID_SYNTH_MIDI_MODE_GM:
modestr = "gm";
break;
case FLUID_SYNTH_MIDI_MODE_GS:
modestr = "gs";
break;
default:
modestr = "default";
break;
}
FLUID_LOG (FLUID_INFO, "midimode\t%s", modestr);
}
fluid_atomic_int_set (&synth->midi_mode, mode);
}
/* Handler for synth.midi-mode-lock setting. */
static int
fluid_synth_update_midi_mode_lock (fluid_synth_t *synth, char *name, char *value)
{
fluid_atomic_int_set (&synth->midi_mode_lock,
value && FLUID_STRCMP (value, "yes") == 0);
return 0;
}
/** /**
* Process a MIDI SYSEX (system exclusive) message. * Process a MIDI SYSEX (system exclusive) message.
* @param synth FluidSynth instance * @param synth FluidSynth instance
@ -1614,15 +1699,6 @@ fluid_synth_sysex(fluid_synth_t *synth, char *data, int len,
char *response, int *response_len, int *handled, int dryrun) char *response, int *response_len, int *handled, int dryrun)
{ {
int avail_response = 0; int avail_response = 0;
int realtime, msgid;
int bank = 0, prog, channels;
double tunedata[128];
int keys[128];
char name[17];
int note, frac, frac2;
uint8 chksum;
int i, count, index;
char *dataptr;
if (handled) *handled = FALSE; if (handled) *handled = FALSE;
@ -1637,21 +1713,68 @@ fluid_synth_sysex(fluid_synth_t *synth, char *data, int len,
fluid_return_val_if_fail (len > 0, FLUID_FAILED); fluid_return_val_if_fail (len > 0, FLUID_FAILED);
fluid_return_val_if_fail (!response || response_len, FLUID_FAILED); fluid_return_val_if_fail (!response || response_len, FLUID_FAILED);
/* Not enough data or not a universal realtime or non-realtime message? */ if (len < 6) return FLUID_OK;
if (len < 6 || (data[0] != MIDI_SYSEX_UNIV_NON_REALTIME
&& data[0] != MIDI_SYSEX_UNIV_REALTIME))
return FLUID_OK;
/* Device ID isn't wildcard and doesn't match our device ID? */ /* MIDI tuning SYSEX message? */
if (data[1] != synth->device_id && data[1] != MIDI_SYSEX_DEVICE_ID_ALL) if ((data[0] == MIDI_SYSEX_UNIV_NON_REALTIME || data[0] == MIDI_SYSEX_UNIV_REALTIME)
return FLUID_OK; && (data[1] == synth->device_id || data[1] == MIDI_SYSEX_DEVICE_ID_ALL)
&& data[2] == MIDI_SYSEX_MIDI_TUNING_ID)
return fluid_synth_sysex_midi_tuning (synth, data, len, response, response_len,
avail_response, handled, dryrun);
/* General MIDI message? */
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)
{
switch (data[3])
{
case MIDI_SYSEX_GM_ON:
if (!fluid_atomic_int_get (&synth->midi_mode_lock))
fluid_synth_setstr (synth, "synth.midi-mode", "gm");
if (handled) *handled = FALSE;
break;
case MIDI_SYSEX_GM_OFF:
if (!fluid_atomic_int_get (&synth->midi_mode_lock))
fluid_synth_setstr (synth, "synth.midi-mode", "normal");
if (handled) *handled = FALSE;
break;
}
}
/* GS reset message? */
if (data[0] == MIDI_SYSEX_MANUF_ROLAND
&& data[1] == 0x10 && data[2] == 0x42 && data[3] == 0x12 && data[4] == 0x40
&& data[5] == 0x00 && data[6] == 0x7F && data[7] == 0x00 && data[8] == 0x41)
{
if (!fluid_atomic_int_get (&synth->midi_mode_lock))
fluid_synth_setstr (synth, "synth.midi-mode", "gs");
if (handled) *handled = FALSE;
}
return FLUID_OK;
}
/* Handler for MIDI tuning SYSEX messages */
static int
fluid_synth_sysex_midi_tuning (fluid_synth_t *synth, char *data, int len,
char *response, int *response_len, int avail_response,
int *handled, int dryrun)
{
int realtime, msgid;
int bank = 0, prog, channels;
double tunedata[128];
int keys[128];
char name[17];
int note, frac, frac2;
uint8 chksum;
int i, count, index;
char *dataptr;
realtime = data[0] == MIDI_SYSEX_UNIV_REALTIME; realtime = data[0] == MIDI_SYSEX_UNIV_REALTIME;
/* Not a MIDI Tuning Standard message? */
if (data[2] != MIDI_SYSEX_MIDI_TUNING_ID)
return FLUID_OK;
msgid = data[3]; msgid = data[3];
switch (msgid) switch (msgid)
@ -3405,6 +3528,9 @@ fluid_synth_process_event_queue_LOCAL (fluid_synth_t *synth,
event->repl_tuning.new_tuning, event->repl_tuning.new_tuning,
event->repl_tuning.apply, TRUE); event->repl_tuning.apply, TRUE);
break; break;
case FLUID_EVENT_QUEUE_ELEM_MIDI_MODE:
fluid_synth_set_midi_mode_LOCAL (synth, event->ival);
break;
} }
fluid_event_queue_next_outptr (queue); fluid_event_queue_next_outptr (queue);

View file

@ -77,6 +77,16 @@ enum fluid_synth_status
#define SYNTH_REVERB_CHANNEL 0 #define SYNTH_REVERB_CHANNEL 0
#define SYNTH_CHORUS_CHANNEL 1 #define SYNTH_CHORUS_CHANNEL 1
/**
* Defines the current MIDI mode.
*/
typedef enum
{
FLUID_SYNTH_MIDI_MODE_NORMAL, /**< Normal MIDI mode (percussion channel not special) */
FLUID_SYNTH_MIDI_MODE_GM, /**< GM MIDI mode, no note-offs on percussion channel (except for long guiro and whistle) */
FLUID_SYNTH_MIDI_MODE_GS /**< GS MIDI mode, identical to #FLUID_SYNTH_MIDI_MODE_GM at the moment */
} fluid_synth_midi_mode_t;
/** /**
* Structure used for sfont_info field in #fluid_synth_t for each loaded * Structure used for sfont_info field in #fluid_synth_t for each loaded
* SoundFont with the SoundFont instance and additional fields. * SoundFont with the SoundFont instance and additional fields.
@ -131,6 +141,8 @@ typedef struct _fluid_sfont_info_t {
* with_reverb * with_reverb
* with_chorus * with_chorus
* state * state
* midi_mode
* midi_mode_lock
* cpu_load * cpu_load
* noteid * noteid
* storeid * storeid
@ -175,6 +187,8 @@ struct _fluid_synth_t
int state; /**< the synthesizer state */ int state; /**< the synthesizer state */
unsigned int ticks; /**< the number of audio samples since the start */ unsigned int ticks; /**< the number of audio samples since the start */
unsigned int start; /**< the start in msec, as returned by system clock */ unsigned int start; /**< the start in msec, as returned by system clock */
int midi_mode; /**< Current MIDI mode (#fluid_synth_midi_mode_t) */
int midi_mode_lock; /**< TRUE if MIDI mode cannot be changed by SYSEX messages */
fluid_list_t *loaders; /**< the SoundFont loaders */ fluid_list_t *loaders; /**< the SoundFont loaders */
fluid_list_t *sfont_info; /**< List of fluid_sfont_info_t for each loaded SoundFont (remains until SoundFont is unloaded) */ fluid_list_t *sfont_info; /**< List of fluid_sfont_info_t for each loaded SoundFont (remains until SoundFont is unloaded) */