mirror of
https://github.com/ZDoom/fluidsynth.git
synced 2024-11-27 06:22:06 +00:00
Add optional per tick callback to player (#780)
Co-authored-by: Arthur Chaloin <arthur.chaloin@gmail.com> Co-authored-by: derselbst <tom.mbrt@googlemail.com>
This commit is contained in:
parent
04c30be0b9
commit
13185d32b2
3 changed files with 70 additions and 0 deletions
|
@ -56,6 +56,43 @@ extern "C" {
|
|||
* a \ref sequencer via fluid_sequencer_add_midi_event_to_buffer().
|
||||
*/
|
||||
typedef int (*handle_midi_event_func_t)(void *data, fluid_midi_event_t *event);
|
||||
|
||||
/**
|
||||
* Generic callback function fired once by MIDI tick change.
|
||||
*
|
||||
* @param data User defined data pointer
|
||||
* @param tick The current (zero-based) tick, which triggered the callback
|
||||
* @return Should return #FLUID_OK on success, #FLUID_FAILED otherwise
|
||||
*
|
||||
* This callback is fired at a constant rate depending on the current BPM and PPQ.
|
||||
* e.g. for PPQ = 192 and BPM = 140 the callback is fired 192 * 140 times per minute (448/sec).
|
||||
*
|
||||
* It can be used to sync external elements with the beat,
|
||||
* or stop / loop the song on a given tick.
|
||||
* Ticks being BPM-dependent, you can manipulate values such as bars or beats,
|
||||
* without having to care about BPM.
|
||||
*
|
||||
* For example, this callback loops the song whenever it reaches the 5th bar :
|
||||
*
|
||||
* @code{.cpp}
|
||||
int handle_tick(void *data, int tick)
|
||||
{
|
||||
fluid_player_t *player = (fluid_player_t *)data;
|
||||
int ppq = 192; // From MIDI header
|
||||
int beatsPerBar = 4; // From the song's time signature
|
||||
int loopBar = 5;
|
||||
int loopTick = (loopBar - 1) * ppq * beatsPerBar;
|
||||
|
||||
if (tick == loopTick)
|
||||
{
|
||||
return fluid_player_seek(player, 0);
|
||||
}
|
||||
|
||||
return FLUID_OK;
|
||||
}
|
||||
* @endcode
|
||||
*/
|
||||
typedef int (*handle_midi_tick_func_t)(void *data, int tick);
|
||||
/* @} */
|
||||
|
||||
/**
|
||||
|
@ -239,6 +276,7 @@ FLUIDSYNTH_API int fluid_player_set_tempo(fluid_player_t *player, int tempo_type
|
|||
FLUID_DEPRECATED FLUIDSYNTH_API int fluid_player_set_midi_tempo(fluid_player_t *player, int tempo);
|
||||
FLUID_DEPRECATED FLUIDSYNTH_API int fluid_player_set_bpm(fluid_player_t *player, int bpm);
|
||||
FLUIDSYNTH_API int fluid_player_set_playback_callback(fluid_player_t *player, handle_midi_event_func_t handler, void *handler_data);
|
||||
FLUIDSYNTH_API int fluid_player_set_tick_callback(fluid_player_t *player, handle_midi_tick_func_t handler, void *handler_data);
|
||||
|
||||
FLUIDSYNTH_API int fluid_player_get_status(fluid_player_t *player);
|
||||
FLUIDSYNTH_API int fluid_player_get_current_tick(fluid_player_t *player);
|
||||
|
|
|
@ -1677,8 +1677,10 @@ new_fluid_player(fluid_synth_t *synth)
|
|||
player->deltatime = 4.0;
|
||||
player->cur_msec = 0;
|
||||
player->cur_ticks = 0;
|
||||
player->last_callback_ticks = -1;
|
||||
fluid_atomic_int_set(&player->seek_ticks, -1);
|
||||
fluid_player_set_playback_callback(player, fluid_synth_handle_midi_event, synth);
|
||||
fluid_player_set_tick_callback(player, NULL, NULL);
|
||||
player->use_system_timer = fluid_settings_str_equal(synth->settings,
|
||||
"player.timing-source", "system");
|
||||
if(player->use_system_timer)
|
||||
|
@ -1833,6 +1835,28 @@ fluid_player_set_playback_callback(fluid_player_t *player,
|
|||
return FLUID_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a listener function for every MIDI tick change.
|
||||
*
|
||||
* @param player MIDI player instance
|
||||
* @param handler Pointer to callback function
|
||||
* @param handler_data Opaque parameter to be sent to the callback function
|
||||
* @returns #FLUID_OK
|
||||
*
|
||||
* This callback is not set by default, but can optionally
|
||||
* be changed to a user-defined function for intercepting all MIDI
|
||||
* tick changes and react to them with precision.
|
||||
*
|
||||
* @since 2.2.0
|
||||
*/
|
||||
int
|
||||
fluid_player_set_tick_callback(fluid_player_t *player, handle_midi_tick_func_t handler, void *handler_data)
|
||||
{
|
||||
player->tick_callback = handler;
|
||||
player->tick_userdata = handler_data;
|
||||
return FLUID_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a MIDI file to a player queue.
|
||||
* @param player MIDI player instance
|
||||
|
@ -2122,6 +2146,11 @@ fluid_player_callback(void *data, unsigned int msec)
|
|||
__LINE__, (msec - player->begin_msec) / 1000.0);
|
||||
loadnextfile = 1;
|
||||
}
|
||||
|
||||
if (player->tick_callback != NULL && player->last_callback_ticks != player->cur_ticks) {
|
||||
player->tick_callback(player->tick_userdata, player->cur_ticks);
|
||||
player->last_callback_ticks = player->cur_ticks;
|
||||
}
|
||||
}
|
||||
while(loadnextfile);
|
||||
|
||||
|
|
|
@ -297,6 +297,7 @@ struct _fluid_player_t
|
|||
fluid_atomic_int_t seek_ticks; /* new position in tempo ticks (midi ticks) for seeking */
|
||||
int start_ticks; /* the number of tempo ticks passed at the last tempo change */
|
||||
int cur_ticks; /* the number of tempo ticks passed */
|
||||
int last_callback_ticks; /* the last tick number that was passed to player->tick_callback */
|
||||
int begin_msec; /* the time (msec) of the beginning of the file */
|
||||
int start_msec; /* the start time of the last tempo change */
|
||||
int cur_msec; /* the current time */
|
||||
|
@ -318,6 +319,8 @@ struct _fluid_player_t
|
|||
|
||||
handle_midi_event_func_t playback_callback; /* function fired on each midi event as it is played */
|
||||
void *playback_userdata; /* pointer to user-defined data passed to playback_callback function */
|
||||
handle_midi_tick_func_t tick_callback; /* function fired on each tick change */
|
||||
void *tick_userdata; /* pointer to user-defined data passed to tick_callback function */
|
||||
};
|
||||
|
||||
void fluid_player_settings(fluid_settings_t *settings);
|
||||
|
|
Loading…
Reference in a new issue