mirror of
https://github.com/ZDoom/fluidsynth.git
synced 2025-02-23 12:21:39 +00:00
Modify sequencer to (optionally) use sample timer instead of system timer
This commit is contained in:
parent
95e985b4c9
commit
7993412330
5 changed files with 194 additions and 18 deletions
|
@ -55,6 +55,7 @@ enum fluid_seq_event_type {
|
|||
FLUID_SEQ_CHORUSSEND, /**< Chorus send set event */
|
||||
FLUID_SEQ_TIMER, /**< Timer event (DOCME) */
|
||||
FLUID_SEQ_ANYCONTROLCHANGE, /**< DOCME (used for remove_events only) */
|
||||
FLUID_SEQ_UNREGISTERING, /**< Called when a sequencer client is being unregistered. @since 1.1.0 */
|
||||
FLUID_SEQ_LASTEVENT /**< Defines the count of event enums */
|
||||
};
|
||||
|
||||
|
@ -101,6 +102,9 @@ FLUIDSYNTH_API void fluid_event_chorus_send(fluid_event_t* evt, int channel, sho
|
|||
/* Only for removing events */
|
||||
FLUIDSYNTH_API void fluid_event_any_control_change(fluid_event_t* evt, int channel);
|
||||
|
||||
/* Only when unregistering clients */
|
||||
FLUIDSYNTH_API void fluid_event_unregistering(fluid_event_t* evt);
|
||||
|
||||
/* Accessing event data */
|
||||
FLUIDSYNTH_API int fluid_event_get_type(fluid_event_t* evt);
|
||||
FLUIDSYNTH_API short fluid_event_get_source(fluid_event_t* evt);
|
||||
|
|
|
@ -32,10 +32,14 @@ typedef void (*fluid_event_callback_t)(unsigned int time, fluid_event_t* event,
|
|||
|
||||
/** Allocate a new sequencer structure */
|
||||
FLUIDSYNTH_API fluid_sequencer_t* new_fluid_sequencer(void);
|
||||
FLUIDSYNTH_API fluid_sequencer_t* new_fluid_sequencer2(int useSystemTimer);
|
||||
|
||||
/** Free the sequencer structure */
|
||||
FLUIDSYNTH_API void delete_fluid_sequencer(fluid_sequencer_t* seq);
|
||||
|
||||
|
||||
FLUIDSYNTH_API int fluid_sequencer_get_useSystemTimer(fluid_sequencer_t* seq);
|
||||
|
||||
/** clients can be sources or destinations of events. These functions ensure a unique ID for any
|
||||
source or dest, for filtering purposes.
|
||||
sources only dont need to register a callback.
|
||||
|
@ -61,7 +65,8 @@ FLUIDSYNTH_API char* fluid_sequencer_get_client_name(fluid_sequencer_t* seq, int
|
|||
/** Returns 1 if client is a destination (has a callback) */
|
||||
FLUIDSYNTH_API int fluid_sequencer_client_is_dest(fluid_sequencer_t* seq, int id);
|
||||
|
||||
|
||||
/** Advance sequencer. Do not use if you created the sequencer with useSystemTimer enabled. */
|
||||
FLUIDSYNTH_API void fluid_sequencer_process(fluid_sequencer_t* seq, unsigned int msec);
|
||||
|
||||
/** Sending an event immediately. */
|
||||
FLUIDSYNTH_API void fluid_sequencer_send_now(fluid_sequencer_t* seq, fluid_event_t* evt);
|
||||
|
|
|
@ -399,6 +399,18 @@ fluid_event_chorus_send(fluid_event_t* evt, int channel, short val)
|
|||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set a sequencer event to be an unregistering event.
|
||||
* @param evt Sequencer event structure
|
||||
*/
|
||||
void
|
||||
fluid_event_unregistering(fluid_event_t* evt)
|
||||
{
|
||||
evt->type = FLUID_SEQ_UNREGISTERING;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Accessing event data
|
||||
*/
|
||||
|
|
|
@ -42,6 +42,8 @@
|
|||
/* Private data for SEQUENCER */
|
||||
struct _fluid_sequencer_t {
|
||||
unsigned int startMs;
|
||||
unsigned int currentMs;
|
||||
gboolean useSystemTimer;
|
||||
double scale; // ticks per second
|
||||
fluid_list_t* clients;
|
||||
short clientsID;
|
||||
|
@ -82,8 +84,26 @@ int _fluid_seq_queue_process(void* data, unsigned int msec); // callback from ti
|
|||
|
||||
/* API implementation */
|
||||
|
||||
/**
|
||||
* Legacy call to new_fluid_sequencer to provide backwards compatibility.
|
||||
* Please use new_fluid_sequencer2 instead.
|
||||
* @deprecated
|
||||
*/
|
||||
fluid_sequencer_t*
|
||||
new_fluid_sequencer()
|
||||
{
|
||||
return new_fluid_sequencer2(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new sequencer object.
|
||||
* @param useSystemTimer if this parameter is non-zero, sequencer will advance
|
||||
* at the rate of the computer's system clock. If zero, call fluid_sequencer_process
|
||||
* to advance the sequencer.
|
||||
* @since 1.1.0
|
||||
*/
|
||||
fluid_sequencer_t*
|
||||
new_fluid_sequencer2(int useSystemTimer)
|
||||
{
|
||||
fluid_sequencer_t* seq;
|
||||
|
||||
|
@ -96,7 +116,8 @@ new_fluid_sequencer()
|
|||
FLUID_MEMSET(seq, 0, sizeof(fluid_sequencer_t));
|
||||
|
||||
seq->scale = 1000; // default value
|
||||
seq->startMs = fluid_curtime();
|
||||
seq->useSystemTimer = useSystemTimer ? TRUE : FALSE;
|
||||
seq->startMs = seq->useSystemTimer ? fluid_curtime() : 0;
|
||||
seq->clients = NULL;
|
||||
seq->clientsID = 0;
|
||||
|
||||
|
@ -129,10 +150,15 @@ delete_fluid_sequencer(fluid_sequencer_t* seq)
|
|||
return;
|
||||
}
|
||||
|
||||
/* cleanup clients */
|
||||
while (seq->clients) {
|
||||
fluid_sequencer_client_t *client = (fluid_sequencer_client_t*)seq->clients->data;
|
||||
fluid_sequencer_unregister_client(seq, client->id);
|
||||
}
|
||||
|
||||
_fluid_seq_queue_end(seq);
|
||||
|
||||
/* cleanup clients */
|
||||
if (seq->clients) {
|
||||
/* if (seq->clients) {
|
||||
fluid_list_t *tmp = seq->clients;
|
||||
while (tmp != NULL) {
|
||||
fluid_sequencer_client_t *client = (fluid_sequencer_client_t*)tmp->data;
|
||||
|
@ -141,7 +167,7 @@ delete_fluid_sequencer(fluid_sequencer_t* seq)
|
|||
}
|
||||
delete_fluid_list(seq->clients);
|
||||
seq->clients = NULL;
|
||||
}
|
||||
}*/
|
||||
|
||||
#if FLUID_SEQ_WITH_TRACE
|
||||
if (seq->tracebuf != NULL)
|
||||
|
@ -152,6 +178,17 @@ delete_fluid_sequencer(fluid_sequencer_t* seq)
|
|||
FLUID_FREE(seq);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return 1 if system timers are enabled, or 0 if system timers are disabled.
|
||||
* @since 1.1.0
|
||||
*/
|
||||
int
|
||||
fluid_sequencer_get_useSystemTimer(fluid_sequencer_t* seq)
|
||||
{
|
||||
return seq->useSystemTimer ? 1 : 0;
|
||||
}
|
||||
|
||||
|
||||
#if FLUID_SEQ_WITH_TRACE
|
||||
|
||||
/* trace */
|
||||
|
@ -232,22 +269,35 @@ short fluid_sequencer_register_client(fluid_sequencer_t* seq, char* name,
|
|||
void fluid_sequencer_unregister_client(fluid_sequencer_t* seq, short id)
|
||||
{
|
||||
fluid_list_t *tmp;
|
||||
fluid_event_t* evt;
|
||||
|
||||
if (seq->clients == NULL) return;
|
||||
|
||||
evt = new_fluid_event();
|
||||
if (evt != NULL) {
|
||||
fluid_event_unregistering(evt);
|
||||
fluid_event_set_dest(evt, id);
|
||||
}
|
||||
|
||||
tmp = seq->clients;
|
||||
while (tmp) {
|
||||
fluid_sequencer_client_t *client = (fluid_sequencer_client_t*)tmp->data;
|
||||
|
||||
if (client->id == id) {
|
||||
/* What should we really do if evt is null due to out-of-memory? */
|
||||
if (client->callback != NULL && evt != NULL)
|
||||
(client->callback)(fluid_sequencer_get_tick(seq),
|
||||
evt, seq, client->data);
|
||||
if (client->name)
|
||||
FLUID_FREE(client->name);
|
||||
seq->clients = fluid_list_remove_link(seq->clients, tmp);
|
||||
delete1_fluid_list(tmp);
|
||||
delete_fluid_event(evt);
|
||||
return;
|
||||
}
|
||||
tmp = tmp->next;
|
||||
}
|
||||
delete_fluid_event(evt);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -368,7 +418,7 @@ fluid_sequencer_remove_events(fluid_sequencer_t* seq, short source, short dest,
|
|||
**************************************/
|
||||
unsigned int fluid_sequencer_get_tick(fluid_sequencer_t* seq)
|
||||
{
|
||||
unsigned int absMs = fluid_curtime();
|
||||
unsigned int absMs = seq->useSystemTimer ? fluid_curtime() : seq->currentMs;
|
||||
double nowFloat;
|
||||
unsigned int now;
|
||||
nowFloat = ((double)(absMs - seq->startMs))*seq->scale/1000.0f;
|
||||
|
@ -414,8 +464,10 @@ void fluid_sequencer_set_time_scale(fluid_sequencer_t* seq, double scale)
|
|||
}
|
||||
|
||||
/* re-start timer */
|
||||
if (seq->useSystemTimer) {
|
||||
seq->timer = new_fluid_timer((int)(1000/seq->scale), _fluid_seq_queue_process, (void *)seq, 1, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Set the conversion from tick to absolute time (ticks per
|
||||
|
@ -534,8 +586,10 @@ _fluid_seq_queue_init(fluid_sequencer_t* seq, int maxEvents)
|
|||
fluid_mutex_init(seq->mutex);
|
||||
|
||||
/* start timer */
|
||||
if (seq->useSystemTimer) {
|
||||
seq->timer = new_fluid_timer((int)(1000/seq->scale), _fluid_seq_queue_process,
|
||||
(void *)seq, 1, 0);
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
|
@ -638,6 +692,19 @@ int
|
|||
_fluid_seq_queue_process(void* data, unsigned int msec)
|
||||
{
|
||||
fluid_sequencer_t* seq = (fluid_sequencer_t *)data;
|
||||
fluid_sequencer_process(seq, msec);
|
||||
/* continue timer */
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Advance sequencer. Do not use if you created the sequencer with useSystemTimer enabled.
|
||||
* @param msec the number of milliseconds (compared to when the sequencer was created).
|
||||
* @since 1.1.0
|
||||
*/
|
||||
void
|
||||
fluid_sequencer_process(fluid_sequencer_t* seq, unsigned int msec)
|
||||
{
|
||||
|
||||
/* process prequeue */
|
||||
fluid_evt_entry* tmp;
|
||||
|
@ -666,10 +733,9 @@ _fluid_seq_queue_process(void* data, unsigned int msec)
|
|||
}
|
||||
|
||||
/* send queued events */
|
||||
seq->currentMs = msec;
|
||||
_fluid_seq_queue_send_queued_events(seq);
|
||||
|
||||
/* continue timer */
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -28,25 +28,107 @@
|
|||
*/
|
||||
|
||||
#include "fluidsynth_priv.h"
|
||||
#include "fluid_synth.h"
|
||||
|
||||
/***************************************************************
|
||||
*
|
||||
* SEQUENCER BINDING
|
||||
*/
|
||||
|
||||
struct _fluid_seqbind_t {
|
||||
fluid_synth_t* synth;
|
||||
fluid_sequencer_t* seq;
|
||||
fluid_sample_timer_t* sample_timer;
|
||||
short client_id;
|
||||
};
|
||||
typedef struct _fluid_seqbind_t fluid_seqbind_t;
|
||||
|
||||
|
||||
int fluid_seqbind_timer_callback(void* data, unsigned int msec);
|
||||
void fluid_seq_fluidsynth_callback(unsigned int time, fluid_event_t* event, fluid_sequencer_t* seq, void* data);
|
||||
|
||||
/* registering the synth */
|
||||
short fluid_sequencer_register_fluidsynth(fluid_sequencer_t* seq, fluid_synth_t* synth)
|
||||
/**
|
||||
* Proper cleanup of the seqbind struct.
|
||||
*/
|
||||
void
|
||||
delete_fluid_seqbind(fluid_seqbind_t* seqbind)
|
||||
{
|
||||
/* register fluidsynth itself */
|
||||
return fluid_sequencer_register_client(seq, "fluidsynth", fluid_seq_fluidsynth_callback, (void *)synth);
|
||||
if (seqbind == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ((seqbind->client_id != -1) && (seqbind->seq != NULL)) {
|
||||
fluid_sequencer_unregister_client(seqbind->seq, seqbind->client_id);
|
||||
seqbind->client_id = -1;
|
||||
}
|
||||
|
||||
if ((seqbind->sample_timer != NULL) && (seqbind->synth != NULL)) {
|
||||
delete_fluid_sample_timer(seqbind->synth, seqbind->sample_timer);
|
||||
seqbind->sample_timer = NULL;
|
||||
}
|
||||
|
||||
FLUID_FREE(seqbind);
|
||||
}
|
||||
|
||||
/* the callback itself */
|
||||
void fluid_seq_fluidsynth_callback(unsigned int time, fluid_event_t* evt, fluid_sequencer_t* seq, void* data)
|
||||
/**
|
||||
* Registers fluidsynth as a client of the given sequencer.
|
||||
* The fluidsynth is registered with the name "fluidsynth".
|
||||
* @returns the fluidsynth destID in the sequencer, or -1 if function failed.
|
||||
*/
|
||||
short
|
||||
fluid_sequencer_register_fluidsynth(fluid_sequencer_t* seq, fluid_synth_t* synth)
|
||||
{
|
||||
fluid_synth_t* synth = (fluid_synth_t *)data;
|
||||
fluid_seqbind_t* seqbind;
|
||||
|
||||
seqbind = FLUID_NEW(fluid_seqbind_t);
|
||||
if (seqbind == NULL) {
|
||||
fluid_log(FLUID_PANIC, "sequencer: Out of memory\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
seqbind->synth = synth;
|
||||
seqbind->seq = seq;
|
||||
seqbind->sample_timer = NULL;
|
||||
seqbind->client_id = -1;
|
||||
|
||||
/* set up the sample timer */
|
||||
if (!fluid_sequencer_get_useSystemTimer(seq)) {
|
||||
seqbind->sample_timer =
|
||||
new_fluid_sample_timer(synth, fluid_seqbind_timer_callback, (void *) seqbind);
|
||||
if (seqbind->sample_timer == NULL) {
|
||||
fluid_log(FLUID_PANIC, "sequencer: Out of memory\n");
|
||||
delete_fluid_seqbind(seqbind);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* register fluidsynth itself */
|
||||
seqbind->client_id =
|
||||
fluid_sequencer_register_client(seq, "fluidsynth", fluid_seq_fluidsynth_callback, (void *)seqbind);
|
||||
if (seqbind->client_id == -1) {
|
||||
delete_fluid_seqbind(seqbind);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return seqbind->client_id;
|
||||
}
|
||||
|
||||
/* Callback for sample timer */
|
||||
int
|
||||
fluid_seqbind_timer_callback(void* data, unsigned int msec)
|
||||
{
|
||||
fluid_seqbind_t* seqbind = (fluid_seqbind_t *) data;
|
||||
fluid_sequencer_process(seqbind->seq, msec);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Callback for midi events */
|
||||
void
|
||||
fluid_seq_fluidsynth_callback(unsigned int time, fluid_event_t* evt, fluid_sequencer_t* seq, void* data)
|
||||
{
|
||||
fluid_synth_t* synth;
|
||||
fluid_seqbind_t* seqbind = (fluid_seqbind_t *) data;
|
||||
synth = seqbind->synth;
|
||||
|
||||
switch (fluid_event_get_type(evt)) {
|
||||
|
||||
|
@ -147,6 +229,13 @@ void fluid_seq_fluidsynth_callback(unsigned int time, fluid_event_t* evt, fluid_
|
|||
}
|
||||
break;
|
||||
|
||||
case FLUID_SEQ_UNREGISTERING: /* free ourselves */
|
||||
{
|
||||
seqbind->client_id = -1; /* avoid recursive call to fluid_sequencer_unregister_client */
|
||||
delete_fluid_seqbind(seqbind);
|
||||
}
|
||||
break;
|
||||
|
||||
case FLUID_SEQ_TIMER:
|
||||
/* nothing in fluidsynth */
|
||||
break;
|
||||
|
|
Loading…
Reference in a new issue