Now setting shadow_preset parameter directly in fluid_channel_set_preset() which fixes crash bug where MIDI system reset event would cause shadow_preset and preset to get out of sync.

Reverted return queuing of program changes. Program changes are once again real-time unsafe.
Added public function fluid_synth_unset_program().
Renamed fluid_synth_get_channel_preset_info() to fluid_synth_get_channel_info().
Changed fluid_preset_info_t to fluid_synth_channel_info_t and moved to synth.h header.
Shell 'channels' command now uses thread safe fluid_synth_get_channel_info().
Removed fluid_synth_set_preset_LOCAL(), now just using fluid_channel_set_preset().
Added New In 1.1.1 section to developer docs.
This commit is contained in:
Josh Green 2009-11-27 22:28:23 +00:00
parent 836a6b45d8
commit 2ee782a6cc
8 changed files with 83 additions and 83 deletions

View file

@ -5,7 +5,7 @@
#---------------------------------------------------------------------------
DOXYFILE_ENCODING = UTF-8
PROJECT_NAME = libfluidsynth
PROJECT_NUMBER = 1.1.0
PROJECT_NUMBER = 1.1.1
OUTPUT_DIRECTORY = api
CREATE_SUBDIRS = NO
OUTPUT_LANGUAGE = English

View file

@ -6,7 +6,7 @@
\author Pedro López-Cabanillas
\author Josh Green
\author Copyright © 2003-2009 Peter Hanappe, Conrad Berhörster, Antoine Schmitt, Pedro López-Cabanillas, Josh Green
\version Revision 1.1.0
\version Revision 1.1.1
\date 2009-10-20
All the source code examples in this document are in the public domain; you can use them as you please. This document is licensed under the Creative Commons Attribution-Share Alike 3.0 Unported License. To view a copy of this license, visit http://creativecommons.org/licenses/by-sa/3.0/ . The FluidSynth library is distributed under the GNU Library General Public License. A copy of the GNU Library General Public License is contained in the FluidSynth package; if not, visit http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt or write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
@ -19,6 +19,7 @@ All the source code examples in this document are in the public domain; you can
- \ref Disclaimer
- \ref Introduction
- \ref NewIn1_1_1
- \ref NewIn1_1_0
- \ref CreatingSettings
- \ref CreatingSynth
@ -55,6 +56,14 @@ What is FluidSynth?
- FluidSynth is open source, in active development. For more details, take a look at http://www.fluidsynth.org
\section NewIn1_1_1 Whats new in 1.1.1?
Changes in FluidSynth 1.1.1 concerning developers:
- fluid_synth_get_channel_preset() marked as deprecated. New function
fluid_synth_get_channel_info() added which is thread safe and should replace
most uses of the older function.
- Added fluid_synth_unset_program() to unset the active preset on a channel.
\section NewIn1_1_0 Whats new in 1.1.0?

View file

@ -229,21 +229,6 @@ struct _fluid_preset_t {
int (*notify)(fluid_preset_t* preset, int reason, int chan);
};
#define FLUID_PRESET_INFO_NAME_LENGTH 32 /**< Length of preset info name field (including zero terminator) */
/**
* Preset information structure.
* @since 1.1.1
*/
struct _fluid_preset_info_t
{
int assigned; /**< TRUE if a preset is assigned, FALSE otherwise */
int sfont_id; /**< ID of parent SoundFont */
int bank; /**< MIDI bank number (0-16383) */
int program; /**< MIDI program number (0-127) */
char name[FLUID_PRESET_INFO_NAME_LENGTH]; /**< Preset name */
};
/**
* Virtual SoundFont sample.
*/

View file

