Fixed a bug in the insertion of event in the queueLater list. When we looped

through the list, the prev variable was not updated. Also, the case when the
event was last in the list was not handled. During the debugging I
factorized some of the code. I kept it that way. Also, this file is indented
using 8 spaces, as it is the Linux kernel coding style.
This commit is contained in:
Peter Hanappe 2004-01-06 10:00:47 +00:00
parent 9444b03d43
commit 45ab6c3cf5

View file

@ -21,10 +21,10 @@
/* /*
2002 : API design by Peter Hanappe and Antoine Schmitt 2002 : API design by Peter Hanappe and Antoine Schmitt
August 2002 : Implementation by Antoine Schmitt as@gratin.org August 2002 : Implementation by Antoine Schmitt as@gratin.org
as part of the infiniteCD author project as part of the infiniteCD author project
http://www.infiniteCD.org/ http://www.infiniteCD.org/
*/ */
#include "fluid_event_priv.h" #include "fluid_event_priv.h"
@ -55,6 +55,7 @@ struct _fluid_sequencer_t {
fluid_evt_entry* queue1[255][2]; fluid_evt_entry* queue1[255][2];
fluid_evt_entry* queueLater; fluid_evt_entry* queueLater;
fluid_evt_heap_t* heap; fluid_evt_heap_t* heap;
fluid_mutex_t mutex;
#if FLUID_SEQ_WITH_TRACE #if FLUID_SEQ_WITH_TRACE
char *tracebuf; char *tracebuf;
char *traceptr; char *traceptr;
@ -84,15 +85,15 @@ int _fluid_seq_queue_process(void* data, unsigned int msec); // callback from ti
fluid_sequencer_t* fluid_sequencer_t*
new_fluid_sequencer() new_fluid_sequencer()
{ {
fluid_sequencer_t* seq; fluid_sequencer_t* seq;
seq = FLUID_NEW(fluid_sequencer_t); seq = FLUID_NEW(fluid_sequencer_t);
if (seq == NULL) { if (seq == NULL) {
fluid_log(FLUID_PANIC, "sequencer: Out of memory\n"); fluid_log(FLUID_PANIC, "sequencer: Out of memory\n");
return NULL; return NULL;
} }
FLUID_MEMSET(seq, 0, sizeof(fluid_sequencer_t)); FLUID_MEMSET(seq, 0, sizeof(fluid_sequencer_t));
seq->scale = 1000; // default value seq->scale = 1000; // default value
seq->startMs = fluid_curtime(); seq->startMs = fluid_curtime();
@ -100,9 +101,9 @@ new_fluid_sequencer()
seq->clientsID = 0; seq->clientsID = 0;
if (-1 == _fluid_seq_queue_init(seq, FLUID_SEQUENCER_EVENTS_MAX)) { if (-1 == _fluid_seq_queue_init(seq, FLUID_SEQUENCER_EVENTS_MAX)) {
FLUID_FREE(seq); FLUID_FREE(seq);
fluid_log(FLUID_PANIC, "sequencer: Out of memory\n"); fluid_log(FLUID_PANIC, "sequencer: Out of memory\n");
return NULL; return NULL;
} }
#if FLUID_SEQ_WITH_TRACE #if FLUID_SEQ_WITH_TRACE
@ -111,8 +112,8 @@ new_fluid_sequencer()
if (seq->tracebuf == NULL) { if (seq->tracebuf == NULL) {
_fluid_seq_queue_end(seq); _fluid_seq_queue_end(seq);
FLUID_FREE(seq); FLUID_FREE(seq);
fluid_log(FLUID_PANIC, "sequencer: Out of memory\n"); fluid_log(FLUID_PANIC, "sequencer: Out of memory\n");
return NULL; return NULL;
} }
seq->traceptr = seq->tracebuf; seq->traceptr = seq->tracebuf;
#endif #endif
@ -124,30 +125,31 @@ void
delete_fluid_sequencer(fluid_sequencer_t* seq) delete_fluid_sequencer(fluid_sequencer_t* seq)
{ {
if (seq == NULL) { if (seq == NULL) {
return; return;
} }
_fluid_seq_queue_end(seq); _fluid_seq_queue_end(seq);
/* cleanup clients */ /* cleanup clients */
if (seq->clients) { if (seq->clients) {
fluid_list_t *tmp = seq->clients; fluid_list_t *tmp = seq->clients;
while (tmp != NULL) { while (tmp != NULL) {
fluid_sequencer_client_t *client = (fluid_sequencer_client_t*)tmp->data; fluid_sequencer_client_t *client = (fluid_sequencer_client_t*)tmp->data;
if (client->name) FLUID_FREE(client->name); if (client->name) FLUID_FREE(client->name);
tmp = tmp->next; tmp = tmp->next;
} }
delete_fluid_list(seq->clients); delete_fluid_list(seq->clients);
seq->clients = NULL; seq->clients = NULL;
} }
#if FLUID_SEQ_WITH_TRACE #if FLUID_SEQ_WITH_TRACE
if (seq->tracebuf != NULL) FLUID_FREE(seq->tracebuf); if (seq->tracebuf != NULL)
seq->tracebuf = NULL; FLUID_FREE(seq->tracebuf);
seq->tracebuf = NULL;
#endif #endif
FLUID_FREE(seq); FLUID_FREE(seq);
} }
#if FLUID_SEQ_WITH_TRACE #if FLUID_SEQ_WITH_TRACE
@ -156,13 +158,13 @@ delete_fluid_sequencer(fluid_sequencer_t* seq)
void void
fluid_seq_dotrace(fluid_sequencer_t* seq, char *fmt, ...) fluid_seq_dotrace(fluid_sequencer_t* seq, char *fmt, ...)
{ {
va_list args; va_list args;
int len, remain = seq->tracelen - (seq->traceptr - seq->tracebuf); int len, remain = seq->tracelen - (seq->traceptr - seq->tracebuf);
if (remain <= 0) return; if (remain <= 0) return;
va_start (args, fmt); va_start (args, fmt);
len = vsnprintf(seq->traceptr, remain, fmt, args); len = vsnprintf(seq->traceptr, remain, fmt, args);
va_end (args); va_end (args);
if (len > 0) { if (len > 0) {
if (len <= remain) { if (len <= remain) {
@ -174,7 +176,7 @@ fluid_seq_dotrace(fluid_sequencer_t* seq, char *fmt, ...)
} }
} }
return; return;
} }
void void
@ -197,22 +199,22 @@ void fluid_seq_dotrace(fluid_sequencer_t* seq, char *fmt, ...) {}
/* clients */ /* clients */
short fluid_sequencer_register_client(fluid_sequencer_t* seq, char* name, short fluid_sequencer_register_client(fluid_sequencer_t* seq, char* name,
fluid_event_callback_t callback, void* data) { fluid_event_callback_t callback, void* data) {
fluid_sequencer_client_t * client; fluid_sequencer_client_t * client;
char * nameCopy; char * nameCopy;
client = FLUID_NEW(fluid_sequencer_client_t); client = FLUID_NEW(fluid_sequencer_client_t);
if (client == NULL) { if (client == NULL) {
fluid_log(FLUID_PANIC, "sequencer: Out of memory\n"); fluid_log(FLUID_PANIC, "sequencer: Out of memory\n");
return -1; return -1;
} }
nameCopy = FLUID_STRDUP(name); nameCopy = FLUID_STRDUP(name);
if (nameCopy == NULL) { if (nameCopy == NULL) {
fluid_log(FLUID_PANIC, "sequencer: Out of memory\n"); fluid_log(FLUID_PANIC, "sequencer: Out of memory\n");
return -1; return -1;
} }
seq->clientsID++; seq->clientsID++;
@ -238,10 +240,11 @@ void fluid_sequencer_unregister_client(fluid_sequencer_t* seq, short id)
fluid_sequencer_client_t *client = (fluid_sequencer_client_t*)tmp->data; fluid_sequencer_client_t *client = (fluid_sequencer_client_t*)tmp->data;
if (client->id == id) { if (client->id == id) {
if (client->name) FLUID_FREE(client->name); if (client->name)
seq->clients = fluid_list_remove_link(seq->clients, tmp); FLUID_FREE(client->name);
delete1_fluid_list(tmp); seq->clients = fluid_list_remove_link(seq->clients, tmp);
return; delete1_fluid_list(tmp);
return;
} }
tmp = tmp->next; tmp = tmp->next;
} }
@ -250,7 +253,8 @@ void fluid_sequencer_unregister_client(fluid_sequencer_t* seq, short id)
int fluid_sequencer_count_clients(fluid_sequencer_t* seq) int fluid_sequencer_count_clients(fluid_sequencer_t* seq)
{ {
if (seq->clients == NULL) return 0; if (seq->clients == NULL)
return 0;
return fluid_list_size(seq->clients); return fluid_list_size(seq->clients);
} }
@ -271,7 +275,8 @@ char* fluid_sequencer_get_client_name(fluid_sequencer_t* seq, int id)
{ {
fluid_list_t *tmp; fluid_list_t *tmp;
if (seq->clients == NULL) return NULL; if (seq->clients == NULL)
return NULL;
tmp = seq->clients; tmp = seq->clients;
while (tmp) { while (tmp) {
@ -314,9 +319,10 @@ void fluid_sequencer_send_now(fluid_sequencer_t* seq, fluid_event_t* evt)
fluid_sequencer_client_t *dest = (fluid_sequencer_client_t*)tmp->data; fluid_sequencer_client_t *dest = (fluid_sequencer_client_t*)tmp->data;
if (dest->id == destID) { if (dest->id == destID) {
if (dest->callback) if (dest->callback)
(dest->callback)(fluid_sequencer_get_tick(seq), evt, seq, dest->data); (dest->callback)(fluid_sequencer_get_tick(seq),
return; evt, seq, dest->data);
return;
} }
tmp = tmp->next; tmp = tmp->next;
} }
@ -357,9 +363,9 @@ fluid_sequencer_remove_events(fluid_sequencer_t* seq, short source, short dest,
} }
/******* /*************************************
time time
********/ **************************************/
unsigned int fluid_sequencer_get_tick(fluid_sequencer_t* seq) unsigned int fluid_sequencer_get_tick(fluid_sequencer_t* seq)
{ {
unsigned int absMs = fluid_curtime(); unsigned int absMs = fluid_curtime();
@ -373,8 +379,8 @@ unsigned int fluid_sequencer_get_tick(fluid_sequencer_t* seq)
void fluid_sequencer_set_time_scale(fluid_sequencer_t* seq, double scale) void fluid_sequencer_set_time_scale(fluid_sequencer_t* seq, double scale)
{ {
if (scale <= 0) { if (scale <= 0) {
fluid_log(FLUID_WARN, "sequencer: scale <= 0 : %f\n", scale); fluid_log(FLUID_WARN, "sequencer: scale <= 0 : %f\n", scale);
return; return;
} }
if (scale > 1000.0) if (scale > 1000.0)
@ -422,56 +428,75 @@ double fluid_sequencer_get_time_scale(fluid_sequencer_t* seq)
/********************** /**********************
the queue the queue
**********************/ **********************/
/* /*
The queue stores all future events to be processed. The queue stores all future events to be processed.
Data structures Data structures
There is a heap, allocated at init time, for managing a pool of event entries, There is a heap, allocated at init time, for managing a pool
that is description of an event, its time, and whether it is a normal event of event entries, that is description of an event, its time,
or a removal command. and whether it is a normal event or a removal command.
The queue is separated in two arrays, and a list. The queue is separated in two arrays, and a list. The first
The first array 'queue0' corresponds to the events to be sent in the next 256 ticks (0 to 255), array 'queue0' corresponds to the events to be sent in the
the second array 'queue1' contains the events to be send from now+256 to now+65535. The list next 256 ticks (0 to 255), the second array 'queue1' contains
called 'queueLater' contains the events to be sent later than that. In each array, one cell contains the events to be send from now+256 to now+65535. The list
a list of events having the same time (in the queue0 array), or the same time/256 (in the queue1 array), called 'queueLater' contains the events to be sent later than
and a pointer to the last event in the list of the cell so as to be able to insert fast at the end of that. In each array, one cell contains a list of events having
the list (i.e. a cell = 2 pointers). the same time (in the queue0 array), or the same time/256 (in
The 'queueLater' list is ordered by time and by post time. the queue1 array), and a pointer to the last event in the list
This way, inserting 'soon' events is fast (below 65535 ticks, that is about 1 minute if 1 tick=1ms). of the cell so as to be able to insert fast at the end of the
Inserting later events is more slow, but this is a realtime engine, isn't it ? list (i.e. a cell = 2 pointers). The 'queueLater' list is
ordered by time and by post time. This way, inserting 'soon'
events is fast (below 65535 ticks, that is about 1 minute if 1
tick=1ms). Inserting later events is more slow, but this is a
realtime engine, isn't it ?
The queue0 starts at queue0StartTime. The queue0 starts at queue0StartTime. When 256 ticks have
When 256 ticks have elapsed, the queue0 array is emptied, and the elapsed, the queue0 array is emptied, and the first cell of
first cell of the queue1 array is expanded in the queue0 array, according to the time of each event. The the queue1 array is expanded in the queue0 array, according to
queue1 array is shifted to the left, and the first events of the queueLater list are inserte in the last the time of each event. The queue1 array is shifted to the
cell of the queue1 array. left, and the first events of the queueLater list are inserte
in the last cell of the queue1 array.
We remember the previously managed cell in queue0 in the prevCellNb variable. When processing the current We remember the previously managed cell in queue0 in the
cell, we process the events in between (late events). prevCellNb variable. When processing the current cell, we
process the events in between (late events).
Functions Functions
The main thread functions first get an event entry from the heap, and copy the The main thread functions first get an event entry from the
given event into it, then merely enqueue it in a preQueue. This is in order to protect the data heap, and copy the given event into it, then merely enqueue it
structure : everything is managed in the callback (thread or interrupt, depending on the architecture). in a preQueue. This is in order to protect the data structure:
everything is managed in the callback (thread or interrupt,
depending on the architecture).
All queue data structure management is done in a timer callback: '_fluid_seq_queue_process'. All queue data structure management is done in a timer
The _fluid_seq_queue_process function first process the preQueue, inserting or removing callback: '_fluid_seq_queue_process'. The
event entrys from the queue, then processes the queue, by sending events ready to be sent _fluid_seq_queue_process function first process the preQueue,
at the current time. inserting or removing event entrys from the queue, then
processes the queue, by sending events ready to be sent at the
current time.
Critical sections between the main thread (or app) and the sequencer thread (or interrupt) are: Critical sections between the main thread (or app) and the
- the heap management (if two threads get a free event at the same time) sequencer thread (or interrupt) are:
- the preQueue access.
These are really small and fast sections (merely a pointer or two changing value). They are not protected - the heap management (if two threads get a free event at the
by a mutex for now (August 2002). Waiting for crossplatform mutex solutions. When changing this code, beware same time)
that the _fluid_seq_queue_pre_insert function may be called by the callback of the queue thread (ex : a note event - the preQueue access.
inserts a noteoff event).
These are really small and fast sections (merely a pointer or
two changing value). They are not protected by a mutex for now
(August 2002). Waiting for crossplatform mutex solutions. When
changing this code, beware that the
_fluid_seq_queue_pre_insert function may be called by the
callback of the queue thread (ex : a note event inserts a
noteoff event).
*/ */
@ -488,23 +513,29 @@ void _fluid_seq_queue_send_queued_events(fluid_sequencer_t* seq);
short short
_fluid_seq_queue_init(fluid_sequencer_t* seq, int maxEvents) _fluid_seq_queue_init(fluid_sequencer_t* seq, int maxEvents)
{ {
int i;
seq->heap = _fluid_evt_heap_init(maxEvents); seq->heap = _fluid_evt_heap_init(maxEvents);
if (seq->heap == NULL) { if (seq->heap == NULL) {
fluid_log(FLUID_PANIC, "sequencer: Out of memory\n"); fluid_log(FLUID_PANIC, "sequencer: Out of memory\n");
return -1; return -1;
} }
seq->preQueue = NULL; seq->preQueue = NULL;
seq->preQueueLast = NULL; seq->preQueueLast = NULL;
FLUID_MEMSET(seq->queue0, 0, 2*256*sizeof(fluid_evt_entry *)); FLUID_MEMSET(seq->queue0, 0, 2*256*sizeof(fluid_evt_entry *));
FLUID_MEMSET(seq->queue1, 0, 2*255*sizeof(fluid_evt_entry *)); FLUID_MEMSET(seq->queue1, 0, 2*255*sizeof(fluid_evt_entry *));
seq->queueLater = NULL; seq->queueLater = NULL;
seq->queue0StartTime = fluid_sequencer_get_tick(seq); seq->queue0StartTime = fluid_sequencer_get_tick(seq);
seq->prevCellNb = -1; seq->prevCellNb = -1;
fluid_mutex_init(seq->mutex);
/* start timer */ /* start timer */
seq->timer = new_fluid_timer((int)(1000/seq->scale), _fluid_seq_queue_process, (void *)seq, 1, 0); seq->timer = new_fluid_timer((int)(1000/seq->scale), _fluid_seq_queue_process,
(void *)seq, 1, 0);
return (0); return (0);
} }
@ -520,6 +551,7 @@ _fluid_seq_queue_end(fluid_sequencer_t* seq)
_fluid_evt_heap_free(seq->heap); _fluid_evt_heap_free(seq->heap);
seq->heap = NULL; seq->heap = NULL;
} }
fluid_mutex_destroy(seq->mutex);
} }
@ -529,15 +561,15 @@ _fluid_seq_queue_end(fluid_sequencer_t* seq)
/********************/ /********************/
/* create event_entry and append to the preQueue */ /* create event_entry and append to the preQueue */
/* may be called from the main thread (usually) but also recursively from the queue thread, when a callback /* may be called from the main thread (usually) but also recursively
itself does an insert... */ from the queue thread, when a callback itself does an insert... */
short short
_fluid_seq_queue_pre_insert(fluid_sequencer_t* seq, fluid_event_t * evt) _fluid_seq_queue_pre_insert(fluid_sequencer_t* seq, fluid_event_t * evt)
{ {
fluid_evt_entry * evtentry = _fluid_seq_heap_get_free(seq->heap); fluid_evt_entry * evtentry = _fluid_seq_heap_get_free(seq->heap);
if (evtentry == NULL) { if (evtentry == NULL) {
/* should not happen */ /* should not happen */
fluid_log(FLUID_PANIC, "sequencer: no more free events\n"); fluid_log(FLUID_PANIC, "sequencer: no more free events\n");
return -1; return -1;
} }
@ -545,7 +577,8 @@ _fluid_seq_queue_pre_insert(fluid_sequencer_t* seq, fluid_event_t * evt)
evtentry->entryType = FLUID_EVT_ENTRY_INSERT; evtentry->entryType = FLUID_EVT_ENTRY_INSERT;
FLUID_MEMCPY(&(evtentry->evt), evt, sizeof(fluid_event_t)); FLUID_MEMCPY(&(evtentry->evt), evt, sizeof(fluid_event_t));
/* critical - should threadlock ? */ fluid_mutex_lock(seq->mutex);
/* append to preQueue */ /* append to preQueue */
if (seq->preQueueLast) { if (seq->preQueueLast) {
seq->preQueueLast->next = evtentry; seq->preQueueLast->next = evtentry;
@ -553,20 +586,22 @@ _fluid_seq_queue_pre_insert(fluid_sequencer_t* seq, fluid_event_t * evt)
seq->preQueue = evtentry; seq->preQueue = evtentry;
} }
seq->preQueueLast = evtentry; seq->preQueueLast = evtentry;
fluid_mutex_unlock(seq->mutex);
return (0); return (0);
} }
/* create event_entry and append to the preQueue */ /* create event_entry and append to the preQueue */
/* may be called from the main thread (usually) but also recursively from the queue thread, when a callback /* may be called from the main thread (usually) but also recursively
itself does an insert... */ from the queue thread, when a callback itself does an insert... */
void void
_fluid_seq_queue_pre_remove(fluid_sequencer_t* seq, short src, short dest, int type) _fluid_seq_queue_pre_remove(fluid_sequencer_t* seq, short src, short dest, int type)
{ {
fluid_evt_entry * evtentry = _fluid_seq_heap_get_free(seq->heap); fluid_evt_entry * evtentry = _fluid_seq_heap_get_free(seq->heap);
if (evtentry == NULL) { if (evtentry == NULL) {
/* should not happen */ /* should not happen */
fluid_log(FLUID_PANIC, "sequencer: no more free events\n"); fluid_log(FLUID_PANIC, "sequencer: no more free events\n");
return; return;
} }
@ -580,7 +615,8 @@ _fluid_seq_queue_pre_remove(fluid_sequencer_t* seq, short src, short dest, int t
evt->type = type; evt->type = type;
} }
/* critical - should threadlock ? */ fluid_mutex_lock(seq->mutex);
/* append to preQueue */ /* append to preQueue */
if (seq->preQueueLast) { if (seq->preQueueLast) {
seq->preQueueLast->next = evtentry; seq->preQueueLast->next = evtentry;
@ -589,14 +625,15 @@ _fluid_seq_queue_pre_remove(fluid_sequencer_t* seq, short src, short dest, int t
} }
seq->preQueueLast = evtentry; seq->preQueueLast = evtentry;
fluid_mutex_unlock(seq->mutex);
return; return;
} }
/***********************/ /***********************
/* callback from timer * callback from timer
* (may be in a different thread, or in an interrupt) * (may be in a different thread, or in an interrupt)
*/ *
/***********************/ ***********************/
int int
_fluid_seq_queue_process(void* data, unsigned int msec) _fluid_seq_queue_process(void* data, unsigned int msec)
{ {
@ -605,12 +642,15 @@ _fluid_seq_queue_process(void* data, unsigned int msec)
/* process prequeue */ /* process prequeue */
fluid_evt_entry* tmp; fluid_evt_entry* tmp;
fluid_evt_entry* next; fluid_evt_entry* next;
/* critical - should threadlock ? */ fluid_mutex_lock(seq->mutex);
/* get the preQueue */ /* get the preQueue */
tmp = seq->preQueue; tmp = seq->preQueue;
seq->preQueue = NULL; seq->preQueue = NULL;
seq->preQueueLast = NULL; seq->preQueueLast = NULL;
fluid_mutex_unlock(seq->mutex);
/* walk all the preQueue and process them in order : inserts and removes */ /* walk all the preQueue and process them in order : inserts and removes */
while (tmp) { while (tmp) {
@ -633,6 +673,88 @@ _fluid_seq_queue_process(void* data, unsigned int msec)
} }
void
_fluid_seq_queue_print_later(fluid_sequencer_t* seq)
{
int count = 0;
fluid_evt_entry* tmp = seq->queueLater;
printf("queueLater:\n");
while (tmp) {
unsigned int delay = tmp->evt.time - seq->queue0StartTime;
printf("queueLater: Delay = %i\n", delay);
tmp = tmp->next;
count++;
}
printf("queueLater: Total of %i events\n", count);
}
void
_fluid_seq_queue_insert_queue0(fluid_sequencer_t* seq, fluid_evt_entry* tmp, int cell)
{
if (seq->queue0[cell][1] == NULL) {
seq->queue0[cell][1] = seq->queue0[cell][0] = tmp;
} else {
seq->queue0[cell][1]->next = tmp;
seq->queue0[cell][1] = tmp;
}
tmp->next = NULL;
}
void
_fluid_seq_queue_insert_queue1(fluid_sequencer_t* seq, fluid_evt_entry* tmp, int cell)
{
if (seq->queue1[cell][1] == NULL) {
seq->queue1[cell][1] = seq->queue1[cell][0] = tmp;
} else {
seq->queue1[cell][1]->next = tmp;
seq->queue1[cell][1] = tmp;
}
tmp->next = NULL;
}
void
_fluid_seq_queue_insert_queue_later(fluid_sequencer_t* seq, fluid_evt_entry* evtentry)
{
fluid_evt_entry* prev;
fluid_evt_entry* tmp;
unsigned int time = evtentry->evt.time;
/* insert in 'queueLater', after the ones that have the same
* time */
/* first? */
if ((seq->queueLater == NULL)
|| (seq->queueLater->evt.time > time)) {
evtentry->next = seq->queueLater;
seq->queueLater = evtentry;
return;
}
/* walk queueLater */
/* this is the only slow thing : if the event is more
than 65535 ticks after the current time */
prev = seq->queueLater;
tmp = prev->next;
while (tmp) {
if (tmp->evt.time > time) {
/* insert before tmp */
evtentry->next = tmp;
prev->next = evtentry;
return;
}
prev = tmp;
tmp = prev->next;
}
/* last */
evtentry->next = NULL;
prev->next = evtentry;
}
void void
_fluid_seq_queue_insert_entry(fluid_sequencer_t* seq, fluid_evt_entry * evtentry) _fluid_seq_queue_insert_entry(fluid_sequencer_t* seq, fluid_evt_entry * evtentry)
{ {
@ -642,82 +764,41 @@ _fluid_seq_queue_insert_entry(fluid_sequencer_t* seq, fluid_evt_entry * evtentry
unsigned int delay; unsigned int delay;
if (seq->queue0StartTime > 0) { if (seq->queue0StartTime > 0) {
/* queue0StartTime could be < 0 if the scale changed a lot early, breaking the following comparison */ /* queue0StartTime could be < 0 if the scale changed a
lot early, breaking the following comparison
*/
if (time < (unsigned int)seq->queue0StartTime) { if (time < (unsigned int)seq->queue0StartTime) {
/* we are late, send now */ /* we are late, send now */
fluid_sequencer_send_now(seq, evt); fluid_sequencer_send_now(seq, evt);
_fluid_seq_heap_set_free(seq->heap, evtentry); _fluid_seq_heap_set_free(seq->heap, evtentry);
return; return;
} }
} }
if (seq->prevCellNb >= 0) { if (seq->prevCellNb >= 0) {
/* prevCellNb could be -1 is seq was just started - unlikely */ /* prevCellNb could be -1 is seq was just started - unlikely */
/* prevCellNb can also be -1 if cellNb was reset to 0 in
_fluid_seq_queue_send_queued_events() */
if (time <= (unsigned int)(seq->queue0StartTime + seq->prevCellNb)) { if (time <= (unsigned int)(seq->queue0StartTime + seq->prevCellNb)) {
/* we are late, send now */ /* we are late, send now */
fluid_sequencer_send_now(seq, evt); fluid_sequencer_send_now(seq, evt);
_fluid_seq_heap_set_free(seq->heap, evtentry); _fluid_seq_heap_set_free(seq->heap, evtentry);
return; return;
} }
} }
delay = time - seq->queue0StartTime; delay = time - seq->queue0StartTime;
if (delay > 65535) { if (delay > 65535) {
/* insert in 'later', after the ones that have the same time */ _fluid_seq_queue_insert_queue_later(seq, evtentry);
if (seq->queueLater == NULL) {
/* first one in later */
seq->queueLater = evtentry;
return;
}
/* first one ?*/
if (seq->queueLater->evt.time > time) {
evtentry->next = seq->queueLater;
seq->queueLater = evtentry;
return;
}
/* walk queueLater */
/* this is the only slow thing : if the event is more
than 65535 ticks after the current time */
{
fluid_evt_entry* prev = seq->queueLater;
fluid_evt_entry* tmp = prev->next;
while (tmp) {
if (tmp->evt.time > time) {
/* insert before tmp */
evtentry->next = tmp;
prev->next = evtentry;
return;
}
tmp = tmp->next;
}
}
} else if (delay > 255) { } else if (delay > 255) {
/* append to the right cell in queue1 */ _fluid_seq_queue_insert_queue1(seq, evtentry, delay/256 - 1);
unsigned int cellnb = delay/256;
if (seq->queue1[cellnb-1][1] == NULL) {
seq->queue1[cellnb-1][1] = seq->queue1[cellnb-1][0] = evtentry;
} else {
seq->queue1[cellnb-1][1]->next = evtentry;
seq->queue1[cellnb-1][1] = evtentry;
}
evtentry->next = NULL;
} else { } else {
/* insert in queue0 */ _fluid_seq_queue_insert_queue0(seq, evtentry, delay);
if (seq->queue0[delay][1] == NULL) {
seq->queue0[delay][1] = seq->queue0[delay][0] = evtentry;
} else {
seq->queue0[delay][1]->next = evtentry;
seq->queue0[delay][1] = evtentry;
}
evtentry->next = NULL;
} }
} }
@ -742,15 +823,14 @@ _fluid_seq_queue_matchevent(fluid_event_t* evt, int templType, short templSrc, s
if (templType == FLUID_SEQ_ANYCONTROLCHANGE) if (templType == FLUID_SEQ_ANYCONTROLCHANGE)
if (eventType == FLUID_SEQ_PITCHBEND || if (eventType == FLUID_SEQ_PITCHBEND ||
eventType == FLUID_SEQ_MODULATION || eventType == FLUID_SEQ_MODULATION ||
eventType == FLUID_SEQ_SUSTAIN || eventType == FLUID_SEQ_SUSTAIN ||
eventType == FLUID_SEQ_PAN || eventType == FLUID_SEQ_PAN ||
eventType == FLUID_SEQ_VOLUME || eventType == FLUID_SEQ_VOLUME ||
eventType == FLUID_SEQ_REVERBSEND || eventType == FLUID_SEQ_REVERBSEND ||
eventType == FLUID_SEQ_CONTROLCHANGE || eventType == FLUID_SEQ_CONTROLCHANGE ||
eventType == FLUID_SEQ_CHORUSSEND eventType == FLUID_SEQ_CHORUSSEND)
) return 1;
return 1;
return 0; return 0;
} }
@ -856,96 +936,98 @@ _fluid_seq_queue_remove_entries_matching(fluid_sequencer_t* seq, fluid_evt_entry
} }
} }
void
_fluid_seq_queue_send_cell_events(fluid_sequencer_t* seq, int cellNb)
{
fluid_evt_entry* next;
fluid_evt_entry* tmp;
tmp = seq->queue0[cellNb][0];
while (tmp) {
fluid_sequencer_send_now(seq, &(tmp->evt));
next = tmp->next;
_fluid_seq_heap_set_free(seq->heap, tmp);
tmp = next;
}
seq->queue0[cellNb][0] = NULL;
seq->queue0[cellNb][1] = NULL;
}
void
_fluid_seq_queue_slide(fluid_sequencer_t* seq)
{
short i;
fluid_evt_entry* next;
fluid_evt_entry* tmp;
int count = 0;
/* do the slide */
seq->queue0StartTime += 256;
/* sort all queue1[0] into queue0 according to new queue0StartTime */
tmp = seq->queue1[0][0];
while (tmp) {
unsigned int delay = tmp->evt.time - seq->queue0StartTime;
next = tmp->next;
if (delay > 255) {
/* should not happen !! */
/* append it to queue1[1] */
_fluid_seq_queue_insert_queue1(seq, tmp, 1);
} else {
_fluid_seq_queue_insert_queue0(seq, tmp, delay);
}
tmp = next;
count++;
}
/* slide all queue1[i] into queue1[i-1] */
for (i = 1 ; i < 255 ; i++) {
seq->queue1[i-1][0] = seq->queue1[i][0];
seq->queue1[i-1][1] = seq->queue1[i][1];
}
seq->queue1[254][0] = NULL;
seq->queue1[254][1] = NULL;
/* append queueLater to queue1[254] */
count = 0;
tmp = seq->queueLater;
while (tmp) {
unsigned int delay = tmp->evt.time - seq->queue0StartTime;
if (delay > 65535) {
break;
}
next = tmp->next;
/* append it */
_fluid_seq_queue_insert_queue1(seq, tmp, 254);
tmp = next;
count++;
}
seq->queueLater = tmp;
}
void void
_fluid_seq_queue_send_queued_events(fluid_sequencer_t* seq) _fluid_seq_queue_send_queued_events(fluid_sequencer_t* seq)
{ {
unsigned int nowTicks = fluid_sequencer_get_tick(seq); unsigned int nowTicks = fluid_sequencer_get_tick(seq);
short cellNb; short cellNb;
fluid_evt_entry* next;
fluid_evt_entry* tmp;
cellNb = seq->prevCellNb + 1; cellNb = seq->prevCellNb + 1;
while (cellNb <= (int)(nowTicks - seq->queue0StartTime)) { while (cellNb <= (int)(nowTicks - seq->queue0StartTime)) {
if (cellNb == 256) { if (cellNb == 256) {
short i;
int more = 1;
/* do the slide */
seq->queue0StartTime += 256;
cellNb = 0; cellNb = 0;
_fluid_seq_queue_slide(seq);
/* sort all queue1[0] into queue0 according to new queue0StartTime */
tmp = seq->queue1[0][0];
while (tmp) {
unsigned int delay = tmp->evt.time - seq->queue0StartTime;
next = tmp->next;
if (delay > 255) {
/* should not happen !! */
/* append it to queue1[1] */
if (seq->queue1[1][1] == NULL) {
seq->queue1[1][1] = seq->queue1[1][0] = tmp;
} else {
seq->queue1[1][1]->next = tmp;
seq->queue1[1][1] = tmp;
}
tmp->next = NULL;
} else {
if (seq->queue0[delay][1] == NULL) {
seq->queue0[delay][1] = seq->queue0[delay][0] = tmp;
} else {
seq->queue0[delay][1]->next = tmp;
seq->queue0[delay][1] = tmp;
}
tmp->next = NULL;
}
tmp = next;
}
/* slide all queue1[i] into queue1[i-1] */
for (i = 1 ; i < 255 ; i++) {
seq->queue1[i-1][0] = seq->queue1[i][0];
seq->queue1[i-1][1] = seq->queue1[i][1];
}
seq->queue1[254][0] = NULL;
seq->queue1[254][1] = NULL;
/* append queueLater to queue1[254] */
more = 1;
tmp = seq->queueLater;
while (tmp && more) {
unsigned int delay = tmp->evt.time - seq->queue0StartTime;
next = tmp->next;
if (delay <= 65535) {
/* append it */
if (seq->queue1[254][1] == NULL) {
seq->queue1[254][1] = seq->queue1[254][0] = tmp;
} else {
seq->queue1[254][1]->next = tmp;
seq->queue1[254][1] = tmp;
}
tmp->next = NULL;
tmp = next;
} else more = 0;
}
seq->queueLater = tmp;
} /* slide */ } /* slide */
/* process queue0[cellNb] */ /* process queue0[cellNb] */
tmp = seq->queue0[cellNb][0]; _fluid_seq_queue_send_cell_events(seq, cellNb);
while (tmp) {
fluid_sequencer_send_now(seq, &(tmp->evt));
next = tmp->next;
_fluid_seq_heap_set_free(seq->heap, tmp);
tmp = next;
}
seq->queue0[cellNb][0] = NULL;
seq->queue0[cellNb][1] = NULL;
/* next cell */ /* next cell */
cellNb++; cellNb++;