Update Fluidsynth to 2.0.1
[ardour.git] / libs / fluidsynth / src / fluid_sys.c
index 328f2556d6238329f68e3b793269d7d498aa1396..c9662f7787d869ee682017b11a8a7a238eeec770 100644 (file)
@@ -3,16 +3,16 @@
  * 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, charbuf, 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.
@@ -116,16 +96,18 @@ int fluid_debug(int level, char * fmt, ...)
  * @return The previously installed function.
  */
 fluid_log_function_t
-fluid_set_log_function(int level, fluid_log_function_t fun, voiddata)
+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;
 }
 
 /**
@@ -135,75 +117,46 @@ fluid_set_log_function(int level, fluid_log_function_t fun, void* data)
  * @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);
 }
 
 /**
@@ -214,22 +167,26 @@ fluid_log_config(void)
  * @return Always returns #FLUID_FAILED
  */
 int
-fluid_log(int level, const charfmt, ...)
+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;
 }
 
 /**
@@ -245,70 +202,77 @@ fluid_log(int level, const char* fmt, ...)
  * @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;
 }
 
 /**
@@ -322,19 +286,23 @@ fluid_error()
 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;
 }
 
 /**
@@ -342,25 +310,43 @@ fluid_is_midifile(const char *filename)
  * @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);
 }
 
 /**
@@ -369,78 +355,121 @@ fluid_is_soundfont(const char *filename)
  */
 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
@@ -480,34 +509,34 @@ fluid_thread_self_set_prio (int prio_level)
  * 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(charexplanation)
+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
@@ -523,47 +552,409 @@ void fluid_clear_fpe_i386 (void)
  */
 
 #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 */
 
 /***************************************************************
  *
@@ -576,25 +967,29 @@ void fluid_profiling_print(void)
 /* 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;
 }
 
 /**
@@ -607,59 +1002,78 @@ fluid_thread_high_prio (gpointer data)
  * @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;
 }
 
 /**
@@ -667,9 +1081,9 @@ new_fluid_thread (const char *name, fluid_thread_func_t func, void *data, int pr
  * @param thread Thread to free
  */
 void
-delete_fluid_thread(fluid_thread_tthread)
+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 */
 }
 
 /**
@@ -678,115 +1092,142 @@ delete_fluid_thread(fluid_thread_t* thread)
  * @return FLUID_OK
  */
 int
-fluid_thread_join(fluid_thread_tthread)
+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;
 }
 
 
@@ -801,9 +1242,9 @@ fluid_timer_join (fluid_timer_t *timer)
  * @return Standard in stream.
  */
 fluid_istream_t
-fluid_get_stdin (void)
+fluid_get_stdin(void)
 {
-  return STDIN_FILENO;
+    return STDIN_FILENO;
 }
 
 /**
@@ -811,9 +1252,9 @@ fluid_get_stdin (void)
  * @return Standard out stream.
  */
 fluid_ostream_t
-fluid_get_stdout (void)
+fluid_get_stdout(void)
 {
-  return STDOUT_FILENO;
+    return STDOUT_FILENO;
 }
 
 /**
@@ -821,31 +1262,34 @@ fluid_get_stdout (void)
  * @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);
+    }
 }
 
 /**
@@ -856,49 +1300,67 @@ fluid_istream_readline (fluid_istream_t in, fluid_ostream_t out, char* prompt,
  * @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;
 }
 
 /**
@@ -909,390 +1371,297 @@ fluid_istream_gets (fluid_istream_t in, char* buf, int len)
  * @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