mirror of
https://github.com/ZDoom/fluidsynth.git
synced 2024-12-11 05:11:33 +00:00
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:
parent
422924ee45
commit
2579d853fb
4 changed files with 175 additions and 25 deletions
|
@ -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 */
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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))
|
/* MIDI tuning SYSEX message? */
|
||||||
return FLUID_OK;
|
if ((data[0] == MIDI_SYSEX_UNIV_NON_REALTIME || data[0] == MIDI_SYSEX_UNIV_REALTIME)
|
||||||
|
&& (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;
|
||||||
|
}
|
||||||
|
|
||||||
/* Device ID isn't wildcard and doesn't match our device ID? */
|
|
||||||
if (data[1] != synth->device_id && data[1] != MIDI_SYSEX_DEVICE_ID_ALL)
|
|
||||||
return FLUID_OK;
|
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);
|
||||||
|
|
|
@ -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) */
|
||||||
|
|
Loading…
Reference in a new issue