mirror of
https://github.com/ZDoom/fluidsynth.git
synced 2024-11-10 15:01:40 +00:00
Tuning unref event is now sent in fluid_channel_init() if there is an old tuning.
Some one liner functions in fluid_chan.c moved to macros in fluid_chan.h. Added tuning_bank and tuning_prog fields to fluid_channel_t. Unnecessary 'if (status & 0x80)' removed from fluid_midi_file_read_event(). Added paramptr field to fluid_midi_event_t for dynamic SYSEX data (size of data stored to param1). SYSEX messages now handled in fluid_midi_file_read_event(). delete_fluid_midi_event() will free paramptr if its a SYSEX message. Removed fluid_midi_send_event() and replaced with fluid_synth_handle_midi_event(). Added some enums and #defines for SYSEX MIDI Tuning Standard messages. Added synth.device-id settings field for SYSEX device ID. Renamed fluid_synth_cc_LOCAL to fluid_synth_cc_real, which now handles event queue determination. Tuning bank and program changes are now handled in fluid_synth_cc_real(). Added fluid_synth_sysex() for processing SYSEX messages (MIDI Tuning Standard messages only currently). Added public fluid_synth_activate_key_tuning() which has an additional apply parameter. Added public fluid_synth_activate_octave_tuning() which has an additional apply parameter. Added public fluid_synth_activate_tuning() which has an additional apply parameter. Added public fluid_synth_deactivate_tuning() which has an additional apply parameter. Reverted behavior of fluid_synth_create_key_tuning, fluid_synth_create_octave_tuning and fluid_synth_reset_tuning, to be non-realtime. SYSEX messages now handled in fluid_synth_handle_midi_event().
This commit is contained in:
parent
ac93e45103
commit
012f627017
6 changed files with 763 additions and 423 deletions
|
@ -65,6 +65,7 @@ new_fluid_channel(fluid_synth_t* synth, int num)
|
|||
static void
|
||||
fluid_channel_init(fluid_channel_t* chan)
|
||||
{
|
||||
fluid_event_queue_elem_t *event;
|
||||
fluid_preset_t *newpreset;
|
||||
int prognum, banknum;
|
||||
|
||||
|
@ -78,9 +79,30 @@ fluid_channel_init(fluid_channel_t* chan)
|
|||
fluid_channel_set_preset(chan, newpreset);
|
||||
|
||||
chan->interp_method = FLUID_INTERP_DEFAULT;
|
||||
chan->tuning = NULL;
|
||||
chan->tuning_bank = 0;
|
||||
chan->tuning_prog = 0;
|
||||
chan->nrpn_select = 0;
|
||||
chan->nrpn_active = 0;
|
||||
|
||||
if (chan->tuning)
|
||||
{
|
||||
event = fluid_event_queue_get_inptr (chan->synth->return_queue);
|
||||
|
||||
if (event)
|
||||
{
|
||||
event->type = FLUID_EVENT_QUEUE_ELEM_UNREF_TUNING;
|
||||
event->unref_tuning.tuning = chan->tuning;
|
||||
event->unref_tuning.count = 1;
|
||||
fluid_event_queue_next_inptr (chan->synth->return_queue);
|
||||
}
|
||||
else
|
||||
{ /* Just unref it in synthesis thread if queue is full */
|
||||
fluid_tuning_unref (chan->tuning, 1);
|
||||
FLUID_LOG (FLUID_ERR, "Synth return event queue full");
|
||||
}
|
||||
|
||||
chan->tuning = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -205,12 +227,6 @@ fluid_channel_set_preset(fluid_channel_t* chan, fluid_preset_t* preset)
|
|||
return FLUID_OK;
|
||||
}
|
||||
|
||||
fluid_preset_t*
|
||||
fluid_channel_get_preset(fluid_channel_t* chan)
|
||||
{
|
||||
return chan->preset;
|
||||
}
|
||||
|
||||
/* Set SoundFont ID, MIDI bank and/or program. Use -1 to use current value. */
|
||||
void
|
||||
fluid_channel_set_sfont_bank_prog(fluid_channel_t* chan, int sfontnum,
|
||||
|
@ -284,43 +300,3 @@ fluid_channel_get_sfont_bank_prog(fluid_channel_t* chan, int *sfont,
|
|||
if (bank) *bank = (sfont_bank_prog & BANK_MASKVAL) >> BANK_SHIFTVAL;
|
||||
if (prog) *prog = (sfont_bank_prog & PROG_MASKVAL) >> PROG_SHIFTVAL;
|
||||
}
|
||||
|
||||
/* Set MIDI custom controller value for a channel */
|
||||
void
|
||||
fluid_channel_set_cc(fluid_channel_t* chan, int num, int val)
|
||||
{
|
||||
if (num >= 0 && num < 128)
|
||||
fluid_atomic_int_set (&chan->cc[num], val);
|
||||
}
|
||||
|
||||
/* Get MIDI custom controller value for a channel */
|
||||
int
|
||||
fluid_channel_get_cc(fluid_channel_t* chan, int num)
|
||||
{
|
||||
return ((num >= 0) && (num < 128)) ? fluid_atomic_int_get (&chan->cc[num]) : 0;
|
||||
}
|
||||
|
||||
/* Get MIDI channel number */
|
||||
int
|
||||
fluid_channel_get_num(fluid_channel_t* chan)
|
||||
{
|
||||
return chan->channum; /* Set only once on channel init */
|
||||
}
|
||||
|
||||
/*
|
||||
* Sets the index of the interpolation method used on this channel,
|
||||
* as in fluid_interp in fluidsynth.h
|
||||
*/
|
||||
void fluid_channel_set_interp_method(fluid_channel_t* chan, int new_method)
|
||||
{
|
||||
fluid_atomic_int_set (&chan->interp_method, new_method);
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns the index of the interpolation method used on this channel,
|
||||
* as in fluid_interp in fluidsynth.h
|
||||
*/
|
||||
int fluid_channel_get_interp_method(fluid_channel_t* chan)
|
||||
{
|
||||
return fluid_atomic_int_get (&chan->interp_method);
|
||||
}
|
||||
|
|
|
@ -70,6 +70,8 @@ struct _fluid_channel_t
|
|||
|
||||
int interp_method; /**< Interpolation method (enum fluid_interp) */
|
||||
fluid_tuning_t* tuning; /**< Micro tuning */
|
||||
int tuning_bank; /**< Current tuning bank number */
|
||||
int tuning_prog; /**< Current tuning program number */
|
||||
|
||||
/* NRPN system */
|
||||
int nrpn_select; /* Generator ID of SoundFont NRPN message */
|
||||
|
@ -112,9 +114,27 @@ int fluid_channel_get_num(fluid_channel_t* chan);
|
|||
void fluid_channel_set_interp_method(fluid_channel_t* chan, int new_method);
|
||||
int fluid_channel_get_interp_method(fluid_channel_t* chan);
|
||||
|
||||
#define fluid_channel_get_preset(chan) ((chan)->preset)
|
||||
#define fluid_channel_set_cc(chan, num, val) \
|
||||
fluid_atomic_int_set (&(chan)->cc[num], val)
|
||||
#define fluid_channel_get_cc(chan, num) \
|
||||
fluid_atomic_int_get (&(chan)->cc[num])
|
||||
#define fluid_channel_get_num(chan) ((chan)->channum)
|
||||
#define fluid_channel_set_interp_method(chan, new_method) \
|
||||
fluid_atomic_int_set (&(chan)->interp_method, new_method)
|
||||
#define fluid_channel_get_interp_method(chan) \
|
||||
fluid_atomic_int_get (&(chan)->interp_method);
|
||||
#define fluid_channel_set_tuning(_c, _t) { (_c)->tuning = _t; }
|
||||
#define fluid_channel_has_tuning(_c) ((_c)->tuning != NULL)
|
||||
#define fluid_channel_get_tuning(_c) ((_c)->tuning)
|
||||
#define fluid_channel_get_tuning_bank(chan) \
|
||||
fluid_atomic_int_get (&(chan)->tuning_bank)
|
||||
#define fluid_channel_set_tuning_bank(chan, bank) \
|
||||
fluid_atomic_int_set (&(chan)->tuning_bank, bank)
|
||||
#define fluid_channel_get_tuning_prog(chan) \
|
||||
fluid_atomic_int_get (&(chan)->tuning_prog)
|
||||
#define fluid_channel_set_tuning_prog(chan, prog) \
|
||||
fluid_atomic_int_set (&(chan)->tuning_prog, prog)
|
||||
#define fluid_channel_sustained(_c) ((_c)->cc[SUSTAIN_SWITCH] >= 64)
|
||||
#define fluid_channel_set_gen(_c, _n, _v, _a) { (_c)->gen[_n] = _v; (_c)->gen_abs[_n] = _a; }
|
||||
#define fluid_channel_get_gen(_c, _n) ((_c)->gen[_n])
|
||||
|
|
|
@ -373,266 +373,264 @@ int fluid_midi_file_read_event(fluid_midi_file* mf, fluid_track_t* track)
|
|||
}
|
||||
|
||||
/* check what message we have */
|
||||
if (status & 0x80) {
|
||||
mf->running_status = status;
|
||||
|
||||
if ((status == MIDI_SYSEX) || (status == MIDI_EOX)) { /* system exclusif */
|
||||
/*
|
||||
* Sysex messages are not handled yet
|
||||
*/
|
||||
/* read the length of the message */
|
||||
if (fluid_midi_file_read_varlen(mf) != FLUID_OK) {
|
||||
mf->running_status = status;
|
||||
|
||||
if ((status == MIDI_SYSEX)) { /* system exclusif */
|
||||
/* read the length of the message */
|
||||
if (fluid_midi_file_read_varlen(mf) != FLUID_OK) {
|
||||
return FLUID_FAILED;
|
||||
}
|
||||
|
||||
if (mf->varlen) {
|
||||
FLUID_LOG(FLUID_DBG, "%s: %d: alloc metadata, len = %d", __FILE__, __LINE__, mf->varlen);
|
||||
metadata = FLUID_MALLOC(mf->varlen + 1);
|
||||
|
||||
if (metadata == NULL) {
|
||||
FLUID_LOG(FLUID_PANIC, "Out of memory");
|
||||
return FLUID_FAILED;
|
||||
}
|
||||
|
||||
if (mf->varlen) {
|
||||
|
||||
if (mf->varlen < 255) {
|
||||
metadata = &static_buf[0];
|
||||
} else {
|
||||
FLUID_LOG(FLUID_DBG, "%s: %d: alloc metadata, len = %d", __FILE__, __LINE__, mf->varlen);
|
||||
dyn_buf = FLUID_MALLOC(mf->varlen + 1);
|
||||
if (dyn_buf == NULL) {
|
||||
FLUID_LOG(FLUID_PANIC, "Out of memory");
|
||||
return FLUID_FAILED;
|
||||
}
|
||||
metadata = dyn_buf;
|
||||
}
|
||||
|
||||
/* read the data of the message */
|
||||
if (fluid_midi_file_read(mf, metadata, mf->varlen) != FLUID_OK) {
|
||||
if (dyn_buf) {
|
||||
FLUID_FREE(dyn_buf);
|
||||
}
|
||||
return FLUID_FAILED;
|
||||
}
|
||||
|
||||
if (dyn_buf) {
|
||||
FLUID_LOG(FLUID_DBG, "%s: %d: free metadata", __FILE__, __LINE__);
|
||||
FLUID_FREE(dyn_buf);
|
||||
}
|
||||
}
|
||||
|
||||
return FLUID_OK;
|
||||
|
||||
} else if (status == MIDI_META_EVENT) { /* meta events */
|
||||
|
||||
int result = FLUID_OK;
|
||||
|
||||
/* get the type of the meta message */
|
||||
type = fluid_midi_file_getc(mf);
|
||||
if (type < 0) {
|
||||
FLUID_LOG(FLUID_ERR, "Unexpected end of file");
|
||||
/* read the data of the message */
|
||||
if (fluid_midi_file_read(mf, metadata, mf->varlen) != FLUID_OK) {
|
||||
FLUID_FREE (metadata);
|
||||
return FLUID_FAILED;
|
||||
}
|
||||
|
||||
/* get the length of the data part */
|
||||
if (fluid_midi_file_read_varlen(mf) != FLUID_OK) {
|
||||
return FLUID_FAILED;
|
||||
}
|
||||
|
||||
if (mf->varlen < 255) {
|
||||
metadata = &static_buf[0];
|
||||
} else {
|
||||
FLUID_LOG(FLUID_DBG, "%s: %d: alloc metadata, len = %d", __FILE__, __LINE__, mf->varlen);
|
||||
dyn_buf = FLUID_MALLOC(mf->varlen + 1);
|
||||
if (dyn_buf == NULL) {
|
||||
FLUID_LOG(FLUID_PANIC, "Out of memory");
|
||||
return FLUID_FAILED;
|
||||
}
|
||||
metadata = dyn_buf;
|
||||
}
|
||||
|
||||
/* read the data */
|
||||
if (mf->varlen)
|
||||
{
|
||||
if (fluid_midi_file_read(mf, metadata, mf->varlen) != FLUID_OK) {
|
||||
if (dyn_buf) {
|
||||
FLUID_FREE(dyn_buf);
|
||||
}
|
||||
return FLUID_FAILED;
|
||||
}
|
||||
}
|
||||
|
||||
/* handle meta data */
|
||||
switch (type) {
|
||||
|
||||
case MIDI_COPYRIGHT:
|
||||
metadata[mf->varlen] = 0;
|
||||
break;
|
||||
|
||||
case MIDI_TRACK_NAME:
|
||||
metadata[mf->varlen] = 0;
|
||||
fluid_track_set_name(track, (char*) metadata);
|
||||
break;
|
||||
|
||||
case MIDI_INST_NAME:
|
||||
metadata[mf->varlen] = 0;
|
||||
break;
|
||||
|
||||
case MIDI_LYRIC:
|
||||
break;
|
||||
|
||||
case MIDI_MARKER:
|
||||
break;
|
||||
|
||||
case MIDI_CUE_POINT:
|
||||
break; /* don't care much for text events */
|
||||
|
||||
case MIDI_EOT:
|
||||
if (mf->varlen != 0) {
|
||||
FLUID_LOG(FLUID_ERR, "Invalid length for EndOfTrack event");
|
||||
result = FLUID_FAILED;
|
||||
break;
|
||||
}
|
||||
mf->eot = 1;
|
||||
break;
|
||||
|
||||
case MIDI_SET_TEMPO:
|
||||
if (mf->varlen != 3) {
|
||||
FLUID_LOG(FLUID_ERR, "Invalid length for SetTempo meta event");
|
||||
result = FLUID_FAILED;
|
||||
break;
|
||||
}
|
||||
tempo = (metadata[0] << 16) + (metadata[1] << 8) + metadata[2];
|
||||
evt = new_fluid_midi_event();
|
||||
if (evt == NULL) {
|
||||
FLUID_LOG(FLUID_ERR, "Out of memory");
|
||||
result = FLUID_FAILED;
|
||||
break;
|
||||
}
|
||||
evt->dtime = mf->dtime;
|
||||
evt->type = MIDI_SET_TEMPO;
|
||||
evt->channel = 0;
|
||||
evt->param1 = tempo;
|
||||
evt->param2 = 0;
|
||||
fluid_track_add_event(track, evt);
|
||||
mf->dtime = 0;
|
||||
break;
|
||||
|
||||
case MIDI_SMPTE_OFFSET:
|
||||
if (mf->varlen != 5) {
|
||||
FLUID_LOG(FLUID_ERR, "Invalid length for SMPTE Offset meta event");
|
||||
result = FLUID_FAILED;
|
||||
break;
|
||||
}
|
||||
break; /* we don't use smtp */
|
||||
|
||||
case MIDI_TIME_SIGNATURE:
|
||||
if (mf->varlen != 4) {
|
||||
FLUID_LOG(FLUID_ERR, "Invalid length for TimeSignature meta event");
|
||||
result = FLUID_FAILED;
|
||||
break;
|
||||
}
|
||||
nominator = metadata[0];
|
||||
denominator = pow(2.0, (double) metadata[1]);
|
||||
clocks = metadata[2];
|
||||
notes = metadata[3];
|
||||
|
||||
FLUID_LOG(FLUID_DBG, "signature=%d/%d, metronome=%d, 32nd-notes=%d",
|
||||
nominator, denominator, clocks, notes);
|
||||
|
||||
break;
|
||||
|
||||
case MIDI_KEY_SIGNATURE:
|
||||
if (mf->varlen != 2) {
|
||||
FLUID_LOG(FLUID_ERR, "Invalid length for KeySignature meta event");
|
||||
result = FLUID_FAILED;
|
||||
break;
|
||||
}
|
||||
sf = metadata[0];
|
||||
mi = metadata[1];
|
||||
break;
|
||||
|
||||
case MIDI_SEQUENCER_EVENT:
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (dyn_buf) {
|
||||
FLUID_LOG(FLUID_DBG, "%s: %d: free metadata", __FILE__, __LINE__);
|
||||
FLUID_FREE(dyn_buf);
|
||||
}
|
||||
|
||||
return result;
|
||||
|
||||
} else { /* channel messages */
|
||||
|
||||
type = status & 0xf0;
|
||||
channel = status & 0x0f;
|
||||
|
||||
/* all channel message have at least 1 byte of associated data */
|
||||
if ((param1 = fluid_midi_file_getc(mf)) < 0) {
|
||||
FLUID_LOG(FLUID_ERR, "Unexpected end of file");
|
||||
return FLUID_FAILED;
|
||||
}
|
||||
|
||||
switch (type) {
|
||||
|
||||
case NOTE_ON:
|
||||
if ((param2 = fluid_midi_file_getc(mf)) < 0) {
|
||||
FLUID_LOG(FLUID_ERR, "Unexpected end of file");
|
||||
return FLUID_FAILED;
|
||||
}
|
||||
break;
|
||||
|
||||
case NOTE_OFF:
|
||||
if ((param2 = fluid_midi_file_getc(mf)) < 0) {
|
||||
FLUID_LOG(FLUID_ERR, "Unexpected end of file");
|
||||
return FLUID_FAILED;
|
||||
}
|
||||
break;
|
||||
|
||||
case KEY_PRESSURE:
|
||||
if ((param2 = fluid_midi_file_getc(mf)) < 0) {
|
||||
FLUID_LOG(FLUID_ERR, "Unexpected end of file");
|
||||
return FLUID_FAILED;
|
||||
}
|
||||
break;
|
||||
|
||||
case CONTROL_CHANGE:
|
||||
if ((param2 = fluid_midi_file_getc(mf)) < 0) {
|
||||
FLUID_LOG(FLUID_ERR, "Unexpected end of file");
|
||||
return FLUID_FAILED;
|
||||
}
|
||||
break;
|
||||
|
||||
case PROGRAM_CHANGE:
|
||||
break;
|
||||
|
||||
case CHANNEL_PRESSURE:
|
||||
break;
|
||||
|
||||
case PITCH_BEND:
|
||||
if ((param2 = fluid_midi_file_getc(mf)) < 0) {
|
||||
FLUID_LOG(FLUID_ERR, "Unexpected end of file");
|
||||
return FLUID_FAILED;
|
||||
}
|
||||
|
||||
param1 = ((param2 & 0x7f) << 7) | (param1 & 0x7f);
|
||||
param2 = 0;
|
||||
break;
|
||||
|
||||
default:
|
||||
/* Can't possibly happen !? */
|
||||
FLUID_LOG(FLUID_ERR, "Unrecognized MIDI event");
|
||||
return FLUID_FAILED;
|
||||
}
|
||||
evt = new_fluid_midi_event();
|
||||
if (evt == NULL) {
|
||||
FLUID_LOG(FLUID_ERR, "Out of memory");
|
||||
FLUID_FREE (metadata);
|
||||
return FLUID_FAILED;
|
||||
}
|
||||
|
||||
evt->dtime = mf->dtime;
|
||||
evt->type = type;
|
||||
evt->channel = channel;
|
||||
evt->param1 = param1;
|
||||
evt->param2 = param2;
|
||||
fluid_track_add_event(track, evt);
|
||||
evt->type = MIDI_SYSEX;
|
||||
evt->paramptr = metadata;
|
||||
evt->param1 = metadata[mf->varlen - 1] == MIDI_EOX ? mf->varlen - 1 : mf->varlen;
|
||||
fluid_track_add_event (track, evt);
|
||||
mf->dtime = 0;
|
||||
}
|
||||
|
||||
return FLUID_OK;
|
||||
|
||||
} else if (status == MIDI_META_EVENT) { /* meta events */
|
||||
|
||||
int result = FLUID_OK;
|
||||
|
||||
/* get the type of the meta message */
|
||||
type = fluid_midi_file_getc(mf);
|
||||
if (type < 0) {
|
||||
FLUID_LOG(FLUID_ERR, "Unexpected end of file");
|
||||
return FLUID_FAILED;
|
||||
}
|
||||
|
||||
/* get the length of the data part */
|
||||
if (fluid_midi_file_read_varlen(mf) != FLUID_OK) {
|
||||
return FLUID_FAILED;
|
||||
}
|
||||
|
||||
if (mf->varlen < 255) {
|
||||
metadata = &static_buf[0];
|
||||
} else {
|
||||
FLUID_LOG(FLUID_DBG, "%s: %d: alloc metadata, len = %d", __FILE__, __LINE__, mf->varlen);
|
||||
dyn_buf = FLUID_MALLOC(mf->varlen + 1);
|
||||
if (dyn_buf == NULL) {
|
||||
FLUID_LOG(FLUID_PANIC, "Out of memory");
|
||||
return FLUID_FAILED;
|
||||
}
|
||||
metadata = dyn_buf;
|
||||
}
|
||||
|
||||
/* read the data */
|
||||
if (mf->varlen)
|
||||
{
|
||||
if (fluid_midi_file_read(mf, metadata, mf->varlen) != FLUID_OK) {
|
||||
if (dyn_buf) {
|
||||
FLUID_FREE(dyn_buf);
|
||||
}
|
||||
return FLUID_FAILED;
|
||||
}
|
||||
}
|
||||
|
||||
/* handle meta data */
|
||||
switch (type) {
|
||||
|
||||
case MIDI_COPYRIGHT:
|
||||
metadata[mf->varlen] = 0;
|
||||
break;
|
||||
|
||||
case MIDI_TRACK_NAME:
|
||||
metadata[mf->varlen] = 0;
|
||||
fluid_track_set_name(track, (char*) metadata);
|
||||
break;
|
||||
|
||||
case MIDI_INST_NAME:
|
||||
metadata[mf->varlen] = 0;
|
||||
break;
|
||||
|
||||
case MIDI_LYRIC:
|
||||
break;
|
||||
|
||||
case MIDI_MARKER:
|
||||
break;
|
||||
|
||||
case MIDI_CUE_POINT:
|
||||
break; /* don't care much for text events */
|
||||
|
||||
case MIDI_EOT:
|
||||
if (mf->varlen != 0) {
|
||||
FLUID_LOG(FLUID_ERR, "Invalid length for EndOfTrack event");
|
||||
result = FLUID_FAILED;
|
||||
break;
|
||||
}
|
||||
mf->eot = 1;
|
||||
break;
|
||||
|
||||
case MIDI_SET_TEMPO:
|
||||
if (mf->varlen != 3) {
|
||||
FLUID_LOG(FLUID_ERR, "Invalid length for SetTempo meta event");
|
||||
result = FLUID_FAILED;
|
||||
break;
|
||||
}
|
||||
tempo = (metadata[0] << 16) + (metadata[1] << 8) + metadata[2];
|
||||
evt = new_fluid_midi_event();
|
||||
if (evt == NULL) {
|
||||
FLUID_LOG(FLUID_ERR, "Out of memory");
|
||||
result = FLUID_FAILED;
|
||||
break;
|
||||
}
|
||||
evt->dtime = mf->dtime;
|
||||
evt->type = MIDI_SET_TEMPO;
|
||||
evt->channel = 0;
|
||||
evt->param1 = tempo;
|
||||
evt->param2 = 0;
|
||||
fluid_track_add_event(track, evt);
|
||||
mf->dtime = 0;
|
||||
break;
|
||||
|
||||
case MIDI_SMPTE_OFFSET:
|
||||
if (mf->varlen != 5) {
|
||||
FLUID_LOG(FLUID_ERR, "Invalid length for SMPTE Offset meta event");
|
||||
result = FLUID_FAILED;
|
||||
break;
|
||||
}
|
||||
break; /* we don't use smtp */
|
||||
|
||||
case MIDI_TIME_SIGNATURE:
|
||||
if (mf->varlen != 4) {
|
||||
FLUID_LOG(FLUID_ERR, "Invalid length for TimeSignature meta event");
|
||||
result = FLUID_FAILED;
|
||||
break;
|
||||
}
|
||||
nominator = metadata[0];
|
||||
denominator = pow(2.0, (double) metadata[1]);
|
||||
clocks = metadata[2];
|
||||
notes = metadata[3];
|
||||
|
||||
FLUID_LOG(FLUID_DBG, "signature=%d/%d, metronome=%d, 32nd-notes=%d",
|
||||
nominator, denominator, clocks, notes);
|
||||
|
||||
break;
|
||||
|
||||
case MIDI_KEY_SIGNATURE:
|
||||
if (mf->varlen != 2) {
|
||||
FLUID_LOG(FLUID_ERR, "Invalid length for KeySignature meta event");
|
||||
result = FLUID_FAILED;
|
||||
break;
|
||||
}
|
||||
sf = metadata[0];
|
||||
mi = metadata[1];
|
||||
break;
|
||||
|
||||
case MIDI_SEQUENCER_EVENT:
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (dyn_buf) {
|
||||
FLUID_LOG(FLUID_DBG, "%s: %d: free metadata", __FILE__, __LINE__);
|
||||
FLUID_FREE(dyn_buf);
|
||||
}
|
||||
|
||||
return result;
|
||||
|
||||
} else { /* channel messages */
|
||||
|
||||
type = status & 0xf0;
|
||||
channel = status & 0x0f;
|
||||
|
||||
/* all channel message have at least 1 byte of associated data */
|
||||
if ((param1 = fluid_midi_file_getc(mf)) < 0) {
|
||||
FLUID_LOG(FLUID_ERR, "Unexpected end of file");
|
||||
return FLUID_FAILED;
|
||||
}
|
||||
|
||||
switch (type) {
|
||||
|
||||
case NOTE_ON:
|
||||
if ((param2 = fluid_midi_file_getc(mf)) < 0) {
|
||||
FLUID_LOG(FLUID_ERR, "Unexpected end of file");
|
||||
return FLUID_FAILED;
|
||||
}
|
||||
break;
|
||||
|
||||
case NOTE_OFF:
|
||||
if ((param2 = fluid_midi_file_getc(mf)) < 0) {
|
||||
FLUID_LOG(FLUID_ERR, "Unexpected end of file");
|
||||
return FLUID_FAILED;
|
||||
}
|
||||
break;
|
||||
|
||||
case KEY_PRESSURE:
|
||||
if ((param2 = fluid_midi_file_getc(mf)) < 0) {
|
||||
FLUID_LOG(FLUID_ERR, "Unexpected end of file");
|
||||
return FLUID_FAILED;
|
||||
}
|
||||
break;
|
||||
|
||||
case CONTROL_CHANGE:
|
||||
if ((param2 = fluid_midi_file_getc(mf)) < 0) {
|
||||
FLUID_LOG(FLUID_ERR, "Unexpected end of file");
|
||||
return FLUID_FAILED;
|
||||
}
|
||||
break;
|
||||
|
||||
case PROGRAM_CHANGE:
|
||||
break;
|
||||
|
||||
case CHANNEL_PRESSURE:
|
||||
break;
|
||||
|
||||
case PITCH_BEND:
|
||||
if ((param2 = fluid_midi_file_getc(mf)) < 0) {
|
||||
FLUID_LOG(FLUID_ERR, "Unexpected end of file");
|
||||
return FLUID_FAILED;
|
||||
}
|
||||
|
||||
param1 = ((param2 & 0x7f) << 7) | (param1 & 0x7f);
|
||||
param2 = 0;
|
||||
break;
|
||||
|
||||
default:
|
||||
/* Can't possibly happen !? */
|
||||
FLUID_LOG(FLUID_ERR, "Unrecognized MIDI event");
|
||||
return FLUID_FAILED;
|
||||
}
|
||||
evt = new_fluid_midi_event();
|
||||
if (evt == NULL) {
|
||||
FLUID_LOG(FLUID_ERR, "Out of memory");
|
||||
return FLUID_FAILED;
|
||||
}
|
||||
evt->dtime = mf->dtime;
|
||||
evt->type = type;
|
||||
evt->channel = channel;
|
||||
evt->param1 = param1;
|
||||
evt->param2 = param2;
|
||||
fluid_track_add_event(track, evt);
|
||||
mf->dtime = 0;
|
||||
}
|
||||
return FLUID_OK;
|
||||
}
|
||||
|
@ -668,6 +666,7 @@ fluid_midi_event_t* new_fluid_midi_event()
|
|||
evt->param1 = 0;
|
||||
evt->param2 = 0;
|
||||
evt->next = NULL;
|
||||
evt->paramptr = NULL;
|
||||
return evt;
|
||||
}
|
||||
|
||||
|
@ -683,6 +682,10 @@ int delete_fluid_midi_event(fluid_midi_event_t* evt)
|
|||
while (evt)
|
||||
{
|
||||
temp = evt->next;
|
||||
|
||||
if (evt->type == MIDI_SYSEX && evt->paramptr)
|
||||
FLUID_FREE (evt->paramptr);
|
||||
|
||||
FLUID_FREE(evt);
|
||||
evt = temp;
|
||||
}
|
||||
|
@ -867,40 +870,6 @@ int fluid_midi_event_set_pitch(fluid_midi_event_t* evt, int val)
|
|||
return FLUID_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* fluid_midi_event_get_param1
|
||||
*/
|
||||
/* int fluid_midi_event_get_param1(fluid_midi_event_t* evt) */
|
||||
/* { */
|
||||
/* return evt->param1; */
|
||||
/* } */
|
||||
|
||||
/*
|
||||
* fluid_midi_event_set_param1
|
||||
*/
|
||||
/* int fluid_midi_event_set_param1(fluid_midi_event_t* evt, int v) */
|
||||
/* { */
|
||||
/* evt->param1 = v; */
|
||||
/* return FLUID_OK; */
|
||||
/* } */
|
||||
|
||||
/*
|
||||
* fluid_midi_event_get_param2
|
||||
*/
|
||||
/* int fluid_midi_event_get_param2(fluid_midi_event_t* evt) */
|
||||
/* { */
|
||||
/* return evt->param2; */
|
||||
/* } */
|
||||
|
||||
/*
|
||||
* fluid_midi_event_set_param2
|
||||
*/
|
||||
/* int fluid_midi_event_set_param2(fluid_midi_event_t* evt, int v) */
|
||||
/* { */
|
||||
/* evt->param2 = v; */
|
||||
/* return FLUID_OK; */
|
||||
/* } */
|
||||
|
||||
/******************************************************
|
||||
*
|
||||
* fluid_track_t
|
||||
|
@ -1082,7 +1051,11 @@ fluid_track_send_events(fluid_track_t* track,
|
|||
|
||||
|
||||
track->ticks += event->dtime;
|
||||
status = fluid_midi_send_event(synth, player, event);
|
||||
|
||||
if (event->type != MIDI_SET_TEMPO)
|
||||
fluid_synth_handle_midi_event (synth, event);
|
||||
else if (player) fluid_player_set_midi_tempo (player, event->param1);
|
||||
|
||||
fluid_track_next_event(track);
|
||||
|
||||
}
|
||||
|
@ -1667,51 +1640,3 @@ int fluid_midi_event_length(unsigned char event){
|
|||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/************************************************************************
|
||||
* fluid_midi_send_event
|
||||
*
|
||||
* This is a utility function that doesn't really belong to any class
|
||||
* or structure. It is called by fluid_midi_track and fluid_midi_device.
|
||||
*/
|
||||
int fluid_midi_send_event(fluid_synth_t* synth, fluid_player_t* player, fluid_midi_event_t* event)
|
||||
{
|
||||
switch (event->type) {
|
||||
case NOTE_ON:
|
||||
if (fluid_synth_noteon(synth, event->channel, event->param1, event->param2) != FLUID_OK) {
|
||||
return FLUID_FAILED;
|
||||
}
|
||||
break;
|
||||
case NOTE_OFF:
|
||||
if (fluid_synth_noteoff(synth, event->channel, event->param1) != FLUID_OK) {
|
||||
return FLUID_FAILED;
|
||||
}
|
||||
break;
|
||||
case CONTROL_CHANGE:
|
||||
if (fluid_synth_cc(synth, event->channel, event->param1, event->param2) != FLUID_OK) {
|
||||
return FLUID_FAILED;
|
||||
}
|
||||
break;
|
||||
case MIDI_SET_TEMPO:
|
||||
if (player != NULL) {
|
||||
if (fluid_player_set_midi_tempo(player, event->param1) != FLUID_OK) {
|
||||
return FLUID_FAILED;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case PROGRAM_CHANGE:
|
||||
if (fluid_synth_program_change(synth, event->channel, event->param1) != FLUID_OK) {
|
||||
return FLUID_FAILED;
|
||||
}
|
||||
break;
|
||||
case PITCH_BEND:
|
||||
if (fluid_synth_pitch_bend(synth, event->channel, event->param1) != FLUID_OK) {
|
||||
return FLUID_FAILED;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return FLUID_OK;
|
||||
}
|
||||
|
|
|
@ -31,8 +31,6 @@ fluid_midi_parser_t* new_fluid_midi_parser(void);
|
|||
int delete_fluid_midi_parser(fluid_midi_parser_t* parser);
|
||||
fluid_midi_event_t* fluid_midi_parser_parse(fluid_midi_parser_t* parser, unsigned char c);
|
||||
|
||||
int fluid_midi_send_event(fluid_synth_t* synth, fluid_player_t* player, fluid_midi_event_t* evt);
|
||||
|
||||
|
||||
/***************************************************************
|
||||
*
|
||||
|
@ -171,6 +169,30 @@ enum midi_meta_event {
|
|||
MIDI_SEQUENCER_EVENT = 0x7f
|
||||
};
|
||||
|
||||
/* MIDI SYSEX useful manufacturer values */
|
||||
enum midi_sysex_manuf {
|
||||
MIDI_SYSEX_UNIV_NON_REALTIME = 0x7E, /**< Universal non 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 */
|
||||
|
||||
/* Sysex sub-ID #1 (following the device ID) for MIDI tuning messages */
|
||||
#define MIDI_SYSEX_MIDI_TUNING_ID 0x08
|
||||
|
||||
enum midi_sysex_tuning_msg_id {
|
||||
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_NOTE_TUNE = 0x02, /**< Tuning note change message (realtime) */
|
||||
MIDI_SYSEX_TUNING_BULK_DUMP_REQ_BANK = 0x03, /**< Bulk tuning dump request (with bank, non-realtime) */
|
||||
MIDI_SYSEX_TUNING_BULK_DUMP_BANK = 0x04, /**< Bulk tuning dump resonse (with bank, non-realtime) */
|
||||
MIDI_SYSEX_TUNING_OCTAVE_DUMP_1BYTE = 0x05, /**< Octave tuning dump using 1 byte values (non-realtime) */
|
||||
MIDI_SYSEX_TUNING_OCTAVE_DUMP_2BYTE = 0x06, /**< Octave tuning dump using 2 byte values (non-realtime) */
|
||||
MIDI_SYSEX_TUNING_NOTE_TUNE_BANK = 0x07, /**< Tuning note change message (with bank, realtime/non-realtime) */
|
||||
MIDI_SYSEX_TUNING_OCTAVE_TUNE_1BYTE = 0x08, /**< Octave tuning message using 1 byte values (realtime/non-realtime) */
|
||||
MIDI_SYSEX_TUNING_OCTAVE_TUNE_2BYTE = 0x09 /**< Octave tuning message using 2 byte values (realtime/non-realtime) */
|
||||
};
|
||||
|
||||
enum fluid_driver_status
|
||||
{
|
||||
FLUID_MIDI_READY,
|
||||
|
@ -192,12 +214,13 @@ enum fluid_driver_status
|
|||
* fluid_midi_event_t
|
||||
*/
|
||||
struct _fluid_midi_event_t {
|
||||
fluid_midi_event_t* next; /* Don't use it, it will dissappear. Used in midi tracks. */
|
||||
fluid_midi_event_t* next; /* Link to next event */
|
||||
void *paramptr; /* Pointer parameter (for SYSEX data), size is stored to param1 */
|
||||
unsigned int dtime; /* Delay (ticks) between this and previous event. midi tracks. */
|
||||
unsigned char type; /* MIDI event type */
|
||||
unsigned char channel; /* MIDI channel */
|
||||
unsigned int param1; /* First parameter */
|
||||
unsigned int param2; /* Second parameter */
|
||||
unsigned char type; /* MIDI event type */
|
||||
unsigned char channel; /* MIDI channel */
|
||||
};
|
||||
|
||||
|
||||
|
@ -328,8 +351,4 @@ int fluid_isasciistring(char* s);
|
|||
long fluid_getlength(unsigned char *s);
|
||||
|
||||
|
||||
|
||||
int fluid_midi_router_send_event(fluid_midi_router_t* router, fluid_midi_event_t* event);
|
||||
|
||||
|
||||
#endif /* _FLUID_MIDI_H */
|
||||
|
|
|
@ -57,8 +57,10 @@ static int fluid_synth_noteon_LOCAL(fluid_synth_t* synth, int chan, int key,
|
|||
int vel);
|
||||
static int fluid_synth_noteoff_LOCAL(fluid_synth_t* synth, int chan, int key);
|
||||
static int fluid_synth_damp_voices_LOCAL(fluid_synth_t* synth, int chan);
|
||||
static int fluid_synth_cc_LOCAL(fluid_synth_t* synth, int channum, int num,
|
||||
int value);
|
||||
static int fluid_synth_cc_real(fluid_synth_t* synth, int channum, int num,
|
||||
int value, int noqueue);
|
||||
static int fluid_synth_update_device_id (fluid_synth_t *synth, char *name,
|
||||
int value);
|
||||
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_system_reset_LOCAL(fluid_synth_t* synth);
|
||||
|
@ -203,21 +205,23 @@ void fluid_synth_settings(fluid_settings_t* settings)
|
|||
fluid_settings_register_str(settings, "midi.portname", "", 0, NULL, NULL);
|
||||
|
||||
fluid_settings_register_int(settings, "synth.polyphony",
|
||||
256, 16, 4096, 0, NULL, NULL);
|
||||
256, 16, 4096, 0, NULL, NULL);
|
||||
fluid_settings_register_int(settings, "synth.midi-channels",
|
||||
16, 16, 256, 0, NULL, NULL);
|
||||
16, 16, 256, 0, NULL, NULL);
|
||||
fluid_settings_register_num(settings, "synth.gain",
|
||||
0.2f, 0.0f, 10.0f,
|
||||
0, NULL, NULL);
|
||||
0.2f, 0.0f, 10.0f,
|
||||
0, NULL, NULL);
|
||||
fluid_settings_register_int(settings, "synth.audio-channels",
|
||||
1, 1, 256, 0, NULL, NULL);
|
||||
1, 1, 256, 0, NULL, NULL);
|
||||
fluid_settings_register_int(settings, "synth.audio-groups",
|
||||
1, 1, 256, 0, NULL, NULL);
|
||||
1, 1, 256, 0, NULL, NULL);
|
||||
fluid_settings_register_int(settings, "synth.effects-channels",
|
||||
2, 2, 2, 0, NULL, NULL);
|
||||
2, 2, 2, 0, NULL, NULL);
|
||||
fluid_settings_register_num(settings, "synth.sample-rate",
|
||||
44100.0f, 22050.0f, 96000.0f,
|
||||
0, NULL, NULL);
|
||||
44100.0f, 22050.0f, 96000.0f,
|
||||
0, NULL, NULL);
|
||||
fluid_settings_register_int(settings, "synth.device-id",
|
||||
0, 126, 0, 0, NULL, NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -537,6 +541,7 @@ new_fluid_synth(fluid_settings_t *settings)
|
|||
fluid_settings_getint(settings, "synth.audio-groups", &synth->audio_groups);
|
||||
fluid_settings_getint(settings, "synth.effects-channels", &synth->effects_channels);
|
||||
fluid_settings_getnum(settings, "synth.gain", &synth->gain);
|
||||
fluid_settings_getint(settings, "synth.device-id", &synth->device_id);
|
||||
|
||||
/* register the callbacks */
|
||||
fluid_settings_register_num(settings, "synth.gain",
|
||||
|
@ -546,6 +551,9 @@ new_fluid_synth(fluid_settings_t *settings)
|
|||
synth->polyphony, 16, 4096, 0,
|
||||
(fluid_int_update_t) fluid_synth_update_polyphony,
|
||||
synth);
|
||||
fluid_settings_register_int(settings, "synth.device-id",
|
||||
synth->device_id, 126, 0, 0,
|
||||
(fluid_int_update_t) fluid_synth_update_device_id, NULL);
|
||||
|
||||
/* do some basic sanity checking on the settings */
|
||||
|
||||
|
@ -1316,10 +1324,7 @@ fluid_synth_cc(fluid_synth_t* synth, int chan, int num, int val)
|
|||
fluid_return_val_if_fail (num >= 0 && num <= 127, FLUID_FAILED);
|
||||
fluid_return_val_if_fail (val >= 0 && val <= 127, FLUID_FAILED);
|
||||
|
||||
/* Process bank MSB/LSB events immediately to prevent out of order issues with program change */
|
||||
if (fluid_synth_should_queue (synth) && num != BANK_SELECT_MSB && num != BANK_SELECT_LSB)
|
||||
return fluid_synth_queue_midi_event (synth, CONTROL_CHANGE, chan, num, val);
|
||||
else return fluid_synth_cc_LOCAL (synth, chan, num, val);
|
||||
fluid_synth_cc_real (synth, chan, num, val, FALSE);
|
||||
|
||||
return FLUID_OK;
|
||||
}
|
||||
|
@ -1328,10 +1333,33 @@ fluid_synth_cc(fluid_synth_t* synth, int chan, int num, int val)
|
|||
* NOTE: Gets called out of synthesis context for BANK_SELECT_MSB and
|
||||
* BANK_SELECT_LSB events, since they should be processed immediately. */
|
||||
static int
|
||||
fluid_synth_cc_LOCAL(fluid_synth_t* synth, int channum, int num, int value)
|
||||
fluid_synth_cc_real (fluid_synth_t* synth, int channum, int num, int value,
|
||||
int noqueue)
|
||||
{
|
||||
fluid_channel_t* chan = synth->channel[channum];
|
||||
int banknum, nrpn_select;
|
||||
int banknum, nrpn_select, nrpn_active = 0;
|
||||
int rpn_msb = 0, rpn_lsb = 0;
|
||||
|
||||
/* nrpn_active, rpn_msb and rpn_lsb may get used multiple times, read them
|
||||
* once atomically if they are needed */
|
||||
if (num == DATA_ENTRY_MSB)
|
||||
{
|
||||
nrpn_active = fluid_atomic_int_get (&chan->nrpn_active);
|
||||
|
||||
if (!nrpn_active)
|
||||
{
|
||||
rpn_msb = fluid_channel_get_cc (chan, RPN_MSB);
|
||||
rpn_lsb = fluid_channel_get_cc (chan, RPN_LSB);
|
||||
}
|
||||
}
|
||||
|
||||
/* Check if event needs to be queued. Bank select messages and tuning
|
||||
* bank/program select RPN messages are not queued. */
|
||||
if (!noqueue && fluid_synth_should_queue (synth)
|
||||
&& num != BANK_SELECT_MSB && num != BANK_SELECT_LSB
|
||||
&& !(num == DATA_ENTRY_MSB && !nrpn_active && rpn_msb == 0
|
||||
&& (rpn_lsb == RPN_TUNING_PROGRAM_CHANGE || rpn_lsb == RPN_TUNING_BANK_SELECT)))
|
||||
return fluid_synth_queue_midi_event (synth, CONTROL_CHANGE, channum, num, value);
|
||||
|
||||
if (synth->verbose)
|
||||
FLUID_LOG(FLUID_INFO, "cc\t%d\t%d\t%d", channum, num, value);
|
||||
|
@ -1362,7 +1390,7 @@ fluid_synth_cc_LOCAL(fluid_synth_t* synth, int channum, int num, int value)
|
|||
{
|
||||
int data = (value << 7) + fluid_channel_get_cc (chan, DATA_ENTRY_LSB);
|
||||
|
||||
if (fluid_atomic_int_get (&chan->nrpn_active)) /* NRPN is active? */
|
||||
if (nrpn_active) /* NRPN is active? */
|
||||
{ /* SontFont 2.01 NRPN Message (Sect. 9.6, p. 74) */
|
||||
if ((fluid_channel_get_cc (chan, NRPN_MSB) == 120)
|
||||
&& (fluid_channel_get_cc (chan, NRPN_LSB) < 100))
|
||||
|
@ -1378,9 +1406,9 @@ fluid_synth_cc_LOCAL(fluid_synth_t* synth, int channum, int num, int value)
|
|||
fluid_atomic_int_set (&chan->nrpn_select, 0); /* Reset to 0 */
|
||||
}
|
||||
}
|
||||
else if (chan->cc[RPN_MSB] == 0) /* RPN is active: MSB = 0? */
|
||||
else if (rpn_msb == 0) /* RPN is active: MSB = 0? */
|
||||
{
|
||||
switch (chan->cc[RPN_LSB])
|
||||
switch (rpn_lsb)
|
||||
{
|
||||
case RPN_PITCH_BEND_RANGE:
|
||||
fluid_synth_pitch_wheel_sens_LOCAL (synth, channum, value); /* Set bend range in semitones */
|
||||
|
@ -1395,8 +1423,13 @@ fluid_synth_cc_LOCAL(fluid_synth_t* synth, int channum, int num, int value)
|
|||
value - 64, FALSE);
|
||||
break;
|
||||
case RPN_TUNING_PROGRAM_CHANGE:
|
||||
fluid_channel_set_tuning_prog (chan, value);
|
||||
fluid_synth_activate_tuning (synth, channum,
|
||||
fluid_channel_get_tuning_bank (chan),
|
||||
value, TRUE);
|
||||
break;
|
||||
case RPN_TUNING_BANK_SELECT:
|
||||
fluid_channel_set_tuning_bank (chan, value);
|
||||
break;
|
||||
case RPN_MODULATION_DEPTH_RANGE:
|
||||
break;
|
||||
|
@ -1456,6 +1489,279 @@ fluid_synth_get_cc(fluid_synth_t* synth, int chan, int num, int* pval)
|
|||
return FLUID_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* Handler for synth.device-id setting.
|
||||
*/
|
||||
static int
|
||||
fluid_synth_update_device_id (fluid_synth_t *synth, char *name, int value)
|
||||
{
|
||||
fluid_atomic_int_set (&synth->device_id, value);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process a MIDI SYSEX (system exclusive) message.
|
||||
* @param synth FluidSynth instance
|
||||
* @param data Buffer containing SYSEX data (not including 0xF0 and 0xF7)
|
||||
* @param len Length of data in buffer
|
||||
* @param response Buffer to store response to or NULL to ignore
|
||||
* @param response_len IN/OUT parameter, in: size of response buffer, out:
|
||||
* amount of data written to response buffer (if FLUID_FAILED is returned and
|
||||
* this value is non-zero, it indicates the response buffer is too small)
|
||||
* @param handled Optional location to store boolean value if message was
|
||||
* recognized and handled or not (set to TRUE if it was handled)
|
||||
* @param dryrun TRUE to just do a dry run but not actually execute the SYSEX
|
||||
* command (useful for checking if a SYSEX message would be handled)
|
||||
* @return FLUID_OK on success, FLUID_FAILED otherwise
|
||||
* @since 1.1.0
|
||||
*/
|
||||
/* SYSEX format (0xF0 and 0xF7 not passed to this function):
|
||||
* Non-realtime: 0xF0 0x7E <DeviceId> [BODY] 0xF7
|
||||
* Realtime: 0xF0 0x7F <DeviceId> [BODY] 0xF7
|
||||
* Tuning messages: 0xF0 0x7E/0x7F <DeviceId> 0x08 <sub ID2> [BODY] <ChkSum> 0xF7
|
||||
*/
|
||||
int
|
||||
fluid_synth_sysex(fluid_synth_t *synth, char *data, int len,
|
||||
char *response, int *response_len, int *handled, int dryrun)
|
||||
{
|
||||
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 (response_len)
|
||||
{
|
||||
avail_response = *response_len;
|
||||
*response_len = 0;
|
||||
}
|
||||
|
||||
fluid_return_val_if_fail (synth != NULL, FLUID_FAILED);
|
||||
fluid_return_val_if_fail (data != NULL, FLUID_FAILED);
|
||||
fluid_return_val_if_fail (len > 0, 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 || (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? */
|
||||
if (data[1] != synth->device_id && data[1] != MIDI_SYSEX_DEVICE_ID_ALL)
|
||||
return FLUID_OK;
|
||||
|
||||
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];
|
||||
|
||||
switch (msgid)
|
||||
{
|
||||
case MIDI_SYSEX_TUNING_BULK_DUMP_REQ:
|
||||
case MIDI_SYSEX_TUNING_BULK_DUMP_REQ_BANK:
|
||||
if (data[3] == MIDI_SYSEX_TUNING_BULK_DUMP_REQ)
|
||||
{
|
||||
if (len != 5 || data[4] & 0x80 || !response)
|
||||
return FLUID_OK;
|
||||
|
||||
*response_len = 406;
|
||||
prog = data[4];
|
||||
}
|
||||
else
|
||||
{
|
||||
if (len != 6 || data[4] & 0x80 || data[5] & 0x80 || !response)
|
||||
return FLUID_OK;
|
||||
|
||||
*response_len = 407;
|
||||
bank = data[4];
|
||||
prog = data[5];
|
||||
}
|
||||
|
||||
if (dryrun)
|
||||
{
|
||||
if (handled) *handled = TRUE;
|
||||
return FLUID_OK;
|
||||
}
|
||||
|
||||
if (avail_response < *response_len) return FLUID_FAILED;
|
||||
|
||||
/* Get tuning data, return if tuning not found */
|
||||
if (fluid_synth_tuning_dump (synth, bank, prog, name, 17, tunedata) == FLUID_FAILED)
|
||||
{
|
||||
*response_len = 0;
|
||||
return FLUID_OK;
|
||||
}
|
||||
|
||||
dataptr = response;
|
||||
|
||||
*dataptr++ = MIDI_SYSEX_UNIV_NON_REALTIME;
|
||||
*dataptr++ = synth->device_id;
|
||||
*dataptr++ = MIDI_SYSEX_MIDI_TUNING_ID;
|
||||
*dataptr++ = MIDI_SYSEX_TUNING_BULK_DUMP;
|
||||
|
||||
if (msgid == MIDI_SYSEX_TUNING_BULK_DUMP_REQ_BANK)
|
||||
*dataptr++ = bank;
|
||||
|
||||
*dataptr++ = prog;
|
||||
FLUID_STRNCPY (dataptr, name, 16);
|
||||
dataptr += 16;
|
||||
|
||||
for (i = 0; i < 128; i++)
|
||||
{
|
||||
note = tunedata[i] / 100.0;
|
||||
fluid_clip (note, 0, 127);
|
||||
|
||||
frac = ((tunedata[i] - note * 100.0) * 16384.0 + 50.0) / 100.0;
|
||||
fluid_clip (frac, 0, 16383);
|
||||
|
||||
*dataptr++ = note;
|
||||
*dataptr++ = frac >> 7;
|
||||
*dataptr++ = frac & 0x7F;
|
||||
}
|
||||
|
||||
if (msgid == MIDI_SYSEX_TUNING_BULK_DUMP_REQ)
|
||||
{ /* NOTE: Checksum is not as straight forward as the bank based messages */
|
||||
chksum = MIDI_SYSEX_UNIV_NON_REALTIME ^ MIDI_SYSEX_MIDI_TUNING_ID
|
||||
^ MIDI_SYSEX_TUNING_BULK_DUMP ^ prog;
|
||||
|
||||
for (i = 21; i < 128 * 3 + 21; i++)
|
||||
chksum ^= response[i];
|
||||
}
|
||||
else
|
||||
{
|
||||
for (i = 1, chksum = 0; i < 406; i++)
|
||||
chksum ^= response[i];
|
||||
}
|
||||
|
||||
*dataptr++ = chksum & 0x7F;
|
||||
|
||||
if (handled) *handled = TRUE;
|
||||
break;
|
||||
case MIDI_SYSEX_TUNING_NOTE_TUNE:
|
||||
case MIDI_SYSEX_TUNING_NOTE_TUNE_BANK:
|
||||
dataptr = data + 4;
|
||||
|
||||
if (msgid == MIDI_SYSEX_TUNING_NOTE_TUNE)
|
||||
{
|
||||
if (len < 10 || data[4] & 0x80 || data[5] & 0x80 || len != data[5] * 4 + 6)
|
||||
return FLUID_OK;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (len < 11 || data[4] & 0x80 || data[5] & 0x80 || data[6] & 0x80
|
||||
|| len != data[5] * 4 + 7)
|
||||
return FLUID_OK;
|
||||
|
||||
bank = *dataptr++;
|
||||
}
|
||||
|
||||
if (dryrun)
|
||||
{
|
||||
if (handled) *handled = TRUE;
|
||||
return FLUID_OK;
|
||||
}
|
||||
|
||||
prog = *dataptr++;
|
||||
count = *dataptr++;
|
||||
|
||||
for (i = 0, index = 0; i < count; i++)
|
||||
{
|
||||
note = *dataptr++;
|
||||
if (note & 0x80) return FLUID_OK;
|
||||
keys[index] = note;
|
||||
|
||||
note = *dataptr++;
|
||||
frac = *dataptr++;
|
||||
frac2 = *dataptr++;
|
||||
|
||||
if (note & 0x80 || frac & 0x80 || frac2 & 0x80)
|
||||
return FLUID_OK;
|
||||
|
||||
frac = frac << 7 | frac2;
|
||||
|
||||
/* No change pitch value? Doesn't really make sense to send that, but.. */
|
||||
if (note == 0x7F && frac == 16383) continue;
|
||||
|
||||
tunedata[index] = note * 100.0 + (frac * 100.0 / 16384.0);
|
||||
index++;
|
||||
}
|
||||
|
||||
if (index > 0)
|
||||
{
|
||||
if (fluid_synth_tune_notes (synth, bank, prog, index, keys, tunedata,
|
||||
realtime) == FLUID_FAILED)
|
||||
return FLUID_FAILED;
|
||||
}
|
||||
|
||||
if (handled) *handled = TRUE;
|
||||
break;
|
||||
case MIDI_SYSEX_TUNING_OCTAVE_TUNE_1BYTE:
|
||||
case MIDI_SYSEX_TUNING_OCTAVE_TUNE_2BYTE:
|
||||
if ((msgid == MIDI_SYSEX_TUNING_OCTAVE_TUNE_1BYTE && len != 19)
|
||||
|| (msgid == MIDI_SYSEX_TUNING_OCTAVE_TUNE_2BYTE && len != 31))
|
||||
return FLUID_OK;
|
||||
|
||||
if (data[4] & 0x80 || data[5] & 0x80 || data[6] & 0x80)
|
||||
return FLUID_OK;
|
||||
|
||||
if (dryrun)
|
||||
{
|
||||
if (handled) *handled = TRUE;
|
||||
return FLUID_OK;
|
||||
}
|
||||
|
||||
channels = (data[4] & 0x03) << 14 | data[5] << 7 | data[6];
|
||||
|
||||
if (msgid == MIDI_SYSEX_TUNING_OCTAVE_TUNE_1BYTE)
|
||||
{
|
||||
for (i = 0; i < 12; i++)
|
||||
{
|
||||
frac = data[i + 7];
|
||||
if (frac & 0x80) return FLUID_OK;
|
||||
tunedata[i] = (int)frac - 64;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (i = 0; i < 12; i++)
|
||||
{
|
||||
frac = data[i * 2 + 7];
|
||||
frac2 = data[i * 2 + 8];
|
||||
if (frac & 0x80 || frac2 & 0x80) return FLUID_OK;
|
||||
tunedata[i] = (((int)frac << 7 | (int)frac2) - 8192) * (200.0 / 16384.0);
|
||||
}
|
||||
}
|
||||
|
||||
if (fluid_synth_activate_octave_tuning (synth, 0, 0, "SYSEX",
|
||||
tunedata, realtime) == FLUID_FAILED)
|
||||
return FLUID_FAILED;
|
||||
|
||||
if (channels)
|
||||
{
|
||||
for (i = 0; i < 16; i++)
|
||||
{
|
||||
if (channels & (1 << i))
|
||||
fluid_synth_activate_tuning (synth, i, 0, 0, realtime);
|
||||
}
|
||||
}
|
||||
|
||||
if (handled) *handled = TRUE;
|
||||
break;
|
||||
}
|
||||
|
||||
return FLUID_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Turn off all notes on a MIDI channel (put them into release phase).
|
||||
* @param synth FluidSynth instance
|
||||
|
@ -2783,8 +3089,9 @@ fluid_synth_process_event_queue_LOCAL (fluid_synth_t *synth,
|
|||
event->midi.param1);
|
||||
break;
|
||||
case CONTROL_CHANGE:
|
||||
fluid_synth_cc_LOCAL (synth, event->midi.channel, event->midi.param1,
|
||||
event->midi.param2);
|
||||
/* Pass TRUE for noqueue, since event should never get re-queued */
|
||||
fluid_synth_cc_real (synth, event->midi.channel, event->midi.param1,
|
||||
event->midi.param2, TRUE);
|
||||
break;
|
||||
case MIDI_SYSTEM_RESET:
|
||||
fluid_synth_system_reset_LOCAL (synth);
|
||||
|
@ -4254,10 +4561,35 @@ fluid_synth_update_voice_tuning_LOCAL (fluid_synth_t *synth, fluid_channel_t *ch
|
|||
* cents, for example normally note 0 is 0.0, 1 is 100.0, 60 is 6000.0, etc).
|
||||
* Pass NULL to create a well-tempered (normal) scale.
|
||||
* @return FLUID_OK on success, FLUID_FAILED otherwise
|
||||
*
|
||||
* NOTE: Tuning is not applied in realtime to existing notes of the replaced
|
||||
* tuning (if any), use fluid_synth_activate_key_tuning() instead to specify
|
||||
* this behavior.
|
||||
*/
|
||||
int
|
||||
fluid_synth_create_key_tuning(fluid_synth_t* synth, int bank, int prog,
|
||||
char* name, double* pitch)
|
||||
{
|
||||
return fluid_synth_activate_key_tuning (synth, bank, prog, name, pitch, FALSE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the tuning of the entire MIDI note scale.
|
||||
* @param synth FluidSynth instance
|
||||
* @param bank Tuning bank number (0-127), not related to MIDI instrument bank
|
||||
* @param prog Tuning preset number (0-127), not related to MIDI instrument program
|
||||
* @param name Label name for this tuning
|
||||
* @param pitch Array of pitch values (length of 128, each value is number of
|
||||
* cents, for example normally note 0 is 0.0, 1 is 100.0, 60 is 6000.0, etc).
|
||||
* Pass NULL to create a well-tempered (normal) scale.
|
||||
* @param apply TRUE to apply new tuning in realtime to existing notes which
|
||||
* are using the replaced tuning (if any), FALSE otherwise
|
||||
* @return FLUID_OK on success, FLUID_FAILED otherwise
|
||||
* @since 1.1.0
|
||||
*/
|
||||
int
|
||||
fluid_synth_activate_key_tuning(fluid_synth_t* synth, int bank, int prog,
|
||||
char* name, double* pitch, int apply)
|
||||
{
|
||||
fluid_tuning_t* tuning;
|
||||
int retval = FLUID_OK;
|
||||
|
@ -4274,7 +4606,7 @@ fluid_synth_create_key_tuning(fluid_synth_t* synth, int bank, int prog,
|
|||
if (tuning)
|
||||
{
|
||||
if (pitch) fluid_tuning_set_all (tuning, pitch);
|
||||
retval = fluid_synth_replace_tuning_LOCK (synth, tuning, bank, prog, FALSE);
|
||||
retval = fluid_synth_replace_tuning_LOCK (synth, tuning, bank, prog, apply);
|
||||
if (retval == FLUID_FAILED) fluid_tuning_unref (tuning, 1);
|
||||
}
|
||||
else retval = FLUID_FAILED;
|
||||
|
@ -4294,10 +4626,35 @@ fluid_synth_create_key_tuning(fluid_synth_t* synth, int bank, int prog,
|
|||
* starting at note C, values are number of offset cents to add to the normal
|
||||
* tuning amount)
|
||||
* @return FLUID_OK on success, FLUID_FAILED otherwise
|
||||
*
|
||||
* NOTE: Tuning is not applied in realtime to existing notes of the replaced
|
||||
* tuning (if any), use fluid_synth_activate_octave_tuning() instead to specify
|
||||
* this behavior.
|
||||
*/
|
||||
int
|
||||
fluid_synth_create_octave_tuning(fluid_synth_t* synth, int bank, int prog,
|
||||
char* name, double* pitch)
|
||||
{
|
||||
return fluid_synth_activate_octave_tuning (synth, bank, prog, name, pitch, FALSE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Activate an octave tuning on every octave in the MIDI note scale.
|
||||
* @param synth FluidSynth instance
|
||||
* @param bank Tuning bank number (0-127), not related to MIDI instrument bank
|
||||
* @param prog Tuning preset number (0-127), not related to MIDI instrument program
|
||||
* @param name Label name for this tuning
|
||||
* @param pitch Array of pitch values (length of 12 for each note of an octave
|
||||
* starting at note C, values are number of offset cents to add to the normal
|
||||
* tuning amount)
|
||||
* @param apply TRUE to apply new tuning in realtime to existing notes which
|
||||
* are using the replaced tuning (if any), FALSE otherwise
|
||||
* @return FLUID_OK on success, FLUID_FAILED otherwise
|
||||
* @since 1.1.0
|
||||
*/
|
||||
int
|
||||
fluid_synth_activate_octave_tuning(fluid_synth_t* synth, int bank, int prog,
|
||||
char* name, double* pitch, int apply)
|
||||
{
|
||||
fluid_tuning_t* tuning;
|
||||
int retval = FLUID_OK;
|
||||
|
@ -4315,7 +4672,7 @@ fluid_synth_create_octave_tuning(fluid_synth_t* synth, int bank, int prog,
|
|||
if (tuning)
|
||||
{
|
||||
fluid_tuning_set_octave (tuning, pitch);
|
||||
retval = fluid_synth_replace_tuning_LOCK (synth, tuning, bank, prog, TRUE);
|
||||
retval = fluid_synth_replace_tuning_LOCK (synth, tuning, bank, prog, apply);
|
||||
if (retval == FLUID_FAILED) fluid_tuning_unref (tuning, 1);
|
||||
}
|
||||
else retval = FLUID_FAILED;
|
||||
|
@ -4334,8 +4691,8 @@ fluid_synth_create_octave_tuning(fluid_synth_t* synth, int bank, int prog,
|
|||
* @param key Array of MIDI key numbers (length of 'len', values 0-127)
|
||||
* @param pitch Array of pitch values (length of 'len', values are number of
|
||||
* cents from MIDI note 0)
|
||||
* @param apply Not used currently, may be used in the future to apply tuning
|
||||
* change in realtime.
|
||||
* @param apply TRUE to apply tuning change in realtime to existing notes using
|
||||
* the specified tuning, FALSE otherwise
|
||||
* @return FLUID_OK on success, FLUID_FAILED otherwise
|
||||
*
|
||||
* NOTE: Prior to version 1.1.0 it was an error to specify a tuning that didn't
|
||||
|
@ -4381,19 +4738,43 @@ fluid_synth_tune_notes(fluid_synth_t* synth, int bank, int prog,
|
|||
}
|
||||
|
||||
/**
|
||||
* Activate a tuning scale on a MIDI channel.
|
||||
* Select a tuning scale on a MIDI channel.
|
||||
* @param synth FluidSynth instance
|
||||
* @param chan MIDI channel number (0 to MIDI channel count - 1)
|
||||
* @param bank Tuning bank number (0-127), not related to MIDI instrument bank
|
||||
* @param prog Tuning preset number (0-127), not related to MIDI instrument program
|
||||
* @return FLUID_OK on success, FLUID_FAILED otherwise
|
||||
*
|
||||
* NOTE: This function does NOT activate tuning in realtime, use
|
||||
* fluid_synth_activate_tuning() instead to specify whether tuning change
|
||||
* should cause existing notes to update.
|
||||
*
|
||||
* NOTE: Prior to version 1.1.0 it was an error to select a tuning that didn't
|
||||
* already exist. Starting with 1.1.0, the default equal tempered scale will be
|
||||
* used, if no tuning exists for the given bank and prog.
|
||||
* already exist. Starting with 1.1.0, a default equal tempered scale will be
|
||||
* created, if no tuning exists for the given bank and prog.
|
||||
*/
|
||||
int
|
||||
fluid_synth_select_tuning(fluid_synth_t* synth, int chan, int bank, int prog)
|
||||
{
|
||||
return fluid_synth_activate_tuning (synth, chan, bank, prog, FALSE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Activate a tuning scale on a MIDI channel.
|
||||
* @param synth FluidSynth instance
|
||||
* @param chan MIDI channel number (0 to MIDI channel count - 1)
|
||||
* @param bank Tuning bank number (0-127), not related to MIDI instrument bank
|
||||
* @param prog Tuning preset number (0-127), not related to MIDI instrument program
|
||||
* @param apply TRUE to apply tuning change to active notes, FALSE otherwise
|
||||
* @return FLUID_OK on success, FLUID_FAILED otherwise
|
||||
* @since 1.1.0
|
||||
*
|
||||
* NOTE: A default equal tempered scale will be created, if no tuning exists
|
||||
* on the given bank and prog.
|
||||
*/
|
||||
int
|
||||
fluid_synth_activate_tuning(fluid_synth_t* synth, int chan, int bank, int prog,
|
||||
int apply)
|
||||
{
|
||||
fluid_event_queue_elem_t *event;
|
||||
fluid_event_queue_t *queue;
|
||||
|
@ -4423,8 +4804,6 @@ fluid_synth_select_tuning(fluid_synth_t* synth, int chan, int bank, int prog)
|
|||
|
||||
if (!tuning) return (FLUID_FAILED);
|
||||
|
||||
/* NOTE: tuning can be NULL, to use default equal tempered scale */
|
||||
|
||||
if (fluid_synth_should_queue (synth))
|
||||
{
|
||||
event = fluid_synth_get_event_elem (synth, &queue);
|
||||
|
@ -4434,7 +4813,7 @@ fluid_synth_select_tuning(fluid_synth_t* synth, int chan, int bank, int prog)
|
|||
fluid_tuning_ref (tuning); /* ++ ref new tuning for event */
|
||||
|
||||
event->type = FLUID_EVENT_QUEUE_ELEM_SET_TUNING;
|
||||
event->set_tuning.apply = TRUE;
|
||||
event->set_tuning.apply = apply;
|
||||
event->set_tuning.channel = chan;
|
||||
event->set_tuning.tuning = tuning;
|
||||
fluid_event_queue_next_inptr (queue);
|
||||
|
@ -4444,7 +4823,7 @@ fluid_synth_select_tuning(fluid_synth_t* synth, int chan, int bank, int prog)
|
|||
else
|
||||
{
|
||||
fluid_tuning_ref (tuning); /* ++ ref new tuning for following function */
|
||||
retval = fluid_synth_set_tuning_LOCAL (synth, chan, tuning, TRUE);
|
||||
retval = fluid_synth_set_tuning_LOCAL (synth, chan, tuning, apply);
|
||||
}
|
||||
|
||||
fluid_tuning_unref (tuning, 1); /* -- unref for outside of lock */
|
||||
|
@ -4495,9 +4874,27 @@ fluid_synth_set_tuning_LOCAL (fluid_synth_t *synth, int chan,
|
|||
* @param synth FluidSynth instance
|
||||
* @param chan MIDI channel number (0 to MIDI channel count - 1)
|
||||
* @return FLUID_OK on success, FLUID_FAILED otherwise
|
||||
*
|
||||
* NOTE: This function does NOT activate tuning change in realtime, use
|
||||
* fluid_synth_deactivate_tuning() instead to specify whether tuning change
|
||||
* should cause existing notes to update.
|
||||
*/
|
||||
int
|
||||
fluid_synth_reset_tuning(fluid_synth_t* synth, int chan)
|
||||
{
|
||||
return fluid_synth_deactivate_tuning (synth, chan, FALSE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear tuning scale on a MIDI channel (use default equal tempered scale).
|
||||
* @param synth FluidSynth instance
|
||||
* @param chan MIDI channel number (0 to MIDI channel count - 1)
|
||||
* @param apply TRUE to apply tuning change to active notes, FALSE otherwise
|
||||
* @return FLUID_OK on success, FLUID_FAILED otherwise
|
||||
* @since 1.1.0
|
||||
*/
|
||||
int
|
||||
fluid_synth_deactivate_tuning(fluid_synth_t* synth, int chan, int apply)
|
||||
{
|
||||
fluid_event_queue_elem_t *event;
|
||||
fluid_event_queue_t *queue;
|
||||
|
@ -4513,14 +4910,14 @@ fluid_synth_reset_tuning(fluid_synth_t* synth, int chan)
|
|||
if (event)
|
||||
{
|
||||
event->type = FLUID_EVENT_QUEUE_ELEM_SET_TUNING;
|
||||
event->set_tuning.apply = TRUE;
|
||||
event->set_tuning.apply = apply;
|
||||
event->set_tuning.channel = chan;
|
||||
event->set_tuning.tuning = NULL;
|
||||
fluid_event_queue_next_inptr (queue);
|
||||
}
|
||||
else retval = FLUID_FAILED;
|
||||
}
|
||||
else retval = fluid_synth_set_tuning_LOCAL (synth, chan, NULL, TRUE);
|
||||
else retval = fluid_synth_set_tuning_LOCAL (synth, chan, NULL, apply);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
@ -4872,16 +5269,16 @@ fluid_synth_handle_midi_event(void* data, fluid_midi_event_t* event)
|
|||
switch(type) {
|
||||
case NOTE_ON:
|
||||
return fluid_synth_noteon(synth, chan,
|
||||
fluid_midi_event_get_key(event),
|
||||
fluid_midi_event_get_velocity(event));
|
||||
fluid_midi_event_get_key(event),
|
||||
fluid_midi_event_get_velocity(event));
|
||||
|
||||
case NOTE_OFF:
|
||||
return fluid_synth_noteoff(synth, chan, fluid_midi_event_get_key(event));
|
||||
|
||||
case CONTROL_CHANGE:
|
||||
return fluid_synth_cc(synth, chan,
|
||||
fluid_midi_event_get_control(event),
|
||||
fluid_midi_event_get_value(event));
|
||||
fluid_midi_event_get_control(event),
|
||||
fluid_midi_event_get_value(event));
|
||||
|
||||
case PROGRAM_CHANGE:
|
||||
return fluid_synth_program_change(synth, chan, fluid_midi_event_get_program(event));
|
||||
|
@ -4894,6 +5291,8 @@ fluid_synth_handle_midi_event(void* data, fluid_midi_event_t* event)
|
|||
|
||||
case MIDI_SYSTEM_RESET:
|
||||
return fluid_synth_system_reset(synth);
|
||||
case MIDI_SYSEX:
|
||||
return fluid_synth_sysex (synth, event->paramptr, event->param1, NULL, NULL, NULL, FALSE);
|
||||
}
|
||||
return FLUID_FAILED;
|
||||
}
|
||||
|
|
|
@ -158,6 +158,7 @@ struct _fluid_synth_t
|
|||
fluid_timer_t *return_queue_timer; /**< Timer thread to process return event queue */
|
||||
|
||||
fluid_settings_t* settings; /**< the synthesizer settings */
|
||||
int device_id; /**< Device ID used for SYSEX messages */
|
||||
int polyphony; /**< maximum polyphony */
|
||||
char with_reverb; /**< Should the synth use the built-in reverb unit? */
|
||||
char with_chorus; /**< Should the synth use the built-in chorus unit? */
|
||||
|
|
Loading…
Reference in a new issue