Modify sequencer to (optionally) use sample timer instead of system timer

This commit is contained in:
David Henningsson 2009-05-03 11:32:44 +00:00
parent 95e985b4c9
commit 7993412330
5 changed files with 194 additions and 18 deletions

View file

@ -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);

View file

@ -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);

View file

@ -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
*/

View file

@ -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;
}

View file

@ -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;