1 /* FluidSynth - A Software Synthesizer
3 * Copyright (C) 2003 Peter Hanappe and others.
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public License
7 * as published by the Free Software Foundation; either version 2.1 of
8 * the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free
17 * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21 #include "fluid_sys.h"
25 #include <readline/readline.h>
26 #include <readline/history.h>
30 #include "fluid_rtkit.h"
33 #if HAVE_PTHREAD_H && !defined(WIN32)
34 // Do not include pthread on windows. It includes winsock.h, which collides with ws2tcpip.h from fluid_sys.h
35 // It isn't need on Windows anyway.
39 /* WIN32 HACK - Flag used to differentiate between a file descriptor and a socket.
40 * Should work, so long as no SOCKET or file descriptor ends up with this bit set. - JG */
42 #define FLUID_SOCKET_FLAG 0x40000000
44 #define FLUID_SOCKET_FLAG 0x00000000
45 #define SOCKET_ERROR -1
46 #define INVALID_SOCKET -1
49 /* SCHED_FIFO priority for high priority timer threads */
50 #define FLUID_SYS_TIMER_HIGH_PRIO_LEVEL 10
55 fluid_thread_func_t func;
58 } fluid_thread_info_t;
63 fluid_timer_callback_t callback;
65 fluid_thread_t *thread;
70 struct _fluid_server_socket_t
72 fluid_socket_t socket;
73 fluid_thread_t *thread;
75 fluid_server_func_t func;
80 static int fluid_istream_gets(fluid_istream_t in, char *buf, int len);
82 static fluid_log_function_t fluid_log_function[LAST_LOG_LEVEL] =
84 fluid_default_log_function,
85 fluid_default_log_function,
86 fluid_default_log_function,
87 fluid_default_log_function,
88 fluid_default_log_function
90 static void *fluid_log_user_data[LAST_LOG_LEVEL] = { NULL };
92 static const char fluid_libname[] = "fluidsynth";
95 * Installs a new log function for a specified log level.
96 * @param level Log level to install handler for.
97 * @param fun Callback function handler to call for logged messages
98 * @param data User supplied data pointer to pass to log function
99 * @return The previously installed function.
102 fluid_set_log_function(int level, fluid_log_function_t fun, void *data)
104 fluid_log_function_t old = NULL;
106 if((level >= 0) && (level < LAST_LOG_LEVEL))
108 old = fluid_log_function[level];
109 fluid_log_function[level] = fun;
110 fluid_log_user_data[level] = data;
117 * Default log function which prints to the stderr.
118 * @param level Log level
119 * @param message Log message
120 * @param data User supplied data (not used)
123 fluid_default_log_function(int level, const char *message, void *data)
136 FLUID_FPRINTF(out, "%s: panic: %s\n", fluid_libname, message);
140 FLUID_FPRINTF(out, "%s: error: %s\n", fluid_libname, message);
144 FLUID_FPRINTF(out, "%s: warning: %s\n", fluid_libname, message);
148 FLUID_FPRINTF(out, "%s: %s\n", fluid_libname, message);
153 FLUID_FPRINTF(out, "%s: debug: %s\n", fluid_libname, message);
158 FLUID_FPRINTF(out, "%s: %s\n", fluid_libname, message);
166 * Print a message to the log.
167 * @param level Log level (#fluid_log_level).
168 * @param fmt Printf style format string for log message
169 * @param ... Arguments for printf 'fmt' message string
170 * @return Always returns #FLUID_FAILED
173 fluid_log(int level, const char *fmt, ...)
175 if((level >= 0) && (level < LAST_LOG_LEVEL))
177 fluid_log_function_t fun = fluid_log_function[level];
185 FLUID_VSNPRINTF(errbuf, sizeof(errbuf), fmt, args);
188 (*fun)(level, errbuf, fluid_log_user_data[level]);
196 * An improved strtok, still trashes the input string, but is portable and
197 * thread safe. Also skips token chars at beginning of token string and never
198 * returns an empty token (will return NULL if source ends in token chars though).
199 * NOTE: NOT part of public API
201 * @param str Pointer to a string pointer of source to tokenize. Pointer gets
202 * updated on each invocation to point to beginning of next token. Note that
203 * token char get's overwritten with a 0 byte. String pointer is set to NULL
204 * when final token is returned.
205 * @param delim String of delimiter chars.
206 * @return Pointer to the next token or NULL if no more tokens.
208 char *fluid_strtok(char **str, const char *delim)
214 if(str == NULL || delim == NULL || !*delim)
216 FLUID_LOG(FLUID_ERR, "Null pointer");
224 return NULL; /* str points to a NULL pointer? (tokenize already ended) */
227 /* skip delimiter chars at beginning of token */
232 if(!c) /* end of source string? */
238 for(d = delim; *d; d++) /* is source char a token char? */
240 if(c == *d) /* token char match? */
242 s++; /* advance to next source char */
247 while(*d); /* while token char match */
249 token = s; /* start of token found */
251 /* search for next token char or end of source string */
252 for(s = s + 1; *s; s++)
256 for(d = delim; *d; d++) /* is source char a token char? */
258 if(c == *d) /* token char match? */
260 *s = '\0'; /* overwrite token char with zero byte to terminate token */
261 *str = s + 1; /* update str to point to beginning of next token */
267 /* we get here only if source string ended */
273 * Suspend the execution of the current thread for the specified amount of time.
274 * @param milliseconds to wait.
276 void fluid_msleep(unsigned int msecs)
278 g_usleep(msecs * 1000);
282 * Get time in milliseconds to be used in relative timing operations.
283 * @return Unix time in milliseconds.
285 unsigned int fluid_curtime(void)
287 static glong initial_seconds = 0;
290 if(initial_seconds == 0)
292 g_get_current_time(&timeval);
293 initial_seconds = timeval.tv_sec;
296 g_get_current_time(&timeval);
298 return (unsigned int)((timeval.tv_sec - initial_seconds) * 1000.0 + timeval.tv_usec / 1000.0);
302 * Get time in microseconds to be used in relative timing operations.
303 * @return time in microseconds.
304 * Note: When used for profiling we need high precision clock given
305 * by g_get_monotonic_time()if available (glib version >= 2.53.3).
306 * If glib version is too old and in the case of Windows the function
307 * uses high precision performance counter instead of g_getmonotic_time().
314 #if GLIB_MAJOR_VERSION == 2 && GLIB_MINOR_VERSION >= 28
315 /* use high precision monotonic clock if available (g_monotonic_time().
316 * For Winfdows, if this clock is actually implemented as low prec. clock
317 * (i.e. in case glib is too old), high precision performance counter are
319 * see: https://bugzilla.gnome.org/show_bug.cgi?id=783340
321 #if defined(WITH_PROFILING) && defined(WIN32) &&\
323 (GLIB_MINOR_VERSION <= 53 && (GLIB_MINOR_VERSION < 53 || GLIB_MICRO_VERSION < 3))
324 /* use high precision performance counter. */
325 static LARGE_INTEGER freq_cache = {0, 0}; /* Performance Frequency */
326 LARGE_INTEGER perf_cpt;
328 if(! freq_cache.QuadPart)
330 QueryPerformanceFrequency(&freq_cache); /* Frequency value */
333 QueryPerformanceCounter(&perf_cpt); /* Counter value */
334 utime = perf_cpt.QuadPart * 1000000.0 / freq_cache.QuadPart; /* time in micros */
336 utime = g_get_monotonic_time();
339 /* fallback to less precise clock */
341 g_get_current_time(&timeval);
342 utime = (timeval.tv_sec * 1000000.0 + timeval.tv_usec);
350 #if defined(WIN32) /* Windoze specific stuff */
353 fluid_thread_self_set_prio(int prio_level)
357 SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_HIGHEST);
362 #elif defined(__OS2__) /* OS/2 specific stuff */
365 fluid_thread_self_set_prio(int prio_level)
369 DosSetPriority(PRTYS_THREAD, PRTYC_REGULAR, PRTYD_MAXIMUM, 0);
373 #else /* POSIX stuff.. Nice POSIX.. Good POSIX. */
376 fluid_thread_self_set_prio(int prio_level)
378 struct sched_param priority;
383 memset(&priority, 0, sizeof(priority));
384 priority.sched_priority = prio_level;
386 if(pthread_setschedparam(pthread_self(), SCHED_FIFO, &priority) == 0)
392 /* Try to gain high priority via rtkit */
394 if(fluid_rtkit_make_realtime(0, prio_level) == 0)
400 FLUID_LOG(FLUID_WARN, "Failed to set thread to high priority");
406 /***************************************************************
408 * Floating point exceptions
410 * The floating point exception functions were taken from Ircam's
411 * jMax source code. http://www.ircam.fr/jmax
413 * FIXME: check in config for i386 machine
415 * Currently not used. I leave the code here in case we want to pick
416 * this up again some time later.
419 /* Exception flags */
420 #define _FPU_STATUS_IE 0x001 /* Invalid Operation */
421 #define _FPU_STATUS_DE 0x002 /* Denormalized Operand */
422 #define _FPU_STATUS_ZE 0x004 /* Zero Divide */
423 #define _FPU_STATUS_OE 0x008 /* Overflow */
424 #define _FPU_STATUS_UE 0x010 /* Underflow */
425 #define _FPU_STATUS_PE 0x020 /* Precision */
426 #define _FPU_STATUS_SF 0x040 /* Stack Fault */
427 #define _FPU_STATUS_ES 0x080 /* Error Summary Status */
429 /* Macros for accessing the FPU status word. */
431 /* get the FPU status */
432 #define _FPU_GET_SW(sw) __asm__ ("fnstsw %0" : "=m" (*&sw))
434 /* clear the FPU status */
435 #define _FPU_CLR_SW() __asm__ ("fnclex" : : )
438 * Checks, if the floating point unit has produced an exception, print a message
439 * if so and clear the exception.
441 unsigned int fluid_check_fpe_i386(char *explanation)
448 s &= _FPU_STATUS_IE | _FPU_STATUS_DE | _FPU_STATUS_ZE | _FPU_STATUS_OE | _FPU_STATUS_UE;
452 FLUID_LOG(FLUID_WARN, "FPE exception (before or in %s): %s%s%s%s%s", explanation,
453 (s & _FPU_STATUS_IE) ? "Invalid operation " : "",
454 (s & _FPU_STATUS_DE) ? "Denormal number " : "",
455 (s & _FPU_STATUS_ZE) ? "Zero divide " : "",
456 (s & _FPU_STATUS_OE) ? "Overflow " : "",
457 (s & _FPU_STATUS_UE) ? "Underflow " : "");
464 * Clear floating point exception.
466 void fluid_clear_fpe_i386(void)
471 #endif // ifdef FPE_CHECK
474 #endif // #else (its POSIX)
477 /***************************************************************
479 * Profiling (Linux, i586 only)
484 /* Profiling interface beetween profiling command shell and audio rendering API
485 (FluidProfile_0004.pdf- 3.2.2).
486 Macros are in defined in fluid_sys.h.
490 -----------------------------------------------------------------------------
491 Shell task side | Profiling interface | Audio task side
492 -----------------------------------------------------------------------------
493 profiling | Internal | | | Audio
494 command <---> |<-- profling -->| Data |<--macros -->| <--> rendering
495 shell | API | | | API
498 /* default parameters for shell command "prof_start" in fluid_sys.c */
499 unsigned short fluid_profile_notes = 0; /* number of generated notes */
500 /* preset bank:0 prog:16 (organ) */
501 unsigned char fluid_profile_bank = FLUID_PROFILE_DEFAULT_BANK;
502 unsigned char fluid_profile_prog = FLUID_PROFILE_DEFAULT_PROG;
505 unsigned char fluid_profile_print = FLUID_PROFILE_DEFAULT_PRINT;
506 /* number of measures */
507 unsigned short fluid_profile_n_prof = FLUID_PROFILE_DEFAULT_N_PROF;
508 /* measure duration in ms */
509 unsigned short fluid_profile_dur = FLUID_PROFILE_DEFAULT_DURATION;
510 /* lock between multiple-shell */
511 fluid_atomic_int_t fluid_profile_lock = 0;
514 /*----------------------------------------------
516 -----------------------------------------------*/
517 unsigned char fluid_profile_status = PROFILE_STOP; /* command and status */
518 unsigned int fluid_profile_end_ticks = 0; /* ending position (in ticks) */
519 fluid_profile_data_t fluid_profile_data[] = /* Data duration */
521 {"synth_write_* ------------>", 1e10, 0.0, 0.0, 0, 0, 0},
522 {"synth_one_block ---------->", 1e10, 0.0, 0.0, 0, 0, 0},
523 {"synth_one_block:clear ---->", 1e10, 0.0, 0.0, 0, 0, 0},
524 {"synth_one_block:one voice->", 1e10, 0.0, 0.0, 0, 0, 0},
525 {"synth_one_block:all voices>", 1e10, 0.0, 0.0, 0, 0, 0},
526 {"synth_one_block:reverb --->", 1e10, 0.0, 0.0, 0, 0, 0},
527 {"synth_one_block:chorus --->", 1e10, 0.0, 0.0, 0, 0, 0},
528 {"voice:note --------------->", 1e10, 0.0, 0.0, 0, 0, 0},
529 {"voice:release ------------>", 1e10, 0.0, 0.0, 0, 0, 0}
533 /*----------------------------------------------
534 Internal profiling API
535 -----------------------------------------------*/
536 /* logging profiling data (used on synthesizer instance deletion) */
537 void fluid_profiling_print(void)
541 printf("fluid_profiling_print\n");
543 FLUID_LOG(FLUID_INFO, "Estimated times: min/avg/max (micro seconds)");
545 for(i = 0; i < FLUID_PROFILE_NBR; i++)
547 if(fluid_profile_data[i].count > 0)
549 FLUID_LOG(FLUID_INFO, "%s: %.3f/%.3f/%.3f",
550 fluid_profile_data[i].description,
551 fluid_profile_data[i].min,
552 fluid_profile_data[i].total / fluid_profile_data[i].count,
553 fluid_profile_data[i].max);
557 FLUID_LOG(FLUID_DBG, "%s: no profiling available",
558 fluid_profile_data[i].description);
563 /* Macro that returns cpu load in percent (%)
564 * @dur: duration (micro second).
565 * @sample_rate: sample_rate used in audio driver (Hz).
566 * @n_amples: number of samples collected during 'dur' duration.
568 #define fluid_profile_load(dur,sample_rate,n_samples) \
569 (dur * sample_rate / n_samples / 10000.0)
572 /* prints cpu loads only
574 * @param sample_rate the sample rate of audio output.
575 * @param out output stream device.
577 * ------------------------------------------------------------------------------
578 * Cpu loads(%) (sr: 44100 Hz, sp: 22.68 microsecond) and maximum voices
579 * ------------------------------------------------------------------------------
580 * nVoices| total(%)|voices(%)| reverb(%)|chorus(%)| voice(%)|estimated maxVoices
581 * -------|---------|---------|----------|---------|---------|-------------------
582 * 250| 41.544| 41.544| 0.000| 0.000| 0.163| 612
584 static void fluid_profiling_print_load(double sample_rate, fluid_ostream_t out)
586 unsigned int n_voices; /* voices number */
587 static const char max_voices_not_available[] = " not available";
588 const char *pmax_voices;
589 char max_voices_available[20];
591 /* First computes data to be printed */
592 double total, voices, reverb, chorus, all_voices, voice;
594 n_voices = fluid_profile_data[FLUID_PROF_ONE_BLOCK_VOICES].count ?
595 fluid_profile_data[FLUID_PROF_ONE_BLOCK_VOICES].n_voices /
596 fluid_profile_data[FLUID_PROF_ONE_BLOCK_VOICES].count : 0;
599 total = fluid_profile_data[FLUID_PROF_WRITE].count ?
600 fluid_profile_load(fluid_profile_data[FLUID_PROF_WRITE].total, sample_rate,
601 fluid_profile_data[FLUID_PROF_WRITE].n_samples) : 0;
603 /* reverb load (%) */
604 reverb = fluid_profile_data[FLUID_PROF_ONE_BLOCK_REVERB].count ?
605 fluid_profile_load(fluid_profile_data[FLUID_PROF_ONE_BLOCK_REVERB].total,
607 fluid_profile_data[FLUID_PROF_ONE_BLOCK_REVERB].n_samples) : 0;
609 /* chorus load (%) */
610 chorus = fluid_profile_data[FLUID_PROF_ONE_BLOCK_CHORUS].count ?
611 fluid_profile_load(fluid_profile_data[FLUID_PROF_ONE_BLOCK_CHORUS].total,
613 fluid_profile_data[FLUID_PROF_ONE_BLOCK_CHORUS].n_samples) : 0;
615 /* total voices load: total - reverb - chorus (%) */
616 voices = total - reverb - chorus;
618 /* One voice load (%): all_voices / n_voices. */
619 all_voices = fluid_profile_data[FLUID_PROF_ONE_BLOCK_VOICES].count ?
620 fluid_profile_load(fluid_profile_data[FLUID_PROF_ONE_BLOCK_VOICES].total,
622 fluid_profile_data[FLUID_PROF_ONE_BLOCK_VOICES].n_samples) : 0;
624 voice = n_voices ? all_voices / n_voices : 0;
626 /* estimated maximum voices number */
629 FLUID_SNPRINTF(max_voices_available, sizeof(max_voices_available),
630 "%17d", (unsigned int)((100.0 - reverb - chorus) / voice));
631 pmax_voices = max_voices_available;
635 pmax_voices = max_voices_not_available;
638 /* Now prints data */
639 fluid_ostream_printf(out,
640 " ------------------------------------------------------------------------------\n");
641 fluid_ostream_printf(out,
642 " Cpu loads(%%) (sr:%6.0f Hz, sp:%6.2f microsecond) and maximum voices\n",
643 sample_rate, 1000000.0 / sample_rate);
644 fluid_ostream_printf(out,
645 " ------------------------------------------------------------------------------\n");
646 fluid_ostream_printf(out,
647 " nVoices| total(%%)|voices(%%)| reverb(%%)|chorus(%%)| voice(%%)|estimated maxVoices\n");
648 fluid_ostream_printf(out,
649 " -------|---------|---------|----------|---------|---------|-------------------\n");
650 fluid_ostream_printf(out,
651 "%8d|%9.3f|%9.3f|%10.3f|%9.3f|%9.3f|%s\n", n_voices, total, voices,
652 reverb, chorus, voice, pmax_voices);
656 * prints profiling data (used by profile shell command: prof_start).
657 * The function is an internal profiling API between the "profile" command
658 * prof_start and audio rendering API (see FluidProfile_0004.pdf - 3.2.2).
660 * @param sample_rate the sample rate of audio output.
661 * @param out output stream device.
663 * When print mode is 1, the function prints all the informations (see below).
664 * When print mode is 0, the fonction prints only the cpu loads.
666 * ------------------------------------------------------------------------------
667 * Duration(microsecond) and cpu loads(%) (sr: 44100 Hz, sp: 22.68 microsecond)
668 * ------------------------------------------------------------------------------
669 * Code under profiling |Voices| Duration (microsecond) | Load(%)
670 * | nbr| min| avg| max|
671 * ---------------------------|------|--------------------------------|----------
672 * synth_write_* ------------>| 250| 3.91| 2188.82| 3275.00| 41.544
673 * synth_one_block ---------->| 250| 1150.70| 2273.56| 3241.47| 41.100
674 * synth_one_block:clear ---->| 250| 3.07| 4.62| 61.18| 0.084
675 * synth_one_block:one voice->| 1| 4.19| 9.02| 1044.27| 0.163
676 * synth_one_block:all voices>| 250| 1138.41| 2259.11| 3217.73| 40.839
677 * synth_one_block:reverb --->| no profiling available
678 * synth_one_block:chorus --->| no profiling available
679 * voice:note --------------->| no profiling available
680 * voice:release ------------>| no profiling available
681 * ------------------------------------------------------------------------------
682 * Cpu loads(%) (sr: 44100 Hz, sp: 22.68 microsecond) and maximum voices
683 * ------------------------------------------------------------------------------
684 * nVoices| total(%)|voices(%)| reverb(%)|chorus(%)| voice(%)|estimated maxVoices
685 * -------|---------|---------|----------|---------|---------|-------------------
686 * 250| 41.544| 41.544| 0.000| 0.000| 0.163| 612
688 void fluid_profiling_print_data(double sample_rate, fluid_ostream_t out)
692 if(fluid_profile_print)
694 /* print all details: Duration(microsecond) and cpu loads(%) */
695 fluid_ostream_printf(out,
696 " ------------------------------------------------------------------------------\n");
697 fluid_ostream_printf(out,
698 " Duration(microsecond) and cpu loads(%%) (sr:%6.0f Hz, sp:%6.2f microsecond)\n",
699 sample_rate, 1000000.0 / sample_rate);
700 fluid_ostream_printf(out,
701 " ------------------------------------------------------------------------------\n");
702 fluid_ostream_printf(out,
703 " Code under profiling |Voices| Duration (microsecond) | Load(%%)\n");
704 fluid_ostream_printf(out,
705 " | nbr| min| avg| max|\n");
706 fluid_ostream_printf(out,
707 " ---------------------------|------|--------------------------------|----------\n");
709 for(i = 0; i < FLUID_PROFILE_NBR; i++)
711 unsigned int count = fluid_profile_data[i].count;
715 /* data are available */
717 if(FLUID_PROF_WRITE <= i && i <= FLUID_PROF_ONE_BLOCK_CHORUS)
719 double load = fluid_profile_load(fluid_profile_data[i].total, sample_rate,
720 fluid_profile_data[i].n_samples);
721 fluid_ostream_printf(out, " %s|%6d|%10.2f|%10.2f|%10.2f|%8.3f\n",
722 fluid_profile_data[i].description, /* code under profiling */
723 fluid_profile_data[i].n_voices / count, /* voices number */
724 fluid_profile_data[i].min, /* minimum duration */
725 fluid_profile_data[i].total / count, /* average duration */
726 fluid_profile_data[i].max, /* maximum duration */
727 load); /* cpu load */
731 /* note and release duration */
732 fluid_ostream_printf(out, " %s|%6d|%10.0f|%10.0f|%10.0f|\n",
733 fluid_profile_data[i].description, /* code under profiling */
734 fluid_profile_data[i].n_voices / count,
735 fluid_profile_data[i].min, /* minimum duration */
736 fluid_profile_data[i].total / count, /* average duration */
737 fluid_profile_data[i].max); /* maximum duration */
742 /* data aren't available */
743 fluid_ostream_printf(out,
744 " %s| no profiling available\n", fluid_profile_data[i].description);
749 /* prints cpu loads only */
750 fluid_profiling_print_load(sample_rate, out);/* prints cpu loads */
754 Returns true if the user cancels the current profiling measurement.
755 Actually this is implemented using the <ENTER> key. To add this functionality:
756 1) Adds #define FLUID_PROFILE_CANCEL in fluid_sys.h.
757 2) Adds the necessary code inside fluid_profile_is_cancel().
759 When FLUID_PROFILE_CANCEL is not defined, the function return FALSE.
761 int fluid_profile_is_cancel_req(void)
763 #ifdef FLUID_PROFILE_CANCEL
765 #if defined(WIN32) /* Windows specific stuff */
766 /* Profile cancellation is supported for Windows */
767 /* returns TRUE if key <ENTER> is depressed */
768 return(GetAsyncKeyState(VK_RETURN) & 0x1);
770 #elif defined(__OS2__) /* OS/2 specific stuff */
771 /* Profile cancellation isn't yet supported for OS2 */
772 /* For OS2, replaces the following line with the function that returns
773 true when the keyboard key <ENTER> is depressed */
774 return FALSE; /* default value */
776 #else /* POSIX stuff */
777 /* Profile cancellation is supported for Linux */
778 /* returns true is <ENTER> is depressed */
780 /* Here select() is used to poll the standard input to see if an input
781 is ready. As the standard input is usually buffered, the user
782 needs to depress <ENTER> to set the input to a "ready" state.
785 fd_set fds; /* just one fds need to be polled */
786 tv.tv_sec = 0; /* Setting both values to 0, means a 0 timeout */
788 FD_ZERO(&fds); /* reset fds */
789 FD_SET(STDIN_FILENO, &fds); /* sets fds to poll standard input only */
790 select(STDIN_FILENO + 1, &fds, NULL, NULL, &tv); /* polling */
791 return (FD_ISSET(0, &fds)); /* returns true if standard input is ready */
793 #endif /* OS stuff */
795 #else /* FLUID_PROFILE_CANCEL not defined */
796 return FALSE; /* default value */
797 #endif /* FLUID_PROFILE_CANCEL */
801 * Returns status used in shell command "prof_start".
802 * The function is an internal profiling API between the "profile" command
803 * prof_start and audio rendering API (see FluidProfile_0004.pdf - 3.2.2).
806 * - PROFILE_READY profiling data are ready.
807 * - PROFILE_RUNNING, profiling data are still under acquisition.
808 * - PROFILE_CANCELED, acquisition has been cancelled by the user.
809 * - PROFILE_STOP, no acquisition in progress.
811 * When status is PROFILE_RUNNING, the caller can do passive waiting, or other
812 * work before recalling the function later.
814 int fluid_profile_get_status(void)
816 /* Checks if user has requested to cancel the current measurement */
817 /* Cancellation must have precedence over other status */
818 if(fluid_profile_is_cancel_req())
820 fluid_profile_start_stop(0, 0); /* stops the measurement */
821 return PROFILE_CANCELED;
824 switch(fluid_profile_status)
827 return PROFILE_READY; /* profiling data are ready */
830 return PROFILE_RUNNING;/* profiling data are under acquisition */
838 * Starts or stops profiling measurement.
839 * The function is an internal profiling API between the "profile" command
840 * prof_start and audio rendering API (see FluidProfile_0004.pdf - 3.2.2).
842 * @param end_tick end position of the measure (in ticks).
843 * - If end_tick is greater then 0, the function starts a measure if a measure
844 * isn't running. If a measure is already running, the function does nothing
846 * - If end_tick is 0, the function stops a measure.
848 * - If clear_data is 0, the function clears fluid_profile_data before starting
849 * a measure, otherwise, the data from the started measure will be accumulated
850 * within fluid_profile_data.
852 void fluid_profile_start_stop(unsigned int end_ticks, short clear_data)
854 if(end_ticks) /* This is a "start" request */
856 /* Checks if a measure is already running */
857 if(fluid_profile_status != PROFILE_START)
860 fluid_profile_end_ticks = end_ticks;
862 /* Clears profile data */
864 for(i = 0; i < FLUID_PROFILE_NBR; i++)
866 fluid_profile_data[i].min = 1e10;/* min sets to max value */
867 fluid_profile_data[i].max = 0; /* maximum sets to min value */
868 fluid_profile_data[i].total = 0; /* total duration microsecond */
869 fluid_profile_data[i].count = 0; /* data count */
870 fluid_profile_data[i].n_voices = 0; /* voices number */
871 fluid_profile_data[i].n_samples = 0;/* audio samples number */
874 fluid_profile_status = PROFILE_START; /* starts profiling */
877 /* else do nothing when profiling is already started */
879 else /* This is a "stop" request */
881 /* forces the current running profile (if any) to stop */
882 fluid_profile_status = PROFILE_STOP; /* stops profiling */
886 #endif /* WITH_PROFILING */
888 /***************************************************************
894 #if OLD_GLIB_THREAD_API
896 /* Rather than inline this one, we just declare it as a function, to prevent
897 * GCC warning about inline failure. */
901 if(!g_thread_supported())
912 fluid_thread_high_prio(gpointer data)
914 fluid_thread_info_t *info = data;
916 fluid_thread_self_set_prio(info->prio_level);
918 info->func(info->data);
925 * Create a new thread.
926 * @param func Function to execute in new thread context
927 * @param data User defined data to pass to func
928 * @param prio_level Priority level. If greater than 0 then high priority scheduling will
929 * be used, with the given priority level (used by pthreads only). 0 uses normal scheduling.
930 * @param detach If TRUE, 'join' does not work and the thread destroys itself when finished.
931 * @return New thread pointer or NULL on error
934 new_fluid_thread(const char *name, fluid_thread_func_t func, void *data, int prio_level, int detach)
937 fluid_thread_info_t *info = NULL;
940 g_return_val_if_fail(func != NULL, NULL);
942 #if OLD_GLIB_THREAD_API
944 /* Make sure g_thread_init has been called.
945 * FIXME - Probably not a good idea in a shared library,
946 * but what can we do *and* remain backwards compatible? */
947 if(!g_thread_supported())
956 info = FLUID_NEW(fluid_thread_info_t);
960 FLUID_LOG(FLUID_ERR, "Out of memory");
966 info->prio_level = prio_level;
967 #if NEW_GLIB_THREAD_API
968 thread = g_thread_try_new(name, fluid_thread_high_prio, info, &err);
970 thread = g_thread_create(fluid_thread_high_prio, info, detach == FALSE, &err);
976 #if NEW_GLIB_THREAD_API
977 thread = g_thread_try_new(name, (GThreadFunc)func, data, &err);
979 thread = g_thread_create((GThreadFunc)func, data, detach == FALSE, &err);
985 FLUID_LOG(FLUID_ERR, "Failed to create the thread: %s",
986 fluid_gerror_message(err));
992 #if NEW_GLIB_THREAD_API
996 g_thread_unref(thread); // Release thread reference, if caller wants to detach
1005 * Frees data associated with a thread (does not actually stop thread).
1006 * @param thread Thread to free
1009 delete_fluid_thread(fluid_thread_t *thread)
1011 /* Threads free themselves when they quit, nothing to do */
1015 * Join a thread (wait for it to terminate).
1016 * @param thread Thread to join
1020 fluid_thread_join(fluid_thread_t *thread)
1022 g_thread_join(thread);
1028 static fluid_thread_return_t
1029 fluid_timer_run(void *data)
1031 fluid_timer_t *timer;
1037 timer = (fluid_timer_t *)data;
1039 /* keep track of the start time for absolute positioning */
1040 start = fluid_curtime();
1044 cont = (*timer->callback)(timer->data, fluid_curtime() - start);
1053 /* to avoid incremental time errors, calculate the delay between
1054 two callbacks bringing in the "absolute" time (count *
1056 delay = (count * timer->msec) - (fluid_curtime() - start);
1060 fluid_msleep(delay);
1064 FLUID_LOG(FLUID_DBG, "Timer thread finished");
1066 if(timer->auto_destroy)
1071 return FLUID_THREAD_RETURN_VALUE;
1075 new_fluid_timer(int msec, fluid_timer_callback_t callback, void *data,
1076 int new_thread, int auto_destroy, int high_priority)
1078 fluid_timer_t *timer;
1080 timer = FLUID_NEW(fluid_timer_t);
1084 FLUID_LOG(FLUID_ERR, "Out of memory");
1089 timer->callback = callback;
1091 timer->cont = TRUE ;
1092 timer->thread = NULL;
1093 timer->auto_destroy = auto_destroy;
1097 timer->thread = new_fluid_thread("timer", fluid_timer_run, timer, high_priority
1098 ? FLUID_SYS_TIMER_HIGH_PRIO_LEVEL : 0, FALSE);
1108 fluid_timer_run(timer); /* Run directly, instead of as a separate thread */
1112 /* do NOT return freed memory */
1121 delete_fluid_timer(fluid_timer_t *timer)
1124 fluid_return_if_fail(timer != NULL);
1126 auto_destroy = timer->auto_destroy;
1129 fluid_timer_join(timer);
1131 /* Shouldn't access timer now if auto_destroy enabled, since it has been destroyed */
1140 fluid_timer_join(fluid_timer_t *timer)
1146 auto_destroy = timer->auto_destroy;
1147 fluid_thread_join(timer->thread);
1151 timer->thread = NULL;
1159 /***************************************************************
1166 * Get standard in stream handle.
1167 * @return Standard in stream.
1170 fluid_get_stdin(void)
1172 return STDIN_FILENO;
1176 * Get standard output stream handle.
1177 * @return Standard out stream.
1180 fluid_get_stdout(void)
1182 return STDOUT_FILENO;
1186 * Read a line from an input stream.
1187 * @return 0 if end-of-stream, -1 if error, non zero otherwise
1190 fluid_istream_readline(fluid_istream_t in, fluid_ostream_t out, char *prompt,
1195 if(in == fluid_get_stdin())
1199 line = readline(prompt);
1206 FLUID_SNPRINTF(buf, len, "%s", line);
1220 fluid_ostream_printf(out, "%s", prompt);
1221 return fluid_istream_gets(in, buf, len);
1226 * Reads a line from an input stream (socket).
1227 * @param in The input socket
1228 * @param buf Buffer to store data to
1229 * @param len Maximum length to store to buf
1230 * @return 1 if a line was read, 0 on end of stream, -1 on error
1233 fluid_istream_gets(fluid_istream_t in, char *buf, int len)
1243 n = read(in, &c, 1);
1252 /* Handle read differently depending on if its a socket or file descriptor */
1253 if(!(in & FLUID_SOCKET_FLAG))
1255 // usually read() is supposed to return '\n' as last valid character of the user input
1256 // when compiled with compatibility for WinXP however, read() may return 0 (EOF) rather than '\n'
1257 // this would cause the shell to exit early
1258 n = read(in, &c, 1);
1267 #ifdef NETWORK_SUPPORT
1268 n = recv(in & ~FLUID_SOCKET_FLAG, &c, 1, 0);
1269 if(n == SOCKET_ERROR)
1281 // return 1 if read from stdin, else 0, to fix early exit of shell
1282 return (in == STDIN_FILENO);
1291 /* Store all characters excluding CR */
1302 * Send a printf style string with arguments to an output stream (socket).
1303 * @param out Output stream
1304 * @param format printf style format string
1305 * @param ... Arguments for the printf format string
1306 * @return Number of bytes written or -1 on error
1309 fluid_ostream_printf(fluid_ostream_t out, const char *format, ...)
1315 va_start(args, format);
1316 len = FLUID_VSNPRINTF(buf, 4095, format, args);
1326 printf("fluid_ostream_printf: buffer overflow");
1333 return write(out, buf, FLUID_STRLEN(buf));
1338 /* Handle write differently depending on if its a socket or file descriptor */
1339 if(!(out & FLUID_SOCKET_FLAG))
1341 return write(out, buf, (unsigned int)FLUID_STRLEN(buf));
1344 #ifdef NETWORK_SUPPORT
1346 retval = send(out & ~FLUID_SOCKET_FLAG, buf, (int)FLUID_STRLEN(buf), 0);
1347 return retval != SOCKET_ERROR ? retval : -1;
1355 #ifdef NETWORK_SUPPORT
1357 int fluid_server_socket_join(fluid_server_socket_t *server_socket)
1359 return fluid_thread_join(server_socket->thread);
1362 static int fluid_socket_init(void)
1366 int res = WSAStartup(MAKEWORD(2, 2), &wsaData);
1370 FLUID_LOG(FLUID_ERR, "Server socket creation error: WSAStartup failed: %d", res);
1371 return FLUID_FAILED;
1379 static void fluid_socket_cleanup(void)
1386 static int fluid_socket_get_error(void)
1389 return (int)WSAGetLastError();
1395 fluid_istream_t fluid_socket_get_istream(fluid_socket_t sock)
1397 return sock | FLUID_SOCKET_FLAG;
1400 fluid_ostream_t fluid_socket_get_ostream(fluid_socket_t sock)
1402 return sock | FLUID_SOCKET_FLAG;
1405 void fluid_socket_close(fluid_socket_t sock)
1407 if(sock != INVALID_SOCKET)
1418 static fluid_thread_return_t fluid_server_socket_run(void *data)
1420 fluid_server_socket_t *server_socket = (fluid_server_socket_t *)data;
1421 fluid_socket_t client_socket;
1423 struct sockaddr_in6 addr;
1425 struct sockaddr_in addr;
1428 #ifdef HAVE_INETNTOP
1430 char straddr[INET6_ADDRSTRLEN];
1432 char straddr[INET_ADDRSTRLEN];
1433 #endif /* IPV6_SUPPORT */
1434 #endif /* HAVE_INETNTOP */
1436 socklen_t addrlen = sizeof(addr);
1438 FLUID_MEMSET((char *)&addr, 0, sizeof(addr));
1440 FLUID_LOG(FLUID_DBG, "Server listening for connections");
1442 while(server_socket->cont)
1444 client_socket = accept(server_socket->socket, (struct sockaddr *)&addr, &addrlen);
1446 FLUID_LOG(FLUID_DBG, "New client connection");
1448 if(client_socket == INVALID_SOCKET)
1450 if(server_socket->cont)
1452 FLUID_LOG(FLUID_ERR, "Failed to accept connection: %ld", fluid_socket_get_error());
1455 server_socket->cont = 0;
1456 return FLUID_THREAD_RETURN_VALUE;
1460 #ifdef HAVE_INETNTOP
1463 inet_ntop(AF_INET6, &addr.sin6_addr, straddr, sizeof(straddr));
1465 inet_ntop(AF_INET, &addr.sin_addr, straddr, sizeof(straddr));
1468 r = server_socket->func(server_socket->data, client_socket,
1471 r = server_socket->func(server_socket->data, client_socket,
1472 inet_ntoa(addr.sin_addr));
1477 fluid_socket_close(client_socket);
1482 FLUID_LOG(FLUID_DBG, "Server closing");
1484 return FLUID_THREAD_RETURN_VALUE;
1487 fluid_server_socket_t *
1488 new_fluid_server_socket(int port, fluid_server_func_t func, void *data)
1490 fluid_server_socket_t *server_socket;
1492 struct sockaddr_in6 addr;
1494 struct sockaddr_in addr;
1497 fluid_socket_t sock;
1499 fluid_return_val_if_fail(func != NULL, NULL);
1501 if(fluid_socket_init() != FLUID_OK)
1507 sock = socket(AF_INET6, SOCK_STREAM, 0);
1509 if(sock == INVALID_SOCKET)
1511 FLUID_LOG(FLUID_ERR, "Failed to create server socket: %ld", fluid_socket_get_error());
1512 fluid_socket_cleanup();
1516 FLUID_MEMSET(&addr, 0, sizeof(addr));
1517 addr.sin6_family = AF_INET6;
1518 addr.sin6_port = htons((uint16_t)port);
1519 addr.sin6_addr = in6addr_any;
1522 sock = socket(AF_INET, SOCK_STREAM, 0);
1524 if(sock == INVALID_SOCKET)
1526 FLUID_LOG(FLUID_ERR, "Failed to create server socket: %ld", fluid_socket_get_error());
1527 fluid_socket_cleanup();
1531 FLUID_MEMSET(&addr, 0, sizeof(addr));
1532 addr.sin_family = AF_INET;
1533 addr.sin_port = htons((uint16_t)port);
1534 addr.sin_addr.s_addr = htonl(INADDR_ANY);
1537 if(bind(sock, (const struct sockaddr *) &addr, sizeof(addr)) == SOCKET_ERROR)
1539 FLUID_LOG(FLUID_ERR, "Failed to bind server socket: %ld", fluid_socket_get_error());
1540 fluid_socket_close(sock);
1541 fluid_socket_cleanup();
1545 if(listen(sock, SOMAXCONN) == SOCKET_ERROR)
1547 FLUID_LOG(FLUID_ERR, "Failed to listen on server socket: %ld", fluid_socket_get_error());
1548 fluid_socket_close(sock);
1549 fluid_socket_cleanup();
1553 server_socket = FLUID_NEW(fluid_server_socket_t);
1555 if(server_socket == NULL)
1557 FLUID_LOG(FLUID_ERR, "Out of memory");
1558 fluid_socket_close(sock);
1559 fluid_socket_cleanup();
1563 server_socket->socket = sock;
1564 server_socket->func = func;
1565 server_socket->data = data;
1566 server_socket->cont = 1;
1568 server_socket->thread = new_fluid_thread("server", fluid_server_socket_run, server_socket,
1571 if(server_socket->thread == NULL)
1573 FLUID_FREE(server_socket);
1574 fluid_socket_close(sock);
1575 fluid_socket_cleanup();
1579 return server_socket;
1582 void delete_fluid_server_socket(fluid_server_socket_t *server_socket)
1584 fluid_return_if_fail(server_socket != NULL);
1586 server_socket->cont = 0;
1588 if(server_socket->socket != INVALID_SOCKET)
1590 fluid_socket_close(server_socket->socket);
1593 if(server_socket->thread)
1595 fluid_thread_join(server_socket->thread);
1596 delete_fluid_thread(server_socket->thread);
1599 FLUID_FREE(server_socket);
1601 // Should be called the same number of times as fluid_socket_init()
1602 fluid_socket_cleanup();
1605 #endif // NETWORK_SUPPORT
1607 FILE* fluid_file_open(const char* path, const char** errMsg)
1609 static const char ErrExist[] = "File does not exist.";
1610 static const char ErrRegular[] = "File is not regular, refusing to open it.";
1611 static const char ErrNull[] = "File does not exists or insufficient permissions to open it.";
1613 FILE* handle = NULL;
1615 if(!g_file_test(path, G_FILE_TEST_EXISTS))
1622 else if(!g_file_test(path, G_FILE_TEST_IS_REGULAR))
1626 *errMsg = ErrRegular;
1629 else if((handle = FLUID_FOPEN(path, "rb")) == NULL)