Updated man page to include additional command line options and all settings.

Removed system specific fluid_timer_t code in fluid_sys.c and created a unified system.
Added checks and calls to g_thread_init() in key thread functions.
Removed g_thread_init() from fluidsynth.c.
This commit is contained in:
Josh Green 2009-10-23 06:52:29 +00:00
parent bcec3dc993
commit ab517db31f
4 changed files with 387 additions and 433 deletions

View file

@ -13,7 +13,7 @@
.\" along with this program; see the file COPYING. If not, write to .\" along with this program; see the file COPYING. If not, write to
.\" the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. .\" the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
.\" .\"
.TH FluidSynth 1 "June 18, 2009" .TH FluidSynth 1 "Oct 22, 2009"
.\" Please update the above date whenever this man page is modified. .\" Please update the above date whenever this man page is modified.
.\" .\"
.\" Some roff macros, for reference: .\" Some roff macros, for reference:
@ -58,30 +58,34 @@ Run fluidsynth with the \-\-help option to check for changes in the list of opti
.SH OPTIONS .SH OPTIONS
\fBfluidsynth\fP accepts the following options: \fBfluidsynth\fP accepts the following options:
.B \-a, \-\-audio\-driver=[label]
The audio driver [alsa,jack,oss,dsound,...]
.TP .TP
.B \-C, \-\-chorus .B \-a, \-\-audio\-driver=[label]
Turn the chorus on or off [0|1|yes|no, default = on] The audio driver to use. "\-a help" to list valid options
.TP .TP
.B \-c, \-\-audio\-bufcount=[count] .B \-c, \-\-audio\-bufcount=[count]
Number of audio buffers Number of audio buffers
.TP .TP
.B \-C, \-\-chorus
Turn the chorus on or off [0|1|yes|no, default = on]
.TP
.B \-d, \-\-dump .B \-d, \-\-dump
Dump incoming and outgoing MIDI events to stdout Dump incoming and outgoing MIDI events to stdout
.TP .TP
.B \-F, \-\-fast\-render=[file] .B \-E, \-\-audio\-file\-endian
Render MIDI file to raw audio data and store in [file] Audio file endian for fast rendering or aufile driver ("\-E help" for list)
.TP .TP
.B \-f, \-\-load\-config .B \-f, \-\-load\-config
Load command configuration file (shell commands) Load command configuration file (shell commands)
.TP .TP
.B \-G, \-\-audio\-groups .B \-F, \-\-fast\-render=[file]
Defines the number of LADSPA audio nodes Render MIDI file to raw audio data and store in [file]
.TP .TP
.B \-g, \-\-gain .B \-g, \-\-gain
Set the master gain [0 < gain < 10, default = 0.2] Set the master gain [0 < gain < 10, default = 0.2]
.TP .TP
.B \-G, \-\-audio\-groups
Defines the number of LADSPA audio nodes
.TP
.B \-h, \-\-help .B \-h, \-\-help
Print out this help summary Print out this help summary
.TP .TP
@ -94,14 +98,14 @@ Attempt to connect the jack outputs to the physical ports
.B \-K, \-\-midi\-channels=[num] .B \-K, \-\-midi\-channels=[num]
The number of midi channels [default = 16] The number of midi channels [default = 16]
.TP .TP
.B \-L, \-\-audio\-channels=[num]
The number of stereo audio channels [default = 1]
.TP
.B \-l, \-\-disable\-lash .B \-l, \-\-disable\-lash
Don't connect to LASH server Don't connect to LASH server
.TP .TP
.B \-L, \-\-audio\-channels=[num]
The number of stereo audio channels [default = 1]
.TP
.B \-m, \-\-midi\-driver=[label] .B \-m, \-\-midi\-driver=[label]
The name of the midi driver to use [oss,alsa,alsa_seq,...] The name of the midi driver to use. "\-m help" to list valid options.
.TP .TP
.B \-n, \-\-no\-midi\-in .B \-n, \-\-no\-midi\-in
Don't create a midi driver to read MIDI input events [default = yes] Don't create a midi driver to read MIDI input events [default = yes]
@ -109,36 +113,237 @@ Don't create a midi driver to read MIDI input events [default = yes]
.B \-o .B \-o
Define a setting, \-o name=value ("\-o help" to dump current values) Define a setting, \-o name=value ("\-o help" to dump current values)
.TP .TP
.B \-O, \-\-audio\-file\-format
Audio file format for fast rendering or aufile driver ("\-O help" for list)
.TP
.B \-p, \-\-portname=[label] .B \-p, \-\-portname=[label]
Set MIDI port name (alsa_seq, coremidi drivers) Set MIDI port name (alsa_seq, coremidi drivers)
.TP .TP
.B \-R, \-\-reverb
Turn the reverb on or off [0|1|yes|no, default = on]
.TP
.B \-r, \-\-sample\-rate .B \-r, \-\-sample\-rate
Set the sample rate Set the sample rate
.TP .TP
.B \-R, \-\-reverb
Turn the reverb on or off [0|1|yes|no, default = on]
.TP
.B \-s, \-\-server .B \-s, \-\-server
Start FluidSynth as a server process Start FluidSynth as a server process
.TP .TP
.B \-V, \-\-version .B \-T, \-\-audio\-file\-type
Show version of program Audio file type for fast rendering or aufile driver ("\T help" for list)
.TP .TP
.B \-v, \-\-verbose .B \-v, \-\-verbose
Print out verbose messages about midi events Print out verbose messages about midi events
.TP .TP
.B \-V, \-\-version
Show version of program
.TP
.B \-z, \-\-audio\-bufsize=[size] .B \-z, \-\-audio\-bufsize=[size]
Size of each audio buffer Size of each audio buffer
.SH SETTINGS
All settings are non-realtime (have no effect if set after startup), except for those
indicated as realtime.
.TP
.B SYNTHESIZER
.TP
.B synth.audio\-channels INT [min=1, max=128, def=1]
Number of audio channels (DOCME!).
.TP
.B synth.audio\-groups INT [min=1, max=128, def=1]
Number of audio groups (DOCME!).
.TP
.B synth.chorus.active BOOL [def=True]
Chorus effect enable toggle.
.TP
.B synth.cpu\-cores INT [min=1, max=256, def=1]
Number of CPU cores to use for multi-core support.
.TP
.B synth.device\-id INT [min=0, max=126, def=0] REALTIME
Device ID to use for accepting incoming SYSEX messages.
.TP
.B synth.dump BOOL [def=False]
No effect currently.
.TP
.B synth.effects\-channels INT [min=2, max=2, def=2]
No effect currently.
.TP
.B synth.gain FLOAT [min=0.000, max=10.000, def=0.200] REALTIME
Master synthesizer gain.
.TP
.B synth.ladspa.active BOOL [def=False]
LADSPA subsystem enable toggle.
.TP
.B synth.midi\-channels INT [min=16, max=256, def=16]
Total MIDI channel count (must be multiple of 16).
.TP
.B synth.min\-note\-length INT [min=0, max=65535, def=10]
Minimum duration for note events (work around for very short percussion notes).
.TP
.B synth.polyphony INT [min=16, max=4096, def=256] REALTIME
Voice polyphony count (number of simultaneous voices allowed).
.TP
.B synth.reverb.active BOOL [def=True]
Reverb effect enable toggle.
.TP
.B synth.sample\-rate FLOAT [min=22050.000, max=96000.000, def=44100.000]
Synthesizer sample rate.
.TP
.B synth.verbose BOOL [def=False]
Print received MIDI events to stdout.
.TP
.B GENERAL AUDIO
.TP
.B audio.driver STR
Audio driver to use. Default and valid options depend on available drivers.
.TP
.B audio.input\-channels INT [min=0, max=2, def=0]
Not used currently? (DOCME).
.TP
.B audio.output\-channels INT [min=2, max=32, def=2]
DOCME
.TP
.B audio.period\-size INT [min=64, max=8192, def=64]
Period size for audio buffers. Used by many audio drivers.
.TP
.B audio.periods INT [min=2, max=64, def=16]
Count of audio buffers. Used by many audio drivers.
.TP
.B audio.realtime BOOL [def=True]
High priority (real time) toggle for audio driver thread.
.TP
.B audio.realtime\-prio INT [min=1, max=99, def=90]
Priority to assign to audio thread if audio.realtime is enabled.
.TP
.B audio.sample\-format STR [def='16bits' vals:'16bits','float']
Audio output format, to select format for those drivers which support 16 bit or floating point.
.TP
.B AUDIO DRIVER SPECIFIC
.TP
.B audio.alsa.device STR [def='default']
ALSA audio driver output device.
.TP
.B audio.coreaudio.device STR [def='default']
CoreAudio driver output device. Valid options depend on system.
.TP
.B audio.dart.device STR [def='default']
OS/2 Dart audio driver device.
.TP
.B audio.dsound.device STR [def='default']
Device to use for DirectSound driver. Valid options depend on system.
.TP
.B audio.file.endian STR [def='auto' vals:'auto','big','cpu','little']
File renderer or file driver byte order selection. 'auto' selects the default for the selected
file type. 'cpu' uses the CPU byte order. Limited to 'cpu' if no libsndfile support.
.TP
.B audio.file.format STR [def='s16' vals:'double','float','s16','s24','s32','s8','u8']
File renderer or file driver audio format. Limited to 's16' if no libsndfile support.
.TP
.B audio.file.name STR [def='fluidsynth.wav']
Output file name for file renderer or file driver.
.TP
.B audio.file.type STR [def='auto' vals:'aiff','au','auto','flac','oga','raw','wav']
Output file type for file renderer or file driver. 'auto' attempts to determine type from file
extension in audio.file.name. Limited to 'raw' if no libsndfile support. Actual options will vary
depending on libsndfile library.
.TP
.B audio.jack.autoconnect BOOL [def=False]
If enabled, then FluidSynth is automatically connected to Jack system audio output ports.
.TP
.B audio.jack.id STR [def='fluidsynth']
Client ID to use when connecting to Jack.
.TP
.B audio.jack.multi BOOL [def=False]
TRUE to enable multi-channel output.
.TP
.B audio.jack.server STR [def='']
Jack server name. Blank for default.
.TP
.B audio.oss.device STR [def='/dev/dsp']
OSS driver output device.
.TP
.B audio.portaudio.device STR [def='PortAudio Default']
PortAudio driver output device. Available options depends on system.
.TP
.B audio.pulseaudio.device STR [def='default']
PulseAudio driver output device.
.TP
.B audio.pulseaudio.server STR [def='default']
PulseAudio driver server.
.TP
.B GENERAL MIDI
.TP
.B midi.driver STR
MIDI driver to use. Default and valid options depend on available drivers.
.TP
.B midi.realtime BOOL [def=True]
High priority (real time) toggle for MIDI driver thread.
.TP
.B midi.realtime\-prio INT [min=1, max=99, def=80]
Priority to assign to MIDI thread if midi.realtime is enabled.
.TP
.B MIDI DRIVER SPECIFIC
.TP
.B midi.alsa.device STR [def='default']
ALSA raw MIDI driver device.
.TP
.B midi.alsa_seq.device STR [def='default']
ALSA sequencer MIDI driver device.
.TP
.B midi.alsa_seq.id STR [def='pid']
ALSA sequencer client ID. 'pid' will use process ID as part of the client name.
.TP
.B midi.coremidi.id STR [def='pid']
Client ID to use for CoreMIDI driver. 'pid' will use process ID as port of the client name.
.TP
.B midi.jack.id STR [def='fluidsynth-midi']
Jack MIDI driver client ID.
.TP
.B midi.jack.server STR [def='']
Jack MIDI driver server. Blank to use default.
.TP
.B midi.oss.device STR [def='/dev/midi']
OSS MIDI driver device.
.TP
.B midi.portname STR [def='']
Port name used for CoreAudio and ALSA sequencer drivers.
.TP
.B midi.winmidi.device STR [def='default']
Device for Windows MIDI driver.
.TP
.B MISCELLANEOUS
.TP
.B player.reset\-synth BOOL [def=True]
TRUE to reset synthesizer MIDI state between MIDI songs.
.TP
.B player.timing\-source STR [def='sample' vals:'sample','system']
Selects timing source for MIDI sequencer. 'system' uses the system timer.
'sample' uses the sample clock (amount of audio output, events synchronized with audio).
.TP
.B shell.port INT [min=1, max=65535, def=9800]
Shell command server TCP/IP port number to use.
.TP
.B shell.prompt STR [def='']
Shell prompt string.
.SH SHELL COMMANDS .SH SHELL COMMANDS
.TP .TP
.B GENERAL .B GENERAL
.TP .TP
.B help .B help
Prints out a summary of the main commands Prints out list of help topics (type "help <topic>")
.TP
.B help help
Prints out list of other help topics (type "help <topic>")
.TP .TP
.B quit .B quit
Quit the synthesizer Quit the synthesizer

