379 lines
8.7 KiB
C
379 lines
8.7 KiB
C
/* 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 <readline/readline.h>
|
|
#include <readline/history.h>
|
|
#endif
|
|
|
|
#ifdef DBUS_SUPPORT
|
|
#include "fluid_rtkit.h"
|
|
#endif
|
|
|
|
#include <sys/time.h>
|
|
#include <time.h>
|
|
|
|
/* 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);
|
|
}
|
|
|
|
|
|
|