mirror of
https://github.com/ZDoom/fluidsynth.git
synced 2024-11-28 06:52:57 +00:00
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:
parent
bcec3dc993
commit
ab517db31f
4 changed files with 387 additions and 433 deletions
|
@ -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 <topic>")
|
||||
Prints out list of help topics (type "help <topic>")
|
||||
.TP
|
||||
.B quit
|
||||
Quit the synthesizer
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 */
|
||||
|
||||
|
|
|
@ -567,8 +567,6 @@ int main(int argc, char** argv)
|
|||
exit (0);
|
||||
}
|
||||
|
||||
g_thread_init (NULL);
|
||||
|
||||
#ifdef WIN32
|
||||
SetPriorityClass(GetCurrentProcess(), REALTIME_PRIORITY_CLASS);
|
||||
#endif
|
||||
|
|
Loading…
Reference in a new issue