* Copyright (C) 2003 Peter Hanappe and others.
*
* This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public License
- * as published by the Free Software Foundation; either version 2 of
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
+ * Lesser General Public License for more details.
*
- * You should have received a copy of the GNU Library General Public
+ * You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA
/* WIN32 HACK - Flag used to differentiate between a file descriptor and a socket.
* Should work, so long as no SOCKET or file descriptor ends up with this bit set. - JG */
-#define WIN32_SOCKET_FLAG 0x40000000
+#ifdef _WIN32
+#define FLUID_SOCKET_FLAG 0x40000000
+#else
+#define FLUID_SOCKET_FLAG 0x00000000
+#define SOCKET_ERROR -1
+#define INVALID_SOCKET -1
+#endif
/* 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_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;
+ 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;
- fluid_thread_t *thread;
- int cont;
- fluid_server_func_t func;
- void *data;
+ fluid_socket_t socket;
+ fluid_thread_t *thread;
+ int cont;
+ fluid_server_func_t func;
+ void *data;
};
-static int fluid_istream_gets(fluid_istream_t in, char* buf, int len);
+static int fluid_istream_gets(fluid_istream_t in, char *buf, int len);
static char fluid_errbuf[512]; /* buffer for error message */
-static fluid_log_function_t fluid_log_function[LAST_LOG_LEVEL];
-static void* fluid_log_user_data[LAST_LOG_LEVEL];
-static int fluid_log_initialized = 0;
-
-static char* fluid_libname = "fluidsynth";
-
-
-void fluid_sys_config()
-{
- fluid_log_config();
-}
-
-
-unsigned int fluid_debug_flags = 0;
-
-#if DEBUG
-/*
- * fluid_debug
- */
-int fluid_debug(int level, char * fmt, ...)
+static fluid_log_function_t fluid_log_function[LAST_LOG_LEVEL] =
{
- if (fluid_debug_flags & level) {
- fluid_log_function_t fun;
- va_list args;
-
- va_start (args, fmt);
- vsnprintf(fluid_errbuf, sizeof (fluid_errbuf), fmt, args);
- va_end (args);
+ fluid_default_log_function,
+ fluid_default_log_function,
+ fluid_default_log_function,
+ fluid_default_log_function,
+ fluid_default_log_function
+};
+static void *fluid_log_user_data[LAST_LOG_LEVEL] = { NULL };
- fun = fluid_log_function[FLUID_DBG];
- if (fun != NULL) {
- (*fun)(level, fluid_errbuf, fluid_log_user_data[FLUID_DBG]);
- }
- }
- return 0;
-}
-#endif
+static const char fluid_libname[] = "fluidsynth";
/**
* Installs a new log function for a specified log level.
* @return The previously installed function.
*/
fluid_log_function_t
-fluid_set_log_function(int level, fluid_log_function_t fun, void* data)
+fluid_set_log_function(int level, fluid_log_function_t fun, void *data)
{
- fluid_log_function_t old = NULL;
-
- if ((level >= 0) && (level < LAST_LOG_LEVEL)) {
- old = fluid_log_function[level];
- fluid_log_function[level] = fun;
- fluid_log_user_data[level] = data;
- }
- return old;
+ fluid_log_function_t old = NULL;
+
+ if((level >= 0) && (level < LAST_LOG_LEVEL))
+ {
+ old = fluid_log_function[level];
+ fluid_log_function[level] = fun;
+ fluid_log_user_data[level] = data;
+ }
+
+ return old;
}
/**
* @param data User supplied data (not used)
*/
void
-fluid_default_log_function(int level, char* message, void* data)
+fluid_default_log_function(int level, const char *message, void *data)
{
- FILE* out;
+ FILE *out;
#if defined(WIN32)
- out = stdout;
+ out = stdout;
#else
- out = stderr;
-#endif
-
- if (fluid_log_initialized == 0) {
- fluid_log_config();
- }
-
- switch (level) {
- case FLUID_PANIC:
- FLUID_FPRINTF(out, "%s: panic: %s\n", fluid_libname, message);
- break;
- case FLUID_ERR:
- FLUID_FPRINTF(out, "%s: error: %s\n", fluid_libname, message);
- break;
- case FLUID_WARN:
- FLUID_FPRINTF(out, "%s: warning: %s\n", fluid_libname, message);
- break;
- case FLUID_INFO:
- FLUID_FPRINTF(out, "%s: %s\n", fluid_libname, message);
- break;
- case FLUID_DBG:
-#if DEBUG
- FLUID_FPRINTF(out, "%s: debug: %s\n", fluid_libname, message);
+ out = stderr;
#endif
- break;
- default:
- FLUID_FPRINTF(out, "%s: %s\n", fluid_libname, message);
- break;
- }
- fflush(out);
-}
-/*
- * fluid_init_log
- */
-void
-fluid_log_config(void)
-{
- if (fluid_log_initialized == 0) {
+ switch(level)
+ {
+ case FLUID_PANIC:
+ FLUID_FPRINTF(out, "%s: panic: %s\n", fluid_libname, message);
+ break;
- fluid_log_initialized = 1;
+ case FLUID_ERR:
+ FLUID_FPRINTF(out, "%s: error: %s\n", fluid_libname, message);
+ break;
- if (fluid_log_function[FLUID_PANIC] == NULL) {
- fluid_set_log_function(FLUID_PANIC, fluid_default_log_function, NULL);
- }
+ case FLUID_WARN:
+ FLUID_FPRINTF(out, "%s: warning: %s\n", fluid_libname, message);
+ break;
- if (fluid_log_function[FLUID_ERR] == NULL) {
- fluid_set_log_function(FLUID_ERR, fluid_default_log_function, NULL);
- }
+ case FLUID_INFO:
+ FLUID_FPRINTF(out, "%s: %s\n", fluid_libname, message);
+ break;
- if (fluid_log_function[FLUID_WARN] == NULL) {
- fluid_set_log_function(FLUID_WARN, fluid_default_log_function, NULL);
- }
+ case FLUID_DBG:
+#if DEBUG
+ FLUID_FPRINTF(out, "%s: debug: %s\n", fluid_libname, message);
+#endif
+ break;
- if (fluid_log_function[FLUID_INFO] == NULL) {
- fluid_set_log_function(FLUID_INFO, fluid_default_log_function, NULL);
+ default:
+ FLUID_FPRINTF(out, "%s: %s\n", fluid_libname, message);
+ break;
}
- if (fluid_log_function[FLUID_DBG] == NULL) {
- fluid_set_log_function(FLUID_DBG, fluid_default_log_function, NULL);
- }
- }
+ fflush(out);
}
/**
* @return Always returns #FLUID_FAILED
*/
int
-fluid_log(int level, const char* fmt, ...)
+fluid_log(int level, const char *fmt, ...)
{
- fluid_log_function_t fun = NULL;
+ fluid_log_function_t fun = NULL;
- va_list args;
- va_start (args, fmt);
- vsnprintf(fluid_errbuf, sizeof (fluid_errbuf), fmt, args);
- va_end (args);
+ va_list args;
+ va_start(args, fmt);
+ FLUID_VSNPRINTF(fluid_errbuf, sizeof(fluid_errbuf), fmt, args);
+ va_end(args);
- if ((level >= 0) && (level < LAST_LOG_LEVEL)) {
- fun = fluid_log_function[level];
- if (fun != NULL) {
- (*fun)(level, fluid_errbuf, fluid_log_user_data[level]);
+ if((level >= 0) && (level < LAST_LOG_LEVEL))
+ {
+ fun = fluid_log_function[level];
+
+ if(fun != NULL)
+ {
+ (*fun)(level, fluid_errbuf, fluid_log_user_data[level]);
+ }
}
- }
- return FLUID_FAILED;
+
+ return FLUID_FAILED;
}
/**
* @param delim String of delimiter chars.
* @return Pointer to the next token or NULL if no more tokens.
*/
-char *fluid_strtok (char **str, char *delim)
+char *fluid_strtok(char **str, const char *delim)
{
- char *s, *d, *token;
- char c;
+ char *s, *token;
+ const char *d;
+ char c;
- if (str == NULL || delim == NULL || !*delim)
- {
- FLUID_LOG(FLUID_ERR, "Null pointer");
- return NULL;
- }
+ if(str == NULL || delim == NULL || !*delim)
+ {
+ FLUID_LOG(FLUID_ERR, "Null pointer");
+ return NULL;
+ }
- s = *str;
- if (!s) return NULL; /* str points to a NULL pointer? (tokenize already ended) */
+ s = *str;
- /* skip delimiter chars at beginning of token */
- do
- {
- c = *s;
- if (!c) /* end of source string? */
+ if(!s)
{
- *str = NULL;
- return NULL;
+ return NULL; /* str points to a NULL pointer? (tokenize already ended) */
}
- for (d = delim; *d; d++) /* is source char a token char? */
+ /* skip delimiter chars at beginning of token */
+ do
{
- if (c == *d) /* token char match? */
- {
- s++; /* advance to next source char */
- break;
- }
+ c = *s;
+
+ if(!c) /* end of source string? */
+ {
+ *str = NULL;
+ return NULL;
+ }
+
+ for(d = delim; *d; d++) /* is source char a token char? */
+ {
+ if(c == *d) /* token char match? */
+ {
+ s++; /* advance to next source char */
+ break;
+ }
+ }
}
- } while (*d); /* while token char match */
+ while(*d); /* while token char match */
- token = s; /* start of token found */
+ token = s; /* start of token found */
- /* search for next token char or end of source string */
- for (s = s+1; *s; s++)
- {
- c = *s;
-
- for (d = delim; *d; d++) /* is source char a token char? */
+ /* search for next token char or end of source string */
+ for(s = s + 1; *s; s++)
{
- if (c == *d) /* token char match? */
- {
- *s = '\0'; /* overwrite token char with zero byte to terminate token */
- *str = s+1; /* update str to point to beginning of next token */
- return token;
- }
+ c = *s;
+
+ for(d = delim; *d; d++) /* is source char a token char? */
+ {
+ if(c == *d) /* token char match? */
+ {
+ *s = '\0'; /* overwrite token char with zero byte to terminate token */
+ *str = s + 1; /* update str to point to beginning of next token */
+ return token;
+ }
+ }
}
- }
- /* we get here only if source string ended */
- *str = NULL;
- return token;
+ /* we get here only if source string ended */
+ *str = NULL;
+ return token;
}
/*
* fluid_error
*/
-char*
+char *
fluid_error()
{
- return fluid_errbuf;
+ return fluid_errbuf;
}
/**
int
fluid_is_midifile(const char *filename)
{
- FILE* fp = fopen(filename, "rb");
- char id[4];
+ FILE *fp = fopen(filename, "rb");
+ char id[4];
+
+ if(fp == NULL)
+ {
+ return 0;
+ }
+
+ if(fread((void *) id, 1, 4, fp) != 4)
+ {
+ fclose(fp);
+ return 0;
+ }
- if (fp == NULL) {
- return 0;
- }
- if (fread((void*) id, 1, 4, fp) != 4) {
fclose(fp);
- return 0;
- }
- fclose(fp);
- return strncmp(id, "MThd", 4) == 0;
+ return FLUID_STRNCMP(id, "MThd", 4) == 0;
}
/**
* @param filename Path to the file to check
* @return TRUE if it could be a SoundFont, FALSE otherwise
*
- * The current implementation only checks for the "RIFF" header in the file.
- * It is useful only to distinguish between SoundFont and MIDI files.
+ * @note The current implementation only checks for the "RIFF" and "sfbk" headers in
+ * the file. It is useful to distinguish between SoundFont and other (e.g. MIDI) files.
*/
int
fluid_is_soundfont(const char *filename)
{
- FILE* fp = fopen(filename, "rb");
- char id[4];
+ FILE *fp = fopen(filename, "rb");
+ char riff_id[4], sfbk_id[4];
+
+ if(fp == NULL)
+ {
+ return 0;
+ }
+
+ if((fread((void *) riff_id, 1, sizeof(riff_id), fp) != sizeof(riff_id)) ||
+ (fseek(fp, 4, SEEK_CUR) != 0) ||
+ (fread((void *) sfbk_id, 1, sizeof(sfbk_id), fp) != sizeof(sfbk_id)))
+ {
+ goto error_rec;
+ }
- if (fp == NULL) {
- return 0;
- }
- if (fread((void*) id, 1, 4, fp) != 4) {
+ fclose(fp);
+ return (FLUID_STRNCMP(riff_id, "RIFF", sizeof(riff_id)) == 0) &&
+ (FLUID_STRNCMP(sfbk_id, "sfbk", sizeof(sfbk_id)) == 0);
+
+error_rec:
fclose(fp);
return 0;
- }
- fclose(fp);
+}
- return strncmp(id, "RIFF", 4) == 0;
+/**
+ * Suspend the execution of the current thread for the specified amount of time.
+ * @param milliseconds to wait.
+ */
+void fluid_msleep(unsigned int msecs)
+{
+ g_usleep(msecs * 1000);
}
/**
*/
unsigned int fluid_curtime(void)
{
- static glong initial_seconds = 0;
- GTimeVal timeval;
+ static glong initial_seconds = 0;
+ GTimeVal timeval;
- if (initial_seconds == 0) {
- g_get_current_time (&timeval);
- initial_seconds = timeval.tv_sec;
- }
+ if(initial_seconds == 0)
+ {
+ g_get_current_time(&timeval);
+ initial_seconds = timeval.tv_sec;
+ }
- g_get_current_time (&timeval);
+ g_get_current_time(&timeval);
- return (unsigned int)((timeval.tv_sec - initial_seconds) * 1000.0 + timeval.tv_usec / 1000.0);
+ return (unsigned int)((timeval.tv_sec - initial_seconds) * 1000.0 + timeval.tv_usec / 1000.0);
}
/**
* Get time in microseconds to be used in relative timing operations.
- * @return Unix time in microseconds.
+ * @return time in microseconds.
+ * Note: When used for profiling we need high precision clock given
+ * by g_get_monotonic_time()if available (glib version >= 2.53.3).
+ * If glib version is too old and in the case of Windows the function
+ * uses high precision performance counter instead of g_getmonotic_time().
*/
double
-fluid_utime (void)
+fluid_utime(void)
{
- GTimeVal timeval;
+ double utime;
+
+#if GLIB_MAJOR_VERSION == 2 && GLIB_MINOR_VERSION >= 28
+ /* use high precision monotonic clock if available (g_monotonic_time().
+ * For Winfdows, if this clock is actually implemented as low prec. clock
+ * (i.e. in case glib is too old), high precision performance counter are
+ * used instead.
+ * see: https://bugzilla.gnome.org/show_bug.cgi?id=783340
+ */
+#if defined(WITH_PROFILING) && defined(WIN32) &&\
+ /* glib < 2.53.3 */\
+ (GLIB_MINOR_VERSION <= 53 && (GLIB_MINOR_VERSION < 53 || GLIB_MICRO_VERSION < 3))
+ /* use high precision performance counter. */
+ static LARGE_INTEGER freq_cache = {0, 0}; /* Performance Frequency */
+ LARGE_INTEGER perf_cpt;
+
+ if(! freq_cache.QuadPart)
+ {
+ QueryPerformanceFrequency(&freq_cache); /* Frequency value */
+ }
- g_get_current_time (&timeval);
+ QueryPerformanceCounter(&perf_cpt); /* Counter value */
+ utime = perf_cpt.QuadPart * 1000000.0 / freq_cache.QuadPart; /* time in micros */
+#else
+ utime = g_get_monotonic_time();
+#endif
+#else
+ /* fallback to less precise clock */
+ GTimeVal timeval;
+ g_get_current_time(&timeval);
+ utime = (timeval.tv_sec * 1000000.0 + timeval.tv_usec);
+#endif
- return (timeval.tv_sec * 1000000.0 + timeval.tv_usec);
+ return utime;
}
+
#if defined(WIN32) /* Windoze specific stuff */
void
-fluid_thread_self_set_prio (int prio_level)
+fluid_thread_self_set_prio(int prio_level)
{
- if (prio_level > 0)
- SetThreadPriority (GetCurrentThread(), THREAD_PRIORITY_HIGHEST);
+ if(prio_level > 0)
+ {
+ SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_HIGHEST);
+ }
}
#elif defined(__OS2__) /* OS/2 specific stuff */
void
-fluid_thread_self_set_prio (int prio_level)
+fluid_thread_self_set_prio(int prio_level)
{
- if (prio_level > 0)
- DosSetPriority (PRTYS_THREAD, PRTYC_REGULAR, PRTYD_MAXIMUM, 0);
+ if(prio_level > 0)
+ {
+ DosSetPriority(PRTYS_THREAD, PRTYC_REGULAR, PRTYD_MAXIMUM, 0);
+ }
}
#else /* POSIX stuff.. Nice POSIX.. Good POSIX. */
void
-fluid_thread_self_set_prio (int prio_level)
+fluid_thread_self_set_prio(int prio_level)
{
- struct sched_param priority;
+ struct sched_param priority;
- if (prio_level > 0)
- {
+ if(prio_level > 0)
+ {
- memset(&priority, 0, sizeof(priority));
- priority.sched_priority = prio_level;
+ memset(&priority, 0, sizeof(priority));
+ priority.sched_priority = prio_level;
+
+ if(pthread_setschedparam(pthread_self(), SCHED_FIFO, &priority) == 0)
+ {
+ return;
+ }
- if (pthread_setschedparam (pthread_self (), SCHED_FIFO, &priority) == 0) {
- return;
- }
#ifdef DBUS_SUPPORT
-/* Try to gain high priority via rtkit */
-
- if (fluid_rtkit_make_realtime(0, prio_level) == 0) {
- return;
- }
+ /* Try to gain high priority via rtkit */
+
+ if(fluid_rtkit_make_realtime(0, prio_level) == 0)
+ {
+ return;
+ }
+
#endif
- FLUID_LOG(FLUID_WARN, "Failed to set thread to high priority");
- }
+ FLUID_LOG(FLUID_WARN, "Failed to set thread to high priority");
+ }
}
#ifdef FPE_CHECK
* Checks, if the floating point unit has produced an exception, print a message
* if so and clear the exception.
*/
-unsigned int fluid_check_fpe_i386(char* explanation)
+unsigned int fluid_check_fpe_i386(char *explanation)
{
- unsigned int s;
+ unsigned int s;
- _FPU_GET_SW(s);
- _FPU_CLR_SW();
+ _FPU_GET_SW(s);
+ _FPU_CLR_SW();
- s &= _FPU_STATUS_IE | _FPU_STATUS_DE | _FPU_STATUS_ZE | _FPU_STATUS_OE | _FPU_STATUS_UE;
+ s &= _FPU_STATUS_IE | _FPU_STATUS_DE | _FPU_STATUS_ZE | _FPU_STATUS_OE | _FPU_STATUS_UE;
- if (s)
- {
- FLUID_LOG(FLUID_WARN, "FPE exception (before or in %s): %s%s%s%s%s", explanation,
- (s & _FPU_STATUS_IE) ? "Invalid operation " : "",
- (s & _FPU_STATUS_DE) ? "Denormal number " : "",
- (s & _FPU_STATUS_ZE) ? "Zero divide " : "",
- (s & _FPU_STATUS_OE) ? "Overflow " : "",
- (s & _FPU_STATUS_UE) ? "Underflow " : "");
- }
+ if(s)
+ {
+ FLUID_LOG(FLUID_WARN, "FPE exception (before or in %s): %s%s%s%s%s", explanation,
+ (s & _FPU_STATUS_IE) ? "Invalid operation " : "",
+ (s & _FPU_STATUS_DE) ? "Denormal number " : "",
+ (s & _FPU_STATUS_ZE) ? "Zero divide " : "",
+ (s & _FPU_STATUS_OE) ? "Overflow " : "",
+ (s & _FPU_STATUS_UE) ? "Underflow " : "");
+ }
- return s;
+ return s;
}
/* Purpose:
* Clear floating point exception.
*/
-void fluid_clear_fpe_i386 (void)
+void fluid_clear_fpe_i386(void)
{
- _FPU_CLR_SW();
+ _FPU_CLR_SW();
}
#endif // ifdef FPE_CHECK
*/
#if WITH_PROFILING
+/* Profiling interface beetween profiling command shell and audio rendering API
+ (FluidProfile_0004.pdf- 3.2.2).
+ Macros are in defined in fluid_sys.h.
+*/
-fluid_profile_data_t fluid_profile_data[] =
+/*
+ -----------------------------------------------------------------------------
+ Shell task side | Profiling interface | Audio task side
+ -----------------------------------------------------------------------------
+ profiling | Internal | | | Audio
+ command <---> |<-- profling -->| Data |<--macros -->| <--> rendering
+ shell | API | | | API
+
+*/
+/* default parameters for shell command "prof_start" in fluid_sys.c */
+unsigned short fluid_profile_notes = 0; /* number of generated notes */
+/* preset bank:0 prog:16 (organ) */
+unsigned char fluid_profile_bank = FLUID_PROFILE_DEFAULT_BANK;
+unsigned char fluid_profile_prog = FLUID_PROFILE_DEFAULT_PROG;
+
+/* print mode */
+unsigned char fluid_profile_print = FLUID_PROFILE_DEFAULT_PRINT;
+/* number of measures */
+unsigned short fluid_profile_n_prof = FLUID_PROFILE_DEFAULT_N_PROF;
+/* measure duration in ms */
+unsigned short fluid_profile_dur = FLUID_PROFILE_DEFAULT_DURATION;
+/* lock between multiple-shell */
+fluid_atomic_int_t fluid_profile_lock = 0;
+/**/
+
+/*----------------------------------------------
+ Profiling Data
+-----------------------------------------------*/
+unsigned char fluid_profile_status = PROFILE_STOP; /* command and status */
+unsigned int fluid_profile_end_ticks = 0; /* ending position (in ticks) */
+fluid_profile_data_t fluid_profile_data[] = /* Data duration */
{
- { FLUID_PROF_WRITE, "fluid_synth_write_* ", 1e10, 0.0, 0.0, 0},
- { FLUID_PROF_ONE_BLOCK, "fluid_synth_one_block ", 1e10, 0.0, 0.0, 0},
- { FLUID_PROF_ONE_BLOCK_CLEAR, "fluid_synth_one_block:clear ", 1e10, 0.0, 0.0, 0},
- { FLUID_PROF_ONE_BLOCK_VOICE, "fluid_synth_one_block:one voice ", 1e10, 0.0, 0.0, 0},
- { FLUID_PROF_ONE_BLOCK_VOICES, "fluid_synth_one_block:all voices", 1e10, 0.0, 0.0, 0},
- { FLUID_PROF_ONE_BLOCK_REVERB, "fluid_synth_one_block:reverb ", 1e10, 0.0, 0.0, 0},
- { FLUID_PROF_ONE_BLOCK_CHORUS, "fluid_synth_one_block:chorus ", 1e10, 0.0, 0.0, 0},
- { FLUID_PROF_VOICE_NOTE, "fluid_voice:note ", 1e10, 0.0, 0.0, 0},
- { FLUID_PROF_VOICE_RELEASE, "fluid_voice:release ", 1e10, 0.0, 0.0, 0},
- { FLUID_PROF_LAST, "last", 1e100, 0.0, 0.0, 0}
+ {"synth_write_* ------------>", 1e10, 0.0, 0.0, 0, 0, 0},
+ {"synth_one_block ---------->", 1e10, 0.0, 0.0, 0, 0, 0},
+ {"synth_one_block:clear ---->", 1e10, 0.0, 0.0, 0, 0, 0},
+ {"synth_one_block:one voice->", 1e10, 0.0, 0.0, 0, 0, 0},
+ {"synth_one_block:all voices>", 1e10, 0.0, 0.0, 0, 0, 0},
+ {"synth_one_block:reverb --->", 1e10, 0.0, 0.0, 0, 0, 0},
+ {"synth_one_block:chorus --->", 1e10, 0.0, 0.0, 0, 0, 0},
+ {"voice:note --------------->", 1e10, 0.0, 0.0, 0, 0, 0},
+ {"voice:release ------------>", 1e10, 0.0, 0.0, 0, 0, 0}
};
+/*----------------------------------------------
+ Internal profiling API
+-----------------------------------------------*/
+/* logging profiling data (used on synthesizer instance deletion) */
void fluid_profiling_print(void)
{
- int i;
+ int i;
- printf("fluid_profiling_print\n");
+ printf("fluid_profiling_print\n");
- FLUID_LOG(FLUID_INFO, "Estimated times: min/avg/max (micro seconds)");
+ FLUID_LOG(FLUID_INFO, "Estimated times: min/avg/max (micro seconds)");
- for (i = 0; i < FLUID_PROF_LAST; i++) {
- if (fluid_profile_data[i].count > 0) {
- FLUID_LOG(FLUID_INFO, "%s: %.3f/%.3f/%.3f",
- fluid_profile_data[i].description,
- fluid_profile_data[i].min,
- fluid_profile_data[i].total / fluid_profile_data[i].count,
- fluid_profile_data[i].max);
- } else {
- FLUID_LOG(FLUID_DBG, "%s: no profiling available", fluid_profile_data[i].description);
+ for(i = 0; i < FLUID_PROFILE_NBR; i++)
+ {
+ if(fluid_profile_data[i].count > 0)
+ {
+ FLUID_LOG(FLUID_INFO, "%s: %.3f/%.3f/%.3f",
+ fluid_profile_data[i].description,
+ fluid_profile_data[i].min,
+ fluid_profile_data[i].total / fluid_profile_data[i].count,
+ fluid_profile_data[i].max);
+ }
+ else
+ {
+ FLUID_LOG(FLUID_DBG, "%s: no profiling available",
+ fluid_profile_data[i].description);
+ }
}
- }
}
+/* Macro that returns cpu load in percent (%)
+ * @dur: duration (micro second).
+ * @sample_rate: sample_rate used in audio driver (Hz).
+ * @n_amples: number of samples collected during 'dur' duration.
+*/
+#define fluid_profile_load(dur,sample_rate,n_samples) \
+ (dur * sample_rate / n_samples / 10000.0)
+
+
+/* prints cpu loads only
+*
+* @param sample_rate the sample rate of audio output.
+* @param out output stream device.
+*
+* ------------------------------------------------------------------------------
+* Cpu loads(%) (sr: 44100 Hz, sp: 22.68 microsecond) and maximum voices
+* ------------------------------------------------------------------------------
+* nVoices| total(%)|voices(%)| reverb(%)|chorus(%)| voice(%)|estimated maxVoices
+* -------|---------|---------|----------|---------|---------|-------------------
+* 250| 41.544| 41.544| 0.000| 0.000| 0.163| 612
+*/
+static void fluid_profiling_print_load(double sample_rate, fluid_ostream_t out)
+{
+ unsigned int n_voices; /* voices number */
+ static const char max_voices_not_available[] = " not available";
+ const char *pmax_voices;
+ char max_voices_available[20];
+
+ /* First computes data to be printed */
+ double total, voices, reverb, chorus, all_voices, voice;
+ /* voices number */
+ n_voices = fluid_profile_data[FLUID_PROF_ONE_BLOCK_VOICES].count ?
+ fluid_profile_data[FLUID_PROF_ONE_BLOCK_VOICES].n_voices /
+ fluid_profile_data[FLUID_PROF_ONE_BLOCK_VOICES].count : 0;
+
+ /* total load (%) */
+ total = fluid_profile_data[FLUID_PROF_WRITE].count ?
+ fluid_profile_load(fluid_profile_data[FLUID_PROF_WRITE].total, sample_rate,
+ fluid_profile_data[FLUID_PROF_WRITE].n_samples) : 0;
+
+ /* reverb load (%) */
+ reverb = fluid_profile_data[FLUID_PROF_ONE_BLOCK_REVERB].count ?
+ fluid_profile_load(fluid_profile_data[FLUID_PROF_ONE_BLOCK_REVERB].total,
+ sample_rate,
+ fluid_profile_data[FLUID_PROF_ONE_BLOCK_REVERB].n_samples) : 0;
+
+ /* chorus load (%) */
+ chorus = fluid_profile_data[FLUID_PROF_ONE_BLOCK_CHORUS].count ?
+ fluid_profile_load(fluid_profile_data[FLUID_PROF_ONE_BLOCK_CHORUS].total,
+ sample_rate,
+ fluid_profile_data[FLUID_PROF_ONE_BLOCK_CHORUS].n_samples) : 0;
+
+ /* total voices load: total - reverb - chorus (%) */
+ voices = total - reverb - chorus;
+
+ /* One voice load (%): all_voices / n_voices. */
+ all_voices = fluid_profile_data[FLUID_PROF_ONE_BLOCK_VOICES].count ?
+ fluid_profile_load(fluid_profile_data[FLUID_PROF_ONE_BLOCK_VOICES].total,
+ sample_rate,
+ fluid_profile_data[FLUID_PROF_ONE_BLOCK_VOICES].n_samples) : 0;
+
+ voice = n_voices ? all_voices / n_voices : 0;
+
+ /* estimated maximum voices number */
+ if(voice > 0)
+ {
+ FLUID_SNPRINTF(max_voices_available, sizeof(max_voices_available),
+ "%17d", (unsigned int)((100.0 - reverb - chorus) / voice));
+ pmax_voices = max_voices_available;
+ }
+ else
+ {
+ pmax_voices = max_voices_not_available;
+ }
-#endif /* WITH_PROFILING */
+ /* Now prints data */
+ fluid_ostream_printf(out,
+ " ------------------------------------------------------------------------------\n");
+ fluid_ostream_printf(out,
+ " Cpu loads(%%) (sr:%6.0f Hz, sp:%6.2f microsecond) and maximum voices\n",
+ sample_rate, 1000000.0 / sample_rate);
+ fluid_ostream_printf(out,
+ " ------------------------------------------------------------------------------\n");
+ fluid_ostream_printf(out,
+ " nVoices| total(%%)|voices(%%)| reverb(%%)|chorus(%%)| voice(%%)|estimated maxVoices\n");
+ fluid_ostream_printf(out,
+ " -------|---------|---------|----------|---------|---------|-------------------\n");
+ fluid_ostream_printf(out,
+ "%8d|%9.3f|%9.3f|%10.3f|%9.3f|%9.3f|%s\n", n_voices, total, voices,
+ reverb, chorus, voice, pmax_voices);
+}
+
+/*
+* prints profiling data (used by profile shell command: prof_start).
+* The function is an internal profiling API between the "profile" command
+* prof_start and audio rendering API (see FluidProfile_0004.pdf - 3.2.2).
+*
+* @param sample_rate the sample rate of audio output.
+* @param out output stream device.
+*
+* When print mode is 1, the function prints all the informations (see below).
+* When print mode is 0, the fonction prints only the cpu loads.
+*
+* ------------------------------------------------------------------------------
+* Duration(microsecond) and cpu loads(%) (sr: 44100 Hz, sp: 22.68 microsecond)
+* ------------------------------------------------------------------------------
+* Code under profiling |Voices| Duration (microsecond) | Load(%)
+* | nbr| min| avg| max|
+* ---------------------------|------|--------------------------------|----------
+* synth_write_* ------------>| 250| 3.91| 2188.82| 3275.00| 41.544
+* synth_one_block ---------->| 250| 1150.70| 2273.56| 3241.47| 41.100
+* synth_one_block:clear ---->| 250| 3.07| 4.62| 61.18| 0.084
+* synth_one_block:one voice->| 1| 4.19| 9.02| 1044.27| 0.163
+* synth_one_block:all voices>| 250| 1138.41| 2259.11| 3217.73| 40.839
+* synth_one_block:reverb --->| no profiling available
+* synth_one_block:chorus --->| no profiling available
+* voice:note --------------->| no profiling available
+* voice:release ------------>| no profiling available
+* ------------------------------------------------------------------------------
+* Cpu loads(%) (sr: 44100 Hz, sp: 22.68 microsecond) and maximum voices
+* ------------------------------------------------------------------------------
+* nVoices| total(%)|voices(%)| reverb(%)|chorus(%)| voice(%)|estimated maxVoices
+* -------|---------|---------|----------|---------|---------|-------------------
+* 250| 41.544| 41.544| 0.000| 0.000| 0.163| 612
+*/
+void fluid_profiling_print_data(double sample_rate, fluid_ostream_t out)
+{
+ int i;
+
+ if(fluid_profile_print)
+ {
+ /* print all details: Duration(microsecond) and cpu loads(%) */
+ fluid_ostream_printf(out,
+ " ------------------------------------------------------------------------------\n");
+ fluid_ostream_printf(out,
+ " Duration(microsecond) and cpu loads(%%) (sr:%6.0f Hz, sp:%6.2f microsecond)\n",
+ sample_rate, 1000000.0 / sample_rate);
+ fluid_ostream_printf(out,
+ " ------------------------------------------------------------------------------\n");
+ fluid_ostream_printf(out,
+ " Code under profiling |Voices| Duration (microsecond) | Load(%%)\n");
+ fluid_ostream_printf(out,
+ " | nbr| min| avg| max|\n");
+ fluid_ostream_printf(out,
+ " ---------------------------|------|--------------------------------|----------\n");
+
+ for(i = 0; i < FLUID_PROFILE_NBR; i++)
+ {
+ unsigned int count = fluid_profile_data[i].count;
+
+ if(count > 0)
+ {
+ /* data are available */
+
+ if(FLUID_PROF_WRITE <= i && i <= FLUID_PROF_ONE_BLOCK_CHORUS)
+ {
+ double load = fluid_profile_load(fluid_profile_data[i].total, sample_rate,
+ fluid_profile_data[i].n_samples);
+ fluid_ostream_printf(out, " %s|%6d|%10.2f|%10.2f|%10.2f|%8.3f\n",
+ fluid_profile_data[i].description, /* code under profiling */
+ fluid_profile_data[i].n_voices / count, /* voices number */
+ fluid_profile_data[i].min, /* minimum duration */
+ fluid_profile_data[i].total / count, /* average duration */
+ fluid_profile_data[i].max, /* maximum duration */
+ load); /* cpu load */
+ }
+ else
+ {
+ /* note and release duration */
+ fluid_ostream_printf(out, " %s|%6d|%10.0f|%10.0f|%10.0f|\n",
+ fluid_profile_data[i].description, /* code under profiling */
+ fluid_profile_data[i].n_voices / count,
+ fluid_profile_data[i].min, /* minimum duration */
+ fluid_profile_data[i].total / count, /* average duration */
+ fluid_profile_data[i].max); /* maximum duration */
+ }
+ }
+ else
+ {
+ /* data aren't available */
+ fluid_ostream_printf(out,
+ " %s| no profiling available\n", fluid_profile_data[i].description);
+ }
+ }
+ }
+
+ /* prints cpu loads only */
+ fluid_profiling_print_load(sample_rate, out);/* prints cpu loads */
+}
+
+/*
+ Returns true if the user cancels the current profiling measurement.
+ Actually this is implemented using the <ENTER> key. To add this functionality:
+ 1) Adds #define FLUID_PROFILE_CANCEL in fluid_sys.h.
+ 2) Adds the necessary code inside fluid_profile_is_cancel().
+
+ When FLUID_PROFILE_CANCEL is not defined, the function return FALSE.
+*/
+int fluid_profile_is_cancel_req(void)
+{
+#ifdef FLUID_PROFILE_CANCEL
+
+#if defined(WIN32) /* Windows specific stuff */
+ /* Profile cancellation is supported for Windows */
+ /* returns TRUE if key <ENTER> is depressed */
+ return(GetAsyncKeyState(VK_RETURN) & 0x1);
+
+#elif defined(__OS2__) /* OS/2 specific stuff */
+ /* Profile cancellation isn't yet supported for OS2 */
+ /* For OS2, replaces the following line with the function that returns
+ true when the keyboard key <ENTER> is depressed */
+ return FALSE; /* default value */
+
+#else /* POSIX stuff */
+ /* Profile cancellation is supported for Linux */
+ /* returns true is <ENTER> is depressed */
+ {
+ /* Here select() is used to poll the standard input to see if an input
+ is ready. As the standard input is usually buffered, the user
+ needs to depress <ENTER> to set the input to a "ready" state.
+ */
+ struct timeval tv;
+ fd_set fds; /* just one fds need to be polled */
+ tv.tv_sec = 0; /* Setting both values to 0, means a 0 timeout */
+ tv.tv_usec = 0;
+ FD_ZERO(&fds); /* reset fds */
+ FD_SET(STDIN_FILENO, &fds); /* sets fds to poll standard input only */
+ select(STDIN_FILENO + 1, &fds, NULL, NULL, &tv); /* polling */
+ return (FD_ISSET(0, &fds)); /* returns true if standard input is ready */
+ }
+#endif /* OS stuff */
+
+#else /* FLUID_PROFILE_CANCEL not defined */
+ return FALSE; /* default value */
+#endif /* FLUID_PROFILE_CANCEL */
+}
+/**
+* Returns status used in shell command "prof_start".
+* The function is an internal profiling API between the "profile" command
+* prof_start and audio rendering API (see FluidProfile_0004.pdf - 3.2.2).
+*
+* @return status
+* - PROFILE_READY profiling data are ready.
+* - PROFILE_RUNNING, profiling data are still under acquisition.
+* - PROFILE_CANCELED, acquisition has been cancelled by the user.
+* - PROFILE_STOP, no acquisition in progress.
+*
+* When status is PROFILE_RUNNING, the caller can do passive waiting, or other
+* work before recalling the function later.
+*/
+int fluid_profile_get_status(void)
+{
+ /* Checks if user has requested to cancel the current measurement */
+ /* Cancellation must have precedence over other status */
+ if(fluid_profile_is_cancel_req())
+ {
+ fluid_profile_start_stop(0, 0); /* stops the measurement */
+ return PROFILE_CANCELED;
+ }
+
+ switch(fluid_profile_status)
+ {
+ case PROFILE_READY:
+ return PROFILE_READY; /* profiling data are ready */
+
+ case PROFILE_START:
+ return PROFILE_RUNNING;/* profiling data are under acquisition */
+
+ default:
+ return PROFILE_STOP;
+ }
+}
+/**
+* Starts or stops profiling measurement.
+* The function is an internal profiling API between the "profile" command
+* prof_start and audio rendering API (see FluidProfile_0004.pdf - 3.2.2).
+*
+* @param end_tick end position of the measure (in ticks).
+* - If end_tick is greater then 0, the function starts a measure if a measure
+* isn't running. If a measure is already running, the function does nothing
+* and returns.
+* - If end_tick is 0, the function stops a measure.
+* @param clear_data,
+* - If clear_data is 0, the function clears fluid_profile_data before starting
+* a measure, otherwise, the data from the started measure will be accumulated
+* within fluid_profile_data.
+*/
+void fluid_profile_start_stop(unsigned int end_ticks, short clear_data)
+{
+ if(end_ticks) /* This is a "start" request */
+ {
+ /* Checks if a measure is already running */
+ if(fluid_profile_status != PROFILE_START)
+ {
+ short i;
+ fluid_profile_end_ticks = end_ticks;
+
+ /* Clears profile data */
+ if(clear_data == 0)
+ for(i = 0; i < FLUID_PROFILE_NBR; i++)
+ {
+ fluid_profile_data[i].min = 1e10;/* min sets to max value */
+ fluid_profile_data[i].max = 0; /* maximum sets to min value */
+ fluid_profile_data[i].total = 0; /* total duration microsecond */
+ fluid_profile_data[i].count = 0; /* data count */
+ fluid_profile_data[i].n_voices = 0; /* voices number */
+ fluid_profile_data[i].n_samples = 0;/* audio samples number */
+ }
+
+ fluid_profile_status = PROFILE_START; /* starts profiling */
+ }
+
+ /* else do nothing when profiling is already started */
+ }
+ else /* This is a "stop" request */
+ {
+ /* forces the current running profile (if any) to stop */
+ fluid_profile_status = PROFILE_STOP; /* stops profiling */
+ }
+}
+
+#endif /* WITH_PROFILING */
/***************************************************************
*
/* Rather than inline this one, we just declare it as a function, to prevent
* GCC warning about inline failure. */
fluid_cond_t *
-new_fluid_cond (void)
+new_fluid_cond(void)
{
- if (!g_thread_supported ()) g_thread_init (NULL);
- return g_cond_new ();
+ if(!g_thread_supported())
+ {
+ g_thread_init(NULL);
+ }
+
+ return g_cond_new();
}
#endif
static gpointer
-fluid_thread_high_prio (gpointer data)
+fluid_thread_high_prio(gpointer data)
{
- fluid_thread_info_t *info = data;
+ fluid_thread_info_t *info = data;
- fluid_thread_self_set_prio (info->prio_level);
+ fluid_thread_self_set_prio(info->prio_level);
- info->func (info->data);
- FLUID_FREE (info);
+ info->func(info->data);
+ FLUID_FREE(info);
- return NULL;
+ return NULL;
}
/**
* @return New thread pointer or NULL on error
*/
fluid_thread_t *
-new_fluid_thread (const char *name, fluid_thread_func_t func, void *data, int prio_level, int detach)
+new_fluid_thread(const char *name, fluid_thread_func_t func, void *data, int prio_level, int detach)
{
- GThread *thread;
- fluid_thread_info_t *info;
- GError *err = NULL;
+ GThread *thread;
+ fluid_thread_info_t *info;
+ GError *err = NULL;
- g_return_val_if_fail (func != NULL, NULL);
+ g_return_val_if_fail(func != NULL, NULL);
#if OLD_GLIB_THREAD_API
- /* 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);
-#endif
-
- if (prio_level > 0)
- {
- info = FLUID_NEW (fluid_thread_info_t);
- if (!info)
+ /* 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())
{
- FLUID_LOG(FLUID_ERR, "Out of memory");
- return NULL;
+ g_thread_init(NULL);
}
- info->func = func;
- info->data = data;
- info->prio_level = prio_level;
+#endif
+
+ if(prio_level > 0)
+ {
+ info = FLUID_NEW(fluid_thread_info_t);
+
+ if(!info)
+ {
+ FLUID_LOG(FLUID_ERR, "Out of memory");
+ return NULL;
+ }
+
+ info->func = func;
+ info->data = data;
+ info->prio_level = prio_level;
#if NEW_GLIB_THREAD_API
- thread = g_thread_try_new (name, fluid_thread_high_prio, info, &err);
+ thread = g_thread_try_new(name, fluid_thread_high_prio, info, &err);
#else
- thread = g_thread_create (fluid_thread_high_prio, info, detach == FALSE, &err);
+ thread = g_thread_create(fluid_thread_high_prio, info, detach == FALSE, &err);
#endif
- }
+ }
+
#if NEW_GLIB_THREAD_API
- else thread = g_thread_try_new (name, (GThreadFunc)func, data, &err);
+ else
+ {
+ thread = g_thread_try_new(name, (GThreadFunc)func, data, &err);
+ }
+
#else
- else thread = g_thread_create ((GThreadFunc)func, data, detach == FALSE, &err);
+ else
+ {
+ thread = g_thread_create((GThreadFunc)func, data, detach == FALSE, &err);
+ }
+
#endif
- if (!thread)
- {
- FLUID_LOG(FLUID_ERR, "Failed to create the thread: %s",
- fluid_gerror_message (err));
- g_clear_error (&err);
- return NULL;
- }
+ if(!thread)
+ {
+ FLUID_LOG(FLUID_ERR, "Failed to create the thread: %s",
+ fluid_gerror_message(err));
+ g_clear_error(&err);
+ return NULL;
+ }
#if NEW_GLIB_THREAD_API
- if (detach) g_thread_unref (thread); // Release thread reference, if caller wants to detach
+
+ if(detach)
+ {
+ g_thread_unref(thread); // Release thread reference, if caller wants to detach
+ }
+
#endif
- return thread;
+ return thread;
}
/**
* @param thread Thread to free
*/
void
-delete_fluid_thread(fluid_thread_t* thread)
+delete_fluid_thread(fluid_thread_t *thread)
{
- /* Threads free themselves when they quit, nothing to do */
+ /* Threads free themselves when they quit, nothing to do */
}
/**
* @return FLUID_OK
*/
int
-fluid_thread_join(fluid_thread_t* thread)
+fluid_thread_join(fluid_thread_t *thread)
{
- g_thread_join (thread);
+ g_thread_join(thread);
- return FLUID_OK;
+ return FLUID_OK;
}
-static void
-fluid_timer_run (void *data)
+static fluid_thread_return_t
+fluid_timer_run(void *data)
{
- fluid_timer_t *timer;
- int count = 0;
- int cont;
- long start;
- long delay;
+ 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();
- timer = (fluid_timer_t *)data;
+ while(timer->cont)
+ {
+ cont = (*timer->callback)(timer->data, fluid_curtime() - start);
- /* keep track of the start time for absolute positioning */
- start = fluid_curtime ();
+ count++;
- while (timer->cont)
- {
- cont = (*timer->callback)(timer->data, fluid_curtime() - start);
+ if(!cont)
+ {
+ break;
+ }
- 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);
- /* 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);
- }
+ if(delay > 0)
+ {
+ fluid_msleep(delay);
+ }
+ }
- FLUID_LOG (FLUID_DBG, "Timer thread finished");
+ FLUID_LOG(FLUID_DBG, "Timer thread finished");
- if (timer->auto_destroy)
- FLUID_FREE (timer);
+ if(timer->auto_destroy)
+ {
+ FLUID_FREE(timer);
+ }
- return;
+ return FLUID_THREAD_RETURN_VALUE;
}
-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 *
+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_timer_t *timer;
- timer = FLUID_NEW (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 = TRUE ;
- timer->thread = NULL;
- timer->auto_destroy = auto_destroy;
-
- if (new_thread)
- {
- timer->thread = new_fluid_thread ("timer", fluid_timer_run, timer, high_priority
- ? FLUID_SYS_TIMER_HIGH_PRIO_LEVEL : 0, FALSE);
- if (!timer->thread)
+ 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("timer", fluid_timer_run, timer, high_priority
+ ? FLUID_SYS_TIMER_HIGH_PRIO_LEVEL : 0, FALSE);
+
+ if(!timer->thread)
+ {
+ FLUID_FREE(timer);
+ return NULL;
+ }
+ }
+ else
{
- FLUID_FREE (timer);
- return NULL;
+ fluid_timer_run(timer); /* Run directly, instead of as a separate thread */
+
+ if(auto_destroy)
+ {
+ /* do NOT return freed memory */
+ return NULL;
+ }
}
- }
- else fluid_timer_run (timer); /* Run directly, instead of as a separate thread */
- return timer;
+ return timer;
}
-int
-delete_fluid_timer (fluid_timer_t *timer)
+void
+delete_fluid_timer(fluid_timer_t *timer)
{
- int auto_destroy = timer->auto_destroy;
+ int auto_destroy;
+ fluid_return_if_fail(timer != NULL);
- timer->cont = 0;
- fluid_timer_join (timer);
+ auto_destroy = timer->auto_destroy;
- /* Shouldn't access timer now if auto_destroy enabled, since it has been destroyed */
+ timer->cont = 0;
+ fluid_timer_join(timer);
- if (!auto_destroy) FLUID_FREE (timer);
+ /* Shouldn't access timer now if auto_destroy enabled, since it has been destroyed */
- return FLUID_OK;
+ if(!auto_destroy)
+ {
+ FLUID_FREE(timer);
+ }
}
int
-fluid_timer_join (fluid_timer_t *timer)
+fluid_timer_join(fluid_timer_t *timer)
{
- int auto_destroy;
+ int auto_destroy;
- if (timer->thread)
- {
- auto_destroy = timer->auto_destroy;
- fluid_thread_join (timer->thread);
+ if(timer->thread)
+ {
+ auto_destroy = timer->auto_destroy;
+ fluid_thread_join(timer->thread);
- if (!auto_destroy) timer->thread = NULL;
- }
+ if(!auto_destroy)
+ {
+ timer->thread = NULL;
+ }
+ }
- return FLUID_OK;
+ return FLUID_OK;
}
* @return Standard in stream.
*/
fluid_istream_t
-fluid_get_stdin (void)
+fluid_get_stdin(void)
{
- return STDIN_FILENO;
+ return STDIN_FILENO;
}
/**
* @return Standard out stream.
*/
fluid_ostream_t
-fluid_get_stdout (void)
+fluid_get_stdout(void)
{
- return STDOUT_FILENO;
+ return STDOUT_FILENO;
}
/**
* @return 0 if end-of-stream, -1 if error, non zero otherwise
*/
int
-fluid_istream_readline (fluid_istream_t in, fluid_ostream_t out, char* prompt,
- char* buf, int len)
+fluid_istream_readline(fluid_istream_t in, fluid_ostream_t out, char *prompt,
+ char *buf, int len)
{
#if WITH_READLINE
- if (in == fluid_get_stdin ())
- {
- char *line;
- line = readline (prompt);
+ if(in == fluid_get_stdin())
+ {
+ char *line;
- if (line == NULL)
- return -1;
+ line = readline(prompt);
- snprintf(buf, len, "%s", line);
- buf[len - 1] = 0;
+ if(line == NULL)
+ {
+ return -1;
+ }
- free(line);
- return 1;
- }
- else
+ FLUID_SNPRINTF(buf, len, "%s", line);
+ buf[len - 1] = 0;
+
+ free(line);
+ return 1;
+ }
+ else
#endif
- {
- fluid_ostream_printf (out, "%s", prompt);
- return fluid_istream_gets (in, buf, len);
- }
+ {
+ fluid_ostream_printf(out, "%s", prompt);
+ return fluid_istream_gets(in, buf, len);
+ }
}
/**
* @return 1 if a line was read, 0 on end of stream, -1 on error
*/
static int
-fluid_istream_gets (fluid_istream_t in, char* buf, int len)
+fluid_istream_gets(fluid_istream_t in, char *buf, int len)
{
- char c;
- int n;
+ char c;
+ int n;
- buf[len - 1] = 0;
+ buf[len - 1] = 0;
- while (--len > 0)
- {
+ while(--len > 0)
+ {
#ifndef WIN32
- n = read(in, &c, 1);
- if (n == -1) return -1;
+ n = read(in, &c, 1);
+
+ if(n == -1)
+ {
+ return -1;
+ }
+
#else
- /* Handle read differently depending on if its a socket or file descriptor */
- if (!(in & WIN32_SOCKET_FLAG))
- {
- n = read(in, &c, 1);
- if (n == -1) return -1;
- }
- else
- {
- n = recv(in & ~WIN32_SOCKET_FLAG, &c, 1, 0);
- if (n == SOCKET_ERROR) return -1;
- }
-#endif
- if (n == 0)
- {
- *buf++ = 0;
- return 0;
- }
+ /* Handle read differently depending on if its a socket or file descriptor */
+ if(!(in & FLUID_SOCKET_FLAG))
+ {
+ n = read(in, &c, 1);
+
+ if(n == -1)
+ {
+ return -1;
+ }
+ }
+ else
+ {
+ n = recv(in & ~FLUID_SOCKET_FLAG, &c, 1, 0);
+
+ if(n == SOCKET_ERROR)
+ {
+ return -1;
+ }
+ }
- if ((c == '\n'))
- {
- *buf++ = 0;
- return 1;
- }
+#endif
- /* Store all characters excluding CR */
- if (c != '\r') *buf++ = c;
- }
+ if(n == 0)
+ {
+ *buf = 0;
+ return 0;
+ }
+
+ if(c == '\n')
+ {
+ *buf = 0;
+ return 1;
+ }
+
+ /* Store all characters excluding CR */
+ if(c != '\r')
+ {
+ *buf++ = c;
+ }
+ }
- return -1;
+ return -1;
}
/**
* @return Number of bytes written or -1 on error
*/
int
-fluid_ostream_printf (fluid_ostream_t out, char* format, ...)
+fluid_ostream_printf(fluid_ostream_t out, const char *format, ...)
{
- char buf[4096];
- va_list args;
- int len;
+ char buf[4096];
+ va_list args;
+ int len;
- va_start (args, format);
- len = vsnprintf (buf, 4095, format, args);
- va_end (args);
+ va_start(args, format);
+ len = FLUID_VSNPRINTF(buf, 4095, format, args);
+ va_end(args);
- if (len == 0)
- {
- return 0;
- }
+ if(len == 0)
+ {
+ return 0;
+ }
- if (len < 0)
- {
- printf("fluid_ostream_printf: buffer overflow");
- return -1;
- }
+ if(len < 0)
+ {
+ printf("fluid_ostream_printf: buffer overflow");
+ return -1;
+ }
- buf[4095] = 0;
+ buf[4095] = 0;
#ifndef WIN32
- return write (out, buf, strlen (buf));
+ return write(out, buf, FLUID_STRLEN(buf));
#else
- {
- int retval;
+ {
+ int retval;
- /* Handle write differently depending on if its a socket or file descriptor */
- if (!(out & WIN32_SOCKET_FLAG))
- return write(out, buf, strlen (buf));
+ /* Handle write differently depending on if its a socket or file descriptor */
+ if(!(out & FLUID_SOCKET_FLAG))
+ {
+ return write(out, buf, FLUID_STRLEN(buf));
+ }
- /* Socket */
- retval = send (out & ~WIN32_SOCKET_FLAG, buf, strlen (buf), 0);
+ /* Socket */
+ retval = send(out & ~FLUID_SOCKET_FLAG, buf, FLUID_STRLEN(buf), 0);
- return retval != SOCKET_ERROR ? retval : -1;
- }
+ return retval != SOCKET_ERROR ? retval : -1;
+ }
#endif
}
-#if 0 // Ardour says: no, thanks
+#ifdef NETWORK_SUPPORT
+
int fluid_server_socket_join(fluid_server_socket_t *server_socket)
{
- return fluid_thread_join (server_socket->thread);
+ return fluid_thread_join(server_socket->thread);
}
+static int fluid_socket_init(void)
+{
+#ifdef _WIN32
+ WSADATA wsaData;
+ int res = WSAStartup(MAKEWORD(2, 2), &wsaData);
-#ifndef WIN32 // Not win32?
-
-#define SOCKET_ERROR -1
+ if(res != 0)
+ {
+ FLUID_LOG(FLUID_ERR, "Server socket creation error: WSAStartup failed: %d", res);
+ return FLUID_FAILED;
+ }
-fluid_istream_t fluid_socket_get_istream (fluid_socket_t sock)
-{
- return sock;
-}
+#endif
-fluid_ostream_t fluid_socket_get_ostream (fluid_socket_t sock)
-{
- return sock;
+ return FLUID_OK;
}
-void fluid_socket_close(fluid_socket_t sock)
+static void fluid_socket_cleanup(void)
{
- if (sock != INVALID_SOCKET)
- close (sock);
+#ifdef _WIN32
+ WSACleanup();
+#endif
}
-static void
-fluid_server_socket_run (void *data)
+static int fluid_socket_get_error(void)
{
- fluid_server_socket_t *server_socket = (fluid_server_socket_t *)data;
- fluid_socket_t client_socket;
-#ifdef IPV6
- struct sockaddr_in6 addr;
- char straddr[INET6_ADDRSTRLEN];
+#ifdef _WIN32
+ return (int)WSAGetLastError();
#else
- struct sockaddr_in addr;
- char straddr[INET_ADDRSTRLEN];
+ return errno;
#endif
- socklen_t addrlen = sizeof (addr);
- int retval;
- FLUID_MEMSET((char *)&addr, 0, sizeof(addr));
-
- FLUID_LOG (FLUID_DBG, "Server listening for connections");
+}
- while (server_socket->cont)
- {
- client_socket = accept (server_socket->socket, (struct sockaddr *)&addr, &addrlen);
+fluid_istream_t fluid_socket_get_istream(fluid_socket_t sock)
+{
+ return sock | FLUID_SOCKET_FLAG;
+}
- FLUID_LOG (FLUID_DBG, "New client connection");
+fluid_ostream_t fluid_socket_get_ostream(fluid_socket_t sock)
+{
+ return sock | FLUID_SOCKET_FLAG;
+}
- if (client_socket == INVALID_SOCKET)
+void fluid_socket_close(fluid_socket_t sock)
+{
+ if(sock != INVALID_SOCKET)
{
- if (server_socket->cont)
- FLUID_LOG(FLUID_ERR, "Failed to accept connection");
-
- server_socket->cont = 0;
- return;
- } else {
-#ifdef IPV6
- inet_ntop(AF_INET6, &addr.sin6_addr, straddr, sizeof(straddr));
+#ifdef _WIN32
+ closesocket(sock);
+
#else
- inet_ntop(AF_INET, &addr.sin_addr, straddr, sizeof(straddr));
+ close(sock);
#endif
- retval = server_socket->func (server_socket->data, client_socket,
- straddr);
-
- if (retval != 0)
- fluid_socket_close(client_socket);
}
- }
-
- FLUID_LOG(FLUID_DBG, "Server closing");
}
-fluid_server_socket_t*
-new_fluid_server_socket(int port, fluid_server_func_t func, void* data)
+static fluid_thread_return_t fluid_server_socket_run(void *data)
{
- fluid_server_socket_t* server_socket;
-#ifdef IPV6
- struct sockaddr_in6 addr;
+ fluid_server_socket_t *server_socket = (fluid_server_socket_t *)data;
+ fluid_socket_t client_socket;
+#ifdef IPV6_SUPPORT
+ struct sockaddr_in6 addr;
#else
- struct sockaddr_in addr;
+ struct sockaddr_in addr;
#endif
- fluid_socket_t sock;
-
- g_return_val_if_fail (func != NULL, NULL);
-#ifdef IPV6
- sock = socket(AF_INET6, SOCK_STREAM, 0);
- if (sock == INVALID_SOCKET) {
- FLUID_LOG(FLUID_ERR, "Failed to create server socket");
- return NULL;
- }
- FLUID_MEMSET((char *)&addr, 0, sizeof(struct sockaddr_in6));
- addr.sin6_family = AF_INET6;
- addr.sin6_addr = in6addr_any;
- addr.sin6_port = htons(port);
+#ifdef HAVE_INETNTOP
+#ifdef IPV6_SUPPORT
+ char straddr[INET6_ADDRSTRLEN];
#else
+ char straddr[INET_ADDRSTRLEN];
+#endif /* IPV6_SUPPORT */
+#endif /* HAVE_INETNTOP */
- sock = socket(AF_INET, SOCK_STREAM, 0);
- if (sock == INVALID_SOCKET) {
- FLUID_LOG(FLUID_ERR, "Failed to create server socket");
- return NULL;
- }
-
- FLUID_MEMSET((char *)&addr, 0, sizeof(struct sockaddr_in));
- addr.sin_family = AF_INET;
- addr.sin_addr.s_addr = htonl(INADDR_ANY);
- addr.sin_port = htons(port);
-#endif
- if (bind(sock, (const struct sockaddr *) &addr, sizeof(addr)) == SOCKET_ERROR) {
- FLUID_LOG(FLUID_ERR, "Failed to bind server socket");
- fluid_socket_close(sock);
- return NULL;
- }
-
- if (listen(sock, 10) == SOCKET_ERROR) {
- FLUID_LOG(FLUID_ERR, "Failed listen on server socket");
- fluid_socket_close(sock);
- return NULL;
- }
-
- server_socket = FLUID_NEW(fluid_server_socket_t);
- if (server_socket == NULL) {
- FLUID_LOG(FLUID_ERR, "Out of memory");
- fluid_socket_close(sock);
- return NULL;
- }
+ socklen_t addrlen = sizeof(addr);
+ int r;
+ FLUID_MEMSET((char *)&addr, 0, sizeof(addr));
- server_socket->socket = sock;
- server_socket->func = func;
- server_socket->data = data;
- server_socket->cont = 1;
-
- server_socket->thread = new_fluid_thread("server", fluid_server_socket_run, server_socket,
- 0, FALSE);
- if (server_socket->thread == NULL) {
- FLUID_FREE(server_socket);
- fluid_socket_close(sock);
- return NULL;
- }
-
- return server_socket;
-}
-
-int delete_fluid_server_socket(fluid_server_socket_t* server_socket)
-{
- server_socket->cont = 0;
- if (server_socket->socket != INVALID_SOCKET) {
- fluid_socket_close(server_socket->socket);
- }
- if (server_socket->thread) {
- delete_fluid_thread(server_socket->thread);
- }
- FLUID_FREE(server_socket);
- return FLUID_OK;
-}
-
-
-#else // Win32 is "special"
+ FLUID_LOG(FLUID_DBG, "Server listening for connections");
+ while(server_socket->cont)
+ {
+ client_socket = accept(server_socket->socket, (struct sockaddr *)&addr, &addrlen);
+
+ FLUID_LOG(FLUID_DBG, "New client connection");
+
+ if(client_socket == INVALID_SOCKET)
+ {
+ if(server_socket->cont)
+ {
+ FLUID_LOG(FLUID_ERR, "Failed to accept connection: %ld", fluid_socket_get_error());
+ }
+
+ server_socket->cont = 0;
+ return FLUID_THREAD_RETURN_VALUE;
+ }
+ else
+ {
+#ifdef HAVE_INETNTOP
+
+#ifdef IPV6_SUPPORT
+ inet_ntop(AF_INET6, &addr.sin6_addr, straddr, sizeof(straddr));
+#else
+ inet_ntop(AF_INET, &addr.sin_addr, straddr, sizeof(straddr));
+#endif
-#ifndef WIN32_LEAN_AND_MEAN
-#define WIN32_LEAN_AND_MEAN
+ r = server_socket->func(server_socket->data, client_socket,
+ straddr);
+#else
+ r = server_socket->func(server_socket->data, client_socket,
+ inet_ntoa(addr.sin_addr));
#endif
-fluid_istream_t fluid_socket_get_istream (fluid_socket_t sock)
-{
- return sock | WIN32_SOCKET_FLAG;
-}
+ if(r != 0)
+ {
+ fluid_socket_close(client_socket);
+ }
+ }
+ }
-fluid_ostream_t fluid_socket_get_ostream (fluid_socket_t sock)
-{
- return sock | WIN32_SOCKET_FLAG;
-}
+ FLUID_LOG(FLUID_DBG, "Server closing");
-void fluid_socket_close (fluid_socket_t sock)
-{
- if (sock != INVALID_SOCKET)
- closesocket (sock);
+ return FLUID_THREAD_RETURN_VALUE;
}
-static void fluid_server_socket_run (void *data)
+fluid_server_socket_t *
+new_fluid_server_socket(int port, fluid_server_func_t func, void *data)
{
- fluid_server_socket_t *server_socket = (fluid_server_socket_t *)data;
- fluid_socket_t client_socket;
-#ifdef IPV6
- struct sockaddr_in6 addr;
- char straddr[INET6_ADDRSTRLEN];
+ fluid_server_socket_t *server_socket;
+#ifdef IPV6_SUPPORT
+ struct sockaddr_in6 addr;
#else
- struct sockaddr_in addr;
- char straddr[INET_ADDRSTRLEN];
+ struct sockaddr_in addr;
#endif
- socklen_t addrlen = sizeof (addr);
- int r;
- FLUID_MEMSET((char *)&addr, 0, sizeof(addr));
- FLUID_LOG(FLUID_DBG, "Server listening for connections");
+ fluid_socket_t sock;
- while (server_socket->cont)
- {
- client_socket = accept (server_socket->socket, (struct sockaddr *)&addr, &addrlen);
+ fluid_return_val_if_fail(func != NULL, NULL);
- FLUID_LOG (FLUID_DBG, "New client connection");
-
- if (client_socket == INVALID_SOCKET)
+ if(fluid_socket_init() != FLUID_OK)
{
- if (server_socket->cont)
- FLUID_LOG (FLUID_ERR, "Failed to accept connection: %ld", WSAGetLastError ());
-
- server_socket->cont = 0;
- return;
+ return NULL;
}
- else
+
+#ifdef IPV6_SUPPORT
+ sock = socket(AF_INET6, SOCK_STREAM, 0);
+
+ if(sock == INVALID_SOCKET)
{
-#ifdef IPV6
- inet_ntop(AF_INET6, &addr.sin6_addr, straddr, sizeof(straddr));
-#else
- inet_ntop(AF_INET, &addr.sin_addr, straddr, sizeof(straddr));
-#endif
- r = server_socket->func (server_socket->data, client_socket,
- straddr);
- if (r != 0)
- fluid_socket_close (client_socket);
+ FLUID_LOG(FLUID_ERR, "Failed to create server socket: %ld", fluid_socket_get_error());
+ fluid_socket_cleanup();
+ return NULL;
}
- }
- FLUID_LOG (FLUID_DBG, "Server closing");
-}
-
-fluid_server_socket_t*
-new_fluid_server_socket(int port, fluid_server_func_t func, void* data)
-{
- fluid_server_socket_t* server_socket;
-#ifdef IPV6
- struct sockaddr_in6 addr;
+ FLUID_MEMSET(&addr, 0, sizeof(addr));
+ addr.sin6_family = AF_INET6;
+ addr.sin6_port = htons((uint16_t)port);
+ addr.sin6_addr = in6addr_any;
#else
- struct sockaddr_in addr;
-#endif
-
- fluid_socket_t sock;
- WSADATA wsaData;
- int retval;
- g_return_val_if_fail (func != NULL, NULL);
+ sock = socket(AF_INET, SOCK_STREAM, 0);
- // Win32 requires initialization of winsock
- retval = WSAStartup (MAKEWORD (2,2), &wsaData);
+ if(sock == INVALID_SOCKET)
+ {
+ FLUID_LOG(FLUID_ERR, "Failed to create server socket: %ld", fluid_socket_get_error());
+ fluid_socket_cleanup();
+ return NULL;
+ }
- if (retval != 0)
- {
- FLUID_LOG(FLUID_ERR, "Server socket creation error: WSAStartup failed: %d", retval);
- return NULL;
- }
-#ifdef IPV6
- sock = socket (AF_INET6, SOCK_STREAM, 0);
- if (sock == INVALID_SOCKET)
- {
- FLUID_LOG (FLUID_ERR, "Failed to create server socket: %ld", WSAGetLastError ());
- WSACleanup ();
- return NULL;
- }
- addr.sin6_family = AF_INET6;
- addr.sin6_port = htons (port);
- addr.sin6_addr = in6addr_any;
-#else
+ FLUID_MEMSET(&addr, 0, sizeof(addr));
+ addr.sin_family = AF_INET;
+ addr.sin_port = htons((uint16_t)port);
+ addr.sin_addr.s_addr = htonl(INADDR_ANY);
+#endif
- sock = socket (AF_INET, SOCK_STREAM, 0);
+ if(bind(sock, (const struct sockaddr *) &addr, sizeof(addr)) == SOCKET_ERROR)
+ {
+ FLUID_LOG(FLUID_ERR, "Failed to bind server socket: %ld", fluid_socket_get_error());
+ fluid_socket_close(sock);
+ fluid_socket_cleanup();
+ return NULL;
+ }
- if (sock == INVALID_SOCKET)
- {
- FLUID_LOG (FLUID_ERR, "Failed to create server socket: %ld", WSAGetLastError ());
- WSACleanup ();
- return NULL;
- }
+ if(listen(sock, SOMAXCONN) == SOCKET_ERROR)
+ {
+ FLUID_LOG(FLUID_ERR, "Failed to listen on server socket: %ld", fluid_socket_get_error());
+ fluid_socket_close(sock);
+ fluid_socket_cleanup();
+ return NULL;
+ }
- addr.sin_family = AF_INET;
- addr.sin_port = htons (port);
- addr.sin_addr.s_addr = htonl (INADDR_ANY);
-#endif
- retval = bind (sock, (struct sockaddr *)&addr, sizeof (addr));
+ server_socket = FLUID_NEW(fluid_server_socket_t);
- if (retval == SOCKET_ERROR)
- {
- FLUID_LOG (FLUID_ERR, "Failed to bind server socket: %ld", WSAGetLastError ());
- fluid_socket_close (sock);
- WSACleanup ();
- return NULL;
- }
+ if(server_socket == NULL)
+ {
+ FLUID_LOG(FLUID_ERR, "Out of memory");
+ fluid_socket_close(sock);
+ fluid_socket_cleanup();
+ return NULL;
+ }
- if (listen (sock, SOMAXCONN) == SOCKET_ERROR)
- {
- FLUID_LOG (FLUID_ERR, "Failed to listen on server socket: %ld", WSAGetLastError ());
- fluid_socket_close (sock);
- WSACleanup ();
- return NULL;
- }
+ server_socket->socket = sock;
+ server_socket->func = func;
+ server_socket->data = data;
+ server_socket->cont = 1;
- server_socket = FLUID_NEW (fluid_server_socket_t);
+ server_socket->thread = new_fluid_thread("server", fluid_server_socket_run, server_socket,
+ 0, FALSE);
- if (server_socket == NULL)
- {
- FLUID_LOG (FLUID_ERR, "Out of memory");
- fluid_socket_close (sock);
- WSACleanup ();
- return NULL;
- }
-
- server_socket->socket = sock;
- server_socket->func = func;
- server_socket->data = data;
- server_socket->cont = 1;
-
- server_socket->thread = new_fluid_thread("server", fluid_server_socket_run, server_socket,
- 0, FALSE);
- if (server_socket->thread == NULL)
- {
- FLUID_FREE (server_socket);
- fluid_socket_close (sock);
- WSACleanup ();
- return NULL;
- }
+ if(server_socket->thread == NULL)
+ {
+ FLUID_FREE(server_socket);
+ fluid_socket_close(sock);
+ fluid_socket_cleanup();
+ return NULL;
+ }
- return server_socket;
+ return server_socket;
}
-int delete_fluid_server_socket(fluid_server_socket_t *server_socket)
+void delete_fluid_server_socket(fluid_server_socket_t *server_socket)
{
- server_socket->cont = 0;
+ fluid_return_if_fail(server_socket != NULL);
- if (server_socket->socket != INVALID_SOCKET)
- fluid_socket_close (server_socket->socket);
+ server_socket->cont = 0;
- if (server_socket->thread)
- delete_fluid_thread (server_socket->thread);
+ if(server_socket->socket != INVALID_SOCKET)
+ {
+ fluid_socket_close(server_socket->socket);
+ }
- FLUID_FREE (server_socket);
+ if(server_socket->thread)
+ {
+ fluid_thread_join(server_socket->thread);
+ delete_fluid_thread(server_socket->thread);
+ }
- WSACleanup (); // Should be called the same number of times as WSAStartup
+ FLUID_FREE(server_socket);
- return FLUID_OK;
+ // Should be called the same number of times as fluid_socket_init()
+ fluid_socket_cleanup();
}
-#endif
-#endif
+#endif // NETWORK_SUPPORT