MIDI input group

Contains MIDI Driver, MIDI Router, MIDI Player and MIDI Events
This commit is contained in:
Marcus Weseloh 2020-11-11 00:39:35 +01:00
parent bae3dec78a
commit 4185b25d6f
4 changed files with 136 additions and 45 deletions

View file

@ -26,12 +26,51 @@ extern "C" {
#endif
/**
* @defgroup MIDI MIDI
* @brief Functions for MIDI events, drivers and MIDI file playback.
* @defgroup midi_input MIDI Input
*
* MIDI Input Subsystem
*
* There are multiple ways to send MIDI events to the synthesizer. They can come
* from MIDI files, from external MIDI sequencers or raw MIDI event sources,
* can be modified via MIDI routers and also generated manually.
*
* The interface connecting all sources and sinks of MIDI events in libfluidsynth
* is \ref handle_midi_event_func_t.
*
* @{
*/
/**
* Generic callback function for MIDI event handler.
*
* @param data User defined data pointer
* @param event The MIDI event
* @return Should return #FLUID_OK on success, #FLUID_FAILED otherwise
*
* This callback is used to pass MIDI events
* - from \ref midi_player, \ref midi_router or \ref midi_driver
* - to \ref midi_router via fluid_midi_router_handle_midi_event()
* - or to \ref synth via fluid_synth_handle_midi_event().
*
* Additionally, there is a translation layer to pass MIDI events to
* 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);
/* @} */
/**
* @defgroup midi_events MIDI Events
* @ingroup midi_input
*
* Functions to create, modify, query and delete MIDI events.
*
* These functions are intended to be used in MIDI routers and other filtering
* and processing functions in the MIDI event path. If you want to simply
* send MIDI messages to the synthesizer, you can use the more convenient
* \ref midi_messages interface.
*
* @{
*/
FLUIDSYNTH_API fluid_midi_event_t *new_fluid_midi_event(void);
FLUIDSYNTH_API void delete_fluid_midi_event(fluid_midi_event_t *event);
@ -61,9 +100,20 @@ FLUIDSYNTH_API int fluid_midi_event_set_lyrics(fluid_midi_event_t *evt,
void *data, int size, int dynamic);
FLUIDSYNTH_API int fluid_midi_event_get_lyrics(fluid_midi_event_t *evt,
void **data, int *size);
/* @} */
/**
* @defgroup midi_router MIDI Router
* @ingroup midi_input
*
* Rule based tranformation and filtering of MIDI events.
*
* @{
*/
/**
* MIDI router rule type.
*
* @since 1.1.0
*/
typedef enum
@ -74,24 +124,11 @@ typedef enum
FLUID_MIDI_ROUTER_RULE_PITCH_BEND, /**< MIDI pitch bend rule */
FLUID_MIDI_ROUTER_RULE_CHANNEL_PRESSURE, /**< MIDI channel pressure rule */
FLUID_MIDI_ROUTER_RULE_KEY_PRESSURE, /**< MIDI key pressure rule */
#ifndef __DOXYGEN__
FLUID_MIDI_ROUTER_RULE_COUNT /**< @internal Total count of rule types @warning This symbol is not part of the public API and ABI stability guarantee and may change at any time!*/
#endif
FLUID_MIDI_ROUTER_RULE_COUNT /**< @internal Total count of rule types. This symbol
is not part of the public API and ABI stability
guarantee and may change at any time!*/
} fluid_midi_router_rule_type;
/**
* Generic callback function for MIDI events.
* @param data User defined data pointer
* @param event The MIDI event
* @return Should return #FLUID_OK on success, #FLUID_FAILED otherwise
*
* Will be used between
* - MIDI driver and MIDI router
* - MIDI router and synth
* to communicate events.
* In the not-so-far future...
*/
typedef int (*handle_midi_event_func_t)(void *data, fluid_midi_event_t *event);
FLUIDSYNTH_API fluid_midi_router_t *new_fluid_midi_router(fluid_settings_t *settings,
handle_midi_event_func_t handler,
@ -112,15 +149,43 @@ FLUIDSYNTH_API void fluid_midi_router_rule_set_param2(fluid_midi_router_rule_t *
FLUIDSYNTH_API int fluid_midi_router_handle_midi_event(void *data, fluid_midi_event_t *event);
FLUIDSYNTH_API int fluid_midi_dump_prerouter(void *data, fluid_midi_event_t *event);
FLUIDSYNTH_API int fluid_midi_dump_postrouter(void *data, fluid_midi_event_t *event);
/* @} */
/**
* @defgroup midi_driver MIDI Driver
* @ingroup midi_input
*
* Functions for managing MIDI drivers.
*
* The available MIDI drivers depend on your platform. See \ref settings_midi for all
* available configuration options.
*
* To create a MIDI driver, you need to specify a source for the MIDI events to be
* forwarded to via the \ref fluid_midi_event_t callback. Normally this will be
* either a \ref midi_router via fluid_midi_router_handle_midi_event() or the synthesizer
* via fluid_synth_handle_midi_event().
*
* But you can also write your own handler function that preprocesses the events and
* forwards them on to the router or synthesizer instead.
*
* @{
*/
FLUIDSYNTH_API
fluid_midi_driver_t *new_fluid_midi_driver(fluid_settings_t *settings,
handle_midi_event_func_t handler,
void *event_handler_data);
FLUIDSYNTH_API void delete_fluid_midi_driver(fluid_midi_driver_t *driver);
/* @} */
/**
* @defgroup midi_player MIDI Player
* @ingroup midi_input
*
* Parse standard MIDI files and emit MIDI events.
*
* @{
*/
/**
* MIDI player status enum.
@ -151,9 +216,6 @@ FLUIDSYNTH_API int fluid_player_get_total_ticks(fluid_player_t *player);
FLUIDSYNTH_API int fluid_player_get_bpm(fluid_player_t *player);
FLUIDSYNTH_API int fluid_player_get_midi_tempo(fluid_player_t *player);
FLUIDSYNTH_API int fluid_player_seek(fluid_player_t *player, int ticks);
///
/* @} */
#ifdef __cplusplus

View file

@ -135,11 +135,14 @@ void fluid_midi_driver_settings(fluid_settings_t *settings)
/**
* Create a new MIDI driver instance.
* @param settings Settings used to configure new MIDI driver.
*
* @param settings Settings used to configure new MIDI driver. See \ref settings_midi for available options.
* @param handler MIDI handler callback (for example: fluid_midi_router_handle_midi_event()
* for MIDI router)
* @param event_handler_data Caller defined data to pass to 'handler'
* @return New MIDI driver instance or NULL on error
*
* Which MIDI driver is actually created depends on the \ref settings_midi_driver option.
*/
fluid_midi_driver_t *new_fluid_midi_driver(fluid_settings_t *settings, handle_midi_event_func_t handler, void *event_handler_data)
{

View file

@ -1798,16 +1798,18 @@ 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
* 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
* them to the synth.
* Change the MIDI callback function.
*
* @param player MIDI player instance
* @param handler Pointer to callback function
* @param handler_data Parameter sent to the callback function
* @returns FLUID_OK
*
* This is usually set to 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 them to the synth.
*
* @since 1.1.4
*/
int
@ -2140,9 +2142,10 @@ fluid_player_play(fluid_player_t *player)
/**
* Pauses the MIDI playback.
*
* It will not rewind to the beginning of the file, use fluid_player_seek() for this purpose.
* @param player MIDI player instance
* @return Always returns #FLUID_OK
*
* It will not rewind to the beginning of the file, use fluid_player_seek() for this purpose.
*/
int
fluid_player_stop(fluid_player_t *player)
@ -2167,15 +2170,17 @@ fluid_player_get_status(fluid_player_t *player)
/**
* 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
* [or, since 2.1.3, if another seek operation is currently in progress],
* #FLUID_OK otherwise.
*
* 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.
*
* @since 2.0.0
*/
int fluid_player_seek(fluid_player_t *player, int ticks)
@ -2210,13 +2215,15 @@ int fluid_player_seek(fluid_player_t *player, int ticks)
/**
* Enable looping of a MIDI player
*
* @param player MIDI player instance
* @param loop Times left to loop the playlist. -1 means loop infinitely.
* @return Always returns #FLUID_OK
* @since 1.1.0
*
* For example, if you want to loop the playlist twice, set loop to 2
* and call this function before you start the player.
*
* @since 1.1.0
*/
int fluid_player_set_loop(fluid_player_t *player, int loop)
{

View file

@ -68,12 +68,15 @@ struct _fluid_midi_router_rule_t
/**
* Create a new midi router. The default rules will pass all events unmodified.
* Create a new midi router.
*
* @param settings Settings used to configure MIDI router
* @param handler MIDI event callback.
* @param event_handler_data Caller defined data pointer which gets passed to 'handler'
* @return New MIDI router instance or NULL on error
*
* The new router will start with default rules and therefore pass all events unmodified.
*
* The MIDI handler callback should process the possibly filtered/modified MIDI
* events from the MIDI router and forward them on to a synthesizer for example.
* The function fluid_synth_handle_midi_event() can be used for \a handle and
@ -151,10 +154,13 @@ delete_fluid_midi_router(fluid_midi_router_t *router)
}
/**
* Set a MIDI router to use default "unity" rules. Such a router will pass all
* events unmodified.
* Set a MIDI router to use default "unity" rules.
*
* @param router Router to set to default rules.
* @return #FLUID_OK on success, #FLUID_FAILED otherwise
*
* Such a router will pass all events unmodified.
*
* @since 1.1.0
*/
int
@ -244,10 +250,13 @@ fluid_midi_router_set_default_rules(fluid_midi_router_t *router)
}
/**
* Clear all rules in a MIDI router. Such a router will drop all events until
* rules are added.
* Clear all rules in a MIDI router.
*
* @param router Router to clear all rules from
* @return #FLUID_OK on success, #FLUID_FAILED otherwise
*
* An empty router will drop all events until rules are added.
*
* @since 1.1.0
*/
int
@ -357,11 +366,13 @@ fluid_midi_router_add_rule(fluid_midi_router_t *router, fluid_midi_router_rule_t
/**
* Create a new MIDI router rule.
*
* @return Newly allocated router rule or NULL if out of memory.
* @since 1.1.0
*
* The new rule is a "unity" rule which will accept any values and wont modify
* them.
*
* @since 1.1.0
*/
fluid_midi_router_rule_t *
new_fluid_midi_router_rule(void)
@ -396,11 +407,13 @@ new_fluid_midi_router_rule(void)
/**
* Free a MIDI router rule.
*
* @param rule Router rule to free
* @since 1.1.0
*
* Note that rules which have been added to a router are managed by the router,
* so this function should seldom be needed.
*
* @since 1.1.0
*/
void
delete_fluid_midi_router_rule(fluid_midi_router_rule_t *rule)
@ -411,12 +424,12 @@ delete_fluid_midi_router_rule(fluid_midi_router_rule_t *rule)
/**
* Set the channel portion of a rule.
*
* @param rule MIDI router rule
* @param min Minimum value for rule match
* @param max Maximum value for rule match
* @param mul Value which is multiplied by matching event's channel value (1.0 to not modify)
* @param add Value which is added to matching event's channel value (0 to not modify)
* @since 1.1.0
*
* The \a min and \a max parameters define a channel range window to match
* incoming events to. If \a min is less than or equal to \a max then an event
@ -426,6 +439,8 @@ delete_fluid_midi_router_rule(fluid_midi_router_rule_t *rule)
*
* The \a mul and \a add values are used to modify event channel values prior to
* sending the event, if the rule matches.
*
* @since 1.1.0
*/
void
fluid_midi_router_rule_set_chan(fluid_midi_router_rule_t *rule, int min, int max,
@ -440,12 +455,12 @@ fluid_midi_router_rule_set_chan(fluid_midi_router_rule_t *rule, int min, int max
/**
* Set the first parameter portion of a rule.
*
* @param rule MIDI router rule
* @param min Minimum value for rule match
* @param max Maximum value for rule match
* @param mul Value which is multiplied by matching event's 1st parameter value (1.0 to not modify)
* @param add Value which is added to matching event's 1st parameter value (0 to not modify)
* @since 1.1.0
*
* The 1st parameter of an event depends on the type of event. For note events
* its the MIDI note #, for CC events its the MIDI control number, for program
@ -464,6 +479,8 @@ fluid_midi_router_rule_set_chan(fluid_midi_router_rule_t *rule, int min, int max
*
* The \a mul and \a add values are used to modify event 1st parameter values prior to
* sending the event, if the rule matches.
*
* @since 1.1.0
*/
void
fluid_midi_router_rule_set_param1(fluid_midi_router_rule_t *rule, int min, int max,
@ -478,12 +495,12 @@ fluid_midi_router_rule_set_param1(fluid_midi_router_rule_t *rule, int min, int m
/**
* Set the second parameter portion of a rule.
*
* @param rule MIDI router rule
* @param min Minimum value for rule match
* @param max Maximum value for rule match
* @param mul Value which is multiplied by matching event's 2nd parameter value (1.0 to not modify)
* @param add Value which is added to matching event's 2nd parameter value (0 to not modify)
* @since 1.1.0
*
* The 2nd parameter of an event depends on the type of event. For note events
* its the MIDI velocity, for CC events its the control value and for key pressure
@ -499,6 +516,8 @@ fluid_midi_router_rule_set_param1(fluid_midi_router_rule_t *rule, int min, int m
*
* The \a mul and \a add values are used to modify event 2nd parameter values prior to
* sending the event, if the rule matches.
*
* @since 1.1.0
*/
void
fluid_midi_router_rule_set_param2(fluid_midi_router_rule_t *rule, int min, int max,