Guard against multiple calls to fluid_player_seek()

Addresses #634
This commit is contained in:
derselbst 2020-04-22 17:26:37 +02:00
parent f14c33a4e6
commit 85cf123d38
2 changed files with 39 additions and 17 deletions

View file

@ -1646,7 +1646,7 @@ new_fluid_player(fluid_synth_t *synth)
return NULL;
}
player->status = FLUID_PLAYER_READY;
fluid_atomic_int_set(&player->status, FLUID_PLAYER_READY);
player->loop = 1;
player->ntracks = 0;
@ -1798,7 +1798,7 @@ fluid_player_add_track(fluid_player_t *player, fluid_track_t *track)
/**
* Change the MIDI callback function. This is usually set to
* fluid_synth_handle_midi_event, but can optionally be changed
* fluid_synth_handle_midi_event(), but can optionally be changed
* to a user-defined function instead, for intercepting all MIDI
* messages sent to the synth. You can also use a midi router as
* the callback function to modify the MIDI messages before sending
@ -2004,7 +2004,7 @@ fluid_player_playlist_load(fluid_player_t *player, unsigned int msec)
if(player->currentfile == NULL)
{
/* Failed to find next song, probably since we're finished */
player->status = FLUID_PLAYER_DONE;
fluid_atomic_int_set(&player->status, FLUID_PLAYER_DONE);
return;
}
@ -2050,7 +2050,7 @@ fluid_player_callback(void *data, unsigned int msec)
loadnextfile = player->currentfile == NULL ? 1 : 0;
if(player->status == FLUID_PLAYER_DONE)
if(fluid_player_get_status(player) == FLUID_PLAYER_DONE)
{
fluid_synth_all_notes_off(synth, -1);
return 1;
@ -2108,7 +2108,7 @@ fluid_player_callback(void *data, unsigned int msec)
}
while(loadnextfile);
player->status = status;
fluid_atomic_int_set(&player->status, status);
return 1;
}
@ -2121,7 +2121,7 @@ fluid_player_callback(void *data, unsigned int msec)
int
fluid_player_play(fluid_player_t *player)
{
if(player->status == FLUID_PLAYER_PLAYING ||
if(fluid_player_get_status(player) == FLUID_PLAYER_PLAYING ||
player->playlist == NULL)
{
return FLUID_OK;
@ -2132,7 +2132,7 @@ fluid_player_play(fluid_player_t *player)
fluid_sample_timer_reset(player->synth, player->sample_timer);
}
player->status = FLUID_PLAYER_PLAYING;
fluid_atomic_int_set(&player->status, FLUID_PLAYER_PLAYING);
return FLUID_OK;
}
@ -2146,7 +2146,7 @@ fluid_player_play(fluid_player_t *player)
int
fluid_player_stop(fluid_player_t *player)
{
player->status = FLUID_PLAYER_DONE;
fluid_atomic_int_set(&player->status, FLUID_PLAYER_DONE);
fluid_player_seek(player, fluid_player_get_current_tick(player));
return FLUID_OK;
}
@ -2160,18 +2160,22 @@ fluid_player_stop(fluid_player_t *player)
int
fluid_player_get_status(fluid_player_t *player)
{
return player->status;
return fluid_atomic_int_get(&player->status);
}
/**
* Seek in the currently playing file.
*
* The actual seek will be performed when the synth calls back the player (i.e. a few
* levels above the player's callback set with fluid_player_set_playback_callback()).
* If the player's status is #FLUID_PLAYER_PLAYING and a previous seek operation has
* not been completed yet, #FLUID_FAILED is returned.
* @param player MIDI player instance
* @param ticks the position to seek to in the current file
* @return #FLUID_FAILED if ticks is negative or after the latest tick of the file,
* #FLUID_OK otherwise
* @return #FLUID_FAILED if ticks is negative or after the latest tick of the file
* [or, since 2.1.3, if another seek operation is currently in progress],
* #FLUID_OK otherwise.
* @since 2.0.0
*
* The actual seek is performed during the player_callback.
*/
int fluid_player_seek(fluid_player_t *player, int ticks)
{
@ -2180,8 +2184,26 @@ int fluid_player_seek(fluid_player_t *player, int ticks)
return FLUID_FAILED;
}
fluid_atomic_int_set(&player->seek_ticks, ticks);
return FLUID_OK;
if(fluid_player_get_status(player) == FLUID_PLAYER_PLAYING)
{
if(fluid_atomic_int_compare_and_exchange(&player->seek_ticks, -1, ticks))
{
// new seek position has been set, as no previous seek was in progress
return FLUID_OK;
}
}
else
{
// If the player is not currently playing, a new seek position can be set at any time. This allows
// the user to do:
// fluid_player_stop();
// fluid_player_seek(0); // to beginning
fluid_atomic_int_set(&player->seek_ticks, ticks);
return FLUID_OK;
}
// a previous seek is still in progress or hasn't been processed yet
return FLUID_FAILED;
}
@ -2242,7 +2264,7 @@ int fluid_player_set_bpm(fluid_player_t *player, int bpm)
int
fluid_player_join(fluid_player_t *player)
{
while(player->status != FLUID_PLAYER_DONE)
while(fluid_player_get_status(player) != FLUID_PLAYER_DONE)
{
fluid_msleep(10);
}

View file

@ -272,7 +272,7 @@ typedef struct
*/
struct _fluid_player_t
{
int status;
fluid_atomic_int_t status;
int ntracks;
fluid_track_t *track[MAX_NUMBER_OF_TRACKS];
fluid_synth_t *synth;