(Credit: jimmy) Allow channels to change state between melodic and drum channels

This commit is contained in:
David Henningsson 2011-02-04 19:19:30 +00:00
parent 8e11587d4e
commit d7b9767598
5 changed files with 52 additions and 9 deletions

View file

@ -100,6 +100,15 @@ FLUIDSYNTH_API int fluid_synth_program_reset(fluid_synth_t* synth);
FLUIDSYNTH_API int fluid_synth_system_reset(fluid_synth_t* synth);
enum fluid_midi_channel_type
{
CHANNEL_TYPE_MELODIC = 0,
CHANNEL_TYPE_DRUM = 1
};
int fluid_synth_set_channel_type(fluid_synth_t* synth, int chan, int type);
/* Low level access */
FLUIDSYNTH_API fluid_preset_t* fluid_synth_get_channel_preset(fluid_synth_t* synth, int chan);
FLUIDSYNTH_API int fluid_synth_start(fluid_synth_t* synth, unsigned int id,

View file

@ -67,8 +67,9 @@ fluid_channel_init(fluid_channel_t* chan)
fluid_preset_t *newpreset;
int prognum, banknum;
chan->channel_type = (chan->channum == 9) ? CHANNEL_TYPE_DRUM : CHANNEL_TYPE_MELODIC;
prognum = 0;
banknum = (chan->channum == 9)? 128 : 0; /* ?? */
banknum = (chan->channel_type == CHANNEL_TYPE_DRUM) ? DRUM_INST_BANK : 0;
chan->sfont_bank_prog = 0 << SFONT_SHIFTVAL | banknum << BANK_SHIFTVAL
| prognum << PROG_SHIFTVAL;
@ -233,7 +234,7 @@ fluid_channel_set_bank_lsb(fluid_channel_t* chan, int banklsb)
style = chan->synth->bank_select;
if (style == FLUID_BANK_STYLE_GM ||
style == FLUID_BANK_STYLE_GS ||
chan->channum == 9) //TODO: ask for channel drum mode, instead of number
chan->channel_type == CHANNEL_TYPE_DRUM)
return; /* ignored */
oldval = chan->sfont_bank_prog;
@ -251,11 +252,19 @@ fluid_channel_set_bank_msb(fluid_channel_t* chan, int bankmsb)
int oldval, newval, style;
style = chan->synth->bank_select;
if (style == FLUID_BANK_STYLE_XG)
{
/* XG bank (128*MSB+LSB), save MSB, do drum-channel auto-switch */
/* The number "120" was based on several keyboards having drums at 120 - 127,
reference: http://lists.nongnu.org/archive/html/fluid-dev/2011-02/msg00003.html */
chan->channel_type = (120 <= bankmsb) ? CHANNEL_TYPE_DRUM : CHANNEL_TYPE_MELODIC;
return;
}
if (style == FLUID_BANK_STYLE_GM ||
style == FLUID_BANK_STYLE_XG ||
chan->channum == 9) //TODO: ask for channel drum mode, instead of number
chan->channel_type == CHANNEL_TYPE_DRUM)
return; /* ignored */
//TODO: if style == XG and bankmsb == 127, convert the channel to drum mode
oldval = chan->sfont_bank_prog;
if (style == FLUID_BANK_STYLE_GS)
@ -263,6 +272,7 @@ fluid_channel_set_bank_msb(fluid_channel_t* chan, int bankmsb)
else /* style == FLUID_BANK_STYLE_MMA */
newval = (oldval & ~BANKMSB_MASKVAL) | (bankmsb << (BANK_SHIFTVAL + 7));
chan->sfont_bank_prog = newval;
}
/* Get SoundFont ID, MIDI bank and/or program. Use NULL to ignore a value. */

View file

@ -74,6 +74,10 @@ struct _fluid_channel_t
* flag indicating whether the NRPN value is absolute or not.
*/
char gen_abs[GEN_LAST];
/* Drum channel flag, CHANNEL_TYPE_MELODIC, or CHANNEL_TYPE_DRUM. */
int channel_type;
};
fluid_channel_t* new_fluid_channel(fluid_synth_t* synth, int num);

View file

@ -1876,13 +1876,13 @@ fluid_synth_program_change(fluid_synth_t* synth, int chan, int prognum)
/* Special handling of channel 10 (or 9 counting from 0). channel
* 10 is the percussion channel.
*
* FIXME - Shouldn't hard code bank selection for channel 10. I think this
* FIXME - I think this
* is a hack for MIDI files that do bank changes in GM mode. Proper way to
* handle this would probably be to ignore bank changes when in GM mode. - JG
*/
if (prognum != FLUID_UNSET_PROGRAM)
{
if (channel->channum == 9)
if (channel->channel_type == CHANNEL_TYPE_DRUM)
preset = fluid_synth_find_preset(synth, DRUM_INST_BANK, prognum);
else preset = fluid_synth_find_preset(synth, banknum, prognum);
@ -1893,7 +1893,7 @@ fluid_synth_program_change(fluid_synth_t* synth, int chan, int prognum)
subst_prog = prognum;
/* Melodic instrument? */
if (channel->channum != 9 && banknum != DRUM_INST_BANK)
if ((channel->channel_type != CHANNEL_TYPE_DRUM) && (DRUM_INST_BANK != banknum))
{
subst_bank = 0;
@ -4990,3 +4990,23 @@ void fluid_synth_api_exit(fluid_synth_t* synth)
}
}
/**
* Set midi channel type
* @param synth FluidSynth instance
* @param chan MIDI channel number (0 to MIDI channel count - 1)
* @param type CHANNEL_TYPE_MELODIC, or CHANNEL_TYPE_DRUM
* @return FLUID_OK on success, FLUID_FAILED otherwise
* @since 1.1.3
*/
int fluid_synth_set_channel_type(fluid_synth_t* synth, int chan, int type)
{
fluid_return_val_if_fail ((type >= CHANNEL_TYPE_MELODIC) && (type <= CHANNEL_TYPE_DRUM), FLUID_FAILED);
FLUID_API_ENTRY_CHAN(FLUID_FAILED);
synth->channel[chan]->channel_type = type;
FLUID_API_RETURN(FLUID_OK);
}

View file

@ -1493,7 +1493,7 @@ fluid_voice_get_overflow_prio(fluid_voice_t* voice,
* Then it is very important.
* Also skip the released and sustained scores.
*/
if (voice->chan == 9){
if (voice->channel->channel_type == CHANNEL_TYPE_DRUM){
this_voice_prio += score->percussion;
}
else if (voice->has_noteoff) {