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

Generated on Sat Nov 17 13:40:23 2007 for libfluidsynth by  doxygen 1.5.3