/* FluidSynth - A Software Synthesizer * * 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 * 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. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA * 02111-1307, USA */ #include "fluid_sys.h" #if WITH_READLINE #include #include #endif #ifdef DBUS_SUPPORT #include "fluid_rtkit.h" #endif #include #include /* 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 /* SCHED_FIFO priority for high priority timer threads */ #define FLUID_SYS_TIMER_HIGH_PRIO_LEVEL 10 struct _fluid_timer_t { long msec; fluid_timer_callback_t callback; void *data; //fluid_thread_t *thread; int cont; int auto_destroy; }; void fluid_sys_config() { //fluid_log_config(); } unsigned int fluid_debug_flags = 0; #if DEBUG /* * fluid_debug */ int fluid_debug(int level, char * fmt, ...) { 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); fun = fluid_log_function[FLUID_DBG]; if (fun != NULL) { (*fun)(level, fluid_errbuf, fluid_log_user_data[FLUID_DBG]); } } return 0; } #endif #if 0 /** * Installs a new log function for a specified log level. * @param level Log level to install handler for. * @param fun Callback function handler to call for logged messages * @param data User supplied data pointer to pass to log function * @return The previously installed function. */ fluid_log_function_t 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; } /** * Default log function which prints to the stderr. * @param level Log level * @param message Log message * @param data User supplied data (not used) */ void fluid_default_log_function(int level, char* message, void* data) { FILE* out; #if defined(WIN32) 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); #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) { fluid_log_initialized = 1; if (fluid_log_function[FLUID_PANIC] == NULL) { fluid_set_log_function(FLUID_PANIC, fluid_default_log_function, NULL); } if (fluid_log_function[FLUID_ERR] == NULL) { fluid_set_log_function(FLUID_ERR, fluid_default_log_function, NULL); } if (fluid_log_function[FLUID_WARN] == NULL) { fluid_set_log_function(FLUID_WARN, fluid_default_log_function, NULL); } if (fluid_log_function[FLUID_INFO] == NULL) { fluid_set_log_function(FLUID_INFO, fluid_default_log_function, NULL); } if (fluid_log_function[FLUID_DBG] == NULL) { fluid_set_log_function(FLUID_DBG, fluid_default_log_function, NULL); } } } #endif /** * Print a message to the log. * @param level Log level (#fluid_log_level). * @param fmt Printf style format string for log message * @param ... Arguments for printf 'fmt' message string * @return Always returns #FLUID_FAILED */ int fluid_log(int level, const char* fmt, ...) { /* fluid_log_function_t fun = NULL; va_list args; va_start (args, fmt); 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]); } } */ return FLUID_FAILED; } /** * An improved strtok, still trashes the input string, but is portable and * thread safe. Also skips token chars at beginning of token string and never * returns an empty token (will return NULL if source ends in token chars though). * NOTE: NOT part of public API * @internal * @param str Pointer to a string pointer of source to tokenize. Pointer gets * updated on each invocation to point to beginning of next token. Note that * token char get's overwritten with a 0 byte. String pointer is set to NULL * when final token is returned. * @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 *s, *d, *token; char c; 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) */ /* skip delimiter chars at beginning of token */ do { 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 */ 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? */ { 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; } /* * fluid_error */ char* fluid_error() { return ""; } /** * Check if a file is a MIDI file. * @param filename Path to the file to check * @return TRUE if it could be a MIDI file, FALSE otherwise * * The current implementation only checks for the "MThd" header in the file. * It is useful only to distinguish between SoundFont and MIDI files. */ int fluid_is_midifile(const char *filename) { 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; } fclose(fp); return strncmp(id, "MThd", 4) == 0; } /** * Check if a file is a SoundFont file. * @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. */ int fluid_is_soundfont(const char *filename) { 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; } fclose(fp); return strncmp(id, "RIFF", 4) == 0; } /** * Get time in milliseconds to be used in relative timing operations. * @return Unix time in milliseconds. */ unsigned int fluid_curtime(void) { static long initial_seconds = 0; struct timeval timeval; if (initial_seconds == 0) { gettimeofday (&timeval, NULL); initial_seconds = timeval.tv_sec; } gettimeofday (&timeval, NULL); 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. */ double fluid_utime (void) { struct timeval timeval; gettimeofday (&timeval, NULL); return (timeval.tv_sec * 1000000.0 + timeval.tv_usec); }