Path: blob/master/libs/fluidsynth/src/utils/fluid_sys.h
4396 views
/* FluidSynth - A Software Synthesizer1*2* Copyright (C) 2003 Peter Hanappe and others.3*4* This library is free software; you can redistribute it and/or5* modify it under the terms of the GNU Lesser General Public License6* as published by the Free Software Foundation; either version 2.1 of7* the License, or (at your option) any later version.8*9* This library is distributed in the hope that it will be useful, but10* WITHOUT ANY WARRANTY; without even the implied warranty of11* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU12* Lesser General Public License for more details.13*14* You should have received a copy of the GNU Lesser General Public15* License along with this library; if not, write to the Free16* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA17* 02110-1301, USA18*/192021/*22* @file fluid_sys.h23*24* This header contains a bunch of (mostly) system and machine25* dependent functions:26*27* - timers28* - current time in milliseconds and microseconds29* - debug logging30* - profiling31* - memory locking32* - checking for floating point exceptions33*34* fluidsynth's wrapper OSAL so to say; include it in .c files, be careful to include35* it in fluidsynth's private header files (see comment in fluid_coreaudio.c)36*/3738#ifndef _FLUID_SYS_H39#define _FLUID_SYS_H4041#include "fluidsynth_priv.h"4243#if HAVE_MATH_H44#include <math.h>45#endif4647#if HAVE_ERRNO_H48#include <errno.h>49#endif5051#if HAVE_STDARG_H52#include <stdarg.h>53#endif5455#if HAVE_UNISTD_H56#include <unistd.h>57#endif5859#if HAVE_FCNTL_H60#include <fcntl.h>61#endif6263#if HAVE_SYS_MMAN_H64#include <sys/mman.h>65#endif6667#if HAVE_SYS_TYPES_H68#include <sys/types.h>69#endif7071#if HAVE_SYS_STAT_H72#include <sys/stat.h>73#endif7475#if HAVE_SYS_TIME_H76#include <sys/time.h>77#endif7879#if HAVE_SYS_SOCKET_H80#include <sys/socket.h>81#endif8283#if HAVE_NETINET_IN_H84#include <netinet/in.h>85#endif8687#if HAVE_NETINET_TCP_H88#include <netinet/tcp.h>89#endif9091#if HAVE_ARPA_INET_H92#include <arpa/inet.h>93#endif9495#if HAVE_LIMITS_H96#include <limits.h>97#endif9899#if HAVE_OPENMP100#include <omp.h>101#endif102103#if HAVE_IO_H104#include <io.h> // _open(), _close(), read(), write() on windows105#endif106107#if HAVE_SIGNAL_H108#include <signal.h>109#endif110111/** Integer types */112#if HAVE_STDINT_H113#include <stdint.h>114115#else116117/* Assume GLIB types */118typedef gint8 int8_t;119typedef guint8 uint8_t;120typedef gint16 int16_t;121typedef guint16 uint16_t;122typedef gint32 int32_t;123typedef guint32 uint32_t;124typedef gint64 int64_t;125typedef guint64 uint64_t;126typedef guintptr uintptr_t;127typedef gintptr intptr_t;128129#endif130131/*132* CYGWIN has its own version of <windows.h>, which can be133* safely included together with POSIX includes.134* Thanks to this, CYGWIN can also run audio output and MIDI135* input drivers from traditional interfaces of Windows.136*/137#if defined(__CYGWIN__) && HAVE_WINDOWS_H138#include <windows.h>139#include <wchar.h>140#endif141142#if defined(_WIN32) && HAVE_WINDOWS_H143#include <winsock2.h>144#include <ws2tcpip.h> /* Provides also socklen_t */145146/* WIN32 special defines */147#define STDIN_FILENO 0148#define STDOUT_FILENO 1149#define STDERR_FILENO 2150151#ifdef _MSC_VER152#pragma warning(disable : 4244)153#pragma warning(disable : 4101)154#pragma warning(disable : 4305)155#pragma warning(disable : 4996)156#endif157158#endif159160/* Darwin special defines (taken from config_macosx.h) */161#ifdef DARWIN162# define MACINTOSH163# define __Types__164#endif165166#ifdef LADSPA167#include <gmodule.h>168#endif169170/* #include <glib/gstdio.h> */171172/**173* Macro used for safely accessing a message from a GError and using a default174* message if it is NULL.175* @param err Pointer to a GError to access the message field of.176* @return Message string177*/178#define fluid_gerror_message(err) ((err) ? err->message : "No error details")179180#if defined(_WIN32) || defined(__CYGWIN__)181char* fluid_get_windows_error(void);182#endif183184#define FLUID_INLINE inline185186#define FLUID_VERSION_CHECK(major, minor, patch) ((major<<16)|(minor<<8)|(patch))187188/* Integer<->pointer conversion */189#define FLUID_POINTER_TO_UINT(x) ((unsigned int)(uintptr_t)(x))190#define FLUID_UINT_TO_POINTER(x) ((void *)(uintptr_t)(x))191#define FLUID_POINTER_TO_INT(x) ((signed int)(intptr_t)(x))192#define FLUID_INT_TO_POINTER(x) ((void *)(intptr_t)(x))193194/* Endian detection */195#define FLUID_IS_BIG_ENDIAN (G_BYTE_ORDER == G_BIG_ENDIAN)196197#define FLUID_LE32TOH(x) GINT32_FROM_LE(x)198#define FLUID_LE16TOH(x) GINT16_FROM_LE(x)199200#if FLUID_IS_BIG_ENDIAN201#define FLUID_FOURCC(_a, _b, _c, _d) \202(uint32_t)(((uint32_t)(_a) << 24) | ((uint32_t)(_b) << 16) | ((uint32_t)(_c) << 8) | (uint32_t)(_d))203#else204#define FLUID_FOURCC(_a, _b, _c, _d) \205(uint32_t)(((uint32_t)(_d) << 24) | ((uint32_t)(_c) << 16) | ((uint32_t)(_b) << 8) | (uint32_t)(_a))206#endif207208/*209* Utility functions210*/211char *fluid_strtok(char **str, char *delim);212213#define FLUID_FILE_TEST_EXISTS G_FILE_TEST_EXISTS214#define FLUID_FILE_TEST_IS_REGULAR G_FILE_TEST_IS_REGULAR215#define fluid_file_test(path, flags) g_file_test(path, flags)216217#define fluid_shell_parse_argv(command_line, argcp, argvp) g_shell_parse_argv(command_line, argcp, argvp, NULL)218#define fluid_strfreev g_strfreev219220#if defined(__OS2__)221#define INCL_DOS222#include <os2.h>223224/* Define socklen_t if not provided */225#if !HAVE_SOCKLEN_T226typedef int socklen_t;227#endif228#endif229230/**231Time functions232233*/234235unsigned int fluid_curtime(void);236double fluid_utime(void);237238239/**240Timers241242*/243244/* if the callback function returns 1 the timer will continue; if it245returns 0 it will stop */246typedef int (*fluid_timer_callback_t)(void *data, unsigned int msec);247248typedef struct _fluid_timer_t fluid_timer_t;249250fluid_timer_t *new_fluid_timer(int msec, fluid_timer_callback_t callback,251void *data, int new_thread, int auto_destroy,252int high_priority);253254void delete_fluid_timer(fluid_timer_t *timer);255int fluid_timer_join(fluid_timer_t *timer);256int fluid_timer_stop(fluid_timer_t *timer);257int fluid_timer_is_running(const fluid_timer_t *timer);258long fluid_timer_get_interval(const fluid_timer_t * timer);259260// Macros to use for pre-processor if statements to test which Glib thread API we have (pre or post 2.32)261#define NEW_GLIB_THREAD_API GLIB_CHECK_VERSION(2,32,0)262#define OLD_GLIB_THREAD_API !GLIB_CHECK_VERSION(2,32,0)263264/* Muteces */265266#if NEW_GLIB_THREAD_API267268/* glib 2.32 and newer */269270/* Regular mutex */271typedef GMutex fluid_mutex_t;272#define FLUID_MUTEX_INIT { 0 }273#define fluid_mutex_init(_m) g_mutex_init (&(_m))274#define fluid_mutex_destroy(_m) g_mutex_clear (&(_m))275#define fluid_mutex_lock(_m) g_mutex_lock(&(_m))276#define fluid_mutex_unlock(_m) g_mutex_unlock(&(_m))277278/* Recursive lock capable mutex */279typedef GRecMutex fluid_rec_mutex_t;280#define fluid_rec_mutex_init(_m) g_rec_mutex_init(&(_m))281#define fluid_rec_mutex_destroy(_m) g_rec_mutex_clear(&(_m))282#define fluid_rec_mutex_lock(_m) g_rec_mutex_lock(&(_m))283#define fluid_rec_mutex_unlock(_m) g_rec_mutex_unlock(&(_m))284285/* Dynamically allocated mutex suitable for fluid_cond_t use */286typedef GMutex fluid_cond_mutex_t;287#define fluid_cond_mutex_lock(m) g_mutex_lock(m)288#define fluid_cond_mutex_unlock(m) g_mutex_unlock(m)289290static FLUID_INLINE fluid_cond_mutex_t *291new_fluid_cond_mutex(void)292{293GMutex *mutex;294mutex = g_new(GMutex, 1);295g_mutex_init(mutex);296return (mutex);297}298299static FLUID_INLINE void300delete_fluid_cond_mutex(fluid_cond_mutex_t *m)301{302fluid_return_if_fail(m != NULL);303g_mutex_clear(m);304g_free(m);305}306307/* Thread condition signaling */308typedef GCond fluid_cond_t;309#define fluid_cond_signal(cond) g_cond_signal(cond)310#define fluid_cond_broadcast(cond) g_cond_broadcast(cond)311#define fluid_cond_wait(cond, mutex) g_cond_wait(cond, mutex)312313static FLUID_INLINE fluid_cond_t *314new_fluid_cond(void)315{316GCond *cond;317cond = g_new(GCond, 1);318g_cond_init(cond);319return (cond);320}321322static FLUID_INLINE void323delete_fluid_cond(fluid_cond_t *cond)324{325fluid_return_if_fail(cond != NULL);326g_cond_clear(cond);327g_free(cond);328}329330/* Thread private data */331332#ifdef _WIN32 /* Wine-specific code */333334typedef DWORD fluid_private_t;335#define fluid_private_init(_priv) (_priv = TlsAlloc())336#define fluid_private_free(_priv) TlsFree(_priv);337#define fluid_private_get(_priv) TlsGetValue(_priv)338#define fluid_private_set(_priv, _data) TlsSetValue(_priv, _data)339340#else /* Wine-specific code */341342typedef GPrivate fluid_private_t;343#define fluid_private_init(_priv) memset (&_priv, 0, sizeof (_priv))344#define fluid_private_free(_priv)345#define fluid_private_get(_priv) g_private_get(&(_priv))346#define fluid_private_set(_priv, _data) g_private_set(&(_priv), _data)347348#endif /* Wine-specific code */349350#else351352/* glib prior to 2.32 */353354/* Regular mutex */355typedef GStaticMutex fluid_mutex_t;356#define FLUID_MUTEX_INIT G_STATIC_MUTEX_INIT357#define fluid_mutex_destroy(_m) g_static_mutex_free(&(_m))358#define fluid_mutex_lock(_m) g_static_mutex_lock(&(_m))359#define fluid_mutex_unlock(_m) g_static_mutex_unlock(&(_m))360361#define fluid_mutex_init(_m) do { \362if (!g_thread_supported ()) g_thread_init (NULL); \363g_static_mutex_init (&(_m)); \364} while(0)365366/* Recursive lock capable mutex */367typedef GStaticRecMutex fluid_rec_mutex_t;368#define fluid_rec_mutex_destroy(_m) g_static_rec_mutex_free(&(_m))369#define fluid_rec_mutex_lock(_m) g_static_rec_mutex_lock(&(_m))370#define fluid_rec_mutex_unlock(_m) g_static_rec_mutex_unlock(&(_m))371372#define fluid_rec_mutex_init(_m) do { \373if (!g_thread_supported ()) g_thread_init (NULL); \374g_static_rec_mutex_init (&(_m)); \375} while(0)376377/* Dynamically allocated mutex suitable for fluid_cond_t use */378typedef GMutex fluid_cond_mutex_t;379#define delete_fluid_cond_mutex(m) g_mutex_free(m)380#define fluid_cond_mutex_lock(m) g_mutex_lock(m)381#define fluid_cond_mutex_unlock(m) g_mutex_unlock(m)382383static FLUID_INLINE fluid_cond_mutex_t *384new_fluid_cond_mutex(void)385{386if(!g_thread_supported())387{388g_thread_init(NULL);389}390391return g_mutex_new();392}393394/* Thread condition signaling */395typedef GCond fluid_cond_t;396fluid_cond_t *new_fluid_cond(void);397#define delete_fluid_cond(cond) g_cond_free(cond)398#define fluid_cond_signal(cond) g_cond_signal(cond)399#define fluid_cond_broadcast(cond) g_cond_broadcast(cond)400#define fluid_cond_wait(cond, mutex) g_cond_wait(cond, mutex)401402/* Thread private data */403typedef GStaticPrivate fluid_private_t;404#define fluid_private_get(_priv) g_static_private_get(&(_priv))405#define fluid_private_set(_priv, _data) g_static_private_set(&(_priv), _data, NULL)406#define fluid_private_free(_priv) g_static_private_free(&(_priv))407408#define fluid_private_init(_priv) do { \409if (!g_thread_supported ()) g_thread_init (NULL); \410g_static_private_init (&(_priv)); \411} while(0)412413#endif414415416/* Atomic operations */417418#define fluid_atomic_int_inc(_pi) g_atomic_int_inc(_pi)419#define fluid_atomic_int_get(_pi) g_atomic_int_get(_pi)420#define fluid_atomic_int_set(_pi, _val) g_atomic_int_set(_pi, _val)421#define fluid_atomic_int_dec_and_test(_pi) g_atomic_int_dec_and_test(_pi)422#define fluid_atomic_int_compare_and_exchange(_pi, _old, _new) \423g_atomic_int_compare_and_exchange(_pi, _old, _new)424425#if GLIB_MAJOR_VERSION > 2 || (GLIB_MAJOR_VERSION == 2 && GLIB_MINOR_VERSION >= 30)426#define fluid_atomic_int_exchange_and_add(_pi, _add) \427g_atomic_int_add(_pi, _add)428#define fluid_atomic_int_add(_pi, _add) \429g_atomic_int_add(_pi, _add)430#else431#define fluid_atomic_int_exchange_and_add(_pi, _add) \432g_atomic_int_exchange_and_add(_pi, _add)433#define fluid_atomic_int_add(_pi, _add) \434g_atomic_int_exchange_and_add(_pi, _add)435#endif436437#define fluid_atomic_pointer_get(_pp) g_atomic_pointer_get(_pp)438#define fluid_atomic_pointer_set(_pp, val) g_atomic_pointer_set(_pp, val)439#define fluid_atomic_pointer_compare_and_exchange(_pp, _old, _new) \440g_atomic_pointer_compare_and_exchange(_pp, _old, _new)441442static FLUID_INLINE void443fluid_atomic_float_set(fluid_atomic_float_t *fptr, float val)444{445int32_t ival;446memcpy(&ival, &val, 4);447fluid_atomic_int_set((fluid_atomic_int_t *)fptr, ival);448}449450static FLUID_INLINE float451fluid_atomic_float_get(fluid_atomic_float_t *fptr)452{453int32_t ival;454float fval;455ival = fluid_atomic_int_get((fluid_atomic_int_t *)fptr);456memcpy(&fval, &ival, 4);457return fval;458}459460461/* Threads */462463/* other thread implementations might change this for their needs */464typedef void *fluid_thread_return_t;465/* static return value for thread functions which requires a return value */466#define FLUID_THREAD_RETURN_VALUE (NULL)467468typedef GThread fluid_thread_t;469typedef fluid_thread_return_t (*fluid_thread_func_t)(void *data);470471#define FLUID_THREAD_ID_NULL NULL /* A NULL "ID" value */472#define fluid_thread_id_t GThread * /* Data type for a thread ID */473#define fluid_thread_get_id() g_thread_self() /* Get unique "ID" for current thread */474475fluid_thread_t *new_fluid_thread(const char *name, fluid_thread_func_t func, void *data,476int prio_level, int detach);477void delete_fluid_thread(fluid_thread_t *thread);478void fluid_thread_self_set_prio(int prio_level);479int fluid_thread_join(fluid_thread_t *thread);480481/* Dynamic Module Loading, currently only used by LADSPA subsystem */482#ifdef LADSPA483484typedef GModule fluid_module_t;485486#define fluid_module_open(_name) g_module_open((_name), G_MODULE_BIND_LOCAL)487#define fluid_module_close(_mod) g_module_close(_mod)488#define fluid_module_error() g_module_error()489#define fluid_module_name(_mod) g_module_name(_mod)490#define fluid_module_symbol(_mod, _name, _ptr) g_module_symbol((_mod), (_name), (_ptr))491492#endif /* LADSPA */493494/* Sockets and I/O */495496int fluid_istream_readline(fluid_istream_t in, fluid_ostream_t out, char *prompt, char *buf, int len);497int fluid_ostream_printf(fluid_ostream_t out, const char *format, ...);498499#if defined(_WIN32)500typedef SOCKET fluid_socket_t;501#else502typedef int fluid_socket_t;503#endif504505/* The function should return 0 if no error occurred, non-zero506otherwise. If the function return non-zero, the socket will be507closed by the server. */508typedef int (*fluid_server_func_t)(void *data, fluid_socket_t client_socket, char *addr);509510fluid_server_socket_t *new_fluid_server_socket(int port, fluid_server_func_t func, void *data);511void delete_fluid_server_socket(fluid_server_socket_t *sock);512int fluid_server_socket_join(fluid_server_socket_t *sock);513void fluid_socket_close(fluid_socket_t sock);514fluid_istream_t fluid_socket_get_istream(fluid_socket_t sock);515fluid_ostream_t fluid_socket_get_ostream(fluid_socket_t sock);516517/* File access */518#define fluid_stat(_filename, _statbuf) g_stat((_filename), (_statbuf))519#if !GLIB_CHECK_VERSION(2, 26, 0)520/* GStatBuf has not been introduced yet, manually typedef to what they had at that time:521* https://github.com/GNOME/glib/blob/e7763678b56e3be073cc55d707a6e92fc2055ee0/glib/gstdio.h#L98-L115522*/523#if defined(_WIN32) || HAVE_WINDOWS_H // somehow reliably mock G_OS_WIN32??524// Any effort from our side to reliably mock GStatBuf on Windows is in vain. E.g. glib-2.16 is broken as it uses struct stat rather than struct _stat32 on Win x86.525// Disable it (the user has been warned by cmake).526#undef fluid_stat527#define fluid_stat(_filename, _statbuf) (-1)528typedef struct _fluid_stat_buf_t{int st_mtime;} fluid_stat_buf_t;529#else530/* posix, OS/2, etc. */531typedef struct stat fluid_stat_buf_t;532#endif533#else534typedef GStatBuf fluid_stat_buf_t;535#endif536537FILE* fluid_file_open(const char* filename, const char** errMsg);538fluid_long_long_t fluid_file_tell(FILE* f);539540541/* Profiling */542#if WITH_PROFILING543/** profiling interface between Profiling command shell and Audio544rendering API (FluidProfile_0004.pdf- 3.2.2)545*/546547/*548-----------------------------------------------------------------------------549Shell task side | Profiling interface | Audio task side550-----------------------------------------------------------------------------551profiling | Internal | | | Audio552command <---> |<-- profiling -->| Data |<--macros -->| <--> rendering553shell | API | | | API554555*/556557/* default parameters for shell command "prof_start" in fluid_sys.c */558#define FLUID_PROFILE_DEFAULT_BANK 0 /* default bank */559#define FLUID_PROFILE_DEFAULT_PROG 16 /* default prog (organ) */560#define FLUID_PROFILE_FIRST_KEY 12 /* first key generated */561#define FLUID_PROFILE_LAST_KEY 108 /* last key generated */562#define FLUID_PROFILE_DEFAULT_VEL 64 /* default note velocity */563#define FLUID_PROFILE_VOICE_ATTEN -0.04f /* gain attenuation per voice (dB) */564565566#define FLUID_PROFILE_DEFAULT_PRINT 0 /* default print mode */567#define FLUID_PROFILE_DEFAULT_N_PROF 1 /* default number of measures */568#define FLUID_PROFILE_DEFAULT_DURATION 500 /* default duration (ms) */569570571extern unsigned short fluid_profile_notes; /* number of generated notes */572extern unsigned char fluid_profile_bank; /* bank,prog preset used by */573extern unsigned char fluid_profile_prog; /* generated notes */574extern unsigned char fluid_profile_print; /* print mode */575576extern unsigned short fluid_profile_n_prof;/* number of measures */577extern unsigned short fluid_profile_dur; /* measure duration in ms */578extern fluid_atomic_int_t fluid_profile_lock ; /* lock between multiple shell */579/**/580581/*----------------------------------------------582Internal profiling API (in fluid_sys.c)583-----------------------------------------------*/584/* Starts a profiling measure used in shell command "prof_start" */585void fluid_profile_start_stop(unsigned int end_ticks, short clear_data);586587/* Returns status used in shell command "prof_start" */588int fluid_profile_get_status(void);589590/* Prints profiling data used in shell command "prof_start" */591void fluid_profiling_print_data(double sample_rate, fluid_ostream_t out);592593/* Returns True if profiling cancellation has been requested */594int fluid_profile_is_cancel_req(void);595596/* For OS that implement <ENTER> key for profile cancellation:5971) Adds #define FLUID_PROFILE_CANCEL5982) Adds the necessary code inside fluid_profile_is_cancel() see fluid_sys.c599*/600#if defined(_WIN32) /* Profile cancellation is supported for Windows */601#define FLUID_PROFILE_CANCEL602603#elif defined(__OS2__) /* OS/2 specific stuff */604/* Profile cancellation isn't yet supported for OS2 */605606#else /* POSIX stuff */607#define FLUID_PROFILE_CANCEL /* Profile cancellation is supported for linux */608#include <unistd.h> /* STDIN_FILENO */609#include <sys/select.h> /* select() */610#endif /* posix */611612/* logging profiling data (used on synthesizer instance deletion) */613void fluid_profiling_print(void);614615/*----------------------------------------------616Profiling Data (in fluid_sys.c)617-----------------------------------------------*/618/** Profiling data. Keep track of min/avg/max values to profile a619piece of code. */620typedef struct _fluid_profile_data_t621{622const char *description; /* name of the piece of code under profiling */623double min, max, total; /* duration (microsecond) */624unsigned int count; /* total count */625unsigned int n_voices; /* voices number */626unsigned int n_samples; /* audio samples number */627} fluid_profile_data_t;628629enum630{631/* commands/status (profiling interface) */632PROFILE_STOP, /* command to stop a profiling measure */633PROFILE_START, /* command to start a profile measure */634PROFILE_READY, /* status to signal that a profiling measure has finished635and ready to be printed */636/*- State returned by fluid_profile_get_status() -*/637/* between profiling commands and internal profiling API */638PROFILE_RUNNING, /* a profiling measure is running */639PROFILE_CANCELED,/* a profiling measure has been canceled */640};641642/* Data interface */643extern unsigned char fluid_profile_status ; /* command and status */644extern unsigned int fluid_profile_end_ticks; /* ending position (in ticks) */645extern fluid_profile_data_t fluid_profile_data[]; /* Profiling data */646647/*----------------------------------------------648Probes macros649-----------------------------------------------*/650/** Macro to obtain a time reference used for the profiling */651#define fluid_profile_ref() fluid_utime()652653/** Macro to create a variable and assign the current reference time for profiling.654* So we don't get unused variable warnings when profiling is disabled. */655#define fluid_profile_ref_var(name) double name = fluid_utime()656657/**658* Profile identifier numbers. List all the pieces of code you want to profile659* here. Be sure to add an entry in the fluid_profile_data table in660* fluid_sys.c661*/662enum663{664FLUID_PROF_WRITE,665FLUID_PROF_ONE_BLOCK,666FLUID_PROF_ONE_BLOCK_CLEAR,667FLUID_PROF_ONE_BLOCK_VOICE,668FLUID_PROF_ONE_BLOCK_VOICES,669FLUID_PROF_ONE_BLOCK_REVERB,670FLUID_PROF_ONE_BLOCK_CHORUS,671FLUID_PROF_VOICE_NOTE,672FLUID_PROF_VOICE_RELEASE,673FLUID_PROFILE_NBR /* number of profile probes */674};675/** Those macros are used to calculate the min/avg/max. Needs a profile number, a676time reference, the voices and samples number. */677678/* local macro : acquiere data */679#define fluid_profile_data(_num, _ref, voices, samples)\680{\681double _now = fluid_utime();\682double _delta = _now - _ref;\683fluid_profile_data[_num].min = _delta < fluid_profile_data[_num].min ?\684_delta : fluid_profile_data[_num].min; \685fluid_profile_data[_num].max = _delta > fluid_profile_data[_num].max ?\686_delta : fluid_profile_data[_num].max;\687fluid_profile_data[_num].total += _delta;\688fluid_profile_data[_num].count++;\689fluid_profile_data[_num].n_voices += voices;\690fluid_profile_data[_num].n_samples += samples;\691_ref = _now;\692}693694/** Macro to collect data, called from inner functions inside audio695rendering API */696#define fluid_profile(_num, _ref, voices, samples)\697{\698if ( fluid_profile_status == PROFILE_START)\699{ /* acquires data */\700fluid_profile_data(_num, _ref, voices, samples)\701}\702}703704/** Macro to collect data, called from audio rendering API (fluid_write_xxxx()).705This macro control profiling ending position (in ticks).706*/707#define fluid_profile_write(_num, _ref, voices, samples)\708{\709if (fluid_profile_status == PROFILE_START)\710{\711/* acquires data first: must be done before checking that profile is712finished to ensure at least one valid data sample.713*/\714fluid_profile_data(_num, _ref, voices, samples)\715if (fluid_synth_get_ticks(synth) >= fluid_profile_end_ticks)\716{\717/* profiling is finished */\718fluid_profile_status = PROFILE_READY;\719}\720}\721}722723#else724725/* No profiling */726#define fluid_profiling_print()727#define fluid_profile_ref() 0728#define fluid_profile_ref_var(name)729#define fluid_profile(_num,_ref,voices, samples)730#define fluid_profile_write(_num,_ref, voices, samples)731#endif /* WITH_PROFILING */732733/**734735Memory locking736737Memory locking is used to avoid swapping of the large block of738sample data.739*/740741#if defined(HAVE_SYS_MMAN_H) && !defined(__OS2__)742#define fluid_mlock(_p,_n) mlock(_p, _n)743#define fluid_munlock(_p,_n) munlock(_p,_n)744#else745#define fluid_mlock(_p,_n) 0746#define fluid_munlock(_p,_n)747#endif748749750/**751752Floating point exceptions753754fluid_check_fpe() checks for "unnormalized numbers" and other755exceptions of the floating point processor.756*/757#ifdef FPE_CHECK758#define fluid_check_fpe(expl) fluid_check_fpe_i386(expl)759#define fluid_clear_fpe() fluid_clear_fpe_i386()760unsigned int fluid_check_fpe_i386(char *explanation_in_case_of_fpe);761void fluid_clear_fpe_i386(void);762#else763#define fluid_check_fpe(expl)764#define fluid_clear_fpe()765#endif766767768/* System control */769void fluid_msleep(unsigned int msecs);770771/**772* Advances the given \c ptr to the next \c alignment byte boundary.773* Make sure you've allocated an extra of \c alignment bytes to avoid a buffer overflow.774*775* @note \c alignment must be a power of two776* @return Returned pointer is guaranteed to be aligned to \c alignment boundary and in range \f[ ptr <= returned_ptr < ptr + alignment \f].777*/778static FLUID_INLINE void *fluid_align_ptr(const void *ptr, unsigned int alignment)779{780uintptr_t ptr_int = (uintptr_t)ptr;781unsigned int offset = ptr_int & (alignment - 1);782unsigned int add = (alignment - offset) & (alignment - 1); // advance the pointer to the next alignment boundary783ptr_int += add;784785/* assert alignment is power of two */786FLUID_ASSERT(!(alignment == 0) && !(alignment & (alignment - 1)));787788return (void *)ptr_int;789}790791#define FLUID_DEFAULT_ALIGNMENT (64U)792793#endif /* _FLUID_SYS_H */794795796