From 7758f5a630f4c6334074eff800f32ac0e3eef6fc Mon Sep 17 00:00:00 2001 From: Josh Green Date: Mon, 16 Nov 2009 07:43:43 +0000 Subject: [PATCH] Added public fluid_synth_get_channel_preset_info() function and fluid_preset_info_t structure. Added shadow_preset field to fluid_channel_t which stores the last assigned preset (irrespective of queuing). Presets now deleted under lock for shadow_preset functionality. Marked fluid_synth_get_channel_preset() as deprecated. --- fluidsynth/include/fluidsynth/sfont.h | 14 +++++ fluidsynth/include/fluidsynth/synth.h | 2 + fluidsynth/include/fluidsynth/types.h | 1 + fluidsynth/src/fluid_chan.c | 1 + fluidsynth/src/fluid_chan.h | 2 + fluidsynth/src/fluid_synth.c | 83 ++++++++++++++++++++++++++- 6 files changed, 100 insertions(+), 3 deletions(-) diff --git a/fluidsynth/include/fluidsynth/sfont.h b/fluidsynth/include/fluidsynth/sfont.h index 38c8290d..61769538 100644 --- a/fluidsynth/include/fluidsynth/sfont.h +++ b/fluidsynth/include/fluidsynth/sfont.h @@ -229,6 +229,20 @@ 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. diff --git a/fluidsynth/include/fluidsynth/synth.h b/fluidsynth/include/fluidsynth/synth.h index 9f3421fd..a7de2111 100644 --- a/fluidsynth/include/fluidsynth/synth.h +++ b/fluidsynth/include/fluidsynth/synth.h @@ -77,6 +77,8 @@ 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_program_reset(fluid_synth_t* synth); FLUIDSYNTH_API int fluid_synth_system_reset(fluid_synth_t* synth); diff --git a/fluidsynth/include/fluidsynth/types.h b/fluidsynth/include/fluidsynth/types.h index 4cf43002..3f658e65 100644 --- a/fluidsynth/include/fluidsynth/types.h +++ b/fluidsynth/include/fluidsynth/types.h @@ -39,6 +39,7 @@ typedef struct _fluid_voice_t fluid_voice_t; /**< Synthesis v 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 */ diff --git a/fluidsynth/src/fluid_chan.c b/fluidsynth/src/fluid_chan.c index f253bab2..4b93cea2 100644 --- a/fluidsynth/src/fluid_chan.c +++ b/fluidsynth/src/fluid_chan.c @@ -53,6 +53,7 @@ new_fluid_channel(fluid_synth_t* synth, int num) chan->synth = synth; chan->channum = num; chan->preset = NULL; + chan->shadow_preset = NULL; chan->tuning = NULL; fluid_channel_init(chan); diff --git a/fluidsynth/src/fluid_chan.h b/fluidsynth/src/fluid_chan.h index f6658bcd..7e21a99d 100644 --- a/fluidsynth/src/fluid_chan.h +++ b/fluidsynth/src/fluid_chan.h @@ -44,6 +44,7 @@ * * Uses atomic operations: * sfont_bank_prog + * shadow_preset * key_pressure * channel_pressure * pitch_bend @@ -60,6 +61,7 @@ struct _fluid_channel_t int sfont_bank_prog; /**< SoundFont ID (bit 21-31), bank (bit 7-20), program (bit 0-6) */ fluid_preset_t* preset; /**< Selected preset */ + fluid_preset_t* shadow_preset; /**< Most recently assigned preset */ int key_pressure; /**< MIDI key pressure */ int channel_pressure; /**< MIDI channel pressure */ diff --git a/fluidsynth/src/fluid_synth.c b/fluidsynth/src/fluid_synth.c index 7cc7ad65..a4774e4e 100644 --- a/fluidsynth/src/fluid_synth.c +++ b/fluidsynth/src/fluid_synth.c @@ -791,6 +791,7 @@ fluid_synth_return_event_process_callback (void* data, unsigned int msec) fluid_synth_t *synth = data; fluid_event_queue_elem_t *event; fluid_preset_t *preset; + fluid_sfont_t *sfont; while ((event = fluid_event_queue_get_outptr (synth->return_queue))) { @@ -827,8 +828,14 @@ fluid_synth_return_event_process_callback (void* data, unsigned int msec) break; case FLUID_EVENT_QUEUE_ELEM_FREE_PRESET: /* Preset free event */ preset = (fluid_preset_t *)(event->pval); - fluid_synth_sfont_unref (synth, preset->sfont); /* -- unref preset's SoundFont */ + sfont = preset->sfont; + + /* Delete presets under mutex lock, to protect chan->shadow_preset */ + fluid_rec_mutex_lock (synth->mutex); delete_fluid_preset (preset); + fluid_rec_mutex_unlock (synth->mutex); + + fluid_synth_sfont_unref (synth, sfont); /* -- unref preset's SoundFont */ break; } @@ -2109,6 +2116,7 @@ fluid_synth_set_preset (fluid_synth_t *synth, int chan, fluid_preset_t *preset) { fluid_event_queue_t *queue; fluid_event_queue_elem_t *event; + fluid_channel_t *channel; fluid_return_val_if_fail (synth != NULL, FLUID_FAILED); fluid_return_val_if_fail (chan >= 0 && chan < synth->midi_channels, FLUID_FAILED); @@ -2118,6 +2126,9 @@ fluid_synth_set_preset (fluid_synth_t *synth, int chan, fluid_preset_t *preset) 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; event->preset.channel = chan; event->preset.preset = preset; @@ -2135,7 +2146,9 @@ fluid_synth_set_preset_LOCAL (fluid_synth_t *synth, int chan, { 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; } @@ -4055,17 +4068,81 @@ 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 * * NOTE: Should only be called from within synthesis thread, which includes - * SoundFont loader preset noteon methods. + * SoundFont loader preset noteon methods. Not thread safe otherwise. */ fluid_preset_t * fluid_synth_get_channel_preset(fluid_synth_t* synth, int chan) { + fluid_channel_t *channel; + fluid_return_val_if_fail (synth != NULL, NULL); fluid_return_val_if_fail (chan >= 0 && chan < synth->midi_channels, NULL); - return fluid_channel_get_preset(synth->channel[chan]); + channel = synth->channel[chan]; + return fluid_atomic_pointer_get (&channel->shadow_preset); +} + +/** + * Get preset information for 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 + * @return #FLUID_OK on success, #FLUID_FAILED otherwise + * @since 1.1.1 + */ +int +fluid_synth_get_channel_preset_info (fluid_synth_t *synth, int chan, + fluid_preset_info_t *info) +{ + fluid_channel_t *channel; + fluid_preset_t *preset; + char *name; + + if (info) + { + info->assigned = FALSE; + info->name[0] = '\0'; + } + + 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 (info != NULL, FLUID_FAILED); + + /* Lock mutex to ensure preset doesn't get deleted, while working on it */ + fluid_rec_mutex_lock (synth->mutex); + + channel = synth->channel[chan]; + preset = fluid_atomic_pointer_get (&channel->shadow_preset); + + if (preset) + { + info->assigned = TRUE; + name = fluid_preset_get_name (preset); + + if (name) + { + strncpy (info->name, name, FLUID_PRESET_INFO_NAME_LENGTH); + info->name[FLUID_PRESET_INFO_NAME_LENGTH - 1] = '\0'; + } + else info->name[0] = '\0'; + + info->sfont_id = preset->sfont->id; + info->bank = fluid_preset_get_banknum (preset); + info->program = fluid_preset_get_num (preset); + } + else + { + info->assigned = FALSE; + fluid_channel_get_sfont_bank_prog (channel, &info->sfont_id, &info->bank, &info->program); + info->name[0] = '\0'; + } + + fluid_rec_mutex_unlock (synth->mutex); + + return FLUID_OK; } /**