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 /* WIN32 HACK - Flag used to differentiate between a file descriptor and a socket.
34 * Should work, so long as no SOCKET or file descriptor ends up with this bit set. - JG */
36 #define FLUID_SOCKET_FLAG 0x40000000
38 #define FLUID_SOCKET_FLAG 0x00000000
39 #define SOCKET_ERROR -1
40 #define INVALID_SOCKET -1
43 /* SCHED_FIFO priority for high priority timer threads */
44 #define FLUID_SYS_TIMER_HIGH_PRIO_LEVEL 10
49 fluid_thread_func_t func;
52 } fluid_thread_info_t;
57 fluid_timer_callback_t callback;
59 fluid_thread_t *thread;
64 struct _fluid_server_socket_t
66 fluid_socket_t socket;
67 fluid_thread_t *thread;
69 fluid_server_func_t func;
74 static int fluid_istream_gets(fluid_istream_t in, char *buf, int len);
77 static char fluid_errbuf[512]; /* buffer for error message */
79 static fluid_log_function_t fluid_log_function[LAST_LOG_LEVEL] =
81 fluid_default_log_function,
82 fluid_default_log_function,
83 fluid_default_log_function,
84 fluid_default_log_function,
85 fluid_default_log_function
87 static void *fluid_log_user_data[LAST_LOG_LEVEL] = { NULL };
89 static const char fluid_libname[] = "fluidsynth";
92 * Installs a new log function for a specified log level.
93 * @param level Log level to install handler for.
94 * @param fun Callback function handler to call for logged messages
95 * @param data User supplied data pointer to pass to log function
96 * @return The previously installed function.
99 fluid_set_log_function(int level, fluid_log_function_t fun, void *data)
101 fluid_log_function_t old = NULL;
103 if((level >= 0) && (level < LAST_LOG_LEVEL))
105 old = fluid_log_function[level];
106 fluid_log_function[level] = fun;
107 fluid_log_user_data[level] = data;
114 * Default log function which prints to the stderr.
115 * @param level Log level
116 * @param message Log message
117 * @param data User supplied data (not used)
120 fluid_default_log_function(int level, const char *message, void *data)
133 FLUID_FPRINTF(out, "%s: panic: %s\n", fluid_libname, message);
137 FLUID_FPRINTF(out, "%s: error: %s\n", fluid_libname, message);
141 FLUID_FPRINTF(out, "%s: warning: %s\n", fluid_libname, message);
145 FLUID_FPRINTF(out, "%s: %s\n", fluid_libname, message);
150 FLUID_FPRINTF(out, "%s: debug: %s\n", fluid_libname, message);
155 FLUID_FPRINTF(out, "%s: %s\n", fluid_libname, message);
163 * Print a message to the log.
164 * @param level Log level (#fluid_log_level).
165 * @param fmt Printf style format string for log message
166 * @param ... Arguments for printf 'fmt' message string
167 * @return Always returns #FLUID_FAILED
170 fluid_log(int level, const char *fmt, ...)
172 fluid_log_function_t fun = NULL;
176 FLUID_VSNPRINTF(fluid_errbuf, sizeof(fluid_errbuf), fmt, args);
179 if((level >= 0) && (level < LAST_LOG_LEVEL))
181 fun = fluid_log_function[level];
185 (*fun)(level, fluid_errbuf, fluid_log_user_data[level]);
193 * An improved strtok, still trashes the input string, but is portable and
194 * thread safe. Also skips token chars at beginning of token string and never
195 * returns an empty token (will return NULL if source ends in token chars though).
196 * NOTE: NOT part of public API
198 * @param str Pointer to a string pointer of source to tokenize. Pointer gets
199 * updated on each invocation to point to beginning of next token. Note that
200 * token char get's overwritten with a 0 byte. String pointer is set to NULL
201 * when final token is returned.
202 * @param delim String of delimiter chars.
203 * @return Pointer to the next token or NULL if no more tokens.
205 char *fluid_strtok(char **str, const char *delim)
211 if(str == NULL || delim == NULL || !*delim)
213 FLUID_LOG(FLUID_ERR, "Null pointer");
221 return NULL; /* str points to a NULL pointer? (tokenize already ended) */
224 /* skip delimiter chars at beginning of token */
229 if(!c) /* end of source string? */
235 for(d = delim; *d; d++) /* is source char a token char? */
237 if(c == *d) /* token char match? */
239 s++; /* advance to next source char */
244 while(*d); /* while token char match */
246 token = s; /* start of token found */
248 /* search for next token char or end of source string */
249 for(s = s + 1; *s; s++)
253 for(d = delim; *d; d++) /* is source char a token char? */
255 if(c == *d) /* token char match? */
257 *s = '\0'; /* overwrite token char with zero byte to terminate token */
258 *str = s + 1; /* update str to point to beginning of next token */
264 /* we get here only if source string ended */
279 * Check if a file is a MIDI file.
280 * @param filename Path to the file to check
281 * @return TRUE if it could be a MIDI file, FALSE otherwise
283 * The current implementation only checks for the "MThd" header in the file.
284 * It is useful only to distinguish between SoundFont and MIDI files.
287 fluid_is_midifile(const char *filename)
289 FILE *fp = fopen(filename, "rb");
297 if(fread((void *) id, 1, 4, fp) != 4)
305 return FLUID_STRNCMP(id, "MThd", 4) == 0;
309 * Check if a file is a SoundFont file.
310 * @param filename Path to the file to check
311 * @return TRUE if it could be a SoundFont, FALSE otherwise
313 * @note The current implementation only checks for the "RIFF" and "sfbk" headers in
314 * the file. It is useful to distinguish between SoundFont and other (e.g. MIDI) files.
317 fluid_is_soundfont(const char *filename)
319 FILE *fp = fopen(filename, "rb");
320 char riff_id[4], sfbk_id[4];
327 if((fread((void *) riff_id, 1, sizeof(riff_id), fp) != sizeof(riff_id)) ||
328 (fseek(fp, 4, SEEK_CUR) != 0) ||
329 (fread((void *) sfbk_id, 1, sizeof(sfbk_id), fp) != sizeof(sfbk_id)))
335 return (FLUID_STRNCMP(riff_id, "RIFF", sizeof(riff_id)) == 0) &&
336 (FLUID_STRNCMP(sfbk_id, "sfbk", sizeof(sfbk_id)) == 0);
344 * Suspend the execution of the current thread for the specified amount of time.
345 * @param milliseconds to wait.
347 void fluid_msleep(unsigned int msecs)
349 g_usleep(msecs * 1000);
353 * Get time in milliseconds to be used in relative timing operations.
354 * @return Unix time in milliseconds.
356 unsigned int fluid_curtime(void)
358 static glong initial_seconds = 0;
361 if(initial_seconds == 0)
363 g_get_current_time(&timeval);
364 initial_seconds = timeval.tv_sec;
367 g_get_current_time(&timeval);
369 return (unsigned int)((timeval.tv_sec - initial_seconds) * 1000.0 + timeval.tv_usec / 1000.0);
373 * Get time in microseconds to be used in relative timing operations.
374 * @return time in microseconds.
375 * Note: When used for profiling we need high precision clock given
376 * by g_get_monotonic_time()if available (glib version >= 2.53.3).
377 * If glib version is too old and in the case of Windows the function
378 * uses high precision performance counter instead of g_getmonotic_time().
385 #if GLIB_MAJOR_VERSION == 2 && GLIB_MINOR_VERSION >= 28
386 /* use high precision monotonic clock if available (g_monotonic_time().
387 * For Winfdows, if this clock is actually implemented as low prec. clock
388 * (i.e. in case glib is too old), high precision performance counter are
390 * see: https://bugzilla.gnome.org/show_bug.cgi?id=783340
392 #if defined(WITH_PROFILING) && defined(WIN32) &&\
394 (GLIB_MINOR_VERSION <= 53 && (GLIB_MINOR_VERSION < 53 || GLIB_MICRO_VERSION < 3))
395 /* use high precision performance counter. */
396 static LARGE_INTEGER freq_cache = {0, 0}; /* Performance Frequency */
397 LARGE_INTEGER perf_cpt;
399 if(! freq_cache.QuadPart)
401 QueryPerformanceFrequency(&freq_cache); /* Frequency value */
404 QueryPerformanceCounter(&perf_cpt); /* Counter value */
405 utime = perf_cpt.QuadPart * 1000000.0 / freq_cache.QuadPart; /* time in micros */
407 utime = g_get_monotonic_time();
410 /* fallback to less precise clock */
412 g_get_current_time(&timeval);
413 utime = (timeval.tv_sec * 1000000.0 + timeval.tv_usec);
421 #if defined(WIN32) /* Windoze specific stuff */
424 fluid_thread_self_set_prio(int prio_level)
428 SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_HIGHEST);
433 #elif defined(__OS2__) /* OS/2 specific stuff */
436 fluid_thread_self_set_prio(int prio_level)
440 DosSetPriority(PRTYS_THREAD, PRTYC_REGULAR, PRTYD_MAXIMUM, 0);
444 #else /* POSIX stuff.. Nice POSIX.. Good POSIX. */
447 fluid_thread_self_set_prio(int prio_level)
449 struct sched_param priority;
454 memset(&priority, 0, sizeof(priority));
455 priority.sched_priority = prio_level;
457 if(pthread_setschedparam(pthread_self(), SCHED_FIFO, &priority) == 0)
463 /* Try to gain high priority via rtkit */
465 if(fluid_rtkit_make_realtime(0, prio_level) == 0)
471 FLUID_LOG(FLUID_WARN, "Failed to set thread to high priority");
477 /***************************************************************
479 * Floating point exceptions
481 * The floating point exception functions were taken from Ircam's
482 * jMax source code. http://www.ircam.fr/jmax
484 * FIXME: check in config for i386 machine
486 * Currently not used. I leave the code here in case we want to pick
487 * this up again some time later.
490 /* Exception flags */
491 #define _FPU_STATUS_IE 0x001 /* Invalid Operation */
492 #define _FPU_STATUS_DE 0x002 /* Denormalized Operand */
493 #define _FPU_STATUS_ZE 0x004 /* Zero Divide */
494 #define _FPU_STATUS_OE 0x008 /* Overflow */
495 #define _FPU_STATUS_UE 0x010 /* Underflow */
496 #define _FPU_STATUS_PE 0x020 /* Precision */
497 #define _FPU_STATUS_SF 0x040 /* Stack Fault */
498 #define _FPU_STATUS_ES 0x080 /* Error Summary Status */
500 /* Macros for accessing the FPU status word. */
502 /* get the FPU status */
503 #define _FPU_GET_SW(sw) __asm__ ("fnstsw %0" : "=m" (*&sw))
505 /* clear the FPU status */
506 #define _FPU_CLR_SW() __asm__ ("fnclex" : : )
509 * Checks, if the floating point unit has produced an exception, print a message
510 * if so and clear the exception.
512 unsigned int fluid_check_fpe_i386(char *explanation)
519 s &= _FPU_STATUS_IE | _FPU_STATUS_DE | _FPU_STATUS_ZE | _FPU_STATUS_OE | _FPU_STATUS_UE;
523 FLUID_LOG(FLUID_WARN, "FPE exception (before or in %s): %s%s%s%s%s", explanation,
524 (s & _FPU_STATUS_IE) ? "Invalid operation " : "",
525 (s & _FPU_STATUS_DE) ? "Denormal number " : "",
526 (s & _FPU_STATUS_ZE) ? "Zero divide " : "",
527 (s & _FPU_STATUS_OE) ? "Overflow " : "",
528 (s & _FPU_STATUS_UE) ? "Underflow " : "");
535 * Clear floating point exception.
537 void fluid_clear_fpe_i386(void)
542 #endif // ifdef FPE_CHECK
545 #endif // #else (its POSIX)
548 /***************************************************************
550 * Profiling (Linux, i586 only)
555 /* Profiling interface beetween profiling command shell and audio rendering API
556 (FluidProfile_0004.pdf- 3.2.2).
557 Macros are in defined in fluid_sys.h.
561 -----------------------------------------------------------------------------
562 Shell task side | Profiling interface | Audio task side
563 -----------------------------------------------------------------------------
564 profiling | Internal | | | Audio
565 command <---> |<-- profling -->| Data |<--macros -->| <--> rendering
566 shell | API | | | API
569 /* default parameters for shell command "prof_start" in fluid_sys.c */
570 unsigned short fluid_profile_notes = 0; /* number of generated notes */
571 /* preset bank:0 prog:16 (organ) */
572 unsigned char fluid_profile_bank = FLUID_PROFILE_DEFAULT_BANK;
573 unsigned char fluid_profile_prog = FLUID_PROFILE_DEFAULT_PROG;
576 unsigned char fluid_profile_print = FLUID_PROFILE_DEFAULT_PRINT;
577 /* number of measures */
578 unsigned short fluid_profile_n_prof = FLUID_PROFILE_DEFAULT_N_PROF;
579 /* measure duration in ms */
580 unsigned short fluid_profile_dur = FLUID_PROFILE_DEFAULT_DURATION;
581 /* lock between multiple-shell */
582 fluid_atomic_int_t fluid_profile_lock = 0;
585 /*----------------------------------------------
587 -----------------------------------------------*/
588 unsigned char fluid_profile_status = PROFILE_STOP; /* command and status */
589 unsigned int fluid_profile_end_ticks = 0; /* ending position (in ticks) */
590 fluid_profile_data_t fluid_profile_data[] = /* Data duration */
592 {"synth_write_* ------------>", 1e10, 0.0, 0.0, 0, 0, 0},
593 {"synth_one_block ---------->", 1e10, 0.0, 0.0, 0, 0, 0},
594 {"synth_one_block:clear ---->", 1e10, 0.0, 0.0, 0, 0, 0},
595 {"synth_one_block:one voice->", 1e10, 0.0, 0.0, 0, 0, 0},
596 {"synth_one_block:all voices>", 1e10, 0.0, 0.0, 0, 0, 0},
597 {"synth_one_block:reverb --->", 1e10, 0.0, 0.0, 0, 0, 0},
598 {"synth_one_block:chorus --->", 1e10, 0.0, 0.0, 0, 0, 0},
599 {"voice:note --------------->", 1e10, 0.0, 0.0, 0, 0, 0},
600 {"voice:release ------------>", 1e10, 0.0, 0.0, 0, 0, 0}
604 /*----------------------------------------------
605 Internal profiling API
606 -----------------------------------------------*/
607 /* logging profiling data (used on synthesizer instance deletion) */
608 void fluid_profiling_print(void)
612 printf("fluid_profiling_print\n");
614 FLUID_LOG(FLUID_INFO, "Estimated times: min/avg/max (micro seconds)");
616 for(i = 0; i < FLUID_PROFILE_NBR; i++)
618 if(fluid_profile_data[i].count > 0)
620 FLUID_LOG(FLUID_INFO, "%s: %.3f/%.3f/%.3f",
621 fluid_profile_data[i].description,
622 fluid_profile_data[i].min,
623 fluid_profile_data[i].total / fluid_profile_data[i].count,
624 fluid_profile_data[i].max);
628 FLUID_LOG(FLUID_DBG, "%s: no profiling available",
629 fluid_profile_data[i].description);
634 /* Macro that returns cpu load in percent (%)
635 * @dur: duration (micro second).
636 * @sample_rate: sample_rate used in audio driver (Hz).
637 * @n_amples: number of samples collected during 'dur' duration.
639 #define fluid_profile_load(dur,sample_rate,n_samples) \
640 (dur * sample_rate / n_samples / 10000.0)
643 /* prints cpu loads only
645 * @param sample_rate the sample rate of audio output.
646 * @param out output stream device.
648 * ------------------------------------------------------------------------------
649 * Cpu loads(%) (sr: 44100 Hz, sp: 22.68 microsecond) and maximum voices
650 * ------------------------------------------------------------------------------
651 * nVoices| total(%)|voices(%)| reverb(%)|chorus(%)| voice(%)|estimated maxVoices
652 * -------|---------|---------|----------|---------|---------|-------------------
653 * 250| 41.544| 41.544| 0.000| 0.000| 0.163| 612
655 static void fluid_profiling_print_load(double sample_rate, fluid_ostream_t out)
657 unsigned int n_voices; /* voices number */
658 static const char max_voices_not_available[] = " not available";
659 const char *pmax_voices;
660 char max_voices_available[20];
662 /* First computes data to be printed */
663 double total, voices, reverb, chorus, all_voices, voice;
665 n_voices = fluid_profile_data[FLUID_PROF_ONE_BLOCK_VOICES].count ?
666 fluid_profile_data[FLUID_PROF_ONE_BLOCK_VOICES].n_voices /
667 fluid_profile_data[FLUID_PROF_ONE_BLOCK_VOICES].count : 0;
670 total = fluid_profile_data[FLUID_PROF_WRITE].count ?
671 fluid_profile_load(fluid_profile_data[FLUID_PROF_WRITE].total, sample_rate,
672 fluid_profile_data[FLUID_PROF_WRITE].n_samples) : 0;
674 /* reverb load (%) */
675 reverb = fluid_profile_data[FLUID_PROF_ONE_BLOCK_REVERB].count ?
676 fluid_profile_load(fluid_profile_data[FLUID_PROF_ONE_BLOCK_REVERB].total,
678 fluid_profile_data[FLUID_PROF_ONE_BLOCK_REVERB].n_samples) : 0;
680 /* chorus load (%) */
681 chorus = fluid_profile_data[FLUID_PROF_ONE_BLOCK_CHORUS].count ?
682 fluid_profile_load(fluid_profile_data[FLUID_PROF_ONE_BLOCK_CHORUS].total,
684 fluid_profile_data[FLUID_PROF_ONE_BLOCK_CHORUS].n_samples) : 0;
686 /* total voices load: total - reverb - chorus (%) */
687 voices = total - reverb - chorus;
689 /* One voice load (%): all_voices / n_voices. */
690 all_voices = fluid_profile_data[FLUID_PROF_ONE_BLOCK_VOICES].count ?
691 fluid_profile_load(fluid_profile_data[FLUID_PROF_ONE_BLOCK_VOICES].total,
693 fluid_profile_data[FLUID_PROF_ONE_BLOCK_VOICES].n_samples) : 0;
695 voice = n_voices ? all_voices / n_voices : 0;
697 /* estimated maximum voices number */
700 FLUID_SNPRINTF(max_voices_available, sizeof(max_voices_available),
701 "%17d", (unsigned int)((100.0 - reverb - chorus) / voice));
702 pmax_voices = max_voices_available;
706 pmax_voices = max_voices_not_available;
709 /* Now prints data */
710 fluid_ostream_printf(out,
711 " ------------------------------------------------------------------------------\n");
712 fluid_ostream_printf(out,
713 " Cpu loads(%%) (sr:%6.0f Hz, sp:%6.2f microsecond) and maximum voices\n",
714 sample_rate, 1000000.0 / sample_rate);
715 fluid_ostream_printf(out,
716 " ------------------------------------------------------------------------------\n");
717 fluid_ostream_printf(out,
718 " nVoices| total(%%)|voices(%%)| reverb(%%)|chorus(%%)| voice(%%)|estimated maxVoices\n");
719 fluid_ostream_printf(out,
720 " -------|---------|---------|----------|---------|---------|-------------------\n");
721 fluid_ostream_printf(out,
722 "%8d|%9.3f|%9.3f|%10.3f|%9.3f|%9.3f|%s\n", n_voices, total, voices,
723 reverb, chorus, voice, pmax_voices);
727 * prints profiling data (used by profile shell command: prof_start).
728 * The function is an internal profiling API between the "profile" command
729 * prof_start and audio rendering API (see FluidProfile_0004.pdf - 3.2.2).
731 * @param sample_rate the sample rate of audio output.
732 * @param out output stream device.
734 * When print mode is 1, the function prints all the informations (see below).
735 * When print mode is 0, the fonction prints only the cpu loads.
737 * ------------------------------------------------------------------------------
738 * Duration(microsecond) and cpu loads(%) (sr: 44100 Hz, sp: 22.68 microsecond)
739 * ------------------------------------------------------------------------------
740 * Code under profiling |Voices| Duration (microsecond) | Load(%)
741 * | nbr| min| avg| max|
742 * ---------------------------|------|--------------------------------|----------
743 * synth_write_* ------------>| 250| 3.91| 2188.82| 3275.00| 41.544
744 * synth_one_block ---------->| 250| 1150.70| 2273.56| 3241.47| 41.100
745 * synth_one_block:clear ---->| 250| 3.07| 4.62| 61.18| 0.084
746 * synth_one_block:one voice->| 1| 4.19| 9.02| 1044.27| 0.163
747 * synth_one_block:all voices>| 250| 1138.41| 2259.11| 3217.73| 40.839
748 * synth_one_block:reverb --->| no profiling available
749 * synth_one_block:chorus --->| no profiling available
750 * voice:note --------------->| no profiling available
751 * voice:release ------------>| no profiling available
752 * ------------------------------------------------------------------------------
753 * Cpu loads(%) (sr: 44100 Hz, sp: 22.68 microsecond) and maximum voices
754 * ------------------------------------------------------------------------------
755 * nVoices| total(%)|voices(%)| reverb(%)|chorus(%)| voice(%)|estimated maxVoices
756 * -------|---------|---------|----------|---------|---------|-------------------
757 * 250| 41.544| 41.544| 0.000| 0.000| 0.163| 612
759 void fluid_profiling_print_data(double sample_rate, fluid_ostream_t out)
763 if(fluid_profile_print)
765 /* print all details: Duration(microsecond) and cpu loads(%) */
766 fluid_ostream_printf(out,
767 " ------------------------------------------------------------------------------\n");
768 fluid_ostream_printf(out,
769 " Duration(microsecond) and cpu loads(%%) (sr:%6.0f Hz, sp:%6.2f microsecond)\n",
770 sample_rate, 1000000.0 / sample_rate);
771 fluid_ostream_printf(out,
772 " ------------------------------------------------------------------------------\n");
773 fluid_ostream_printf(out,
774 " Code under profiling |Voices| Duration (microsecond) | Load(%%)\n");
775 fluid_ostream_printf(out,
776 " | nbr| min| avg| max|\n");
777 fluid_ostream_printf(out,
778 " ---------------------------|------|--------------------------------|----------\n");
780 for(i = 0; i < FLUID_PROFILE_NBR; i++)
782 unsigned int count = fluid_profile_data[i].count;
786 /* data are available */
788 if(FLUID_PROF_WRITE <= i && i <= FLUID_PROF_ONE_BLOCK_CHORUS)
790 double load = fluid_profile_load(fluid_profile_data[i].total, sample_rate,
791 fluid_profile_data[i].n_samples);
792 fluid_ostream_printf(out, " %s|%6d|%10.2f|%10.2f|%10.2f|%8.3f\n",
793 fluid_profile_data[i].description, /* code under profiling */
794 fluid_profile_data[i].n_voices / count, /* voices number */
795 fluid_profile_data[i].min, /* minimum duration */
796 fluid_profile_data[i].total / count, /* average duration */
797 fluid_profile_data[i].max, /* maximum duration */
798 load); /* cpu load */
802 /* note and release duration */
803 fluid_ostream_printf(out, " %s|%6d|%10.0f|%10.0f|%10.0f|\n",
804 fluid_profile_data[i].description, /* code under profiling */
805 fluid_profile_data[i].n_voices / count,
806 fluid_profile_data[i].min, /* minimum duration */
807 fluid_profile_data[i].total / count, /* average duration */
808 fluid_profile_data[i].max); /* maximum duration */
813 /* data aren't available */
814 fluid_ostream_printf(out,
815 " %s| no profiling available\n", fluid_profile_data[i].description);
820 /* prints cpu loads only */
821 fluid_profiling_print_load(sample_rate, out);/* prints cpu loads */
825 Returns true if the user cancels the current profiling measurement.
826 Actually this is implemented using the <ENTER> key. To add this functionality:
827 1) Adds #define FLUID_PROFILE_CANCEL in fluid_sys.h.
828 2) Adds the necessary code inside fluid_profile_is_cancel().
830 When FLUID_PROFILE_CANCEL is not defined, the function return FALSE.
832 int fluid_profile_is_cancel_req(void)
834 #ifdef FLUID_PROFILE_CANCEL
836 #if defined(WIN32) /* Windows specific stuff */
837 /* Profile cancellation is supported for Windows */
838 /* returns TRUE if key <ENTER> is depressed */
839 return(GetAsyncKeyState(VK_RETURN) & 0x1);
841 #elif defined(__OS2__) /* OS/2 specific stuff */
842 /* Profile cancellation isn't yet supported for OS2 */
843 /* For OS2, replaces the following line with the function that returns
844 true when the keyboard key <ENTER> is depressed */
845 return FALSE; /* default value */
847 #else /* POSIX stuff */
848 /* Profile cancellation is supported for Linux */
849 /* returns true is <ENTER> is depressed */
851 /* Here select() is used to poll the standard input to see if an input
852 is ready. As the standard input is usually buffered, the user
853 needs to depress <ENTER> to set the input to a "ready" state.
856 fd_set fds; /* just one fds need to be polled */
857 tv.tv_sec = 0; /* Setting both values to 0, means a 0 timeout */
859 FD_ZERO(&fds); /* reset fds */
860 FD_SET(STDIN_FILENO, &fds); /* sets fds to poll standard input only */
861 select(STDIN_FILENO + 1, &fds, NULL, NULL, &tv); /* polling */
862 return (FD_ISSET(0, &fds)); /* returns true if standard input is ready */
864 #endif /* OS stuff */
866 #else /* FLUID_PROFILE_CANCEL not defined */
867 return FALSE; /* default value */
868 #endif /* FLUID_PROFILE_CANCEL */
872 * Returns status used in shell command "prof_start".
873 * The function is an internal profiling API between the "profile" command
874 * prof_start and audio rendering API (see FluidProfile_0004.pdf - 3.2.2).
877 * - PROFILE_READY profiling data are ready.
878 * - PROFILE_RUNNING, profiling data are still under acquisition.
879 * - PROFILE_CANCELED, acquisition has been cancelled by the user.
880 * - PROFILE_STOP, no acquisition in progress.
882 * When status is PROFILE_RUNNING, the caller can do passive waiting, or other
883 * work before recalling the function later.
885 int fluid_profile_get_status(void)
887 /* Checks if user has requested to cancel the current measurement */
888 /* Cancellation must have precedence over other status */
889 if(fluid_profile_is_cancel_req())
891 fluid_profile_start_stop(0, 0); /* stops the measurement */
892 return PROFILE_CANCELED;
895 switch(fluid_profile_status)
898 return PROFILE_READY; /* profiling data are ready */
901 return PROFILE_RUNNING;/* profiling data are under acquisition */
909 * Starts or stops profiling measurement.
910 * The function is an internal profiling API between the "profile" command
911 * prof_start and audio rendering API (see FluidProfile_0004.pdf - 3.2.2).
913 * @param end_tick end position of the measure (in ticks).
914 * - If end_tick is greater then 0, the function starts a measure if a measure
915 * isn't running. If a measure is already running, the function does nothing
917 * - If end_tick is 0, the function stops a measure.
919 * - If clear_data is 0, the function clears fluid_profile_data before starting
920 * a measure, otherwise, the data from the started measure will be accumulated
921 * within fluid_profile_data.
923 void fluid_profile_start_stop(unsigned int end_ticks, short clear_data)
925 if(end_ticks) /* This is a "start" request */
927 /* Checks if a measure is already running */
928 if(fluid_profile_status != PROFILE_START)
931 fluid_profile_end_ticks = end_ticks;
933 /* Clears profile data */
935 for(i = 0; i < FLUID_PROFILE_NBR; i++)
937 fluid_profile_data[i].min = 1e10;/* min sets to max value */
938 fluid_profile_data[i].max = 0; /* maximum sets to min value */
939 fluid_profile_data[i].total = 0; /* total duration microsecond */
940 fluid_profile_data[i].count = 0; /* data count */
941 fluid_profile_data[i].n_voices = 0; /* voices number */
942 fluid_profile_data[i].n_samples = 0;/* audio samples number */
945 fluid_profile_status = PROFILE_START; /* starts profiling */
948 /* else do nothing when profiling is already started */
950 else /* This is a "stop" request */
952 /* forces the current running profile (if any) to stop */
953 fluid_profile_status = PROFILE_STOP; /* stops profiling */
957 #endif /* WITH_PROFILING */
959 /***************************************************************
965 #if OLD_GLIB_THREAD_API
967 /* Rather than inline this one, we just declare it as a function, to prevent
968 * GCC warning about inline failure. */
972 if(!g_thread_supported())
983 fluid_thread_high_prio(gpointer data)
985 fluid_thread_info_t *info = data;
987 fluid_thread_self_set_prio(info->prio_level);
989 info->func(info->data);
996 * Create a new thread.
997 * @param func Function to execute in new thread context
998 * @param data User defined data to pass to func
999 * @param prio_level Priority level. If greater than 0 then high priority scheduling will
1000 * be used, with the given priority level (used by pthreads only). 0 uses normal scheduling.
1001 * @param detach If TRUE, 'join' does not work and the thread destroys itself when finished.
1002 * @return New thread pointer or NULL on error
1005 new_fluid_thread(const char *name, fluid_thread_func_t func, void *data, int prio_level, int detach)
1008 fluid_thread_info_t *info;
1011 g_return_val_if_fail(func != NULL, NULL);
1013 #if OLD_GLIB_THREAD_API
1015 /* Make sure g_thread_init has been called.
1016 * FIXME - Probably not a good idea in a shared library,
1017 * but what can we do *and* remain backwards compatible? */
1018 if(!g_thread_supported())
1020 g_thread_init(NULL);
1027 info = FLUID_NEW(fluid_thread_info_t);
1031 FLUID_LOG(FLUID_ERR, "Out of memory");
1037 info->prio_level = prio_level;
1038 #if NEW_GLIB_THREAD_API
1039 thread = g_thread_try_new(name, fluid_thread_high_prio, info, &err);
1041 thread = g_thread_create(fluid_thread_high_prio, info, detach == FALSE, &err);
1045 #if NEW_GLIB_THREAD_API
1048 thread = g_thread_try_new(name, (GThreadFunc)func, data, &err);
1054 thread = g_thread_create((GThreadFunc)func, data, detach == FALSE, &err);
1061 FLUID_LOG(FLUID_ERR, "Failed to create the thread: %s",
1062 fluid_gerror_message(err));
1063 g_clear_error(&err);
1067 #if NEW_GLIB_THREAD_API
1071 g_thread_unref(thread); // Release thread reference, if caller wants to detach
1080 * Frees data associated with a thread (does not actually stop thread).
1081 * @param thread Thread to free
1084 delete_fluid_thread(fluid_thread_t *thread)
1086 /* Threads free themselves when they quit, nothing to do */
1090 * Join a thread (wait for it to terminate).
1091 * @param thread Thread to join
1095 fluid_thread_join(fluid_thread_t *thread)
1097 g_thread_join(thread);
1103 static fluid_thread_return_t
1104 fluid_timer_run(void *data)
1106 fluid_timer_t *timer;
1112 timer = (fluid_timer_t *)data;
1114 /* keep track of the start time for absolute positioning */
1115 start = fluid_curtime();
1119 cont = (*timer->callback)(timer->data, fluid_curtime() - start);
1128 /* to avoid incremental time errors, calculate the delay between
1129 two callbacks bringing in the "absolute" time (count *
1131 delay = (count * timer->msec) - (fluid_curtime() - start);
1135 fluid_msleep(delay);
1139 FLUID_LOG(FLUID_DBG, "Timer thread finished");
1141 if(timer->auto_destroy)
1146 return FLUID_THREAD_RETURN_VALUE;
1150 new_fluid_timer(int msec, fluid_timer_callback_t callback, void *data,
1151 int new_thread, int auto_destroy, int high_priority)
1153 fluid_timer_t *timer;
1155 timer = FLUID_NEW(fluid_timer_t);
1159 FLUID_LOG(FLUID_ERR, "Out of memory");
1164 timer->callback = callback;
1166 timer->cont = TRUE ;
1167 timer->thread = NULL;
1168 timer->auto_destroy = auto_destroy;
1172 timer->thread = new_fluid_thread("timer", fluid_timer_run, timer, high_priority
1173 ? FLUID_SYS_TIMER_HIGH_PRIO_LEVEL : 0, FALSE);
1183 fluid_timer_run(timer); /* Run directly, instead of as a separate thread */
1187 /* do NOT return freed memory */
1196 delete_fluid_timer(fluid_timer_t *timer)
1199 fluid_return_if_fail(timer != NULL);
1201 auto_destroy = timer->auto_destroy;
1204 fluid_timer_join(timer);
1206 /* Shouldn't access timer now if auto_destroy enabled, since it has been destroyed */
1215 fluid_timer_join(fluid_timer_t *timer)
1221 auto_destroy = timer->auto_destroy;
1222 fluid_thread_join(timer->thread);
1226 timer->thread = NULL;
1234 /***************************************************************
1241 * Get standard in stream handle.
1242 * @return Standard in stream.
1245 fluid_get_stdin(void)
1247 return STDIN_FILENO;
1251 * Get standard output stream handle.
1252 * @return Standard out stream.
1255 fluid_get_stdout(void)
1257 return STDOUT_FILENO;
1261 * Read a line from an input stream.
1262 * @return 0 if end-of-stream, -1 if error, non zero otherwise
1265 fluid_istream_readline(fluid_istream_t in, fluid_ostream_t out, char *prompt,
1270 if(in == fluid_get_stdin())
1274 line = readline(prompt);
1281 FLUID_SNPRINTF(buf, len, "%s", line);
1290 fluid_ostream_printf(out, "%s", prompt);
1291 return fluid_istream_gets(in, buf, len);
1296 * Reads a line from an input stream (socket).
1297 * @param in The input socket
1298 * @param buf Buffer to store data to
1299 * @param len Maximum length to store to buf
1300 * @return 1 if a line was read, 0 on end of stream, -1 on error
1303 fluid_istream_gets(fluid_istream_t in, char *buf, int len)
1313 n = read(in, &c, 1);
1322 /* Handle read differently depending on if its a socket or file descriptor */
1323 if(!(in & FLUID_SOCKET_FLAG))
1325 n = read(in, &c, 1);
1334 n = recv(in & ~FLUID_SOCKET_FLAG, &c, 1, 0);
1336 if(n == SOCKET_ERROR)
1356 /* Store all characters excluding CR */
1367 * Send a printf style string with arguments to an output stream (socket).
1368 * @param out Output stream
1369 * @param format printf style format string
1370 * @param ... Arguments for the printf format string
1371 * @return Number of bytes written or -1 on error
1374 fluid_ostream_printf(fluid_ostream_t out, const char *format, ...)
1380 va_start(args, format);
1381 len = FLUID_VSNPRINTF(buf, 4095, format, args);
1391 printf("fluid_ostream_printf: buffer overflow");
1398 return write(out, buf, FLUID_STRLEN(buf));
1403 /* Handle write differently depending on if its a socket or file descriptor */
1404 if(!(out & FLUID_SOCKET_FLAG))
1406 return write(out, buf, FLUID_STRLEN(buf));
1410 retval = send(out & ~FLUID_SOCKET_FLAG, buf, FLUID_STRLEN(buf), 0);
1412 return retval != SOCKET_ERROR ? retval : -1;
1417 #ifdef NETWORK_SUPPORT
1419 int fluid_server_socket_join(fluid_server_socket_t *server_socket)
1421 return fluid_thread_join(server_socket->thread);
1424 static int fluid_socket_init(void)
1428 int res = WSAStartup(MAKEWORD(2, 2), &wsaData);
1432 FLUID_LOG(FLUID_ERR, "Server socket creation error: WSAStartup failed: %d", res);
1433 return FLUID_FAILED;
1441 static void fluid_socket_cleanup(void)
1448 static int fluid_socket_get_error(void)
1451 return (int)WSAGetLastError();
1457 fluid_istream_t fluid_socket_get_istream(fluid_socket_t sock)
1459 return sock | FLUID_SOCKET_FLAG;
1462 fluid_ostream_t fluid_socket_get_ostream(fluid_socket_t sock)
1464 return sock | FLUID_SOCKET_FLAG;
1467 void fluid_socket_close(fluid_socket_t sock)
1469 if(sock != INVALID_SOCKET)
1480 static fluid_thread_return_t fluid_server_socket_run(void *data)
1482 fluid_server_socket_t *server_socket = (fluid_server_socket_t *)data;
1483 fluid_socket_t client_socket;
1485 struct sockaddr_in6 addr;
1487 struct sockaddr_in addr;
1490 #ifdef HAVE_INETNTOP
1492 char straddr[INET6_ADDRSTRLEN];
1494 char straddr[INET_ADDRSTRLEN];
1495 #endif /* IPV6_SUPPORT */
1496 #endif /* HAVE_INETNTOP */
1498 socklen_t addrlen = sizeof(addr);
1500 FLUID_MEMSET((char *)&addr, 0, sizeof(addr));
1502 FLUID_LOG(FLUID_DBG, "Server listening for connections");
1504 while(server_socket->cont)
1506 client_socket = accept(server_socket->socket, (struct sockaddr *)&addr, &addrlen);
1508 FLUID_LOG(FLUID_DBG, "New client connection");
1510 if(client_socket == INVALID_SOCKET)
1512 if(server_socket->cont)
1514 FLUID_LOG(FLUID_ERR, "Failed to accept connection: %ld", fluid_socket_get_error());
1517 server_socket->cont = 0;
1518 return FLUID_THREAD_RETURN_VALUE;
1522 #ifdef HAVE_INETNTOP
1525 inet_ntop(AF_INET6, &addr.sin6_addr, straddr, sizeof(straddr));
1527 inet_ntop(AF_INET, &addr.sin_addr, straddr, sizeof(straddr));
1530 r = server_socket->func(server_socket->data, client_socket,
1533 r = server_socket->func(server_socket->data, client_socket,
1534 inet_ntoa(addr.sin_addr));
1539 fluid_socket_close(client_socket);
1544 FLUID_LOG(FLUID_DBG, "Server closing");
1546 return FLUID_THREAD_RETURN_VALUE;
1549 fluid_server_socket_t *
1550 new_fluid_server_socket(int port, fluid_server_func_t func, void *data)
1552 fluid_server_socket_t *server_socket;
1554 struct sockaddr_in6 addr;
1556 struct sockaddr_in addr;
1559 fluid_socket_t sock;
1561 fluid_return_val_if_fail(func != NULL, NULL);
1563 if(fluid_socket_init() != FLUID_OK)
1569 sock = socket(AF_INET6, SOCK_STREAM, 0);
1571 if(sock == INVALID_SOCKET)
1573 FLUID_LOG(FLUID_ERR, "Failed to create server socket: %ld", fluid_socket_get_error());
1574 fluid_socket_cleanup();
1578 FLUID_MEMSET(&addr, 0, sizeof(addr));
1579 addr.sin6_family = AF_INET6;
1580 addr.sin6_port = htons((uint16_t)port);
1581 addr.sin6_addr = in6addr_any;
1584 sock = socket(AF_INET, SOCK_STREAM, 0);
1586 if(sock == INVALID_SOCKET)
1588 FLUID_LOG(FLUID_ERR, "Failed to create server socket: %ld", fluid_socket_get_error());
1589 fluid_socket_cleanup();
1593 FLUID_MEMSET(&addr, 0, sizeof(addr));
1594 addr.sin_family = AF_INET;
1595 addr.sin_port = htons((uint16_t)port);
1596 addr.sin_addr.s_addr = htonl(INADDR_ANY);
1599 if(bind(sock, (const struct sockaddr *) &addr, sizeof(addr)) == SOCKET_ERROR)
1601 FLUID_LOG(FLUID_ERR, "Failed to bind server socket: %ld", fluid_socket_get_error());
1602 fluid_socket_close(sock);
1603 fluid_socket_cleanup();
1607 if(listen(sock, SOMAXCONN) == SOCKET_ERROR)
1609 FLUID_LOG(FLUID_ERR, "Failed to listen on server socket: %ld", fluid_socket_get_error());
1610 fluid_socket_close(sock);
1611 fluid_socket_cleanup();
1615 server_socket = FLUID_NEW(fluid_server_socket_t);
1617 if(server_socket == NULL)
1619 FLUID_LOG(FLUID_ERR, "Out of memory");
1620 fluid_socket_close(sock);
1621 fluid_socket_cleanup();
1625 server_socket->socket = sock;
1626 server_socket->func = func;
1627 server_socket->data = data;
1628 server_socket->cont = 1;
1630 server_socket->thread = new_fluid_thread("server", fluid_server_socket_run, server_socket,
1633 if(server_socket->thread == NULL)
1635 FLUID_FREE(server_socket);
1636 fluid_socket_close(sock);
1637 fluid_socket_cleanup();
1641 return server_socket;
1644 void delete_fluid_server_socket(fluid_server_socket_t *server_socket)
1646 fluid_return_if_fail(server_socket != NULL);
1648 server_socket->cont = 0;
1650 if(server_socket->socket != INVALID_SOCKET)
1652 fluid_socket_close(server_socket->socket);
1655 if(server_socket->thread)
1657 fluid_thread_join(server_socket->thread);
1658 delete_fluid_thread(server_socket->thread);
1661 FLUID_FREE(server_socket);
1663 // Should be called the same number of times as fluid_socket_init()
1664 fluid_socket_cleanup();
1667 #endif // NETWORK_SUPPORT