Main Page   Data Structures   File List   Data Fields   Globals  

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 #elif defined(__OS2__)
00640 /*=============================================================*/
00641 /*                                                             */
00642 /*                           OS2                               */
00643 /*                                                             */
00644 /*=============================================================*/
00645 
00646 /***************************************************************
00647  *
00648  *               Timer
00649  *
00650  */
00651 
00652 struct _fluid_timer_t
00653 {
00654   long msec;
00655   fluid_timer_callback_t callback;
00656   void* data;
00657   int thread_id;
00658   int cont;
00659   int auto_destroy;
00660 };
00661 
00662 static int fluid_timer_count = 0;
00663 void fluid_timer_run(void *data);
00664 
00665 fluid_timer_t*
00666 new_fluid_timer(int msec, fluid_timer_callback_t callback, void* data,
00667            int new_thread, int auto_destroy)
00668 {
00669   fluid_timer_t* timer = FLUID_NEW(fluid_timer_t);
00670   if (timer == NULL) {
00671     FLUID_LOG(FLUID_ERR, "Out of memory");
00672     return NULL;
00673   }
00674 
00675   timer->cont = 1;
00676   timer->msec = msec;
00677   timer->callback = callback;
00678   timer->data = data;
00679   timer->thread_id =-1;
00680   timer->auto_destroy = auto_destroy;
00681 
00682   if (new_thread) {
00683     timer->thread_id = _beginthread( fluid_timer_run, NULL, 256 * 1024, ( void * )timer );
00684     if (timer->thread_id == -1) {
00685       FLUID_LOG(FLUID_ERR, "Couldn't create timer thread");
00686       FLUID_FREE(timer);
00687       return NULL;
00688     }
00689     DosSetPriority(PRTYS_THREAD, PRTYC_TIMECRITICAL, PRTYD_MAXIMUM, timer->thread_id);
00690   } else {
00691     fluid_timer_run(( void * )timer);
00692   }
00693   return timer;
00694 }
00695 
00696 void
00697 fluid_timer_run(void *data)
00698 {
00699   int count = 0;
00700   int cont = 1;
00701   long start;
00702   long delay;
00703   fluid_timer_t* timer;
00704   timer = (fluid_timer_t*) data;
00705 
00706   if ((timer == NULL) || (timer->callback == NULL)) {
00707     return;
00708   }
00709 
00710   DosSetPriority( PRTYS_THREAD, PRTYC_REGULAR, PRTYD_MAXIMUM, 0 );
00711 
00712   /* keep track of the start time for absolute positioning */
00713   start = fluid_curtime();
00714 
00715   while (cont) {
00716 
00717     /* do whatever we have to do */
00718     cont = (*timer->callback)(timer->data, fluid_curtime() - start);
00719 
00720     count++;
00721 
00722     /* to avoid incremental time errors, I calculate the delay between
00723        two callbacks bringing in the "absolute" time (count *
00724        timer->msec) */
00725     delay = (count * timer->msec) - (fluid_curtime() - start);
00726     if (delay > 0) {
00727       DosSleep(delay);
00728     }
00729 
00730     cont &= timer->cont;
00731   }
00732 
00733   FLUID_LOG(FLUID_DBG, "Timer thread finished");
00734 
00735   if (timer->auto_destroy) {
00736     FLUID_FREE(timer);
00737   }
00738 
00739   return;
00740 }
00741 
00742 int
00743 delete_fluid_timer(fluid_timer_t* timer)
00744 {
00745   timer->cont = 0;
00746   fluid_timer_join(timer);
00747   FLUID_FREE(timer);
00748   return FLUID_OK;
00749 }
00750 
00751 int
00752 fluid_timer_join(fluid_timer_t* timer)
00753 {
00754   ULONG wait_result;
00755   if (timer->thread_id == -1) {
00756     return FLUID_OK;
00757   }
00758   wait_result = DosWaitThread(&timer->thread_id, DCWW_WAIT);
00759   return (wait_result == 0)? FLUID_OK : FLUID_FAILED;
00760 }
00761 
00762 
00763 /***************************************************************
00764  *
00765  *               Time
00766  */
00767 
00768 double rdtsc(void);
00769 double fluid_estimate_cpu_frequency(void);
00770 
00771 static double fluid_cpu_frequency = -1.0;
00772 
00773 void fluid_time_config(void)
00774 {
00775   if (fluid_cpu_frequency < 0.0) {
00776     fluid_cpu_frequency = fluid_estimate_cpu_frequency() / 1000000.0;
00777   }
00778 }
00779 
00780 unsigned int fluid_curtime(void)
00781 {
00782   ULONG ulMS;
00783   DosQuerySysInfo( QSV_MS_COUNT, QSV_MS_COUNT, &ulMS, sizeof( ULONG ));
00784   return ulMS;
00785 }
00786 
00787 double fluid_utime(void)
00788 {
00789   return (rdtsc() / fluid_cpu_frequency);
00790 }
00791 
00792 #define Q2ULL( q ) (*(unsigned long long *)&q)
00793 
00794 double rdtsc(void)
00795 {
00796   QWORD t;
00797   DosTmrQueryTime(&t);
00798   return (double)Q2ULL(t);
00799 }
00800 
00801 double fluid_estimate_cpu_frequency(void)
00802 {
00803   unsigned int before, after;
00804   QWORD start, stop;
00805 
00806   before = fluid_curtime();
00807   DosTmrQueryTime(&start);
00808 
00809   DosSleep(1000);
00810 
00811   after = fluid_curtime();
00812   DosTmrQueryTime(&stop);
00813 
00814   return (double) 1000 * (Q2ULL(stop) - Q2ULL(start)) / (after - before);
00815 }
00816 
00817 
00818 
00819 #else
00820 
00821 /*=============================================================*/
00822 /*                                                             */
00823 /*                           POSIX                             */
00824 /*                                                             */
00825 /*=============================================================*/
00826 
00827 
00828 /***************************************************************
00829  *
00830  *               Timer
00831  */
00832 
00833 struct _fluid_timer_t
00834 {
00835   long msec;
00836   fluid_timer_callback_t callback;
00837   void* data;
00838   pthread_t thread;
00839   int cont;
00840   int auto_destroy;
00841 };
00842 
00843 void*
00844 fluid_timer_start(void *data)
00845 {
00846   int count = 0;
00847   int cont = 1;
00848   long start;
00849   long delay;
00850   fluid_timer_t* timer;
00851   timer = (fluid_timer_t*) data;
00852 
00853   /* keep track of the start time for absolute positioning */
00854   start = fluid_curtime();
00855 
00856   while (cont) {
00857 
00858     /* do whatever we have to do */
00859     cont = (*timer->callback)(timer->data, fluid_curtime() - start);
00860 
00861     count++;
00862 
00863     /* to avoid incremental time errors, calculate the delay between
00864        two callbacks bringing in the "absolute" time (count *
00865        timer->msec) */
00866     delay = (count * timer->msec) - (fluid_curtime() - start);
00867     if (delay > 0) {
00868       usleep(delay * 1000);
00869     }
00870 
00871     cont &= timer->cont;
00872   }
00873 
00874   FLUID_LOG(FLUID_DBG, "Timer thread finished");
00875   if (timer->thread != 0) {
00876     pthread_exit(NULL);
00877   }
00878 
00879   if (timer->auto_destroy) {
00880     FLUID_FREE(timer);
00881   }
00882 
00883   return NULL;
00884 }
00885 
00886 fluid_timer_t*
00887 new_fluid_timer(int msec, fluid_timer_callback_t callback, void* data,
00888            int new_thread, int auto_destroy)
00889 {
00890   pthread_attr_t *attr = NULL;
00891   pthread_attr_t rt_attr;
00892   int sched = SCHED_FIFO;
00893   struct sched_param priority;
00894   int err;
00895 
00896   fluid_timer_t* timer = FLUID_NEW(fluid_timer_t);
00897   if (timer == NULL) {
00898     FLUID_LOG(FLUID_ERR, "Out of memory");
00899     return NULL;
00900   }
00901   timer->msec = msec;
00902   timer->callback = callback;
00903   timer->data = data;
00904   timer->cont = 1;
00905   timer->thread = 0;
00906   timer->auto_destroy = auto_destroy;
00907 
00908   err = pthread_attr_init(&rt_attr);
00909   if (err == 0) {
00910       err = pthread_attr_setschedpolicy(&rt_attr, SCHED_FIFO);
00911       if (err == 0) {
00912           priority.sched_priority = 10;
00913           err = pthread_attr_setschedparam(&rt_attr, &priority);
00914           if (err == 0) {
00915               attr = &rt_attr;
00916           }
00917       }
00918   }
00919 
00920   if (new_thread) {
00921       err = pthread_create(&timer->thread, attr, fluid_timer_start, (void*) timer);
00922       if (err == 0) {
00923           FLUID_LOG(FLUID_DBG, "The timer thread was created with real-time priority");
00924       } else {
00925           /* Create the thread with default attributes */
00926           err = pthread_create(&timer->thread, NULL, fluid_timer_start, (void*) timer);
00927           if (err != 0) {
00928               FLUID_LOG(FLUID_ERR, "Failed to create the timer thread");
00929               FLUID_FREE(timer);
00930               return NULL;
00931           } else {
00932               FLUID_LOG(FLUID_DBG, "The timer thread does not have real-time priority");
00933           }
00934       }
00935   } else {
00936     fluid_timer_start((void*) timer);
00937   }
00938   return timer;
00939 }
00940 
00941 int
00942 delete_fluid_timer(fluid_timer_t* timer)
00943 {
00944   timer->cont = 0;
00945   fluid_timer_join(timer);
00946   FLUID_LOG(FLUID_DBG, "Joined player thread");
00947   FLUID_FREE(timer);
00948   return FLUID_OK;
00949 }
00950 
00951 int
00952 fluid_timer_join(fluid_timer_t* timer)
00953 {
00954   int err = 0;
00955 
00956   if (timer->thread != 0) {
00957     err = pthread_join(timer->thread, NULL);
00958   }
00959   FLUID_LOG(FLUID_DBG, "Joined player thread");
00960   return (err == 0)? FLUID_OK : FLUID_FAILED;
00961 }
00962 
00963 
00964 /***************************************************************
00965  *
00966  *               Time
00967  */
00968 
00969 static double fluid_cpu_frequency = -1.0;
00970 
00971 double rdtsc(void);
00972 double fluid_estimate_cpu_frequency(void);
00973 
00974 void fluid_time_config(void)
00975 {
00976   if (fluid_cpu_frequency < 0.0) {
00977     fluid_cpu_frequency = fluid_estimate_cpu_frequency() / 1000000.0;
00978     if (fluid_cpu_frequency == 0.0) fluid_cpu_frequency = 1.0;
00979   }
00980 }
00981 
00982 unsigned int fluid_curtime()
00983 {
00984   struct timeval now;
00985   gettimeofday(&now, NULL);
00986   return now.tv_sec * 1000 + now.tv_usec / 1000;
00987 }
00988 
00989 double fluid_utime(void)
00990 {
00991   return (rdtsc() / fluid_cpu_frequency);
00992 }
00993 
00994 #if !defined(__i386__)
00995 
00996 double rdtsc(void)
00997 {
00998   return 0.0;
00999 }
01000 
01001 double fluid_estimate_cpu_frequency(void)
01002 {
01003   return 1.0;
01004 }
01005 
01006 #else
01007 
01008 double rdtsc(void)
01009 {
01010   unsigned int a, b;
01011 
01012   __asm__ ("rdtsc" : "=a" (a), "=d" (b));
01013   return (double)b * (double)0x10000 * (double)0x10000 + a;
01014 }
01015 
01016 double fluid_estimate_cpu_frequency(void)
01017 {
01018   double start, stop;
01019   unsigned int a0, b0, a1, b1;
01020   unsigned int before, after;
01021 
01022   before = fluid_curtime();
01023   __asm__ ("rdtsc" : "=a" (a0), "=d" (b0));
01024 
01025   sleep(1);
01026 
01027   after = fluid_curtime();
01028   __asm__ ("rdtsc" : "=a" (a1), "=d" (b1));
01029 
01030 
01031   start = (double)b0 * (double)0x10000 * (double)0x10000 + a0;
01032   stop = (double)b1 * (double)0x10000 * (double)0x10000 + a1;
01033 
01034   return 1000 * (stop - start) / (after - before);
01035 }
01036 #endif
01037 
01038 
01039 #ifdef FPE_CHECK
01040 
01041 /***************************************************************
01042  *
01043  *               Floating point exceptions
01044  *
01045  *  The floating point exception functions were taken from Ircam's
01046  *  jMax source code. http://www.ircam.fr/jmax
01047  *
01048  *  FIXME: check in config for i386 machine
01049  *
01050  *  Currently not used. I leave the code here in case we want to pick
01051  *  this up again some time later.
01052  */
01053 
01054 /* Exception flags */
01055 #define _FPU_STATUS_IE    0x001  /* Invalid Operation */
01056 #define _FPU_STATUS_DE    0x002  /* Denormalized Operand */
01057 #define _FPU_STATUS_ZE    0x004  /* Zero Divide */
01058 #define _FPU_STATUS_OE    0x008  /* Overflow */
01059 #define _FPU_STATUS_UE    0x010  /* Underflow */
01060 #define _FPU_STATUS_PE    0x020  /* Precision */
01061 #define _FPU_STATUS_SF    0x040  /* Stack Fault */
01062 #define _FPU_STATUS_ES    0x080  /* Error Summary Status */
01063 
01064 /* Macros for accessing the FPU status word.  */
01065 
01066 /* get the FPU status */
01067 #define _FPU_GET_SW(sw) __asm__ ("fnstsw %0" : "=m" (*&sw))
01068 
01069 /* clear the FPU status */
01070 #define _FPU_CLR_SW() __asm__ ("fnclex" : : )
01071 
01072 /* Purpose:
01073  * Checks, if the floating point unit has produced an exception, print a message
01074  * if so and clear the exception.
01075  */
01076 unsigned int fluid_check_fpe_i386(char* explanation)
01077 {
01078   unsigned int s;
01079 
01080   _FPU_GET_SW(s);
01081   _FPU_CLR_SW();
01082 
01083   s &= _FPU_STATUS_IE | _FPU_STATUS_DE | _FPU_STATUS_ZE | _FPU_STATUS_OE | _FPU_STATUS_UE;
01084 
01085   if (s)
01086   {
01087       FLUID_LOG(FLUID_WARN, "FPE exception (before or in %s): %s%s%s%s%s", explanation,
01088            (s & _FPU_STATUS_IE) ? "Invalid operation " : "",
01089            (s & _FPU_STATUS_DE) ? "Denormal number " : "",
01090            (s & _FPU_STATUS_ZE) ? "Zero divide " : "",
01091            (s & _FPU_STATUS_OE) ? "Overflow " : "",
01092            (s & _FPU_STATUS_UE) ? "Underflow " : "");
01093   }
01094 
01095   return s;
01096 }
01097 
01098 /* Purpose:
01099  * Clear floating point exception.
01100  */
01101 void fluid_clear_fpe_i386 (void)
01102 {
01103   _FPU_CLR_SW();
01104 }
01105 
01106 #endif  // ifdef FPE_CHECK
01107 
01108 
01109 #endif  // #else    (its POSIX)
01110 
01111 
01112 /***************************************************************
01113  *
01114  *               Profiling (Linux, i586 only)
01115  *
01116  */
01117 
01118 #if WITH_PROFILING
01119 
01120 fluid_profile_data_t fluid_profile_data[] =
01121 {
01122   { FLUID_PROF_WRITE_S16,        "fluid_synth_write_s16           ", 1e10, 0.0, 0.0, 0},
01123   { FLUID_PROF_ONE_BLOCK,        "fluid_synth_one_block           ", 1e10, 0.0, 0.0, 0},
01124   { FLUID_PROF_ONE_BLOCK_CLEAR,  "fluid_synth_one_block:clear     ", 1e10, 0.0, 0.0, 0},
01125   { FLUID_PROF_ONE_BLOCK_VOICE,  "fluid_synth_one_block:one voice ", 1e10, 0.0, 0.0, 0},
01126   { FLUID_PROF_ONE_BLOCK_VOICES, "fluid_synth_one_block:all voices", 1e10, 0.0, 0.0, 0},
01127   { FLUID_PROF_ONE_BLOCK_REVERB, "fluid_synth_one_block:reverb    ", 1e10, 0.0, 0.0, 0},
01128   { FLUID_PROF_ONE_BLOCK_CHORUS, "fluid_synth_one_block:chorus    ", 1e10, 0.0, 0.0, 0},
01129   { FLUID_PROF_VOICE_NOTE,       "fluid_voice:note                ", 1e10, 0.0, 0.0, 0},
01130   { FLUID_PROF_VOICE_RELEASE,    "fluid_voice:release             ", 1e10, 0.0, 0.0, 0},
01131   { FLUID_PROF_LAST, "last", 1e100, 0.0, 0.0, 0}
01132 };
01133 
01134 
01135 void fluid_profiling_print(void)
01136 {
01137   int i;
01138 
01139   printf("fluid_profiling_print\n");
01140 
01141   FLUID_LOG(FLUID_INFO, "Estimated CPU frequency: %.0f MHz", fluid_cpu_frequency);
01142   FLUID_LOG(FLUID_INFO, "Estimated times: min/avg/max (micro seconds)");
01143 
01144   for (i = 0; i < FLUID_PROF_LAST; i++) {
01145     if (fluid_profile_data[i].count > 0) {
01146       FLUID_LOG(FLUID_INFO, "%s: %.3f/%.3f/%.3f",
01147            fluid_profile_data[i].description,
01148            fluid_profile_data[i].min,
01149            fluid_profile_data[i].total / fluid_profile_data[i].count,
01150            fluid_profile_data[i].max);
01151     } else {
01152       FLUID_LOG(FLUID_DBG, "%s: no profiling available", fluid_profile_data[i].description);
01153     }
01154   }
01155 }
01156 
01157 
01158 #endif /* WITH_PROFILING */
01159 
01160 
01161 
01162 /***************************************************************
01163  *
01164  *               Threads
01165  *
01166  */
01167 
01168 #if defined(MACOS9)
01169 /* Not implemented */
01170 fluid_thread_t* new_fluid_thread(fluid_thread_func_t func, void* data, int detach) { return NULL; }
01171 int delete_fluid_thread(fluid_thread_t* thread) { return 0; }
01172 int fluid_thread_join(fluid_thread_t* thread) { return 0; }
01173 
01174 #elif defined(WIN32)
01175 
01176 struct _fluid_thread_t {
01177   HANDLE thread;
01178   DWORD thread_id;
01179   fluid_thread_func_t func;
01180   void* data;
01181   int detached;
01182 };
01183 
01184 static DWORD WINAPI fluid_thread_start(LPVOID data)
01185 {
01186   fluid_thread_t* thread = (fluid_thread_t*) data;
01187 
01188   thread->func(thread->data);
01189 
01190   if (thread->detached) {
01191     FLUID_FREE(thread);
01192   }
01193 
01194   return 0;
01195 }
01196 
01197 
01198 fluid_thread_t* new_fluid_thread(fluid_thread_func_t func, void* data, int detach)
01199 {
01200   fluid_thread_t* thread;
01201 
01202   if (func == NULL) {
01203     FLUID_LOG(FLUID_ERR, "Invalid thread function");
01204     return NULL;
01205   }
01206 
01207   thread = FLUID_NEW(fluid_thread_t);
01208   if (thread == NULL) {
01209     FLUID_LOG(FLUID_ERR, "Out of memory");
01210     return NULL;
01211   }
01212 
01213   thread->data = data;
01214   thread->func = func;
01215   thread->detached = detach;
01216 
01217   thread->thread = CreateThread(NULL, 0, fluid_thread_start, (LPVOID) thread,
01218                 0, &thread->thread_id);
01219   if (thread->thread == NULL) {
01220     FLUID_LOG(FLUID_ERR, "Couldn't create the thread");
01221     FLUID_FREE(thread);
01222     return NULL;
01223   }
01224 
01225   return thread;
01226 }
01227 
01228 int delete_fluid_thread(fluid_thread_t* thread)
01229 {
01230   FLUID_FREE(thread);
01231   return FLUID_OK;
01232 }
01233 
01234 
01235 int fluid_thread_join(fluid_thread_t* thread)
01236 {
01237   DWORD wait_result;
01238   if (thread->thread == 0) {
01239     return FLUID_OK;
01240   }
01241   wait_result = WaitForSingleObject(thread->thread, INFINITE);
01242   return (wait_result == WAIT_OBJECT_0)? FLUID_OK : FLUID_FAILED;
01243 }
01244 
01245 #elif defined(__OS2__)
01246 
01247 struct _fluid_thread_t {
01248   int thread_id;
01249   fluid_thread_func_t func;
01250   void* data;
01251   int detached;
01252 };
01253 
01254 static void fluid_thread_start(void *data)
01255 {
01256   fluid_thread_t* thread = (fluid_thread_t*) data;
01257 
01258   thread->func(thread->data);
01259 
01260   if (thread->detached) {
01261     FLUID_FREE(thread);
01262   }
01263 
01264   return 0;
01265 }
01266 
01267 
01268 fluid_thread_t* new_fluid_thread(fluid_thread_func_t func, void* data, int detach)
01269 {
01270   fluid_thread_t* thread;
01271 
01272   if (func == NULL) {
01273     FLUID_LOG(FLUID_ERR, "Invalid thread function");
01274     return NULL;
01275   }
01276 
01277   thread = FLUID_NEW(fluid_thread_t);
01278   if (thread == NULL) {
01279     FLUID_LOG(FLUID_ERR, "Out of memory");
01280     return NULL;
01281   }
01282 
01283   thread->data = data;
01284   thread->func = func;
01285   thread->detached = detach;
01286 
01287   thread->thread_id = _beginthread(fluid_thread_start, NULL, 256 * 1024, (void *) thread);
01288   if (thread->thread_id == -1) {
01289     FLUID_LOG(FLUID_ERR, "Couldn't create the thread");
01290     FLUID_FREE(thread);
01291     return NULL;
01292   }
01293 
01294   return thread;
01295 }
01296 
01297 int delete_fluid_thread(fluid_thread_t* thread)
01298 {
01299   FLUID_FREE(thread);
01300   return FLUID_OK;
01301 }
01302 
01303 
01304 int fluid_thread_join(fluid_thread_t* thread)
01305 {
01306   ULONG wait_result;
01307   if (thread->thread_id == -1) {
01308     return FLUID_OK;
01309   }
01310   wait_result = DosWaitThread(&thread->thread_id, DCWW_WAIT);
01311   return (wait_result == 0)? FLUID_OK : FLUID_FAILED;
01312 }
01313 
01314 #else
01315 
01316 
01317 struct _fluid_thread_t {
01318   pthread_t pthread;
01319   fluid_thread_func_t func;
01320   void* data;
01321   int detached;
01322 };
01323 
01324 static void* fluid_thread_start(void *data)
01325 {
01326   fluid_thread_t* thread = (fluid_thread_t*) data;
01327 
01328   thread->func(thread->data);
01329 
01330   if (thread->detached) {
01331     FLUID_FREE(thread);
01332   }
01333 
01334   return NULL;
01335 }
01336 
01337 fluid_thread_t* new_fluid_thread(fluid_thread_func_t func, void* data, int detach)
01338 {
01339   fluid_thread_t* thread;
01340   pthread_attr_t attr;
01341 
01342   if (func == NULL) {
01343     FLUID_LOG(FLUID_ERR, "Invalid thread function");
01344     return NULL;
01345   }
01346 
01347   thread = FLUID_NEW(fluid_thread_t);
01348   if (thread == NULL) {
01349     FLUID_LOG(FLUID_ERR, "Out of memory");
01350     return NULL;
01351   }
01352 
01353   thread->data = data;
01354   thread->func = func;
01355   thread->detached = detach;
01356 
01357   pthread_attr_init(&attr);
01358 
01359   if (detach) {
01360     pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
01361   }
01362 
01363   if (pthread_create(&thread->pthread, &attr, fluid_thread_start, thread)) {
01364     FLUID_LOG(FLUID_ERR, "Failed to create the thread");
01365     FLUID_FREE(thread);
01366     return NULL;
01367   }
01368 
01369   return thread;
01370 }
01371 
01372 int delete_fluid_thread(fluid_thread_t* thread)
01373 {
01374   FLUID_FREE(thread);
01375   return FLUID_OK;
01376 }
01377 
01378 int fluid_thread_join(fluid_thread_t* thread)
01379 {
01380   int err = 0;
01381 
01382   if (thread->pthread != 0) {
01383     err = pthread_join(thread->pthread, NULL);
01384   }
01385   return (err == 0)? FLUID_OK : FLUID_FAILED;
01386 }
01387 
01388 #endif
01389 
01390 
01391 
01392 /***************************************************************
01393  *
01394  *               Sockets
01395  *
01396  */
01397 
01398 
01399 #if defined(MACINTOSH)
01400 /* Not implemented */
01401 
01402 
01403 #elif defined(WIN32)
01404 
01405 #if 0
01406 typedef unsigned int socklen_t;
01407 
01408 #define fluid_socket_read(_S,_B,_L) recv(_S,_B,_L,0)
01409 #define fluid_socket_write(_S,_B,_L) send(_S,_B,_L,0)
01410 
01411 void fluid_socket_close(fluid_socket_t sock)
01412 {
01413   int r;
01414   char buf[1024];
01415   if (sock != INVALID_SOCKET) {
01416     shutdown(sock, 0x02);
01417     while (1) {
01418       r = recv(sock, buf, 1024, 0);
01419       if ((r == 0) || (r == SOCKET_ERROR)) {
01420     break;
01421       }
01422     }
01423     closesocket(sock);
01424   }
01425 }
01426 #endif
01427 
01428 
01429 #else
01430 #define fluid_socket_read(_S,_B,_L) read(_S,_B,_L)
01431 #define fluid_socket_write(_S,_B,_L) write(_S,_B,_L)
01432 #define SOCKET_ERROR -1
01433 
01434 void fluid_socket_close(fluid_socket_t sock)
01435 {
01436   if (sock != INVALID_SOCKET) {
01437     close(sock);
01438   }
01439 }
01440 
01441 #endif
01442 
01443 #if !defined(MACINTOSH) && !defined(WIN32)
01444 
01445 
01446 fluid_istream_t fluid_socket_get_istream(fluid_socket_t sock)
01447 {
01448   return sock;
01449 }
01450 
01451 fluid_ostream_t fluid_socket_get_ostream(fluid_socket_t sock)
01452 {
01453   return sock;
01454 }
01455 
01456 
01457 
01458 struct _fluid_server_socket_t {
01459   fluid_socket_t socket;
01460   fluid_thread_t* thread;
01461   int cont;
01462   fluid_server_func_t func;
01463   void* data;
01464 };
01465 
01466 
01467 static void fluid_server_socket_run(void* data)
01468 {
01469   fluid_server_socket_t* server_socket = (fluid_server_socket_t*) data;
01470   fluid_socket_t client_socket;
01471   struct sockaddr_in addr;
01472   socklen_t addrlen = sizeof(addr);
01473 
01474   FLUID_LOG(FLUID_DBG, "Server listening for connections");
01475 
01476   while (server_socket->cont) {
01477 
01478     client_socket = accept(server_socket->socket, (struct sockaddr*) &addr, &addrlen);
01479 
01480     FLUID_LOG(FLUID_DBG, "New client connection");
01481 
01482     if (client_socket == INVALID_SOCKET) {
01483       if (server_socket->cont) {
01484     FLUID_LOG(FLUID_ERR, "Failed to accept connection");
01485       }
01486       server_socket->cont = 0;
01487       return;
01488     } else {
01489       int r;
01490       r = (*server_socket->func)(server_socket->data, client_socket, inet_ntoa(addr.sin_addr));
01491       if (r != 0) {
01492     fluid_socket_close(client_socket);
01493       }
01494     }
01495   }
01496 
01497   FLUID_LOG(FLUID_DBG, "Server closing");
01498 }
01499 
01500 fluid_server_socket_t*
01501 new_fluid_server_socket(int port, fluid_server_func_t func, void* data)
01502 {
01503   fluid_server_socket_t* server_socket;
01504   struct sockaddr_in addr;
01505   fluid_socket_t sock;
01506 
01507   if (func == NULL) {
01508     FLUID_LOG(FLUID_ERR, "Invalid callback function");
01509     return NULL;
01510   }
01511 
01512   sock = socket(AF_INET, SOCK_STREAM, 0);
01513   if (sock == INVALID_SOCKET) {
01514     FLUID_LOG(FLUID_ERR, "Failed to create server socket");
01515     return NULL;
01516   }
01517 
01518   FLUID_MEMSET((char *)&addr, 0, sizeof(struct sockaddr_in));
01519   addr.sin_family = AF_INET;
01520   addr.sin_addr.s_addr = htonl(INADDR_ANY);
01521   addr.sin_port = htons(port);
01522 
01523   if (bind(sock, (const struct sockaddr *) &addr, sizeof(struct sockaddr_in)) == SOCKET_ERROR) {
01524     FLUID_LOG(FLUID_ERR, "Failed to bind server socket");
01525     fluid_socket_close(sock);
01526     return NULL;
01527   }
01528 
01529   if (listen(sock, 10) == SOCKET_ERROR) {
01530     FLUID_LOG(FLUID_ERR, "Failed listen on server socket");
01531     fluid_socket_close(sock);
01532     return NULL;
01533   }
01534 
01535   server_socket = FLUID_NEW(fluid_server_socket_t);
01536   if (server_socket == NULL) {
01537     FLUID_LOG(FLUID_ERR, "Out of memory");
01538     fluid_socket_close(sock);
01539     return NULL;
01540   }
01541 
01542   server_socket->socket = sock;
01543   server_socket->func = func;
01544   server_socket->data = data;
01545   server_socket->cont = 1;
01546 
01547   server_socket->thread = new_fluid_thread(fluid_server_socket_run, server_socket, 0);
01548   if (server_socket->thread == NULL) {
01549     FLUID_FREE(server_socket);
01550     fluid_socket_close(sock);
01551     return NULL;
01552   }
01553 
01554   return server_socket;
01555 }
01556 
01557 int delete_fluid_server_socket(fluid_server_socket_t* server_socket)
01558 {
01559   server_socket->cont = 0;
01560   if (server_socket->socket != INVALID_SOCKET) {
01561     fluid_socket_close(server_socket->socket);
01562   }
01563   if (server_socket->thread) {
01564     delete_fluid_thread(server_socket->thread);
01565   }
01566   FLUID_FREE(server_socket);
01567   return FLUID_OK;
01568 }
01569 
01570 int fluid_server_socket_join(fluid_server_socket_t* server_socket)
01571 {
01572   return fluid_thread_join(server_socket->thread);
01573 }
01574 
01575 #endif

Generated on Tue Aug 26 12:20:27 2008 for libfluidsynth by doxygen1.2.11.1 written by Dimitri van Heesch, © 1997-2001