From ab517db31f1ff7812d098a5674fbffac0e3188be Mon Sep 17 00:00:00 2001 From: Josh Green Date: Fri, 23 Oct 2009 06:52:29 +0000 Subject: [PATCH] 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. --- fluidsynth/doc/fluidsynth.1 | 249 +++++++++++++++-- fluidsynth/src/fluid_sys.c | 522 +++++++++--------------------------- fluidsynth/src/fluid_sys.h | 47 +++- fluidsynth/src/fluidsynth.c | 2 - 4 files changed, 387 insertions(+), 433 deletions(-) diff --git a/fluidsynth/doc/fluidsynth.1 b/fluidsynth/doc/fluidsynth.1 index e4c44e51..6209a41b 100644 --- a/fluidsynth/doc/fluidsynth.1 +++ b/fluidsynth/doc/fluidsynth.1 @@ -13,7 +13,7 @@ .\" along with this program; see the file COPYING. If not, write to .\" 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. .\" .\" 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 \fBfluidsynth\fP accepts the following options: -.B \-a, \-\-audio\-driver=[label] -The audio driver [alsa,jack,oss,dsound,...] .TP -.B \-C, \-\-chorus -Turn the chorus on or off [0|1|yes|no, default = on] +.B \-a, \-\-audio\-driver=[label] +The audio driver to use. "\-a help" to list valid options .TP .B \-c, \-\-audio\-bufcount=[count] Number of audio buffers .TP +.B \-C, \-\-chorus +Turn the chorus on or off [0|1|yes|no, default = on] +.TP .B \-d, \-\-dump Dump incoming and outgoing MIDI events to stdout .TP -.B \-F, \-\-fast\-render=[file] -Render MIDI file to raw audio data and store in [file] +.B \-E, \-\-audio\-file\-endian +Audio file endian for fast rendering or aufile driver ("\-E help" for list) .TP .B \-f, \-\-load\-config Load command configuration file (shell commands) .TP -.B \-G, \-\-audio\-groups -Defines the number of LADSPA audio nodes +.B \-F, \-\-fast\-render=[file] +Render MIDI file to raw audio data and store in [file] .TP .B \-g, \-\-gain Set the master gain [0 < gain < 10, default = 0.2] .TP +.B \-G, \-\-audio\-groups +Defines the number of LADSPA audio nodes +.TP .B \-h, \-\-help Print out this help summary .TP @@ -94,14 +98,14 @@ Attempt to connect the jack outputs to the physical ports .B \-K, \-\-midi\-channels=[num] The number of midi channels [default = 16] .TP -.B \-L, \-\-audio\-channels=[num] -The number of stereo audio channels [default = 1] -.TP .B \-l, \-\-disable\-lash Don't connect to LASH server .TP +.B \-L, \-\-audio\-channels=[num] +The number of stereo audio channels [default = 1] +.TP .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 .B \-n, \-\-no\-midi\-in 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 Define a setting, \-o name=value ("\-o help" to dump current values) .TP +.B \-O, \-\-audio\-file\-format +Audio file format for fast rendering or aufile driver ("\-O help" for list) +.TP .B \-p, \-\-portname=[label] Set MIDI port name (alsa_seq, coremidi drivers) .TP -.B \-R, \-\-reverb -Turn the reverb on or off [0|1|yes|no, default = on] -.TP .B \-r, \-\-sample\-rate Set the sample rate .TP +.B \-R, \-\-reverb +Turn the reverb on or off [0|1|yes|no, default = on] +.TP .B \-s, \-\-server Start FluidSynth as a server process .TP -.B \-V, \-\-version -Show version of program +.B \-T, \-\-audio\-file\-type +Audio file type for fast rendering or aufile driver ("\T help" for list) .TP .B \-v, \-\-verbose Print out verbose messages about midi events .TP +.B \-V, \-\-version +Show version of program +.TP .B \-z, \-\-audio\-bufsize=[size] 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 .TP .B GENERAL .TP .B help -Prints out a summary of the main commands -.TP -.B help help -Prints out list of other help topics (type "help ") +Prints out list of help topics (type "help ") .TP .B quit Quit the synthesizer diff --git a/fluidsynth/src/fluid_sys.c b/fluidsynth/src/fluid_sys.c index bc3bd6f6..2a4ada71 100644 --- a/fluidsynth/src/fluid_sys.c +++ b/fluidsynth/src/fluid_sys.c @@ -30,6 +30,27 @@ * Should work, so long as no SOCKET or file descriptor ends up with this bit set. - JG */ #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 { fluid_socket_t socket; @@ -366,13 +387,7 @@ fluid_utime (void) } -#if defined(WIN32) - -/*=============================================================*/ -/* */ -/* Win32 */ -/* */ -/*=============================================================*/ +#if defined(WIN32) /* Windoze specific stuff */ void 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); } -/*************************************************************** - * - * Timer - * - */ -struct _fluid_timer_t -{ - 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 */ -/* */ -/*=============================================================*/ +#elif defined(__OS2__) /* OS/2 specific stuff */ void 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); } -/*************************************************************** - * - * 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 */ -/* */ -/*=============================================================*/ +#else /* POSIX stuff.. Nice POSIX.. Good POSIX. */ void 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 /*************************************************************** @@ -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 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); + /* 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) { 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 diff --git a/fluidsynth/src/fluid_sys.h b/fluidsynth/src/fluid_sys.h index c167e310..798dcba6 100644 --- a/fluidsynth/src/fluid_sys.h +++ b/fluidsynth/src/fluid_sys.h @@ -129,34 +129,54 @@ int fluid_timer_stop(fluid_timer_t* timer); /* Regular mutex */ typedef GStaticMutex fluid_mutex_t; #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_lock(_m) g_static_mutex_lock(&(_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 */ 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_lock(_m) g_static_rec_mutex_lock(&(_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 */ typedef GMutex fluid_cond_mutex_t; -#define new_fluid_cond_mutex g_mutex_new -#define delete_fluid_cond_mutex g_mutex_free -#define fluid_cond_mutex_lock g_mutex_lock -#define fluid_cond_mutex_unlock g_mutex_unlock +#define delete_fluid_cond_mutex(m) g_mutex_free(m) +#define fluid_cond_mutex_lock(m) g_mutex_lock(m) +#define fluid_cond_mutex_unlock(m) g_mutex_unlock(m) + +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 */ typedef GCond fluid_cond_t; -#define new_fluid_cond g_cond_new -#define delete_fluid_cond g_cond_free -#define fluid_cond_signal g_cond_signal -#define fluid_cond_broadcast g_cond_broadcast -#define fluid_cond_wait g_cond_wait +#define delete_fluid_cond(cond) g_cond_free(cond) +#define fluid_cond_signal(cond) g_cond_signal(cond) +#define fluid_cond_broadcast(cond) g_cond_broadcast(cond) +#define fluid_cond_wait(cond, mutex) g_cond_wait(cond, mutex) + +static FLUID_INLINE fluid_cond_t * +new_fluid_cond (void) +{ + if (!g_thread_supported ()) g_thread_init (NULL); + return g_cond_new (); +} /* Atomic operations */ @@ -198,11 +218,14 @@ fluid_atomic_float_get(volatile float *fptr) /* Thread private data */ 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_set(_priv, _data, _notify) g_static_private_set(&(_priv), _data, _notify) #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 */ diff --git a/fluidsynth/src/fluidsynth.c b/fluidsynth/src/fluidsynth.c index 3adf91b0..3b45fbc6 100644 --- a/fluidsynth/src/fluidsynth.c +++ b/fluidsynth/src/fluidsynth.c @@ -567,8 +567,6 @@ int main(int argc, char** argv) exit (0); } - g_thread_init (NULL); - #ifdef WIN32 SetPriorityClass(GetCurrentProcess(), REALTIME_PRIORITY_CLASS); #endif