View file

@ -30,6 +30,27 @@
* Should work, so long as no SOCKET or file descriptor ends up with this bit set. - JG */ * Should work, so long as no SOCKET or file descriptor ends up with this bit set. - JG */
#define WIN32_SOCKET_FLAG 0x40000000 #define WIN32_SOCKET_FLAG 0x40000000
/* SCHED_FIFO priority for high priority timer threads */
#define FLUID_SYS_TIMER_HIGH_PRIO_LEVEL 10
typedef struct
{
fluid_thread_func_t func;
void *data;
int prio_level;
} fluid_thread_info_t;
struct _fluid_timer_t
{
long msec;
fluid_timer_callback_t callback;
void *data;
fluid_thread_t *thread;
int cont;
int auto_destroy;
};
struct _fluid_server_socket_t struct _fluid_server_socket_t
{ {
fluid_socket_t socket; fluid_socket_t socket;
@ -366,13 +387,7 @@ fluid_utime (void)
} }
#if defined(WIN32) #if defined(WIN32) /* Windoze specific stuff */
/*=============================================================*/
/* */
/* Win32 */
/* */
/*=============================================================*/
void void
fluid_thread_self_set_prio (fluid_thread_prio_t prio, int prio_level) fluid_thread_self_set_prio (fluid_thread_prio_t prio, int prio_level)
@ -381,132 +396,8 @@ fluid_thread_self_set_prio (fluid_thread_prio_t prio, int prio_level)
SetThreadPriority (GetCurrentThread(), THREAD_PRIORITY_HIGHEST); SetThreadPriority (GetCurrentThread(), THREAD_PRIORITY_HIGHEST);
} }
/***************************************************************
*
* Timer
*
*/
struct _fluid_timer_t #elif defined(__OS2__) /* OS/2 specific stuff */
{
long msec;
fluid_timer_callback_t callback;
void* data;
HANDLE thread;
DWORD thread_id;
int cont;
int auto_destroy;
};
DWORD WINAPI fluid_timer_run(LPVOID data);
fluid_timer_t*
new_fluid_timer(int msec, fluid_timer_callback_t callback, void* data,
int new_thread, int auto_destroy, int high_priority)
{
fluid_timer_t* timer = FLUID_NEW(fluid_timer_t);
if (timer == NULL) {
FLUID_LOG(FLUID_ERR, "Out of memory");
return NULL;
}
timer->cont = 1;
timer->msec = msec;
timer->callback = callback;
timer->data = data;
timer->thread = 0;
timer->auto_destroy = auto_destroy;
if (new_thread) {
timer->thread = CreateThread(NULL, 0, fluid_timer_run, (LPVOID) timer, 0, &timer->thread_id);
if (timer->thread == NULL) {
FLUID_LOG(FLUID_ERR, "Couldn't create timer thread");
FLUID_FREE(timer);
return NULL;
}
if (high_priority)
SetThreadPriority(timer->thread, THREAD_PRIORITY_TIME_CRITICAL);
} else {
fluid_timer_run((LPVOID) timer);
}
return timer;
}
DWORD WINAPI
fluid_timer_run(LPVOID data)
{
int count = 0;
int cont;
long start;
long delay;
fluid_timer_t* timer;
timer = (fluid_timer_t*) data;
if ((timer == NULL) || (timer->callback == NULL)) {
return 0;
}
SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_HIGHEST);
/* keep track of the start time for absolute positioning */
start = fluid_curtime();
while (timer->cont) {
/* do whatever we have to do */
cont = (*timer->callback)(timer->data, fluid_curtime() - start);
count++;
if (!cont) break;
/* to avoid incremental time errors, I calculate the delay between
two callbacks bringing in the "absolute" time (count *
timer->msec) */
delay = (count * timer->msec) - (fluid_curtime() - start);
if (delay > 0) Sleep (delay);
}
FLUID_LOG(FLUID_DBG, "Timer thread finished");
if (timer->auto_destroy) {
FLUID_FREE(timer);
}
ExitThread(0);
return 0;
}
int
delete_fluid_timer(fluid_timer_t* timer)
{
int destroy = !timer->auto_destroy;
timer->cont = 0;
fluid_timer_join(timer);
if (destroy) FLUID_FREE(timer);
return FLUID_OK;
}
int
fluid_timer_join(fluid_timer_t* timer)
{
DWORD wait_result;
if (timer->thread == 0) {
return FLUID_OK;
}
wait_result = WaitForSingleObject(timer->thread, INFINITE);
return (wait_result == WAIT_OBJECT_0)? FLUID_OK : FLUID_FAILED;
}
#elif defined(__OS2__)
/*=============================================================*/
/* */
/* OS2 */
/* */
/*=============================================================*/
void void
fluid_thread_self_set_prio (fluid_thread_prio_t prio, int prio_level) fluid_thread_self_set_prio (fluid_thread_prio_t prio, int prio_level)
@ -515,130 +406,7 @@ fluid_thread_self_set_prio (fluid_thread_prio_t prio, int prio_level)
DosSetPriority (PRTYS_THREAD, PRTYC_REGULAR, PRTYD_MAXIMUM, 0); DosSetPriority (PRTYS_THREAD, PRTYC_REGULAR, PRTYD_MAXIMUM, 0);
} }
/*************************************************************** #else /* POSIX stuff.. Nice POSIX.. Good POSIX. */
*
* Timer
*
*/
struct _fluid_timer_t
{
long msec;
fluid_timer_callback_t callback;
void* data;
int thread_id;
int cont;
int auto_destroy;
};
void fluid_timer_run(void *data);
fluid_timer_t*
new_fluid_timer(int msec, fluid_timer_callback_t callback, void* data,
int new_thread, int auto_destroy, int high_priority)
{
fluid_timer_t* timer = FLUID_NEW(fluid_timer_t);
if (timer == NULL) {
FLUID_LOG(FLUID_ERR, "Out of memory");
return NULL;
}
timer->cont = 1;
timer->msec = msec;
timer->callback = callback;
timer->data = data;
timer->thread_id =-1;
timer->auto_destroy = auto_destroy;
if (new_thread) {
timer->thread_id = _beginthread( fluid_timer_run, NULL, 256 * 1024, ( void * )timer );
if (timer->thread_id == -1) {
FLUID_LOG(FLUID_ERR, "Couldn't create timer thread");
FLUID_FREE(timer);
return NULL;
}
if (high_priority)
DosSetPriority(PRTYS_THREAD, PRTYC_TIMECRITICAL, PRTYD_MAXIMUM, timer->thread_id);
} else {
fluid_timer_run(( void * )timer);
}
return timer;
}
void
fluid_timer_run(void *data)
{
int count = 0;
int cont;
long start;
long delay;
fluid_timer_t* timer;
timer = (fluid_timer_t*) data;
if ((timer == NULL) || (timer->callback == NULL)) {
return;
}
DosSetPriority( PRTYS_THREAD, PRTYC_REGULAR, PRTYD_MAXIMUM, 0 );
/* keep track of the start time for absolute positioning */
start = fluid_curtime();
while (timer->cont) {
/* do whatever we have to do */
cont = (*timer->callback)(timer->data, fluid_curtime() - start);
count++;
if (!cont) break;
/* to avoid incremental time errors, I calculate the delay between
two callbacks bringing in the "absolute" time (count *
timer->msec) */
delay = (count * timer->msec) - (fluid_curtime() - start);
if (delay > 0) DosSleep (delay);
}
FLUID_LOG(FLUID_DBG, "Timer thread finished");
if (timer->auto_destroy) {
FLUID_FREE(timer);
}
return;
}
int
delete_fluid_timer(fluid_timer_t* timer)
{
int destroy = !timer->auto_destroy;
timer->cont = 0;
fluid_timer_join(timer);
if (destroy) FLUID_FREE(timer);
return FLUID_OK;
}
int
fluid_timer_join(fluid_timer_t* timer)
{
ULONG wait_result;
if (timer->thread_id == -1) {
return FLUID_OK;
}
wait_result = DosWaitThread(&timer->thread_id, DCWW_WAIT);
return (wait_result == 0)? FLUID_OK : FLUID_FAILED;
}
#else
/*=============================================================*/
/* */
/* POSIX */
/* */
/*=============================================================*/
void void
fluid_thread_self_set_prio (fluid_thread_prio_t prio, int prio_level) fluid_thread_self_set_prio (fluid_thread_prio_t prio, int prio_level)
@ -654,140 +422,6 @@ fluid_thread_self_set_prio (fluid_thread_prio_t prio, int prio_level)
} }
} }
/***************************************************************
*
* Timer
*/
struct _fluid_timer_t
{
long msec;
fluid_timer_callback_t callback;
void* data;
pthread_t thread;
int cont;
int auto_destroy;
};
void*
fluid_timer_run(void *data)
{
int count = 0;
int cont;
long start;
long delay;
fluid_timer_t* timer;
timer = (fluid_timer_t*) data;
/* keep track of the start time for absolute positioning */
start = fluid_curtime();
while (timer->cont) {
/* do whatever we have to do */
cont = (*timer->callback)(timer->data, fluid_curtime() - start);
count++;
if (!cont) break;
/* to avoid incremental time errors, calculate the delay between
two callbacks bringing in the "absolute" time (count *
timer->msec) */
delay = (count * timer->msec) - (fluid_curtime() - start);
if (delay > 0) usleep (delay * 1000);
}
FLUID_LOG(FLUID_DBG, "Timer thread finished");
if (timer->thread != 0) {
pthread_exit(NULL);
}
if (timer->auto_destroy) {
FLUID_FREE(timer);
}
return NULL;
}
fluid_timer_t*
new_fluid_timer(int msec, fluid_timer_callback_t callback, void* data,
int new_thread, int auto_destroy, int high_priority)
{
pthread_attr_t *attr = NULL;
pthread_attr_t rt_attr;
struct sched_param priority;
int err;
fluid_timer_t* timer = FLUID_NEW(fluid_timer_t);
if (timer == NULL) {
FLUID_LOG(FLUID_ERR, "Out of memory");
return NULL;
}
timer->msec = msec;
timer->callback = callback;
timer->data = data;
timer->cont = 1;
timer->thread = 0;
timer->auto_destroy = auto_destroy;
if (high_priority) {
priority.sched_priority = 10;
if (pthread_attr_init (&rt_attr) == 0
&& pthread_attr_setschedpolicy (&rt_attr, SCHED_FIFO) == 0
&& pthread_attr_setschedparam (&rt_attr, &priority) == 0)
attr = &rt_attr;
}
if (new_thread) {
err = pthread_create(&timer->thread, attr, fluid_timer_run, (void*) timer);
if (err == 0) {
if (attr) FLUID_LOG(FLUID_DBG, "Timer thread created with real-time priority");
else FLUID_LOG(FLUID_DBG, "Timer thread created with normal priority");
} else {
if (attr == NULL
|| pthread_create (&timer->thread, NULL, fluid_timer_run, (void*) timer) != 0) {
FLUID_LOG(FLUID_ERR, "Failed to create timer thread");
FLUID_FREE(timer);
return NULL;
} else {
FLUID_LOG(FLUID_DBG, "Timer thread created, but not with real-time priority");
}
}
} else {
fluid_timer_run((void*) timer);
}
return timer;
}
int
delete_fluid_timer(fluid_timer_t* timer)
{
int destroy = !timer->auto_destroy;
timer->cont = 0;
fluid_timer_join(timer);
FLUID_LOG(FLUID_DBG, "Joined player thread");
if (destroy) FLUID_FREE(timer);
return FLUID_OK;
}
int
fluid_timer_join(fluid_timer_t* timer)
{
int err = 0;
if (timer->thread != 0) {
err = pthread_join(timer->thread, NULL);
}
FLUID_LOG(FLUID_DBG, "Joined player thread");
return (err == 0)? FLUID_OK : FLUID_FAILED;
}
#ifdef FPE_CHECK #ifdef FPE_CHECK
/*************************************************************** /***************************************************************
@ -916,13 +550,6 @@ void fluid_profiling_print(void)
* *
*/ */
typedef struct
{
fluid_thread_func_t func;
void *data;
int prio_level;
} fluid_thread_info_t;
static gpointer static gpointer
fluid_thread_high_prio (gpointer data) fluid_thread_high_prio (gpointer data)
{ {
@ -955,6 +582,11 @@ new_fluid_thread (fluid_thread_func_t func, void *data,
g_return_val_if_fail (func != NULL, NULL); g_return_val_if_fail (func != NULL, NULL);
/* Make sure g_thread_init has been called.
* FIXME - Probably not a good idea in a shared library,
* but what can we do *and* remain backwards compatible? */
if (!g_thread_supported ()) g_thread_init (NULL);
if (prio == FLUID_THREAD_PRIO_HIGH) if (prio == FLUID_THREAD_PRIO_HIGH)
{ {
info = FLUID_NEW (fluid_thread_info_t); info = FLUID_NEW (fluid_thread_info_t);
@ -1006,6 +638,102 @@ fluid_thread_join(fluid_thread_t* thread)
} }
void
fluid_timer_run (void *data)
{
fluid_timer_t *timer;
int count = 0;
int cont;
long start;
long delay;
timer = (fluid_timer_t *)data;
/* keep track of the start time for absolute positioning */
start = fluid_curtime ();
while (timer->cont)
{
cont = (*timer->callback)(timer->data, fluid_curtime() - start);
count++;
if (!cont) break;
/* to avoid incremental time errors, calculate the delay between
two callbacks bringing in the "absolute" time (count *
timer->msec) */
delay = (count * timer->msec) - (fluid_curtime() - start);
if (delay > 0) g_usleep (delay * 1000);
}
FLUID_LOG (FLUID_DBG, "Timer thread finished");
if (timer->auto_destroy)
FLUID_FREE (timer);
return;
}
fluid_timer_t*
new_fluid_timer (int msec, fluid_timer_callback_t callback, void* data,
int new_thread, int auto_destroy, int high_priority)
{
fluid_timer_t *timer;
timer = FLUID_NEW (fluid_timer_t);
if (timer == NULL)
{
FLUID_LOG (FLUID_ERR, "Out of memory");
return NULL;
}
timer->msec = msec;
timer->callback = callback;
timer->data = data;
timer->cont = TRUE ;
timer->thread = NULL;
timer->auto_destroy = auto_destroy;
if (new_thread)
{
timer->thread = new_fluid_thread (fluid_timer_run, timer, high_priority
? FLUID_THREAD_PRIO_HIGH : FLUID_THREAD_PRIO_NORMAL,
FLUID_SYS_TIMER_HIGH_PRIO_LEVEL, FALSE);
if (!timer->thread)
{
FLUID_FREE (timer);
return NULL;
}
}
else fluid_timer_run (timer); /* Run directly, instead of as a separate thread */
return timer;
}
int
delete_fluid_timer (fluid_timer_t *timer)
{
timer->cont = 0;
fluid_timer_join (timer);
if (!timer->auto_destroy) FLUID_FREE (timer);
return FLUID_OK;
}
int
fluid_timer_join (fluid_timer_t *timer)
{
if (timer->thread)
{
fluid_thread_join (timer->thread);
timer->thread = NULL;
}
return FLUID_OK;
}
/*************************************************************** /***************************************************************
* *
* Sockets and I/O * Sockets and I/O

View file

@ -129,34 +129,54 @@ int fluid_timer_stop(fluid_timer_t* timer);
/* Regular mutex */ /* Regular mutex */
typedef GStaticMutex fluid_mutex_t; typedef GStaticMutex fluid_mutex_t;
#define FLUID_MUTEX_INIT G_STATIC_MUTEX_INIT #define FLUID_MUTEX_INIT G_STATIC_MUTEX_INIT
#define fluid_mutex_init(_m) g_static_mutex_init(&(_m))
#define fluid_mutex_destroy(_m) g_static_mutex_free(&(_m)) #define fluid_mutex_destroy(_m) g_static_mutex_free(&(_m))
#define fluid_mutex_lock(_m) g_static_mutex_lock(&(_m)) #define fluid_mutex_lock(_m) g_static_mutex_lock(&(_m))
#define fluid_mutex_unlock(_m) g_static_mutex_unlock(&(_m)) #define fluid_mutex_unlock(_m) g_static_mutex_unlock(&(_m))
#define fluid_mutex_init(_m) G_STMT_START { \
if (!g_thread_supported ()) g_thread_init (NULL); \
g_static_mutex_init (&(_m)); \
} G_STMT_END;
/* Recursive lock capable mutex */ /* Recursive lock capable mutex */
typedef GStaticRecMutex fluid_rec_mutex_t; typedef GStaticRecMutex fluid_rec_mutex_t;
#define fluid_rec_mutex_init(_m) g_static_rec_mutex_init(&(_m))
#define fluid_rec_mutex_destroy(_m) g_static_rec_mutex_free(&(_m)) #define fluid_rec_mutex_destroy(_m) g_static_rec_mutex_free(&(_m))
#define fluid_rec_mutex_lock(_m) g_static_rec_mutex_lock(&(_m)) #define fluid_rec_mutex_lock(_m) g_static_rec_mutex_lock(&(_m))
#define fluid_rec_mutex_unlock(_m) g_static_rec_mutex_unlock(&(_m)) #define fluid_rec_mutex_unlock(_m) g_static_rec_mutex_unlock(&(_m))
#define fluid_rec_mutex_init(_m) G_STMT_START { \
if (!g_thread_supported ()) g_thread_init (NULL); \
g_static_rec_mutex_init (&(_m)); \
} G_STMT_END;
/* Dynamically allocated mutex suitable for fluid_cond_t use */ /* Dynamically allocated mutex suitable for fluid_cond_t use */
typedef GMutex fluid_cond_mutex_t; typedef GMutex fluid_cond_mutex_t;
#define new_fluid_cond_mutex g_mutex_new #define delete_fluid_cond_mutex(m) g_mutex_free(m)
#define delete_fluid_cond_mutex g_mutex_free #define fluid_cond_mutex_lock(m) g_mutex_lock(m)
#define fluid_cond_mutex_lock g_mutex_lock #define fluid_cond_mutex_unlock(m) g_mutex_unlock(m)
#define fluid_cond_mutex_unlock g_mutex_unlock
static FLUID_INLINE fluid_cond_mutex_t *
new_fluid_cond_mutex (void)
{
if (!g_thread_supported ()) g_thread_init (NULL);
return g_mutex_new ();
}
/* Thread condition signaling */ /* Thread condition signaling */
typedef GCond fluid_cond_t; typedef GCond fluid_cond_t;
#define new_fluid_cond g_cond_new #define delete_fluid_cond(cond) g_cond_free(cond)
#define delete_fluid_cond g_cond_free #define fluid_cond_signal(cond) g_cond_signal(cond)
#define fluid_cond_signal g_cond_signal #define fluid_cond_broadcast(cond) g_cond_broadcast(cond)
#define fluid_cond_broadcast g_cond_broadcast #define fluid_cond_wait(cond, mutex) g_cond_wait(cond, mutex)
#define fluid_cond_wait g_cond_wait
static FLUID_INLINE fluid_cond_t *
new_fluid_cond (void)
{
if (!g_thread_supported ()) g_thread_init (NULL);
return g_cond_new ();
}
/* Atomic operations */ /* Atomic operations */
@ -198,11 +218,14 @@ fluid_atomic_float_get(volatile float *fptr)
/* Thread private data */ /* Thread private data */
typedef GStaticPrivate fluid_private_t; typedef GStaticPrivate fluid_private_t;
#define fluid_private_init(_priv) g_static_private_init(&(_priv))
#define fluid_private_get(_priv) g_static_private_get(&(_priv)) #define fluid_private_get(_priv) g_static_private_get(&(_priv))
#define fluid_private_set(_priv, _data, _notify) g_static_private_set(&(_priv), _data, _notify) #define fluid_private_set(_priv, _data, _notify) g_static_private_set(&(_priv), _data, _notify)
#define fluid_private_free(_priv) g_static_private_free(&(_priv)) #define fluid_private_free(_priv) g_static_private_free(&(_priv))
#define fluid_private_init(_priv) G_STMT_START { \
if (!g_thread_supported ()) g_thread_init (NULL); \
g_static_private_init (&(_priv)); \
} G_STMT_END;
/* Threads */ /* Threads */

View file

@ -567,8 +567,6 @@ int main(int argc, char** argv)
exit (0); exit (0);
} }
g_thread_init (NULL);
#ifdef WIN32 #ifdef WIN32
SetPriorityClass(GetCurrentProcess(), REALTIME_PRIORITY_CLASS); SetPriorityClass(GetCurrentProcess(), REALTIME_PRIORITY_CLASS);
#endif #endif