# src/fluid_sys.c

    00001 /* FluidSynth - A Software Synthesizer
    00002  *
    00003  * Copyright (C) 2003  Peter Hanappe and others.
    00004  *
    00005  * This library is free software; you can redistribute it and/or
    00006  * modify it under the terms of the GNU Library General Public License
    00007  * as published by the Free Software Foundation; either version 2 of
    00008  * the License, or (at your option) any later version.
    00009  *
    00010  * This library is distributed in the hope that it will be useful, but
    00011  * WITHOUT ANY WARRANTY; without even the implied warranty of
    00012  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    00013  * Library General Public License for more details.
    00014  *
    00015  * You should have received a copy of the GNU Library General Public
    00016  * License along with this library; if not, write to the Free
    00017  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
    00018  * 02111-1307, USA
    00019  */
    00020
    00021
    00022 #include "fluid_sys.h"
    00023
    00024 static char fluid_errbuf[512];  /* buffer for error message */
    00025
    00026 static fluid_log_function_t fluid_log_function[LAST_LOG_LEVEL];
    00027 static void* fluid_log_user_data[LAST_LOG_LEVEL];
    00028 static int fluid_log_initialized = 0;
    00029
    00030 static char* fluid_libname = "fluidsynth";
    00031
    00032
    00033 void fluid_sys_config()
    00034 {
    00035   fluid_log_config();
    00036   fluid_time_config();
    00037 }
    00038
    00039
    00040 unsigned int fluid_debug_flags = 0;
    00041
    00042 #if DEBUG
    00043 /*
    00044  * fluid_debug
    00045  */
    00046 int fluid_debug(int level, char * fmt, ...)
    00047 {
    00048   if (fluid_debug_flags & level) {
    00049     fluid_log_function_t fun;
    00050     va_list args;
    00051
    00052     va_start (args, fmt);
    00053     vsnprintf(fluid_errbuf, sizeof (fluid_errbuf), fmt, args);
    00054     va_end (args);
    00055
    00056     fun = fluid_log_function[FLUID_DBG];
    00057     if (fun != NULL) {
    00058       (*fun)(level, fluid_errbuf, fluid_log_user_data[FLUID_DBG]);
    00059     }
    00060   }
    00061   return 0;
    00062 }
    00063 #endif
    00064
    00072 fluid_log_function_t
    00073 fluid_set_log_function(int level, fluid_log_function_t fun, void* data)
    00074 {
    00075   fluid_log_function_t old = NULL;
    00076
    00077   if ((level >= 0) && (level < LAST_LOG_LEVEL)) {
    00078     old = fluid_log_function[level];
    00079     fluid_log_function[level] = fun;
    00080     fluid_log_user_data[level] = data;
    00081   }
    00082   return old;
    00083 }
    00084
    00091 void
    00092 fluid_default_log_function(int level, char* message, void* data)
    00093 {
    00094   FILE* out;
    00095
    00096 #if defined(WIN32)
    00097   out = stdout;
    00098 #else
    00099   out = stderr;
    00100 #endif
    00101
    00102   if (fluid_log_initialized == 0) {
    00103     fluid_log_config();
    00104   }
    00105
    00106   switch (level) {
    00107   case FLUID_PANIC:
    00108     FLUID_FPRINTF(out, "%s: panic: %s\n", fluid_libname, message);
    00109     break;
    00110   case FLUID_ERR:
    00111     FLUID_FPRINTF(out, "%s: error: %s\n", fluid_libname, message);
    00112     break;
    00113   case FLUID_WARN:
    00114     FLUID_FPRINTF(out, "%s: warning: %s\n", fluid_libname, message);
    00115     break;
    00116   case FLUID_INFO:
    00117     FLUID_FPRINTF(out, "%s: %s\n", fluid_libname, message);
    00118     break;
    00119   case FLUID_DBG:
    00120 #if DEBUG
    00121     FLUID_FPRINTF(out, "%s: debug: %s\n", fluid_libname, message);
    00122 #endif
    00123     break;
    00124   default:
    00125     FLUID_FPRINTF(out, "%s: %s\n", fluid_libname, message);
    00126     break;
    00127   }
    00128   fflush(out);
    00129 }
    00130
    00131 /*
    00132  * fluid_init_log
    00133  */
    00134 void
    00135 fluid_log_config(void)
    00136 {
    00137   if (fluid_log_initialized == 0) {
    00138
    00139     fluid_log_initialized = 1;
    00140
    00141     if (fluid_log_function[FLUID_PANIC] == NULL) {
    00142       fluid_set_log_function(FLUID_PANIC, fluid_default_log_function, NULL);
    00143     }
    00144
    00145     if (fluid_log_function[FLUID_ERR] == NULL) {
    00146       fluid_set_log_function(FLUID_ERR, fluid_default_log_function, NULL);
    00147     }
    00148
    00149     if (fluid_log_function[FLUID_WARN] == NULL) {
    00150       fluid_set_log_function(FLUID_WARN, fluid_default_log_function, NULL);
    00151     }
    00152
    00153     if (fluid_log_function[FLUID_INFO] == NULL) {
    00154       fluid_set_log_function(FLUID_INFO, fluid_default_log_function, NULL);
    00155     }
    00156
    00157     if (fluid_log_function[FLUID_DBG] == NULL) {
    00158       fluid_set_log_function(FLUID_DBG, fluid_default_log_function, NULL);
    00159     }
    00160   }
    00161 }
    00162
    00170 int
    00171 fluid_log(int level, char* fmt, ...)
    00172 {
    00173   fluid_log_function_t fun = NULL;
    00174
    00175   va_list args;
    00176   va_start (args, fmt);
    00177   vsnprintf(fluid_errbuf, sizeof (fluid_errbuf), fmt, args);
    00178   va_end (args);
    00179
    00180   if ((level >= 0) && (level < LAST_LOG_LEVEL)) {
    00181     fun = fluid_log_function[level];
    00182     if (fun != NULL) {
    00183       (*fun)(level, fluid_errbuf, fluid_log_user_data[level]);
    00184     }
    00185   }
    00186   return FLUID_FAILED;
    00187 }
    00188
    00202 char *fluid_strtok (char **str, char *delim)
    00203 {
    00204   char *s, *d, *token;
    00205   char c;
    00206
    00207   if (str == NULL || delim == NULL || !*delim)
    00208   {
    00209     FLUID_LOG(FLUID_ERR, "Null pointer");
    00210     return NULL;
    00211   }
    00212
    00213   s = *str;
    00214   if (!s) return NULL;  /* str points to a NULL pointer? (tokenize already ended) */
    00215
    00216   /* skip delimiter chars at beginning of token */
    00217   do
    00218   {
    00219     c = *s;
    00220     if (!c)     /* end of source string? */
    00221     {
    00222       *str = NULL;
    00223       return NULL;
    00224     }
    00225
    00226     for (d = delim; *d; d++)    /* is source char a token char? */
    00227     {
    00228       if (c == *d)      /* token char match? */
    00229       {
    00230         s++;            /* advance to next source char */
    00231         break;
    00232       }
    00233     }
    00234   } while (*d);         /* while token char match */
    00235
    00236   token = s;            /* start of token found */
    00237
    00238   /* search for next token char or end of source string */
    00239   for (s = s+1; *s; s++)
    00240   {
    00241     c = *s;
    00242
    00243     for (d = delim; *d; d++)    /* is source char a token char? */
    00244     {
    00245       if (c == *d)      /* token char match? */
    00246       {
    00247         *s = '\0';      /* overwrite token char with zero byte to terminate token */
    00248         *str = s+1;     /* update str to point to beginning of next token */
    00249         return token;
    00250       }
    00251     }
    00252   }
    00253
    00254   /* we get here only if source string ended */
    00255   *str = NULL;
    00256   return token;
    00257 }
    00258
    00259 /*
    00260  * fluid_error
    00261  */
    00262 char*
    00263 fluid_error()
    00264 {
    00265   return fluid_errbuf;
    00266 }
    00267
    00268
    00269 /*
    00270  *
    00271  *  fluid_is_midifile
    00272  */
    00273 int
    00274 fluid_is_midifile(char* filename)
    00275 {
    00276   FILE* fp = fopen(filename, "rb");
    00277   char id[4];
    00278
    00279   if (fp == NULL) {
    00280     return 0;
    00281   }
    00282   if (fread((void*) id, 1, 4, fp) != 4) {
    00283     fclose(fp);
    00284     return 0;
    00285   }
    00286   fclose(fp);
    00287
    00288   return strncmp(id, "MThd", 4) == 0;
    00289 }
    00290
    00291 /*
    00292  *  fluid_is_soundfont
    00293  *
    00294  */
    00295 int
    00296 fluid_is_soundfont(char* filename)
    00297 {
    00298   FILE* fp = fopen(filename, "rb");
    00299   char id[4];
    00300
    00301   if (fp == NULL) {
    00302     return 0;
    00303   }
    00304   if (fread((void*) id, 1, 4, fp) != 4) {
    00305     fclose(fp);
    00306     return 0;
    00307   }
    00308   fclose(fp);
    00309
    00310   return strncmp(id, "RIFF", 4) == 0;
    00311 }
    00312
    00313 #if defined(WIN32)
    00314
    00315 /*=============================================================*/
    00316 /*                                                             */
    00317 /*                           Win32                             */
    00318 /*                                                             */
    00319 /*=============================================================*/
    00320
    00321 /***************************************************************
    00322  *
    00323  *               Timer
    00324  *
    00325  */
    00326
    00327 struct _fluid_timer_t
    00328 {
    00329   long msec;
    00330   fluid_timer_callback_t callback;
    00331   void* data;
    00332   HANDLE thread;
    00333   DWORD thread_id;
    00334   int cont;
    00335   int auto_destroy;
    00336 };
    00337
    00338 static int fluid_timer_count = 0;
    00339 DWORD WINAPI fluid_timer_run(LPVOID data);
    00340
    00341 fluid_timer_t*
    00342 new_fluid_timer(int msec, fluid_timer_callback_t callback, void* data,
    00343                int new_thread, int auto_destroy)
    00344 {
    00345   fluid_timer_t* timer = FLUID_NEW(fluid_timer_t);
    00346   if (timer == NULL) {
    00347     FLUID_LOG(FLUID_ERR, "Out of memory");
    00348     return NULL;
    00349   }
    00350
    00351   timer->cont = 1;
    00352   timer->msec = msec;
    00353   timer->callback = callback;
    00354   timer->data = data;
    00355   timer->thread = 0;
    00356   timer->auto_destroy = auto_destroy;
    00357
    00358   if (new_thread) {
    00359     timer->thread = CreateThread(NULL, 0, fluid_timer_run, (LPVOID) timer, 0, &timer->thread_id);
    00360     if (timer->thread == NULL) {
    00361       FLUID_LOG(FLUID_ERR, "Couldn't create timer thread");
    00362       FLUID_FREE(timer);
    00363       return NULL;
    00364     }
    00365     SetThreadPriority(timer->thread, THREAD_PRIORITY_TIME_CRITICAL);
    00366   } else {
    00367     fluid_timer_run((LPVOID) timer);
    00368   }
    00369   return timer;
    00370 }
    00371
    00372 DWORD WINAPI
    00373 fluid_timer_run(LPVOID data)
    00374 {
    00375   int count = 0;
    00376   int cont = 1;
    00377   long start;
    00378   long delay;
    00379   fluid_timer_t* timer;
    00380   timer = (fluid_timer_t*) data;
    00381
    00382   if ((timer == NULL) || (timer->callback == NULL)) {
    00383     return 0;
    00384   }
    00385
    00386   SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_HIGHEST);
    00387
    00388   /* keep track of the start time for absolute positioning */
    00389   start = fluid_curtime();
    00390
    00391   while (cont) {
    00392
    00393     /* do whatever we have to do */
    00394     cont = (*timer->callback)(timer->data, fluid_curtime() - start);
    00395
    00396     count++;
    00397
    00398     /* to avoid incremental time errors, I calculate the delay between
    00399        two callbacks bringing in the "absolute" time (count *
    00400        timer->msec) */
    00401     delay = (count * timer->msec) - (fluid_curtime() - start);
    00402     if (delay > 0) {
    00403       Sleep(delay);
    00404     }
    00405
    00406     cont &= timer->cont;
    00407   }
    00408
    00409   FLUID_LOG(FLUID_DBG, "Timer thread finished");
    00410
    00411   if (timer->auto_destroy) {
    00412     FLUID_FREE(timer);
    00413   }
    00414
    00415   ExitThread(0);
    00416   return 0;
    00417 }
    00418
    00419 int
    00420 delete_fluid_timer(fluid_timer_t* timer)
    00421 {
    00422   timer->cont = 0;
    00423   fluid_timer_join(timer);
    00424   FLUID_FREE(timer);
    00425   return FLUID_OK;
    00426 }
    00427
    00428 int
    00429 fluid_timer_join(fluid_timer_t* timer)
    00430 {
    00431   DWORD wait_result;
    00432   if (timer->thread == 0) {
    00433     return FLUID_OK;
    00434   }
    00435   wait_result = WaitForSingleObject(timer->thread, INFINITE);
    00436   return (wait_result == WAIT_OBJECT_0)? FLUID_OK : FLUID_FAILED;
    00437 }
    00438
    00439
    00440 /***************************************************************
    00441  *
    00442  *               Time
    00443  */
    00444
    00445 double rdtsc(void);
    00446 double fluid_estimate_cpu_frequency(void);
    00447
    00448 static double fluid_cpu_frequency = -1.0;
    00449
    00450 void fluid_time_config(void)
    00451 {
    00452   if (fluid_cpu_frequency < 0.0) {
    00453     fluid_cpu_frequency = fluid_estimate_cpu_frequency() / 1000000.0;
    00454   }
    00455 }
    00456
    00457 double fluid_utime(void)
    00458 {
    00459   return (rdtsc() / fluid_cpu_frequency);
    00460 }
    00461
    00462 double rdtsc(void)
    00463 {
    00464   LARGE_INTEGER t;
    00465   QueryPerformanceCounter(&t);
    00466   return (double) t.QuadPart;
    00467 }
    00468
    00469 double fluid_estimate_cpu_frequency(void)
    00470 {
    00471 #if 0
    00472   LONGLONG start, stop, ticks;
    00473   unsigned int before, after, delta;
    00474   double freq;
    00475
    00476   start = rdtsc();
    00477   stop = start;
    00478   before = fluid_curtime();
    00479   after = before;
    00480
    00481   while (1) {
    00482     if (after - before > 1000) {
    00483         break;
    00484     }
    00485     after = fluid_curtime();
    00486     stop = rdtsc();
    00487   }
    00488
    00489   delta = after - before;
    00490   ticks = stop - start;
    00491
    00492   freq = 1000 * ticks / delta;
    00493
    00494   return freq;
    00495
    00496 #else
    00497   unsigned int before, after;
    00498   LARGE_INTEGER start, stop;
    00499
    00500   before = fluid_curtime();
    00501   QueryPerformanceCounter(&start);
    00502
    00503   Sleep(1000);
    00504
    00505   after = fluid_curtime();
    00506   QueryPerformanceCounter(&stop);
    00507
    00508   return (double) 1000 * (stop.QuadPart - start.QuadPart) / (after - before);
    00509 #endif
    00510 }
    00511
    00512
    00513
    00514 #elif defined(MACOS9)
    00515 /*=============================================================*/
    00516 /*                                                             */
    00517 /*                           MacOS 9                           */
    00518 /*                                                             */
    00519 /*=============================================================*/
    00520
    00521
    00522 /***************************************************************
    00523  *
    00524  *               Timer
    00525  */
    00526
    00527 struct _fluid_timer_t
    00528 {
    00529         TMTask myTmTask;
    00530   long msec;
    00531   unsigned int start;
    00532   unsigned int count;
    00533   int isInstalled;
    00534   fluid_timer_callback_t callback;
    00535   void* data;
    00536   int auto_destroy;
    00537 };
    00538
    00539 static TimerUPP myTimerUPP;
    00540
    00541 void
    00542 _timerCallback(fluid_timer_t *timer)
    00543 {
    00544         int cont;
    00545   cont = (*timer->callback)(timer->data, fluid_curtime() - timer->start);
    00546   if (cont) {
    00547         PrimeTime((QElemPtr)timer, timer->msec);
    00548         } else {
    00549                 timer->isInstalled = 0;
    00550         }
    00551   timer->count++;
    00552 }
    00553
    00554 fluid_timer_t*
    00555 new_fluid_timer(int msec, fluid_timer_callback_t callback, void* data,
    00556                int new_thread, int auto_destroy)
    00557 {
    00558   fluid_timer_t* timer = FLUID_NEW(fluid_timer_t);
    00559   if (timer == NULL) {
    00560     FLUID_LOG(FLUID_ERR, "Out of memory");
    00561     return NULL;
    00562   }
    00563
    00564         if (!myTimerUPP)
    00565                 myTimerUPP = NewTimerProc(_timerCallback);
    00566
    00567   /* setup tmtask */
    00568         timer->myTmTask.tmAddr = myTimerUPP;
    00569         timer->myTmTask.qLink = NULL;
    00570         timer->myTmTask.qType = 0;
    00571         timer->myTmTask.tmCount = 0L;
    00572         timer->myTmTask.tmWakeUp = 0L;
    00573         timer->myTmTask.tmReserved = 0L;
    00574
    00575   timer->callback = callback;
    00576
    00577   timer->msec = msec;
    00578   timer->data = data;
    00579   timer->start = fluid_curtime();
    00580   timer->isInstalled = 1;
    00581   timer->count = 0;
    00582   timer->auto_destroy = auto_destroy;
    00583
    00584   InsXTime((QElemPtr)timer);
    00585   PrimeTime((QElemPtr)timer, msec);
    00586
    00587   return timer;
    00588 }
    00589
    00590 int
    00591 delete_fluid_timer(fluid_timer_t* timer)
    00592 {
    00593         if (timer->isInstalled) {
    00594                 RmvTime((QElemPtr)timer);
    00595         }
    00596   FLUID_FREE(timer);
    00597   return FLUID_OK;
    00598 }
    00599
    00600 int
    00601 fluid_timer_join(fluid_timer_t* timer)
    00602 {
    00603         if (timer->isInstalled) {
    00604                 int count = timer->count;
    00605                 /* wait until count has incremented */
    00606                 while (count == timer->count) {}
    00607         }
    00608   return FLUID_OK;
    00609 }
    00610
    00611 /***************************************************************
    00612  *
    00613  *               Time
    00614  */
    00615 #define kTwoPower32 (4294967296.0)      /* 2^32 */
    00616
    00617 void fluid_time_config(void)
    00618 {
    00619 }
    00620
    00621 unsigned int fluid_curtime()
    00622 {
    00623         /* could be optimized by not going though a double */
    00624         UnsignedWide    uS;
    00625         double mSf;
    00626         unsigned int ms;
    00627
    00628         Microseconds(&uS);
    00629
    00630   mSf = ((((double) uS.hi) * kTwoPower32) + uS.lo)/1000.0f;
    00631
    00632   ms = mSf;
    00633
    00634   return (ms);
    00635 }
    00636
    00637
    00638
    00639 #else
    00640
    00641 /*=============================================================*/
    00642 /*                                                             */
    00643 /*                           POSIX                             */
    00644 /*                                                             */
    00645 /*=============================================================*/
    00646
    00647
    00648 /***************************************************************
    00649  *
    00650  *               Timer
    00651  */
    00652
    00653 struct _fluid_timer_t
    00654 {
    00655   long msec;
    00656   fluid_timer_callback_t callback;
    00657   void* data;
    00658   pthread_t thread;
    00659   int cont;
    00660   int auto_destroy;
    00661 };
    00662
    00663 void*
    00664 fluid_timer_start(void *data)
    00665 {
    00666   int count = 0;
    00667   int cont = 1;
    00668   long start;
    00669   long delay;
    00670   fluid_timer_t* timer;
    00671   timer = (fluid_timer_t*) data;
    00672
    00673   /* keep track of the start time for absolute positioning */
    00674   start = fluid_curtime();
    00675
    00676   while (cont) {
    00677
    00678     /* do whatever we have to do */
    00679     cont = (*timer->callback)(timer->data, fluid_curtime() - start);
    00680
    00681     count++;
    00682
    00683     /* to avoid incremental time errors, calculate the delay between
    00684        two callbacks bringing in the "absolute" time (count *
    00685        timer->msec) */
    00686     delay = (count * timer->msec) - (fluid_curtime() - start);
    00687     if (delay > 0) {
    00688       usleep(delay * 1000);
    00689     }
    00690
    00691     cont &= timer->cont;
    00692   }
    00693
    00694   FLUID_LOG(FLUID_DBG, "Timer thread finished");
    00695   if (timer->thread != 0) {
    00696     pthread_exit(NULL);
    00697   }
    00698
    00699   if (timer->auto_destroy) {
    00700     FLUID_FREE(timer);
    00701   }
    00702
    00703   return NULL;
    00704 }
    00705
    00706 fluid_timer_t*
    00707 new_fluid_timer(int msec, fluid_timer_callback_t callback, void* data,
    00708                int new_thread, int auto_destroy)
    00709 {
    00710   pthread_attr_t *attr = NULL;
    00711   pthread_attr_t rt_attr;
    00712   int sched = SCHED_FIFO;
    00713   struct sched_param priority;
    00714   int err;
    00715
    00716   fluid_timer_t* timer = FLUID_NEW(fluid_timer_t);
    00717   if (timer == NULL) {
    00718     FLUID_LOG(FLUID_ERR, "Out of memory");
    00719     return NULL;
    00720   }
    00721   timer->msec = msec;
    00722   timer->callback = callback;
    00723   timer->data = data;
    00724   timer->cont = 1;
    00725   timer->thread = 0;
    00726   timer->auto_destroy = auto_destroy;
    00727
    00728   err = pthread_attr_init(&rt_attr);
    00729   if (err == 0) {
    00730           err = pthread_attr_setschedpolicy(&rt_attr, SCHED_FIFO);
    00731           if (err == 0) {
    00732                   priority.sched_priority = 10;
    00733                   err = pthread_attr_setschedparam(&rt_attr, &priority);
    00734                   if (err == 0) {
    00735                           attr = &rt_attr;
    00736                   }
    00737           }
    00738   }
    00739
    00740   if (new_thread) {
    00741           err = pthread_create(&timer->thread, attr, fluid_timer_start, (void*) timer);
    00742           if (err == 0) {
    00743                   FLUID_LOG(FLUID_DBG, "The timer thread was created with real-time priority");
    00744           } else {
    00745                   /* Create the thread with default attributes */
    00746                   err = pthread_create(&timer->thread, NULL, fluid_timer_start, (void*) timer);
    00747                   if (err != 0) {
    00748                           FLUID_LOG(FLUID_ERR, "Failed to create the timer thread");
    00749                           FLUID_FREE(timer);
    00750                           return NULL;
    00751                   } else {
    00752                           FLUID_LOG(FLUID_DBG, "The timer thread does not have real-time priority");
    00753                   }
    00754           }
    00755   } else {
    00756     fluid_timer_start((void*) timer);
    00757   }
    00758   return timer;
    00759 }
    00760
    00761 int
    00762 delete_fluid_timer(fluid_timer_t* timer)
    00763 {
    00764   timer->cont = 0;
    00765   fluid_timer_join(timer);
    00766   FLUID_LOG(FLUID_DBG, "Joined player thread");
    00767   FLUID_FREE(timer);
    00768   return FLUID_OK;
    00769 }
    00770
    00771 int
    00772 fluid_timer_join(fluid_timer_t* timer)
    00773 {
    00774   int err = 0;
    00775
    00776   if (timer->thread != 0) {
    00777     err = pthread_join(timer->thread, NULL);
    00778   }
    00779   FLUID_LOG(FLUID_DBG, "Joined player thread");
    00780   return (err == 0)? FLUID_OK : FLUID_FAILED;
    00781 }
    00782
    00783
    00784 /***************************************************************
    00785  *
    00786  *               Time
    00787  */
    00788
    00789 static double fluid_cpu_frequency = -1.0;
    00790
    00791 double rdtsc(void);
    00792 double fluid_estimate_cpu_frequency(void);
    00793
    00794 void fluid_time_config(void)
    00795 {
    00796   if (fluid_cpu_frequency < 0.0) {
    00797     fluid_cpu_frequency = fluid_estimate_cpu_frequency() / 1000000.0;
    00798     if (fluid_cpu_frequency == 0.0) fluid_cpu_frequency = 1.0;
    00799   }
    00800 }
    00801
    00802 unsigned int fluid_curtime()
    00803 {
    00804   struct timeval now;
    00805   gettimeofday(&now, NULL);
    00806   return now.tv_sec * 1000 + now.tv_usec / 1000;
    00807 }
    00808
    00809 double fluid_utime(void)
    00810 {
    00811   return (rdtsc() / fluid_cpu_frequency);
    00812 }
    00813
    00814 #if !defined(__i386__)
    00815
    00816 double rdtsc(void)
    00817 {
    00818   return 0.0;
    00819 }
    00820
    00821 double fluid_estimate_cpu_frequency(void)
    00822 {
    00823   return 1.0;
    00824 }
    00825
    00826 #else
    00827
    00828 double rdtsc(void)
    00829 {
    00830   unsigned int a, b;
    00831
    00832   __asm__ ("rdtsc" : "=a" (a), "=d" (b));
    00833   return (double)b * (double)0x10000 * (double)0x10000 + a;
    00834 }
    00835
    00836 double fluid_estimate_cpu_frequency(void)
    00837 {
    00838   double start, stop;
    00839   unsigned int a0, b0, a1, b1;
    00840   unsigned int before, after;
    00841
    00842   before = fluid_curtime();
    00843   __asm__ ("rdtsc" : "=a" (a0), "=d" (b0));
    00844
    00845   sleep(1);
    00846
    00847   after = fluid_curtime();
    00848   __asm__ ("rdtsc" : "=a" (a1), "=d" (b1));
    00849
    00850
    00851   start = (double)b0 * (double)0x10000 * (double)0x10000 + a0;
    00852   stop = (double)b1 * (double)0x10000 * (double)0x10000 + a1;
    00853
    00854   return 1000 * (stop - start) / (after - before);
    00855 }
    00856 #endif
    00857
    00858
    00859 #ifdef FPE_CHECK
    00860
    00861 /***************************************************************
    00862  *
    00863  *               Floating point exceptions
    00864  *
    00865  *  The floating point exception functions were taken from Ircam's
    00866  *  jMax source code. http://www.ircam.fr/jmax
    00867  *
    00868  *  FIXME: check in config for i386 machine
    00869  *
    00870  *  Currently not used. I leave the code here in case we want to pick
    00871  *  this up again some time later.
    00872  */
    00873
    00874 /* Exception flags */
    00875 #define _FPU_STATUS_IE    0x001  /* Invalid Operation */
    00876 #define _FPU_STATUS_DE    0x002  /* Denormalized Operand */
    00877 #define _FPU_STATUS_ZE    0x004  /* Zero Divide */
    00878 #define _FPU_STATUS_OE    0x008  /* Overflow */
    00879 #define _FPU_STATUS_UE    0x010  /* Underflow */
    00880 #define _FPU_STATUS_PE    0x020  /* Precision */
    00881 #define _FPU_STATUS_SF    0x040  /* Stack Fault */
    00882 #define _FPU_STATUS_ES    0x080  /* Error Summary Status */
    00883
    00884 /* Macros for accessing the FPU status word.  */
    00885
    00886 /* get the FPU status */
    00887 #define _FPU_GET_SW(sw) __asm__ ("fnstsw %0" : "=m" (*&sw))
    00888
    00889 /* clear the FPU status */
    00890 #define _FPU_CLR_SW() __asm__ ("fnclex" : : )
    00891
    00892 /* Purpose:
    00893  * Checks, if the floating point unit has produced an exception, print a message
    00894  * if so and clear the exception.
    00895  */
    00896 unsigned int fluid_check_fpe_i386(char* explanation)
    00897 {
    00898   unsigned int s;
    00899
    00900   _FPU_GET_SW(s);
    00901   _FPU_CLR_SW();
    00902
    00903   s &= _FPU_STATUS_IE | _FPU_STATUS_DE | _FPU_STATUS_ZE | _FPU_STATUS_OE | _FPU_STATUS_UE;
    00904
    00905   if (s)
    00906   {
    00907       FLUID_LOG(FLUID_WARN, "FPE exception (before or in %s): %s%s%s%s%s", explanation,
    00908                (s & _FPU_STATUS_IE) ? "Invalid operation " : "",
    00909                (s & _FPU_STATUS_DE) ? "Denormal number " : "",
    00910                (s & _FPU_STATUS_ZE) ? "Zero divide " : "",
    00911                (s & _FPU_STATUS_OE) ? "Overflow " : "",
    00912                (s & _FPU_STATUS_UE) ? "Underflow " : "");
    00913   }
    00914
    00915   return s;
    00916 }
    00917
    00918 /* Purpose:
    00919  * Clear floating point exception.
    00920  */
    00921 void fluid_clear_fpe_i386 (void)
    00922 {
    00923   _FPU_CLR_SW();
    00924 }
    00925
    00926 #endif  // ifdef FPE_CHECK
    00927
    00928
    00929 #endif  // #else    (its POSIX)
    00930
    00931
    00932 /***************************************************************
    00933  *
    00934  *               Profiling (Linux, i586 only)
    00935  *
    00936  */
    00937
    00938 #if WITH_PROFILING
    00939
    00940 fluid_profile_data_t fluid_profile_data[] =
    00941 {
    00942   { FLUID_PROF_WRITE_S16,        "fluid_synth_write_s16           ", 1e10, 0.0, 0.0, 0},
    00943   { FLUID_PROF_ONE_BLOCK,        "fluid_synth_one_block           ", 1e10, 0.0, 0.0, 0},
    00944   { FLUID_PROF_ONE_BLOCK_CLEAR,  "fluid_synth_one_block:clear     ", 1e10, 0.0, 0.0, 0},
    00945   { FLUID_PROF_ONE_BLOCK_VOICE,  "fluid_synth_one_block:one voice ", 1e10, 0.0, 0.0, 0},
    00946   { FLUID_PROF_ONE_BLOCK_VOICES, "fluid_synth_one_block:all voices", 1e10, 0.0, 0.0, 0},
    00947   { FLUID_PROF_ONE_BLOCK_REVERB, "fluid_synth_one_block:reverb    ", 1e10, 0.0, 0.0, 0},
    00948   { FLUID_PROF_ONE_BLOCK_CHORUS, "fluid_synth_one_block:chorus    ", 1e10, 0.0, 0.0, 0},
    00949   { FLUID_PROF_VOICE_NOTE,       "fluid_voice:note                ", 1e10, 0.0, 0.0, 0},
    00950   { FLUID_PROF_VOICE_RELEASE,    "fluid_voice:release             ", 1e10, 0.0, 0.0, 0},
    00951   { FLUID_PROF_LAST, "last", 1e100, 0.0, 0.0, 0}
    00952 };
    00953
    00954
    00955 void fluid_profiling_print(void)
    00956 {
    00957   int i;
    00958
    00959   printf("fluid_profiling_print\n");
    00960
    00961   FLUID_LOG(FLUID_INFO, "Estimated CPU frequency: %.0f MHz", fluid_cpu_frequency);
    00962   FLUID_LOG(FLUID_INFO, "Estimated times: min/avg/max (micro seconds)");
    00963
    00964   for (i = 0; i < FLUID_PROF_LAST; i++) {
    00965     if (fluid_profile_data[i].count > 0) {
    00966       FLUID_LOG(FLUID_INFO, "%s: %.3f/%.3f/%.3f",
    00967                fluid_profile_data[i].description,
    00968                fluid_profile_data[i].min,
    00969                fluid_profile_data[i].total / fluid_profile_data[i].count,
    00970                fluid_profile_data[i].max);
    00971     } else {
    00972       FLUID_LOG(FLUID_DBG, "%s: no profiling available", fluid_profile_data[i].description);
    00973     }
    00974   }
    00975 }
    00976
    00977
    00978 #endif /* WITH_PROFILING */
    00979
    00980
    00981
    00982 /***************************************************************
    00983  *
    00984  *               Threads
    00985  *
    00986  */
    00987
    00988 #if defined(MACOS9)
    00989 /* Not implemented */
    00990 fluid_thread_t* new_fluid_thread(fluid_thread_func_t func, void* data, int detach) { return NULL; }
    00991 int delete_fluid_thread(fluid_thread_t* thread) { return 0; }
    00992 int fluid_thread_join(fluid_thread_t* thread) { return 0; }
    00993
    00994 #elif defined(WIN32)
    00995
    00996 struct _fluid_thread_t {
    00997   HANDLE thread;
    00998   DWORD thread_id;
    00999   fluid_thread_func_t func;
    01000   void* data;
    01001   int detached;
    01002 };
    01003
    01004 static DWORD WINAPI fluid_thread_start(LPVOID data)
    01005 {
    01006   fluid_thread_t* thread = (fluid_thread_t*) data;
    01007
    01008   thread->func(thread->data);
    01009
    01010   if (thread->detached) {
    01011     FLUID_FREE(thread);
    01012   }
    01013
    01014   return 0;
    01015 }
    01016
    01017
    01018 fluid_thread_t* new_fluid_thread(fluid_thread_func_t func, void* data, int detach)
    01019 {
    01020   fluid_thread_t* thread;
    01021
    01022   if (func == NULL) {
    01023     FLUID_LOG(FLUID_ERR, "Invalid thread function");
    01024     return NULL;
    01025   }
    01026
    01027   thread = FLUID_NEW(fluid_thread_t);
    01028   if (thread == NULL) {
    01029     FLUID_LOG(FLUID_ERR, "Out of memory");
    01030     return NULL;
    01031   }
    01032
    01033   thread->data = data;
    01034   thread->func = func;
    01035   thread->detached = detach;
    01036
    01037   thread->thread = CreateThread(NULL, 0, fluid_thread_start, (LPVOID) thread,
    01038                                 0, &thread->thread_id);
    01039   if (thread->thread == NULL) {
    01040     FLUID_LOG(FLUID_ERR, "Couldn't create the thread");
    01041     FLUID_FREE(thread);
    01042     return NULL;
    01043   }
    01044
    01045   return thread;
    01046 }
    01047
    01048 int delete_fluid_thread(fluid_thread_t* thread)
    01049 {
    01050   FLUID_FREE(thread);
    01051   return FLUID_OK;
    01052 }
    01053
    01054
    01055 int fluid_thread_join(fluid_thread_t* thread)
    01056 {
    01057   DWORD wait_result;
    01058   if (thread->thread == 0) {
    01059     return FLUID_OK;
    01060   }
    01061   wait_result = WaitForSingleObject(thread->thread, INFINITE);
    01062   return (wait_result == WAIT_OBJECT_0)? FLUID_OK : FLUID_FAILED;
    01063 }
    01064
    01065 #else
    01066
    01067
    01068 struct _fluid_thread_t {
    01069   pthread_t pthread;
    01070   fluid_thread_func_t func;
    01071   void* data;
    01072   int detached;
    01073 };
    01074
    01075 static void* fluid_thread_start(void *data)
    01076 {
    01077   fluid_thread_t* thread = (fluid_thread_t*) data;
    01078
    01079   thread->func(thread->data);
    01080
    01081   if (thread->detached) {
    01082     FLUID_FREE(thread);
    01083   }
    01084
    01085   return NULL;
    01086 }
    01087
    01088 fluid_thread_t* new_fluid_thread(fluid_thread_func_t func, void* data, int detach)
    01089 {
    01090   fluid_thread_t* thread;
    01091   pthread_attr_t attr;
    01092
    01093   if (func == NULL) {
    01094     FLUID_LOG(FLUID_ERR, "Invalid thread function");
    01095     return NULL;
    01096   }
    01097
    01098   thread = FLUID_NEW(fluid_thread_t);
    01099   if (thread == NULL) {
    01100     FLUID_LOG(FLUID_ERR, "Out of memory");
    01101     return NULL;
    01102   }
    01103
    01104   thread->data = data;
    01105   thread->func = func;
    01106   thread->detached = detach;
    01107
    01108   pthread_attr_init(&attr);
    01109
    01110   if (detach) {
    01111     pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
    01112   }
    01113
    01114   if (pthread_create(&thread->pthread, &attr, fluid_thread_start, thread)) {
    01115     FLUID_LOG(FLUID_ERR, "Failed to create the thread");
    01116     FLUID_FREE(thread);
    01117     return NULL;
    01118   }
    01119
    01120   return thread;
    01121 }
    01122
    01123 int delete_fluid_thread(fluid_thread_t* thread)
    01124 {
    01125   FLUID_FREE(thread);
    01126   return FLUID_OK;
    01127 }
    01128
    01129 int fluid_thread_join(fluid_thread_t* thread)
    01130 {
    01131   int err = 0;
    01132
    01133   if (thread->pthread != 0) {
    01134     err = pthread_join(thread->pthread, NULL);
    01135   }
    01136   return (err == 0)? FLUID_OK : FLUID_FAILED;
    01137 }
    01138
    01139 #endif
    01140
    01141
    01142
    01143 /***************************************************************
    01144  *
    01145  *               Sockets
    01146  *
    01147  */
    01148
    01149
    01150 #if defined(MACINTOSH)
    01151 /* Not implemented */
    01152
    01153
    01154 #elif defined(WIN32)
    01155
    01156 #if 0
    01157 typedef unsigned int socklen_t;
    01158
    01159 #define fluid_socket_read(_S,_B,_L) recv(_S,_B,_L,0)
    01160 #define fluid_socket_write(_S,_B,_L) send(_S,_B,_L,0)
    01161
    01162 void fluid_socket_close(fluid_socket_t sock)
    01163 {
    01164   int r;
    01165   char buf[1024];
    01166   if (sock != INVALID_SOCKET) {
    01167     shutdown(sock, 0x02);
    01168     while (1) {
    01169       r = recv(sock, buf, 1024, 0);
    01170       if ((r == 0) || (r == SOCKET_ERROR)) {
    01171         break;
    01172       }
    01173     }
    01174     closesocket(sock);
    01175   }
    01176 }
    01177 #endif
    01178
    01179
    01180 #else
    01181 #define fluid_socket_read(_S,_B,_L) read(_S,_B,_L)
    01182 #define fluid_socket_write(_S,_B,_L) write(_S,_B,_L)
    01183 #define SOCKET_ERROR -1
    01184
    01185 void fluid_socket_close(fluid_socket_t sock)
    01186 {
    01187   if (sock != INVALID_SOCKET) {
    01188     close(sock);
    01189   }
    01190 }
    01191
    01192 #endif
    01193
    01194 #if !defined(MACINTOSH) && !defined(WIN32)
    01195
    01196
    01197 fluid_istream_t fluid_socket_get_istream(fluid_socket_t sock)
    01198 {
    01199   return sock;
    01200 }
    01201
    01202 fluid_ostream_t fluid_socket_get_ostream(fluid_socket_t sock)
    01203 {
    01204   return sock;
    01205 }
    01206
    01207
    01208
    01209 struct _fluid_server_socket_t {
    01210   fluid_socket_t socket;
    01211   fluid_thread_t* thread;
    01212   int cont;
    01213   fluid_server_func_t func;
    01214   void* data;
    01215 };
    01216
    01217
    01218 static void fluid_server_socket_run(void* data)
    01219 {
    01220   fluid_server_socket_t* server_socket = (fluid_server_socket_t*) data;
    01221   fluid_socket_t client_socket;
    01222   struct sockaddr_in addr;
    01223   socklen_t addrlen = sizeof(addr);
    01224
    01225   FLUID_LOG(FLUID_DBG, "Server listening for connections");
    01226
    01227   while (server_socket->cont) {
    01228
    01229     client_socket = accept(server_socket->socket, (struct sockaddr*) &addr, &addrlen);
    01230
    01231     FLUID_LOG(FLUID_DBG, "New client connection");
    01232
    01233     if (client_socket == INVALID_SOCKET) {
    01234       if (server_socket->cont) {
    01235         FLUID_LOG(FLUID_ERR, "Failed to accept connection");
    01236       }
    01237       server_socket->cont = 0;
    01238       return;
    01239     } else {
    01240       int r;
    01241       r = (*server_socket->func)(server_socket->data, client_socket, inet_ntoa(addr.sin_addr));
    01242       if (r != 0) {
    01243         fluid_socket_close(client_socket);
    01244       }
    01245     }
    01246   }
    01247
    01248   FLUID_LOG(FLUID_DBG, "Server closing");
    01249 }
    01250
    01251 fluid_server_socket_t*
    01252 new_fluid_server_socket(int port, fluid_server_func_t func, void* data)
    01253 {
    01254   fluid_server_socket_t* server_socket;
    01255   struct sockaddr_in addr;
    01256   fluid_socket_t sock;
    01257
    01258   if (func == NULL) {
    01259     FLUID_LOG(FLUID_ERR, "Invalid callback function");
    01260     return NULL;
    01261   }
    01262
    01263   sock = socket(AF_INET, SOCK_STREAM, 0);
    01264   if (sock == INVALID_SOCKET) {
    01265     FLUID_LOG(FLUID_ERR, "Failed to create server socket");
    01266     return NULL;
    01267   }
    01268
    01269   FLUID_MEMSET((char *)&addr, 0, sizeof(struct sockaddr_in));
    01270   addr.sin_family = AF_INET;
    01271   addr.sin_addr.s_addr = htonl(INADDR_ANY);
    01272   addr.sin_port = htons(port);
    01273
    01274   if (bind(sock, (const struct sockaddr *) &addr, sizeof(struct sockaddr_in)) == SOCKET_ERROR) {
    01275     FLUID_LOG(FLUID_ERR, "Failed to bind server socket");
    01276     fluid_socket_close(sock);
    01277     return NULL;
    01278   }
    01279
    01280   if (listen(sock, 10) == SOCKET_ERROR) {
    01281     FLUID_LOG(FLUID_ERR, "Failed listen on server socket");
    01282     fluid_socket_close(sock);
    01283     return NULL;
    01284   }
    01285
    01286   server_socket = FLUID_NEW(fluid_server_socket_t);
    01287   if (server_socket == NULL) {
    01288     FLUID_LOG(FLUID_ERR, "Out of memory");
    01289     fluid_socket_close(sock);
    01290     return NULL;
    01291   }
    01292
    01293   server_socket->socket = sock;
    01294   server_socket->func = func;
    01295   server_socket->data = data;
    01296   server_socket->cont = 1;
    01297
    01298   server_socket->thread = new_fluid_thread(fluid_server_socket_run, server_socket, 0);
    01299   if (server_socket->thread == NULL) {
    01300     FLUID_FREE(server_socket);
    01301     fluid_socket_close(sock);
    01302     return NULL;
    01303   }
    01304
    01305   return server_socket;
    01306 }
    01307
    01308 int delete_fluid_server_socket(fluid_server_socket_t* server_socket)
    01309 {
    01310   server_socket->cont = 0;
    01311   if (server_socket->socket != INVALID_SOCKET) {
    01312     fluid_socket_close(server_socket->socket);
    01313   }
    01314   if (server_socket->thread) {
    01315     delete_fluid_thread(server_socket->thread);
    01316   }
    01317   FLUID_FREE(server_socket);
    01318   return FLUID_OK;
    01319 }
    01320
    01321 int fluid_server_socket_join(fluid_server_socket_t* server_socket)
    01322 {
    01323   return fluid_thread_join(server_socket->thread);
    01324 }
    01325
    01326 #endif