diff --git a/headers/libs/fluidsynth/fluidsynth/version.h b/headers/libs/fluidsynth/fluidsynth/version.h index 68a0c146c5..8dc10160af 100644 --- a/headers/libs/fluidsynth/fluidsynth/version.h +++ b/headers/libs/fluidsynth/fluidsynth/version.h @@ -26,10 +26,10 @@ extern "C" { #endif -#define FLUIDSYNTH_VERSION "1.0.8" +#define FLUIDSYNTH_VERSION "1.0.9" #define FLUIDSYNTH_VERSION_MAJOR 1 #define FLUIDSYNTH_VERSION_MINOR 0 -#define FLUIDSYNTH_VERSION_MICRO 8 +#define FLUIDSYNTH_VERSION_MICRO 9 FLUIDSYNTH_API void fluid_version(int *major, int *minor, int *micro); diff --git a/src/libs/fluidsynth/AUTHORS b/src/libs/fluidsynth/AUTHORS index 1580adf427..d158852d4a 100644 --- a/src/libs/fluidsynth/AUTHORS +++ b/src/libs/fluidsynth/AUTHORS @@ -1,3 +1,10 @@ +[:Team:] +Current development team + +Josh Green +Bernat Arlandis i Maņķ +Pedro Lopez-Cabanillas + [:Idea:] @@ -12,25 +19,24 @@ author. Josh Green is the current maintainer. Below you'll find a summary of contributions. -* Peter Hanappe. Initiated the project. files: sticked his nose in all +* Peter Hanappe. Initiated the project. files: stuck his nose in all files. * Josh Green is the current maintainer and contributed a lot of code directly or indirectly through the Swami and Smurf code base. The SoundFont loader is completely based on his code. He also wrote the alsa sequencer driver. He made many changes and bug fixes, - but above all, he's one of the driver forces behind the synthesizer. + but above all, he's one of the driving forces behind the synthesizer. He also created the current FluidSynth graphic logo with Blender (the blue waves with FluidSynth letters partially submerged). - files: iiwu_defsfont.{c,h}, iiwu_alsa{c,h} and others. * Markus Nentwig (re-)designed the resonant filter, the chorus, the LADSPA subsystem, the MIDI router, optimized for SSE, made many changes and bug fixes and got the synthesizer to actually work. Most - importantly, he used it on stage to make music. files: - iiwu_ladspa.{c,h}, iiwu_cmd.{c,h}, iiwu_voice.{c,h}, iiwu_synth.c, - iiwu_sse.h, iiwu_dsp_core.h, iiwu_rev.{c,h}, and basically all the - other files. + importantly, he used it on stage to make music. + +* S. Christian Collins did much testing of FluidSynth in regards to + EMU10K1 compatibility and provided many synthesis fixes in that regard. * Stephane Letz from Grame wrote most of the MidiShare driver, all of the PortAudio driver, ported iiwusynth to MacOS X, and sent in many @@ -98,7 +104,11 @@ summary of contributions. signed integer type). Mozilla NSPR library, www.mozilla.org. file: iiwu_phase.h -* Growing list of individuals who contributed bug fixes and corrections: +* KO Myung-Hun for OS/2 support with Dart audio driver. + +* Growing list of individuals who contributed bug fixes, corrections and minor features: +Pedro Lopez-Cabanillas for midi.winmidi.device setting. +Nicolas Boulicault for ALSA sequencer midi.portname setting. Werner Schweer Dave Philips Anthony Green diff --git a/src/libs/fluidsynth/src/config.h b/src/libs/fluidsynth/src/config.h index 8b9a92fbc8..c5a18ec6a7 100644 --- a/src/libs/fluidsynth/src/config.h +++ b/src/libs/fluidsynth/src/config.h @@ -160,11 +160,8 @@ /* Define to 1 if you have the ANSI C header files. */ #define STDC_HEADERS 1 -/* Define to use long long type, where appropriate */ -/* #undef USE_LONGLONG */ - /* Version number of package */ -#define VERSION "1.0.7" +#define VERSION "1.0.9" /* Define to do all DSP in single floating point precision */ #define WITH_FLOAT 1 diff --git a/src/libs/fluidsynth/src/fluid_adriver.c b/src/libs/fluidsynth/src/fluid_adriver.c index 4b49da728c..2749fe4c9a 100644 --- a/src/libs/fluidsynth/src/fluid_adriver.c +++ b/src/libs/fluidsynth/src/fluid_adriver.c @@ -37,6 +37,14 @@ typedef struct _fluid_audriver_definition_t } fluid_audriver_definition_t; +#if PULSE_SUPPORT +fluid_audio_driver_t* new_fluid_pulse_audio_driver(fluid_settings_t* settings, + fluid_synth_t* synth); +fluid_audio_driver_t* new_fluid_pulse_audio_driver2(fluid_settings_t* settings, + fluid_audio_func_t func, void* data); +int delete_fluid_pulse_audio_driver(fluid_audio_driver_t* p); +void fluid_pulse_audio_driver_settings(fluid_settings_t* settings); +#endif #if ALSA_SUPPORT fluid_audio_driver_t* new_fluid_alsa_audio_driver(fluid_settings_t* settings, @@ -74,6 +82,7 @@ void fluid_dsound_audio_driver_settings(fluid_settings_t* settings); #endif #if PORTAUDIO_SUPPORT +void fluid_portaudio_driver_settings (fluid_settings_t *settings); fluid_audio_driver_t* new_fluid_portaudio_driver(fluid_settings_t* settings, fluid_synth_t* synth); int delete_fluid_portaudio_driver(fluid_audio_driver_t* p); @@ -96,6 +105,13 @@ fluid_audio_driver_t* new_fluid_sndmgr_audio_driver2(fluid_settings_t* settings, int delete_fluid_sndmgr_audio_driver(fluid_audio_driver_t* p); #endif +#if DART_SUPPORT +fluid_audio_driver_t* new_fluid_dart_audio_driver(fluid_settings_t* settings, + fluid_synth_t* synth); +int delete_fluid_dart_audio_driver(fluid_audio_driver_t* p); +void fluid_dart_audio_driver_settings(fluid_settings_t* settings); +#endif + #define AUFILE_SUPPORT 1 #if AUFILE_SUPPORT fluid_audio_driver_t* new_fluid_file_audio_driver(fluid_settings_t* settings, @@ -104,13 +120,14 @@ int delete_fluid_file_audio_driver(fluid_audio_driver_t* p); void fluid_file_audio_driver_settings(fluid_settings_t* settings); #endif +/* Available audio drivers, listed in order of preference */ fluid_audriver_definition_t fluid_audio_drivers[] = { -#if OSS_SUPPORT - { "oss", - new_fluid_oss_audio_driver, - new_fluid_oss_audio_driver2, - delete_fluid_oss_audio_driver, - fluid_oss_audio_driver_settings }, +#if JACK_SUPPORT + { "jack", + new_fluid_jack_audio_driver, + new_fluid_jack_audio_driver2, + delete_fluid_jack_audio_driver, + fluid_jack_audio_driver_settings }, #endif #if ALSA_SUPPORT { "alsa", @@ -119,6 +136,20 @@ fluid_audriver_definition_t fluid_audio_drivers[] = { delete_fluid_alsa_audio_driver, fluid_alsa_audio_driver_settings }, #endif +#if OSS_SUPPORT + { "oss", + new_fluid_oss_audio_driver, + new_fluid_oss_audio_driver2, + delete_fluid_oss_audio_driver, + fluid_oss_audio_driver_settings }, +#endif +#if PULSE_SUPPORT + { "pulseaudio", + new_fluid_pulse_audio_driver, + new_fluid_pulse_audio_driver2, + delete_fluid_pulse_audio_driver, + fluid_pulse_audio_driver_settings }, +#endif #if COREAUDIO_SUPPORT { "coreaudio", new_fluid_core_audio_driver, @@ -138,7 +169,7 @@ fluid_audriver_definition_t fluid_audio_drivers[] = { new_fluid_portaudio_driver, NULL, delete_fluid_portaudio_driver, - NULL }, + fluid_portaudio_driver_settings }, #endif #if SNDMAN_SUPPORT { "sndman", @@ -147,12 +178,12 @@ fluid_audriver_definition_t fluid_audio_drivers[] = { delete_fluid_sndmgr_audio_driver, NULL }, #endif -#if JACK_SUPPORT - { "jack", - new_fluid_jack_audio_driver, - new_fluid_jack_audio_driver2, - delete_fluid_jack_audio_driver, - fluid_jack_audio_driver_settings }, +#if DART_SUPPORT + { "dart", + new_fluid_dart_audio_driver, + NULL, + delete_fluid_dart_audio_driver, + fluid_dart_audio_driver_settings }, #endif #if AUFILE_SUPPORT { "file", @@ -191,8 +222,12 @@ void fluid_audio_driver_settings(fluid_settings_t* settings) #endif /* Set the default driver */ -#if ALSA_SUPPORT +#if JACK_SUPPORT + fluid_settings_register_str(settings, "audio.driver", "jack", 0, NULL, NULL); +#elif ALSA_SUPPORT fluid_settings_register_str(settings, "audio.driver", "alsa", 0, NULL, NULL); +#elif PULSE_SUPPORT + fluid_settings_register_str(settings, "audio.driver", "pulseaudio", 0, NULL, NULL); #elif OSS_SUPPORT fluid_settings_register_str(settings, "audio.driver", "oss", 0, NULL, NULL); #elif COREAUDIO_SUPPORT @@ -203,8 +238,8 @@ void fluid_audio_driver_settings(fluid_settings_t* settings) fluid_settings_register_str(settings, "audio.driver", "sndman", 0, NULL, NULL); #elif PORTAUDIO_SUPPORT fluid_settings_register_str(settings, "audio.driver", "portaudio", 0, NULL, NULL); -#elif JACK_SUPPORT - fluid_settings_register_str(settings, "audio.driver", "jack", 0, NULL, NULL); +#elif DART_SUPPORT + fluid_settings_register_str(settings, "audio.driver", "dart", 0, NULL, NULL); #elif AUFILE_SUPPORT fluid_settings_register_str(settings, "audio.driver", "file", 0, NULL, NULL); #else @@ -212,6 +247,9 @@ void fluid_audio_driver_settings(fluid_settings_t* settings) #endif /* Add all drivers to the list of options */ +#if PULSE_SUPPORT + fluid_settings_add_option(settings, "audio.driver", "pulseaudio"); +#endif #if ALSA_SUPPORT fluid_settings_add_option(settings, "audio.driver", "alsa"); #endif @@ -233,6 +271,9 @@ void fluid_audio_driver_settings(fluid_settings_t* settings) #if JACK_SUPPORT fluid_settings_add_option(settings, "audio.driver", "jack"); #endif +#if DART_SUPPORT + fluid_settings_add_option(settings, "audio.driver", "dart"); +#endif #if AUFILE_SUPPORT fluid_settings_add_option(settings, "audio.driver", "file"); #endif diff --git a/src/libs/fluidsynth/src/fluid_chan.c b/src/libs/fluidsynth/src/fluid_chan.c index f0e7346ade..3406c4ba85 100644 --- a/src/libs/fluidsynth/src/fluid_chan.c +++ b/src/libs/fluidsynth/src/fluid_chan.c @@ -62,6 +62,7 @@ fluid_channel_init(fluid_channel_t* chan) chan->interp_method = FLUID_INTERP_DEFAULT; chan->tuning = NULL; chan->nrpn_select = 0; + chan->nrpn_active = 0; } void @@ -85,16 +86,20 @@ fluid_channel_init_ctrl(fluid_channel_t* chan) } /* Volume / initial attenuation (MSB & LSB) */ - SETCC(chan, 7, 127); - SETCC(chan, 39, 0); + SETCC(chan, VOLUME_MSB, 127); + SETCC(chan, VOLUME_LSB, 0); /* Pan (MSB & LSB) */ - SETCC(chan, 10, 64); - SETCC(chan, 10, 64); + SETCC(chan, PAN_MSB, 64); + SETCC(chan, PAN_LSB, 0); /* Expression (MSB & LSB) */ - SETCC(chan, 11, 127); - SETCC(chan, 43, 127); + SETCC(chan, EXPRESSION_MSB, 127); + SETCC(chan, EXPRESSION_LSB, 127); + + /* Set RPN controllers to NULL state */ + SETCC(chan, RPN_LSB, 127); + SETCC(chan, RPN_MSB, 127); } void @@ -241,18 +246,52 @@ fluid_channel_cc(fluid_channel_t* chan, int num, int value) { int data = (value << 7) + chan->cc[DATA_ENTRY_LSB]; - /* SontFont 2.01 NRPN Message (Sect. 9.6, p. 74) */ - if ((chan->cc[NRPN_MSB] == 120) && (chan->cc[NRPN_LSB] < 100)) { - float val = fluid_gen_scale_nrpn(chan->nrpn_select, data); - FLUID_LOG(FLUID_WARN, "%s: %d: Data = %d, value = %f", __FILE__, __LINE__, data, val); - fluid_synth_set_gen(chan->synth, chan->channum, chan->nrpn_select, val); + if (chan->nrpn_active) /* NRPN is active? */ + { + /* SontFont 2.01 NRPN Message (Sect. 9.6, p. 74) */ + if ((chan->cc[NRPN_MSB] == 120) && (chan->cc[NRPN_LSB] < 100)) + { + if (chan->nrpn_select < GEN_LAST) + { + float val = fluid_gen_scale_nrpn(chan->nrpn_select, data); + fluid_synth_set_gen(chan->synth, chan->channum, chan->nrpn_select, val); + } + + chan->nrpn_select = 0; /* Reset to 0 */ + } } + else if (chan->cc[RPN_MSB] == 0) /* RPN is active: MSB = 0? */ + { + switch (chan->cc[RPN_LSB]) + { + case RPN_PITCH_BEND_RANGE: + fluid_channel_pitch_wheel_sens (chan, value); /* Set bend range in semitones */ + /* FIXME - Handle LSB? (Fine bend range in cents) */ + break; + case RPN_CHANNEL_FINE_TUNE: /* Fine tune is 14 bit over 1 semitone (+/- 50 cents, 8192 = center) */ + fluid_synth_set_gen(chan->synth, chan->channum, GEN_FINETUNE, + (data - 8192) / 8192.0 * 50.0); + break; + case RPN_CHANNEL_COARSE_TUNE: /* Coarse tune is 7 bit and in semitones (64 is center) */ + fluid_synth_set_gen(chan->synth, chan->channum, GEN_COARSETUNE, + value - 64); + break; + case RPN_TUNING_PROGRAM_CHANGE: + break; + case RPN_TUNING_BANK_SELECT: + break; + case RPN_MODULATION_DEPTH_RANGE: + break; + } + } + break; } case NRPN_MSB: chan->cc[NRPN_LSB] = 0; chan->nrpn_select = 0; + chan->nrpn_active = 1; break; case NRPN_LSB: @@ -266,19 +305,15 @@ fluid_channel_cc(fluid_channel_t* chan, int num, int value) chan->nrpn_select += 10000; } else if (value < 100) { chan->nrpn_select += value; - FLUID_LOG(FLUID_WARN, "%s: %d: NRPN Select = %d", __FILE__, __LINE__, chan->nrpn_select); } } + + chan->nrpn_active = 1; break; case RPN_MSB: - break; - case RPN_LSB: - /* erase any previously received NRPN message */ - chan->cc[NRPN_MSB] = 0; - chan->cc[NRPN_LSB] = 0; - chan->nrpn_select = 0; + chan->nrpn_active = 0; break; default: @@ -297,6 +332,17 @@ fluid_channel_get_cc(fluid_channel_t* chan, int num) return ((num >= 0) && (num < 128))? chan->cc[num] : 0; } +/* + * fluid_channel_pressure + */ +int +fluid_channel_pressure(fluid_channel_t* chan, int val) +{ + chan->channel_pressure = val; + fluid_synth_modulate_voices(chan->synth, chan->channum, 0, FLUID_MOD_CHANNELPRESSURE); + return FLUID_OK; +} + /* * fluid_channel_pitch_bend */ diff --git a/src/libs/fluidsynth/src/fluid_chan.h b/src/libs/fluidsynth/src/fluid_chan.h index 72e201849f..504aabb9a2 100644 --- a/src/libs/fluidsynth/src/fluid_chan.h +++ b/src/libs/fluidsynth/src/fluid_chan.h @@ -53,6 +53,7 @@ struct _fluid_channel_t /* NRPN system */ short nrpn_select; + short nrpn_active; /* 1 if data entry CCs are for NRPN, 0 if RPN */ /* The values of the generators, set by NRPN messages, or by * fluid_synth_set_gen(), are cached in the channel so they can be @@ -87,6 +88,7 @@ int fluid_channel_set_banknum(fluid_channel_t* chan, unsigned int bank); int fluid_channel_set_prognum(fluid_channel_t* chan, int prognum); int fluid_channel_get_prognum(fluid_channel_t* chan); int fluid_channel_cc(fluid_channel_t* chan, int ctrl, int val); +int fluid_channel_pressure(fluid_channel_t* chan, int val); int fluid_channel_pitch_bend(fluid_channel_t* chan, int val); int fluid_channel_pitch_wheel_sens(fluid_channel_t* chan, int val); int fluid_channel_get_cc(fluid_channel_t* chan, int num); diff --git a/src/libs/fluidsynth/src/fluid_conv.h b/src/libs/fluidsynth/src/fluid_conv.h index ec9b7bdaa7..83bb21e908 100644 --- a/src/libs/fluidsynth/src/fluid_conv.h +++ b/src/libs/fluidsynth/src/fluid_conv.h @@ -32,7 +32,8 @@ /* EMU 8k/10k don't follow spec in regards to volume attenuation. * This factor is used in the equation pow (10.0, cb / FLUID_ATTEN_POWER_FACTOR). * By the standard this should be -200.0. */ -#define FLUID_ATTEN_POWER_FACTOR (-531.509) +/* 07/11/2008 modified by S. Christian Collins for increased velocity sensitivity. Now it equals the response of EMU10K1 programming.*/ +#define FLUID_ATTEN_POWER_FACTOR (-200.0) /* was (-531.509)*/ void fluid_conversion_config(void); diff --git a/src/libs/fluidsynth/src/fluid_defsfont.c b/src/libs/fluidsynth/src/fluid_defsfont.c index ba0f7eb2d0..c6bd713bc0 100644 --- a/src/libs/fluidsynth/src/fluid_defsfont.c +++ b/src/libs/fluidsynth/src/fluid_defsfont.c @@ -689,7 +689,7 @@ fluid_defpreset_noteon(fluid_defpreset_t* preset, fluid_synth_t* synth, int chan * page 69, 'bullet' 3 defines 'identical'. */ for (i = 0; i < mod_list_count; i++){ - if (fluid_mod_test_identity(mod,mod_list[i])){ + if (mod_list[i] && fluid_mod_test_identity(mod,mod_list[i])){ mod_list[i] = NULL; } } @@ -768,7 +768,7 @@ fluid_defpreset_noteon(fluid_defpreset_t* preset, fluid_synth_t* synth, int chan mod = preset_zone->mod; while (mod){ for (i = 0; i < mod_list_count; i++){ - if (fluid_mod_test_identity(mod,mod_list[i])){ + if (mod_list[i] && fluid_mod_test_identity(mod,mod_list[i])){ mod_list[i] = NULL; } } diff --git a/src/libs/fluidsynth/src/fluid_mdriver.c b/src/libs/fluidsynth/src/fluid_mdriver.c index c9d3886aee..7ce5c217e6 100644 --- a/src/libs/fluidsynth/src/fluid_mdriver.c +++ b/src/libs/fluidsynth/src/fluid_mdriver.c @@ -37,6 +37,15 @@ int delete_fluid_alsa_seq_driver(fluid_midi_driver_t* p); void fluid_alsa_seq_driver_settings(fluid_settings_t* settings); #endif +/* JACK */ +#if JACK_SUPPORT +void fluid_jack_midi_driver_settings (fluid_settings_t *settings); +fluid_midi_driver_t *new_fluid_jack_midi_driver (fluid_settings_t *settings, + handle_midi_event_func_t handler, + void *data); +int delete_fluid_jack_midi_driver(fluid_midi_driver_t *p); +#endif + /* OSS */ #if OSS_SUPPORT fluid_midi_driver_t* new_fluid_oss_midi_driver(fluid_settings_t* settings, @@ -52,6 +61,7 @@ fluid_midi_driver_t* new_fluid_winmidi_driver(fluid_settings_t* settings, handle_midi_event_func_t handler, void* event_handler_data); int delete_fluid_winmidi_driver(fluid_midi_driver_t* p); +void fluid_winmidi_midi_driver_settings(fluid_settings_t* settings); #endif /* definitions for the MidiShare driver */ @@ -62,6 +72,14 @@ fluid_midi_driver_t* new_fluid_midishare_midi_driver(fluid_settings_t* settings, int delete_fluid_midishare_midi_driver(fluid_midi_driver_t* p); #endif +/* definitions for the CoreMidi driver */ +#if COREMIDI_SUPPORT +fluid_midi_driver_t* new_fluid_coremidi_driver(fluid_settings_t* settings, + void* event_handler_data, + handle_midi_event_func_t handler); +int delete_fluid_coremidi_driver(fluid_midi_driver_t* p); +void fluid_coremidi_driver_settings(fluid_settings_t* settings); +#endif /* @@ -78,6 +96,12 @@ struct fluid_mdriver_definition_t { struct fluid_mdriver_definition_t fluid_midi_drivers[] = { +#if JACK_SUPPORT + { "jack", + new_fluid_jack_midi_driver, + delete_fluid_jack_midi_driver, + fluid_jack_midi_driver_settings }, +#endif #if OSS_SUPPORT { "oss", new_fluid_oss_midi_driver, @@ -98,13 +122,19 @@ struct fluid_mdriver_definition_t fluid_midi_drivers[] = { { "winmidi", new_fluid_winmidi_driver, delete_fluid_winmidi_driver, - NULL }, + fluid_winmidi_midi_driver_settings }, #endif #if MIDISHARE_SUPPORT { "midishare", new_fluid_midishare_midi_driver, delete_fluid_midishare_midi_driver, NULL }, +#endif +#if COREMIDI_SUPPORT + { "coremidi", + new_fluid_coremidi_driver, + delete_fluid_coremidi_driver, + fluid_coremidi_driver_settings }, #endif { NULL, NULL, NULL, NULL } }; @@ -118,12 +148,16 @@ void fluid_midi_driver_settings(fluid_settings_t* settings) /* Set the default driver */ #if ALSA_SUPPORT fluid_settings_register_str(settings, "midi.driver", "alsa_seq", 0, NULL, NULL); +#elif JACK_SUPPORT + fluid_settings_register_str(settings, "midi.driver", "jack", 0, NULL, NULL); #elif OSS_SUPPORT fluid_settings_register_str(settings, "midi.driver", "oss", 0, NULL, NULL); #elif WINMIDI_SUPPORT fluid_settings_register_str(settings, "midi.driver", "winmidi", 0, NULL, NULL); #elif MIDISHARE_SUPPORT fluid_settings_register_str(settings, "midi.driver", "midishare", 0, NULL, NULL); +#elif COREMIDI_SUPPORT + fluid_settings_register_str(settings, "midi.driver", "coremidi", 0, NULL, NULL); #else fluid_settings_register_str(settings, "midi.driver", "", 0, NULL, NULL); #endif @@ -133,6 +167,9 @@ void fluid_midi_driver_settings(fluid_settings_t* settings) fluid_settings_add_option(settings, "midi.driver", "alsa_seq"); fluid_settings_add_option(settings, "midi.driver", "alsa_raw"); #endif +#if JACK_SUPPORT + fluid_settings_add_option(settings, "midi.driver", "jack"); +#endif #if OSS_SUPPORT fluid_settings_add_option(settings, "midi.driver", "oss"); #endif @@ -142,6 +179,9 @@ void fluid_midi_driver_settings(fluid_settings_t* settings) #if MIDISHARE_SUPPORT fluid_settings_add_option(settings, "midi.driver", "midishare"); #endif +#if COREMIDI_SUPPORT + fluid_settings_add_option(settings, "midi.driver", "coremidi"); +#endif for (i = 0; fluid_midi_drivers[i].name != NULL; i++) { if (fluid_midi_drivers[i].settings != NULL) { @@ -168,7 +208,7 @@ fluid_midi_driver_t* new_fluid_midi_driver(fluid_settings_t* settings, handle_mi FLUID_LOG(FLUID_DBG, "Using '%s' midi driver", fluid_midi_drivers[i].name); driver = fluid_midi_drivers[i].new(settings, handler, event_handler_data); if (driver) { - driver->name = fluid_midi_drivers[i].name; + driver->name = fluid_midi_drivers[i].name; } return driver; } diff --git a/src/libs/fluidsynth/src/fluid_midi.c b/src/libs/fluidsynth/src/fluid_midi.c index 5579b99f1d..31105a5d29 100644 --- a/src/libs/fluidsynth/src/fluid_midi.c +++ b/src/libs/fluidsynth/src/fluid_midi.c @@ -272,6 +272,7 @@ int fluid_midi_file_read_track(fluid_midi_file* mf, fluid_player_t* player, int return FLUID_FAILED; } id[4]='\0'; + mf->dtime = 0; while (!found_track){ @@ -354,7 +355,6 @@ int fluid_midi_file_read_varlen(fluid_midi_file* mf) */ int fluid_midi_file_read_event(fluid_midi_file* mf, fluid_track_t* track) { - int dtime; int status; int type; int tempo; @@ -371,7 +371,7 @@ int fluid_midi_file_read_event(fluid_midi_file* mf, fluid_track_t* track) if (fluid_midi_file_read_varlen(mf) != FLUID_OK) { return FLUID_FAILED; } - dtime = mf->varlen; + mf->dtime += mf->varlen; /* read the status byte */ status = fluid_midi_file_getc(mf); @@ -519,12 +519,13 @@ int fluid_midi_file_read_event(fluid_midi_file* mf, fluid_track_t* track) result = FLUID_FAILED; break; } - evt->dtime = dtime; + 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: @@ -642,12 +643,13 @@ int fluid_midi_file_read_event(fluid_midi_file* mf, fluid_track_t* track) FLUID_LOG(FLUID_ERR, "Out of memory"); return FLUID_FAILED; } - evt->dtime = dtime; + 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; diff --git a/src/libs/fluidsynth/src/fluid_midi.h b/src/libs/fluidsynth/src/fluid_midi.h index 1fe556286a..8f0dd248bb 100644 --- a/src/libs/fluidsynth/src/fluid_midi.h +++ b/src/libs/fluidsynth/src/fluid_midi.h @@ -146,6 +146,16 @@ enum fluid_midi_control_change { POLY_ON = 0x7F }; +/* General MIDI RPN event numbers (LSB, MSB = 0) */ +enum midi_rpn_event { + RPN_PITCH_BEND_RANGE = 0x00, + RPN_CHANNEL_FINE_TUNE = 0x01, + RPN_CHANNEL_COARSE_TUNE = 0x02, + RPN_TUNING_PROGRAM_CHANGE = 0x03, + RPN_TUNING_BANK_SELECT = 0x04, + RPN_MODULATION_DEPTH_RANGE = 0x05 +}; + enum midi_meta_event { MIDI_COPYRIGHT = 0x02, MIDI_TRACK_NAME = 0x03, @@ -280,6 +290,7 @@ typedef struct { int trackpos; int eot; int varlen; + int dtime; } fluid_midi_file; fluid_midi_file* new_fluid_midi_file(char* filename); diff --git a/src/libs/fluidsynth/src/fluid_mod.c b/src/libs/fluidsynth/src/fluid_mod.c index c8839ab4e7..a092e4259e 100644 --- a/src/libs/fluidsynth/src/fluid_mod.c +++ b/src/libs/fluidsynth/src/fluid_mod.c @@ -146,12 +146,17 @@ fluid_mod_get_value(fluid_mod_t* mod, fluid_channel_t* chan, fluid_voice_t* voic (mod->flags2 == (FLUID_MOD_GC | FLUID_MOD_UNIPOLAR | FLUID_MOD_POSITIVE | FLUID_MOD_SWITCH)) && (mod->dest == GEN_FILTERFC)) { +// S. Christian Collins' mod, to stop forcing velocity based filtering +/* if (voice->vel < 64){ return (fluid_real_t) mod->amount / 2.0; } else { return (fluid_real_t) mod->amount * (127 - voice->vel) / 127; } +*/ + return 0; // (fluid_real_t) mod->amount / 2.0; } +// end S. Christian Collins' mod /* get the initial value of the first source */ if (mod->src1 > 0) { @@ -198,7 +203,7 @@ fluid_mod_get_value(fluid_mod_t* mod, fluid_channel_t* chan, fluid_voice_t* voic v1 = -1.0f + 2.0f * v1 / range1; break; case 3: /* linear, bipolar, negative */ - v1 = -1.0f + 2.0f * v1 / range1; + v1 = 1.0f - 2.0f * v1 / range1; break; case 4: /* concave, unipolar, positive */ v1 = fluid_concave(v1); @@ -219,7 +224,7 @@ fluid_mod_get_value(fluid_mod_t* mod, fluid_channel_t* chan, fluid_voice_t* voic v1 = fluid_convex(127 - v1); break; case 10: /* convex, bipolar, positive */ - v1 = (v1 > 64)? -fluid_convex(2 * (v1 - 64)) : fluid_convex(2 * (64 - v1)); + v1 = (v1 > 64)? fluid_convex(2 * (v1 - 64)) : -fluid_convex(2 * (64 - v1)); break; case 11: /* convex, bipolar, negative */ v1 = (v1 > 64)? -fluid_convex(2 * (v1 - 64)) : fluid_convex(2 * (64 - v1)); diff --git a/src/libs/fluidsynth/src/fluid_synth.c b/src/libs/fluidsynth/src/fluid_synth.c index d8307d7bf5..a81c3ba8f7 100644 --- a/src/libs/fluidsynth/src/fluid_synth.c +++ b/src/libs/fluidsynth/src/fluid_synth.c @@ -112,6 +112,7 @@ void fluid_synth_settings(fluid_settings_t* settings) fluid_settings_register_str(settings, "synth.reverb.active", "yes", 0, NULL, NULL); fluid_settings_register_str(settings, "synth.chorus.active", "yes", 0, NULL, NULL); fluid_settings_register_str(settings, "synth.ladspa.active", "no", 0, NULL, NULL); + fluid_settings_register_str(settings, "midi.portname", "", 0, NULL, NULL); fluid_settings_register_int(settings, "synth.polyphony", 256, 16, 4096, 0, NULL, NULL); @@ -996,8 +997,48 @@ fluid_synth_modulate_voices_all(fluid_synth_t* synth, int chan) return FLUID_OK; } -/* - * fluid_synth_pitch_bend +/** + * Set the MIDI channel pressure controller value. + * @param synth FluidSynth instance + * @param chan MIDI channel number + * @param val MIDI channel pressure value (7 bit, 0-127) + * @return FLUID_OK on success + * + * Assign to the MIDI channel pressure controller value on a specific MIDI channel + * in real time. + */ +int +fluid_synth_channel_pressure(fluid_synth_t* synth, int chan, int val) +{ + +/* fluid_mutex_lock(synth->busy); /\* Don't interfere with the audio thread *\/ */ +/* fluid_mutex_unlock(synth->busy); */ + + /* check the ranges of the arguments */ + if ((chan < 0) || (chan >= synth->midi_channels)) { + FLUID_LOG(FLUID_WARN, "Channel out of range"); + return FLUID_FAILED; + } + + if (synth->verbose) { + FLUID_LOG(FLUID_INFO, "channelpressure\t%d\t%d", chan, val); + } + + /* set the channel pressure value in the channel */ + fluid_channel_pressure(synth->channel[chan], val); + + return FLUID_OK; +} + +/** + * Set the MIDI pitch bend controller value. + * @param synth FluidSynth instance + * @param chan MIDI channel number + * @param val MIDI pitch bend value (14 bit, 0-16383 with 8192 being center) + * @return FLUID_OK on success + * + * Assign to the MIDI pitch bend controller value on a specific MIDI channel + * in real time. */ int fluid_synth_pitch_bend(fluid_synth_t* synth, int chan, int val) @@ -1169,48 +1210,72 @@ fluid_synth_program_change(fluid_synth_t* synth, int chan, int prognum) fluid_channel_t* channel; unsigned int banknum; unsigned int sfont_id; + int subst_bank, subst_prog; -/* fluid_mutex_lock(synth->busy); /\* Don't interfere with the audio thread *\/ */ -/* fluid_mutex_unlock(synth->busy); */ - - if ((prognum >= 0) && (prognum < FLUID_NUM_PROGRAMS) && - (chan >= 0) && (chan < synth->midi_channels)) { - - channel = synth->channel[chan]; - banknum = fluid_channel_get_banknum(channel); - - /* inform the channel of the new program number */ - fluid_channel_set_prognum(channel, prognum); - - if (synth->verbose) { - FLUID_LOG(FLUID_INFO, "prog\t%d\t%d\t%d", chan, banknum, prognum); - } - - /* special handling of channel 10 (or 9 counting from 0). channel - 10 is the percussion channel. */ - if (channel->channum == 9) { - - /* try to search the drum instrument first */ - preset = fluid_synth_find_preset(synth, banknum | DRUM_INST_MASK, prognum); - - /* if that fails try to search the melodic instrument */ - if (preset == NULL) { - preset = fluid_synth_find_preset(synth, banknum, prognum); - } - - } else { - preset = fluid_synth_find_preset(synth, banknum, prognum); - } - - sfont_id = preset? fluid_sfont_get_id(preset->sfont) : 0; - fluid_channel_set_sfontnum(channel, sfont_id); - fluid_channel_set_preset(channel, preset); - - return FLUID_OK; + if ((prognum < 0) || (prognum >= FLUID_NUM_PROGRAMS) || + (chan < 0) || (chan >= synth->midi_channels)) + { + FLUID_LOG(FLUID_ERR, "Index out of range (chan=%d, prog=%d)", chan, prognum); + return FLUID_FAILED; } - FLUID_LOG(FLUID_ERR, "Index out of range (chan=%d, prog=%d)", chan, prognum); - return FLUID_FAILED; + channel = synth->channel[chan]; + banknum = fluid_channel_get_banknum(channel); + + /* inform the channel of the new program number */ + fluid_channel_set_prognum(channel, prognum); + + if (synth->verbose) + FLUID_LOG(FLUID_INFO, "prog\t%d\t%d\t%d", chan, banknum, 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 + * 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. + */ + if (channel->channum == 9) + preset = fluid_synth_find_preset(synth, DRUM_INST_BANK, prognum); + else preset = fluid_synth_find_preset(synth, banknum, prognum); + + /* Fallback to another preset if not found */ + if (!preset) + { + subst_bank = banknum; + subst_prog = prognum; + + /* Melodic instrument? */ + if (channel->channum != 9 && banknum != DRUM_INST_BANK) + { + subst_bank = 0; + + /* Fallback first to bank 0:prognum */ + preset = fluid_synth_find_preset(synth, 0, prognum); + + /* Fallback to first preset in bank 0 */ + if (!preset && prognum != 0) + { + preset = fluid_synth_find_preset(synth, 0, 0); + subst_prog = 0; + } + } + else /* Percussion: Fallback to preset 0 in percussion bank */ + { + preset = fluid_synth_find_preset(synth, DRUM_INST_BANK, 0); + subst_prog = 0; + } + + if (preset) + FLUID_LOG(FLUID_WARN, "Instrument not found on channel %d [bank=%d prog=%d], substituted [bank=%d prog=%d]", + chan, banknum, prognum, subst_bank, subst_prog); + } + + sfont_id = preset? fluid_sfont_get_id(preset->sfont) : 0; + fluid_channel_set_sfontnum(channel, sfont_id); + fluid_channel_set_preset(channel, preset); + + return FLUID_OK; } /* @@ -1562,13 +1627,11 @@ void fluid_synth_set_chorus(fluid_synth_t* synth, int nr, double level, */ int fluid_synth_nwrite_float(fluid_synth_t* synth, int len, - float** left, float** right, - float** fx_left, float** fx_right) + float** left, float** right, + float** fx_left, float** fx_right) { fluid_real_t** left_in = synth->left_buf; fluid_real_t** right_in = synth->right_buf; - fluid_real_t** fx_left_in = synth->fx_left_buf; - fluid_real_t** fx_right_in = synth->fx_right_buf; double time = fluid_utime(); int i, num, available, count, bytes; @@ -1590,10 +1653,6 @@ fluid_synth_nwrite_float(fluid_synth_t* synth, int len, FLUID_MEMCPY(left[i], left_in[i] + synth->cur, bytes); FLUID_MEMCPY(right[i], right_in[i] + synth->cur, bytes); } - for (i = 0; i < synth->effects_channels; i++) { - FLUID_MEMCPY(fx_left[i], fx_left_in[i] + synth->cur, bytes); - FLUID_MEMCPY(fx_right[i], fx_right_in[i] + synth->cur, bytes); - } count += num; num += synth->cur; /* if we're now done, num becomes the new synth->cur below */ } @@ -1609,10 +1668,6 @@ fluid_synth_nwrite_float(fluid_synth_t* synth, int len, FLUID_MEMCPY(left[i] + count, left_in[i], bytes); FLUID_MEMCPY(right[i] + count, right_in[i], bytes); } - for (i = 0; i < synth->effects_channels; i++) { - FLUID_MEMCPY(fx_left[i] + count, fx_left_in[i], bytes); - FLUID_MEMCPY(fx_right[i] + count, fx_right_in[i], bytes); - } count += num; } @@ -1628,11 +1683,28 @@ fluid_synth_nwrite_float(fluid_synth_t* synth, int len, return 0; } + int fluid_synth_process(fluid_synth_t* synth, int len, int nin, float** in, int nout, float** out) { - return fluid_synth_write_float(synth, len, out[0], 0, 1, out[1], 0, 1); + if (nout==2) { + return fluid_synth_write_float(synth, len, out[0], 0, 1, out[1], 0, 1); + } + else { + float **left, **right; + int i; + left = FLUID_ARRAY(float*, nout/2); + right = FLUID_ARRAY(float*, nout/2); + for(i=0; icont = 1; + timer->msec = msec; + timer->callback = callback; + timer->data = data; + timer->thread_id =-1; + timer->auto_destroy = auto_destroy; + + if (new_thread) { + timer->thread_id = _beginthread( fluid_timer_run, NULL, 256 * 1024, ( void * )timer ); + if (timer->thread_id == -1) { + FLUID_LOG(FLUID_ERR, "Couldn't create timer thread"); + FLUID_FREE(timer); + return NULL; + } + DosSetPriority(PRTYS_THREAD, PRTYC_TIMECRITICAL, PRTYD_MAXIMUM, timer->thread_id); + } else { + fluid_timer_run(( void * )timer); + } + return timer; +} + +void +fluid_timer_run(void *data) +{ + int count = 0; + int cont = 1; + long start; + long delay; + fluid_timer_t* timer; + timer = (fluid_timer_t*) data; + + if ((timer == NULL) || (timer->callback == NULL)) { + return; + } + + DosSetPriority( PRTYS_THREAD, PRTYC_REGULAR, PRTYD_MAXIMUM, 0 ); + + /* keep track of the start time for absolute positioning */ + start = fluid_curtime(); + + while (cont) { + + /* do whatever we have to do */ + cont = (*timer->callback)(timer->data, fluid_curtime() - start); + + count++; + + /* to avoid incremental time errors, I calculate the delay between + two callbacks bringing in the "absolute" time (count * + timer->msec) */ + delay = (count * timer->msec) - (fluid_curtime() - start); + if (delay > 0) { + DosSleep(delay); + } + + cont &= timer->cont; + } + + FLUID_LOG(FLUID_DBG, "Timer thread finished"); + + if (timer->auto_destroy) { + FLUID_FREE(timer); + } + + return; +} + +int +delete_fluid_timer(fluid_timer_t* timer) +{ + timer->cont = 0; + fluid_timer_join(timer); + FLUID_FREE(timer); + return FLUID_OK; +} + +int +fluid_timer_join(fluid_timer_t* timer) +{ + ULONG wait_result; + if (timer->thread_id == -1) { + return FLUID_OK; + } + wait_result = DosWaitThread(&timer->thread_id, DCWW_WAIT); + return (wait_result == 0)? FLUID_OK : FLUID_FAILED; +} + + +/*************************************************************** + * + * Time + */ + +double rdtsc(void); +double fluid_estimate_cpu_frequency(void); + +static double fluid_cpu_frequency = -1.0; + +void fluid_time_config(void) +{ + if (fluid_cpu_frequency < 0.0) { + fluid_cpu_frequency = fluid_estimate_cpu_frequency() / 1000000.0; + } +} + +unsigned int fluid_curtime(void) +{ + ULONG ulMS; + DosQuerySysInfo( QSV_MS_COUNT, QSV_MS_COUNT, &ulMS, sizeof( ULONG )); + return ulMS; +} + +double fluid_utime(void) +{ + return (rdtsc() / fluid_cpu_frequency); +} + +#define Q2ULL( q ) (*(unsigned long long *)&q) + +double rdtsc(void) +{ + QWORD t; + DosTmrQueryTime(&t); + return (double)Q2ULL(t); +} + +double fluid_estimate_cpu_frequency(void) +{ + unsigned int before, after; + QWORD start, stop; + + before = fluid_curtime(); + DosTmrQueryTime(&start); + + DosSleep(1000); + + after = fluid_curtime(); + DosTmrQueryTime(&stop); + + return (double) 1000 * (Q2ULL(stop) - Q2ULL(start)) / (after - before); +} + #elif defined(__BEOS__) || defined(__HAIKU__) struct _fluid_timer_t @@ -1153,6 +1332,75 @@ int fluid_thread_join(fluid_thread_t* thread) return (wait_result == WAIT_OBJECT_0)? FLUID_OK : FLUID_FAILED; } +#elif defined(__OS2__) + +struct _fluid_thread_t { + int thread_id; + fluid_thread_func_t func; + void* data; + int detached; +}; + +static void fluid_thread_start(void *data) +{ + fluid_thread_t* thread = (fluid_thread_t*) data; + + thread->func(thread->data); + + if (thread->detached) { + FLUID_FREE(thread); + } + + return 0; +} + + +fluid_thread_t* new_fluid_thread(fluid_thread_func_t func, void* data, int detach) +{ + fluid_thread_t* thread; + + if (func == NULL) { + FLUID_LOG(FLUID_ERR, "Invalid thread function"); + return NULL; + } + + thread = FLUID_NEW(fluid_thread_t); + if (thread == NULL) { + FLUID_LOG(FLUID_ERR, "Out of memory"); + return NULL; + } + + thread->data = data; + thread->func = func; + thread->detached = detach; + + thread->thread_id = _beginthread(fluid_thread_start, NULL, 256 * 1024, (void *) thread); + if (thread->thread_id == -1) { + FLUID_LOG(FLUID_ERR, "Couldn't create the thread"); + FLUID_FREE(thread); + return NULL; + } + + return thread; +} + +int delete_fluid_thread(fluid_thread_t* thread) +{ + FLUID_FREE(thread); + return FLUID_OK; +} + + +int fluid_thread_join(fluid_thread_t* thread) +{ + ULONG wait_result; + if (thread->thread_id == -1) { + return FLUID_OK; + } + wait_result = DosWaitThread(&thread->thread_id, DCWW_WAIT); + return (wait_result == 0)? FLUID_OK : FLUID_FAILED; +} + #elif defined(__BEOS__) || defined(__HAIKU__) /* Not implemented */ fluid_thread_t* new_fluid_thread(fluid_thread_func_t func, void* data, int detach) { return NULL; } diff --git a/src/libs/fluidsynth/src/fluid_sys.h b/src/libs/fluidsynth/src/fluid_sys.h index c82745a10e..38b9b3b1bd 100644 --- a/src/libs/fluidsynth/src/fluid_sys.h +++ b/src/libs/fluidsynth/src/fluid_sys.h @@ -90,6 +90,15 @@ double fluid_utime(void); unsigned int fluid_curtime(); #define fluid_utime() 0.0 +#elif defined(__OS2__) +#define INCL_DOS +#include + +typedef int socklen_t; + +unsigned int fluid_curtime(void); +double fluid_utime(void); + #elif (defined(__BEOS__) || defined(__HAIKU__)) #include @@ -143,13 +152,12 @@ typedef HANDLE fluid_mutex_t; #define fluid_mutex_lock(_m) WaitForSingleObject(_m, INFINITE) #define fluid_mutex_unlock(_m) ReleaseMutex(_m) -#else -#ifndef HAIKU_TARGET_PLATFORM_HAIKU -typedef sem_id fluid_mutex_t; -#define fluid_mutex_init(_m) { (_m) = create_sem(1, "fs_sem"); } -#define fluid_mutex_destroy(_m) delete_sem(_m); -#define fluid_mutex_lock(_m) acquire_sem(_m); -#define fluid_mutex_unlock(_m) release_sem(_m); +#elif defined(__OS2__) +typedef HMTX fluid_mutex_t; +#define fluid_mutex_init(_m) { (_m) = 0; DosCreateMutexSem( NULL, &(_m), 0, FALSE ); } +#define fluid_mutex_destroy(_m) if (_m) { DosCloseMutexSem(_m); } +#define fluid_mutex_lock(_m) DosRequestMutexSem(_m, -1L) +#define fluid_mutex_unlock(_m) DosReleaseMutexSem(_m) #else typedef pthread_mutex_t fluid_mutex_t; @@ -158,7 +166,6 @@ typedef pthread_mutex_t fluid_mutex_t; #define fluid_mutex_lock(_m) pthread_mutex_lock(&(_m)) #define fluid_mutex_unlock(_m) pthread_mutex_unlock(&(_m)) #endif -#endif /** @@ -283,7 +290,7 @@ extern fluid_profile_data_t fluid_profile_data[]; sample data. */ -#if HAVE_SYS_MMAN_H +#if defined(HAVE_SYS_MMAN_H) && !defined(__OS2__) #define fluid_mlock(_p,_n) mlock(_p, _n) #define fluid_munlock(_p,_n) munlock(_p,_n) #else diff --git a/src/libs/fluidsynth/src/fluid_voice.c b/src/libs/fluidsynth/src/fluid_voice.c index d8cc676b50..843aeacb74 100644 --- a/src/libs/fluidsynth/src/fluid_voice.c +++ b/src/libs/fluidsynth/src/fluid_voice.c @@ -283,6 +283,10 @@ fluid_voice_write(fluid_voice_t* voice, /* skip to the next section of the envelope if necessary */ while (voice->volenv_count >= env_data->count) { + // If we're switching envelope stages from decay to sustain, force the value to be the end value of the previous stage + if (env_data && voice->volenv_section == FLUID_VOICE_ENVDECAY) + voice->volenv_val = env_data->min * env_data->coeff; + env_data = &voice->volenv_data[++voice->volenv_section]; voice->volenv_count = 0; } @@ -515,7 +519,7 @@ fluid_voice_write(fluid_voice_t* voice, * into account for both significant frequency relocation and for * bandwidth readjustment'. */ - fluid_real_t omega = (fluid_real_t) (2.0 * M_PI * (fres / 44100.0f)); + fluid_real_t omega = (fluid_real_t) (2.0 * M_PI * (fres / ((float) voice->output_rate))); fluid_real_t sin_coeff = (fluid_real_t) sin(omega); fluid_real_t cos_coeff = (fluid_real_t) cos(omega); fluid_real_t alpha_coeff = sin_coeff / (2.0f * voice->q_lin); @@ -1031,6 +1035,8 @@ fluid_voice_update_param(fluid_voice_t* voice, int gen) fluid_real_t x; fluid_real_t y; unsigned int count; + // Alternate attenuation scale used by EMU10K1 cards when setting the attenuation at the preset or instrument level within the SoundFont bank. + static const float ALT_ATTENUATION_SCALE = 0.4; switch (gen) { @@ -1042,7 +1048,8 @@ fluid_voice_update_param(fluid_voice_t* voice, int gen) break; case GEN_ATTENUATION: - voice->attenuation = _GEN(voice, GEN_ATTENUATION); + voice->attenuation = ((fluid_real_t)(voice)->gen[GEN_ATTENUATION].val*ALT_ATTENUATION_SCALE) + + (fluid_real_t)(voice)->gen[GEN_ATTENUATION].mod + (fluid_real_t)(voice)->gen[GEN_ATTENUATION].nrpn; /* Range: SF2.01 section 8.1.3 # 48 * Motivation for range checking: diff --git a/src/libs/fluidsynth/src/fluidsynth.c b/src/libs/fluidsynth/src/fluidsynth.c index c7b003ba56..23d5843353 100644 --- a/src/libs/fluidsynth/src/fluidsynth.c +++ b/src/libs/fluidsynth/src/fluidsynth.c @@ -213,7 +213,7 @@ int main(int argc, char** argv) int with_server = 0; int dump = 0; int connect_lash = 1; - char *optchars = "a:C:c:df:G:g:hijK:L:lm:no:R:r:sVvz:"; + char *optchars = "a:C:c:df:G:g:hijK:L:lm:no:p:R:r:sVvz:"; #ifdef LASH_ENABLED int enabled_lash = 0; /* set to TRUE if lash gets enabled */ fluid_lash_args_t *lash_args; @@ -247,6 +247,7 @@ int main(int argc, char** argv) {"no-midi-in", 0, 0, 'n'}, {"no-shell", 0, 0, 'i'}, {"option", 1, 0, 'o'}, + {"portname", 1, 0, 'p'}, {"reverb", 1, 0, 'R'}, {"sample-rate", 1, 0, 'r'}, {"server", 0, 0, 's'}, @@ -264,7 +265,7 @@ int main(int argc, char** argv) char *optarg; /* Skip non switch arguments (assume they are file names) */ - if ((argv[i][0] != '-') || (argv[i][1] == '\0')) continue; + if ((argv[i][0] != '-') || (argv[i][1] == '\0')) break; c = argv[i][1]; @@ -355,6 +356,9 @@ int main(int argc, char** argv) case 'o': process_o_cmd_line_option(settings, optarg); break; + case 'p' : + fluid_settings_setstr(settings, "midi.portname", optarg); + break; case 'R': if ((optarg != NULL) && ((strcmp(optarg, "0") == 0) || (strcmp(optarg, "no") == 0))) { fluid_settings_setstr(settings, "synth.reverb.active", "no"); @@ -688,6 +692,8 @@ print_help() " The name of the midi driver to use [oss,alsa,alsa_seq,...]\n"); printf(" -n, --no-midi-in\n" " Don't create a midi driver to read MIDI input events [default = yes]\n"); + printf(" -p, --portname=[label]\n" + " Set MIDI port name (alsa_seq, coremidi drivers)\n"); printf(" -o\n" " Define a setting, -o name=value (\"-o help\" to dump current values)\n"); printf(" -R, --reverb\n"