@ -45,6 +45,22 @@ extern "C" {
* fluid_synth_noteon(), fluid_synth_noteoff(), ...
*/
#define FLUID_SYNTH_CHANNEL_INFO_NAME_SIZE 32 /**< Length of channel info name field (including zero terminator) */
/**
* Channel information structure for fluid_synth_get_channel_info().
* @since 1.1.1
*/
struct _fluid_synth_channel_info_t
{
int assigned : 1; /**< TRUE if a preset is assigned, FALSE otherwise */
/* Reserved flag bits (at the least 31) */
int sfont_id; /**< ID of parent SoundFont */
int bank; /**< MIDI bank number (0-16383) */
int program; /**< MIDI program number (0-127) */
char name[FLUID_SYNTH_CHANNEL_INFO_NAME_SIZE]; /**< Channel preset name */
char reserved[32]; /**< Reserved data for future expansion */
};
FLUIDSYNTH_API fluid_synth_t* new_fluid_synth(fluid_settings_t* settings);
FLUIDSYNTH_API int delete_fluid_synth(fluid_synth_t* synth);
@ -77,8 +93,9 @@ fluid_synth_program_select_by_sfont_name (fluid_synth_t* synth, int chan,
FLUIDSYNTH_API
int fluid_synth_get_program(fluid_synth_t* synth, int chan, unsigned int* sfont_id,
unsigned int* bank_num, unsigned int* preset_num);
FLUIDSYNTH_API int fluid_synth_get_channel_preset_info (fluid_synth_t *synth, int chan,
fluid_preset_info_t *info);
FLUIDSYNTH_API int fluid_synth_unset_program (fluid_synth_t *synth, int chan);
FLUIDSYNTH_API int fluid_synth_get_channel_info (fluid_synth_t *synth, int chan,
fluid_synth_channel_info_t *info);
FLUIDSYNTH_API int fluid_synth_program_reset(fluid_synth_t* synth);
FLUIDSYNTH_API int fluid_synth_system_reset(fluid_synth_t* synth);

View file

@ -35,11 +35,11 @@ extern "C" {
typedef struct _fluid_hashtable_t fluid_settings_t; /**< Configuration settings instance */
typedef struct _fluid_synth_t fluid_synth_t; /**< Synthesizer instance */
typedef struct _fluid_synth_channel_info_t fluid_synth_channel_info_t; /**< SoundFont channel info */
typedef struct _fluid_voice_t fluid_voice_t; /**< Synthesis voice instance */
typedef struct _fluid_sfloader_t fluid_sfloader_t; /**< SoundFont loader plugin */
typedef struct _fluid_sfont_t fluid_sfont_t; /**< SoundFont */
typedef struct _fluid_preset_t fluid_preset_t; /**< SoundFont preset */
typedef struct _fluid_preset_info_t fluid_preset_info_t; /**< SoundFont preset info */
typedef struct _fluid_sample_t fluid_sample_t; /**< SoundFont sample */
typedef struct _fluid_mod_t fluid_mod_t; /**< SoundFont modulator */
typedef struct _fluid_audio_driver_t fluid_audio_driver_t; /**< Audio driver instance */

View file

@ -75,6 +75,7 @@ fluid_channel_init(fluid_channel_t* chan)
chan->sfont_bank_prog = 0 << SFONT_SHIFTVAL | banknum << BANK_SHIFTVAL
| prognum << PROG_SHIFTVAL;
/* FIXME - fluid_synth_find_preset not real-time safe */
newpreset = fluid_synth_find_preset(chan->synth, banknum, prognum);
fluid_channel_set_preset(chan, newpreset);
@ -191,6 +192,7 @@ delete_fluid_channel(fluid_channel_t* chan)
return FLUID_OK;
}
/* FIXME - Calls fluid_channel_init() potentially in synthesis context */
void
fluid_channel_reset(fluid_channel_t* chan)
{
@ -206,6 +208,9 @@ fluid_channel_set_preset(fluid_channel_t* chan, fluid_preset_t* preset)
fluid_preset_notify (chan->preset, FLUID_PRESET_UNSELECTED, chan->channum);
/* Set shadow preset again, so it contains the actual latest assigned value */
fluid_atomic_pointer_set (&chan->shadow_preset, preset);
if (chan->preset) /* Queue preset free (shouldn't free() in synth context) */
{
event = fluid_event_queue_get_inptr (chan->synth->return_queue);

View file

@ -543,22 +543,25 @@ fluid_handle_inst(fluid_synth_t* synth, int ac, char** av, fluid_ostream_t out)
int
fluid_handle_channels(fluid_synth_t* synth, int ac, char** av, fluid_ostream_t out)
{
int i;
fluid_preset_t* preset;
fluid_synth_channel_info_t info;
int verbose = 0;
int i;
if (ac > 0 && strcmp( av[0], "-verbose") == 0) verbose = 1;
for (i = 0; i < fluid_synth_count_midi_channels(synth); i++) {
preset = fluid_synth_get_channel_preset(synth, i);
if (preset == NULL) fluid_ostream_printf(out, "chan %d, no preset\n", i);
else if (!verbose) fluid_ostream_printf(out, "chan %d, %s\n", i, fluid_preset_get_name(preset));
else fluid_ostream_printf(out, "chan %d, sfont %d, bank %d, preset %d, %s\n", i,
fluid_sfont_get_id( preset->sfont),
fluid_preset_get_banknum(preset),
fluid_preset_get_num(preset),
fluid_preset_get_name(preset));
for (i = 0; i < fluid_synth_count_midi_channels (synth); i++)
{
fluid_synth_get_channel_info (synth, i, &info);
if (!verbose)
fluid_ostream_printf (out, "chan %d, %s\n", i,
info.assigned ? info.name : "no preset");
else
fluid_ostream_printf (out, "chan %d, sfont %d, bank %d, preset %d, %s\n", i,
info.sfont_id, info.bank, info.program,
info.assigned ? info.name : "no preset");
}
return 0;
}

View file

@ -76,8 +76,6 @@ static int fluid_synth_update_pitch_bend_LOCAL(fluid_synth_t* synth, int chan);
static int fluid_synth_update_pitch_wheel_sens_LOCAL(fluid_synth_t* synth, int chan);
static int fluid_synth_set_preset (fluid_synth_t *synth, int chan,
fluid_preset_t *preset);
static int fluid_synth_set_preset_LOCAL (fluid_synth_t *synth, int chan,
fluid_preset_t *preset);
static fluid_preset_t*
fluid_synth_get_preset(fluid_synth_t* synth, unsigned int sfontnum,
unsigned int banknum, unsigned int prognum);
@ -859,10 +857,6 @@ fluid_synth_return_event_process_thread (void* data)
fluid_synth_sfont_unref (synth, sfont); /* -- unref preset's SoundFont */
break;
case FLUID_EVENT_QUEUE_ELEM_MIDI:
if (event->midi.type == PROGRAM_CHANGE)
fluid_synth_program_change (synth, event->midi.channel, event->midi.param1);
break;
}
fluid_event_queue_next_outptr (synth->return_queue);
@ -2166,12 +2160,13 @@ fluid_synth_set_preset (fluid_synth_t *synth, int chan, fluid_preset_t *preset)
fluid_return_val_if_fail (synth != NULL, FLUID_FAILED);
fluid_return_val_if_fail (chan >= 0 && chan < synth->midi_channels, FLUID_FAILED);
channel = synth->channel[chan];
if (fluid_synth_should_queue (synth))
{
event = fluid_synth_get_event_elem (synth, &queue);
if (!event) return FLUID_FAILED;
channel = synth->channel[chan];
fluid_atomic_pointer_set (&channel->shadow_preset, preset);
event->type = FLUID_EVENT_QUEUE_ELEM_PRESET;
@ -2181,21 +2176,7 @@ fluid_synth_set_preset (fluid_synth_t *synth, int chan, fluid_preset_t *preset)
fluid_event_queue_next_inptr (queue);
return FLUID_OK;
}
else return fluid_synth_set_preset_LOCAL (synth, chan, preset);
}
/* Local synthesis thread variant of set channel preset */
static int
fluid_synth_set_preset_LOCAL (fluid_synth_t *synth, int chan,
fluid_preset_t *preset)
{
fluid_channel_t *channel;
/* Set shadow preset again, so it contains the actual latest assigned value */
channel = synth->channel[chan];
fluid_atomic_pointer_set (&channel->shadow_preset, preset);
fluid_channel_set_preset (channel, preset);
return FLUID_OK;
else return fluid_channel_set_preset (channel, preset);
}
/* Get a preset by SoundFont, bank and program numbers.
@ -2303,39 +2284,19 @@ fluid_synth_find_preset(fluid_synth_t* synth, unsigned int banknum,
* @param prognum MIDI program number (0-127)
* @return FLUID_OK on success, FLUID_FAILED otherwise
*/
/* FIXME - Currently not real-time safe, due to preset allocation and mutex lock,
* and may be called from within synthesis context. */
int
fluid_synth_program_change(fluid_synth_t* synth, int chan, int prognum)
{
fluid_preset_t* preset = NULL;
fluid_channel_t* channel;
fluid_event_queue_elem_t *event;
int subst_bank, subst_prog, banknum;
fluid_return_val_if_fail (synth != NULL, FLUID_FAILED);
fluid_return_val_if_fail (chan >= 0 && chan < synth->midi_channels, FLUID_FAILED);
fluid_return_val_if_fail (prognum >= 0 && prognum <= FLUID_NUM_PROGRAMS, FLUID_FAILED);
/* If this is the synthesis thread, send program change via return queue, to
* avoid mutex locks and other realtime naughties */
if (fluid_synth_is_synth_thread (synth))
{
event = fluid_event_queue_get_inptr (synth->return_queue);
if (!event)
{
FLUID_LOG (FLUID_ERR, "Synth return event queue full");
return FLUID_FAILED;
}
event->type = FLUID_EVENT_QUEUE_ELEM_MIDI;
event->midi.type = PROGRAM_CHANGE;
event->midi.param1 = prognum;
event->midi.channel = chan;
fluid_event_queue_next_inptr (synth->return_queue);
return FLUID_OK;
}
channel = synth->channel[chan];
fluid_channel_get_sfont_bank_prog(channel, NULL, &banknum, NULL);
@ -2447,6 +2408,26 @@ fluid_synth_sfont_select_LOCAL (fluid_synth_t *synth, int chan, unsigned int sfo
fluid_channel_set_sfont_bank_prog(synth->channel[chan], sfont_id, -1, -1);
}
/**
* Set the preset of a MIDI channel to an unassigned state.
* @param synth FluidSynth instance
* @param chan MIDI channel number (0 to MIDI channel count - 1)
* @return #FLUID_OK on success, #FLUID_FAILED otherwise
* @since 1.1.1
*
* Note: Channel retains its SoundFont ID, bank and program numbers. Certain
* operations, such as fluid_synth_reset() or MIDI program changes may
* re-assign the preset, if one matches.
*/
int
fluid_synth_unset_program (fluid_synth_t *synth, int chan)
{
fluid_return_val_if_fail (synth != NULL, FLUID_FAILED);
fluid_return_val_if_fail (chan >= 0 && chan < synth->midi_channels, FLUID_FAILED);
return fluid_synth_set_preset (synth, chan, NULL);
}
/**
* Get current SoundFont ID, bank number and program number for a MIDI channel.
* @param synth FluidSynth instance
@ -3435,8 +3416,8 @@ fluid_synth_process_event_queue_LOCAL (fluid_synth_t *synth,
event->gen.value, event->gen.absolute);
break;
case FLUID_EVENT_QUEUE_ELEM_PRESET:
fluid_synth_set_preset_LOCAL (synth, event->preset.channel,
event->preset.preset);
fluid_channel_set_preset (synth->channel[event->preset.channel],
event->preset.preset);
break;
case FLUID_EVENT_QUEUE_ELEM_STOP_VOICES:
fluid_synth_stop_LOCAL (synth, event->ival);
@ -4155,7 +4136,7 @@ fluid_synth_get_sfont_by_name(fluid_synth_t* synth, const char *name)
* @param synth FluidSynth instance
* @param chan MIDI channel number (0 to MIDI channel count - 1)
* @return Preset or NULL if no preset active on channel
* @deprecated
* @deprecated fluid_synth_get_channel_info() should replace most use cases.
*
* NOTE: Should only be called from within synthesis thread, which includes
* SoundFont loader preset noteon methods. Not thread safe otherwise.
@ -4173,7 +4154,7 @@ fluid_synth_get_channel_preset(fluid_synth_t* synth, int chan)
}
/**
* Get preset information for the currently selected preset on a MIDI channel.
* Get information on the currently selected preset on a MIDI channel.
* @param synth FluidSynth instance
* @param chan MIDI channel number (0 to MIDI channel count - 1)
* @param info Caller supplied structure to fill with preset information
@ -4181,8 +4162,8 @@ fluid_synth_get_channel_preset(fluid_synth_t* synth, int chan)
* @since 1.1.1
*/
int
fluid_synth_get_channel_preset_info (fluid_synth_t *synth, int chan,
fluid_preset_info_t *info)
fluid_synth_get_channel_info (fluid_synth_t *synth, int chan,
fluid_synth_channel_info_t *info)
{
fluid_channel_t *channel;
fluid_preset_t *preset;
@ -4211,8 +4192,8 @@ fluid_synth_get_channel_preset_info (fluid_synth_t *synth, int chan,
if (name)
{
strncpy (info->name, name, FLUID_PRESET_INFO_NAME_LENGTH);
info->name[FLUID_PRESET_INFO_NAME_LENGTH - 1] = '\0';
strncpy (info->name, name, FLUID_SYNTH_CHANNEL_INFO_NAME_SIZE);
info->name[FLUID_SYNTH_CHANNEL_INFO_NAME_SIZE - 1] = '\0';
}
else info->name[0] = '\0';