import 0.1.7.1
[aubio.git] / src / timer.c
1 /* 
2  *
3  * This library is free software; you can redistribute it and/or
4  * modify it under the terms of the GNU Library General Public License
5  * as published by the Free Software Foundation; either version 2 of
6  * the License, or (at your option) any later version.
7  *
8  * This library is distributed in the hope that it will be useful, but
9  * WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11  * Library General Public License for more details.
12  *  
13  * You should have received a copy of the GNU Library General Public
14  * License along with this library; if not, write to the Free
15  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
16  * 02111-1307, USA
17  */
18
19 /* this file originally taken from FluidSynth - A Software Synthesizer
20  * Copyright (C) 2003  Peter Hanappe and others.
21  */
22
23 #include "aubio_priv.h"
24 #include "timer.h"
25
26 #if defined(WIN32)
27
28 /*=============================================================*/
29 /*                                                             */
30 /*                           Win32                             */
31 /*                                                             */
32 /*=============================================================*/
33
34 /***************************************************************
35  *
36  *               Timer
37  *
38  */
39 #include <windef.h>
40
41 #if 0
42 #include <winbase.h>
43
44 struct _aubio_timer_t 
45 {
46   long msec;
47   aubio_timer_callback_t callback;
48   void* data;
49   HANDLE thread;
50   DWORD thread_id;
51   int cont;
52   int auto_destroy;
53 };
54
55 static int aubio_timer_count = 0;
56 DWORD WINAPI aubio_timer_run(LPVOID data);
57
58 aubio_timer_t* 
59 new_aubio_timer(int msec, aubio_timer_callback_t callback, void* data, 
60            int new_thread, int auto_destroy)
61 {
62   aubio_timer_t* timer = AUBIO_NEW(aubio_timer_t);
63   if (timer == NULL) {
64     AUBIO_ERR( "Out of memory");     
65     return NULL;
66   }
67
68   timer->cont = 1;
69   timer->msec = msec;
70   timer->callback = callback;
71   timer->data = data;
72   timer->thread = 0;
73   timer->auto_destroy = auto_destroy;
74
75   if (new_thread) {
76     timer->thread = CreateThread(NULL, 0, aubio_timer_run, (LPVOID) timer, 0, &timer->thread_id);
77     if (timer->thread == NULL) {
78       AUBIO_ERR( "Couldn't create timer thread");     
79       AUBIO_FREE(timer);
80       return NULL;
81     }
82     SetThreadPriority(timer->thread, THREAD_PRIORITY_TIME_CRITICAL);
83   } else {
84     aubio_timer_run((LPVOID) timer); 
85   }
86   return timer;
87 }
88
89 DWORD WINAPI 
90 aubio_timer_run(LPVOID data)
91 {
92   int count = 0;
93   int cont = 1;
94   long start;
95   long delay;
96   aubio_timer_t* timer;
97   timer = (aubio_timer_t*) data;
98
99   if ((timer == NULL) || (timer->callback == NULL)) {
100     return 0;
101   }
102
103   SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_HIGHEST);
104
105   /* keep track of the start time for absolute positioning */
106   start = aubio_curtime();
107
108   while (cont) {
109
110     /* do whatever we have to do */
111     cont = (*timer->callback)(timer->data, aubio_curtime() - start);
112
113     count++;
114
115     /* to avoid incremental time errors, I calculate the delay between
116        two callbacks bringing in the "absolute" time (count *
117        timer->msec) */
118     delay = (count * timer->msec) - (aubio_curtime() - start);
119     if (delay > 0) {
120       Sleep(delay);
121     }
122
123     cont &= timer->cont;
124   }
125
126   AUBIO_DBG( "Timer thread finished");
127
128   if (timer->auto_destroy) {
129     AUBIO_FREE(timer);
130   }
131
132   ExitThread(0);
133   return 0;
134 }
135
136 int 
137 delete_aubio_timer(aubio_timer_t* timer)
138 {
139   timer->cont = 0;
140   aubio_timer_join(timer); 
141   AUBIO_FREE(timer);
142   return AUBIO_OK;
143 }
144
145 int 
146 aubio_timer_join(aubio_timer_t* timer)
147 {
148   DWORD wait_result;
149   if (timer->thread == 0) {
150     return AUBIO_OK;
151   }
152   wait_result = WaitForSingleObject(timer->thread, INFINITE);
153   return (wait_result == WAIT_OBJECT_0)? AUBIO_OK : AUBIO_FAIL;
154 }
155 /***************************************************************
156  *
157  *               Time
158  */
159
160 double rdtsc(void);
161 double aubio_estimate_cpu_frequency(void);
162
163 static double aubio_cpu_frequency = -1.0;
164
165 void aubio_time_config(void)
166 {
167   if (aubio_cpu_frequency < 0.0) {
168     aubio_cpu_frequency = aubio_estimate_cpu_frequency() / 1000000.0;  
169   }
170 }
171
172 double aubio_utime(void)
173 {
174   return (rdtsc() / aubio_cpu_frequency);
175 }
176
177 double rdtsc(void)
178 {
179   LARGE_INTEGER t;
180   QueryPerformanceCounter(&t);
181   return (double) t.QuadPart;
182 }
183
184 double aubio_estimate_cpu_frequency(void)
185 {
186 #if 0
187   LONGLONG start, stop, ticks;
188   unsigned int before, after, delta;
189   double freq;
190
191   start = rdtsc();
192   stop = start;
193   before = aubio_curtime();
194   after = before;
195
196   while (1) {
197     if (after - before > 1000) {
198     break;
199     }
200     after = aubio_curtime();
201     stop = rdtsc();
202   }
203
204   delta = after - before;
205   ticks = stop - start;
206
207   freq = 1000 * ticks / delta;
208
209   return freq;
210
211 #else
212   unsigned int before, after;
213   LARGE_INTEGER start, stop;
214
215   before = aubio_curtime();
216   QueryPerformanceCounter(&start);
217
218   Sleep(1000);
219   
220   after = aubio_curtime();
221   QueryPerformanceCounter(&stop);
222
223   return (double) 1000 * (stop.QuadPart - start.QuadPart) / (after - before);
224 #endif
225 }
226
227 #endif
228
229
230 #elif defined(MACOS9)
231 /*=============================================================*/
232 /*                                                             */
233 /*                           MacOS 9                           */
234 /*                                                             */
235 /*=============================================================*/
236
237
238 /***************************************************************
239  *
240  *               Timer
241  */
242
243 struct _aubio_timer_t 
244 {
245     TMTask myTmTask;
246   long msec;
247   unsigned int start;
248   unsigned int count;
249   int isInstalled;
250   aubio_timer_callback_t callback;
251   void* data;
252   int auto_destroy;
253 };
254
255 static TimerUPP myTimerUPP;
256
257 void
258 _timerCallback(aubio_timer_t *timer)
259 {
260     int cont;
261   cont = (*timer->callback)(timer->data, aubio_curtime() - timer->start);
262   if (cont) {
263     PrimeTime((QElemPtr)timer, timer->msec);
264     } else {
265         timer->isInstalled = 0;
266     }
267   timer->count++;
268 }
269
270 aubio_timer_t* 
271 new_aubio_timer(int msec, aubio_timer_callback_t callback, void* data, 
272            int new_thread, int auto_destroy)
273 {
274   aubio_timer_t* timer = AUBIO_NEW(aubio_timer_t);
275   if (timer == NULL) {
276     AUBIO_ERR( "Out of memory");     
277     return NULL;
278   }
279
280     if (!myTimerUPP)
281         myTimerUPP = NewTimerProc(_timerCallback);
282
283   /* setup tmtask */
284     timer->myTmTask.tmAddr = myTimerUPP;
285     timer->myTmTask.qLink = NULL;
286     timer->myTmTask.qType = 0;
287     timer->myTmTask.tmCount = 0L;
288     timer->myTmTask.tmWakeUp = 0L;
289     timer->myTmTask.tmReserved = 0L;
290
291   timer->callback = callback;
292
293   timer->msec = msec;
294   timer->data = data;
295   timer->start = aubio_curtime();
296   timer->isInstalled = 1;
297   timer->count = 0;
298   timer->auto_destroy = auto_destroy;
299   
300   InsXTime((QElemPtr)timer);
301   PrimeTime((QElemPtr)timer, msec);
302
303   return timer;
304 }
305
306 int 
307 delete_aubio_timer(aubio_timer_t* timer)
308 {
309     if (timer->isInstalled) {
310         RmvTime((QElemPtr)timer);
311     }
312   AUBIO_FREE(timer);
313   return AUBIO_OK;
314 }
315
316 int 
317 aubio_timer_join(aubio_timer_t* timer)
318 {
319     if (timer->isInstalled) {
320         int count = timer->count;
321         /* wait until count has incremented */
322         while (count == timer->count) {}
323     }
324   return AUBIO_OK;
325 }
326
327 /***************************************************************
328  *
329  *               Time
330  */
331 #define kTwoPower32 (4294967296.0)      /* 2^32 */
332
333 void aubio_time_config(void)
334 {
335 }
336
337 unsigned int aubio_curtime()
338 {
339     /* could be optimized by not going though a double */
340     UnsignedWide    uS;
341     double mSf;
342     unsigned int ms;
343     
344     Microseconds(&uS);
345     
346   mSf = ((((double) uS.hi) * kTwoPower32) + uS.lo)/1000.0f;
347   
348   ms = mSf;
349   
350   return (ms);
351 }
352
353
354
355 #else
356
357 /*=============================================================*/
358 /*                                                             */
359 /*                           POSIX                             */
360 /*                                                             */
361 /*=============================================================*/
362
363 #include <pthread.h>
364 #include <unistd.h>
365 #include <sys/time.h>
366
367
368 /***************************************************************
369  *
370  *               Timer
371  */
372  
373 struct _aubio_timer_t 
374 {
375   long msec;
376   aubio_timer_callback_t callback;
377   void* data;
378   pthread_t thread;
379   int cont;
380   int auto_destroy;
381 };
382
383 void* 
384 aubio_timer_start(void *data)
385 {
386   int count = 0;
387   int cont = 1;
388   long start;
389   long delay;
390   aubio_timer_t* timer;
391   timer = (aubio_timer_t*) data;
392
393   /* keep track of the start time for absolute positioning */
394   start = aubio_curtime();
395
396   while (cont) {
397
398     /* do whatever we have to do */
399     cont = (*timer->callback)(timer->data, aubio_curtime() - start);
400
401     count++;
402
403     /* to avoid incremental time errors, calculate the delay between
404        two callbacks bringing in the "absolute" time (count *
405        timer->msec) */
406     delay = (count * timer->msec) - (aubio_curtime() - start);
407     if (delay > 0) {
408       usleep(delay * 1000);
409     }
410
411     cont &= timer->cont;
412   }
413
414   AUBIO_DBG( "Timer thread finished");
415   if (timer->thread != 0) {
416     pthread_exit(NULL);
417   }
418
419   if (timer->auto_destroy) {
420     AUBIO_FREE(timer);
421   }
422
423   return NULL;
424 }
425
426 aubio_timer_t* 
427 new_aubio_timer(int msec, aubio_timer_callback_t callback, void* data, 
428            int new_thread, int auto_destroy)
429 {
430   aubio_timer_t* timer = AUBIO_NEW(aubio_timer_t);
431   if (timer == NULL) {
432     AUBIO_ERR( "Out of memory");     
433     return NULL;
434   }
435   timer->msec = msec;
436   timer->callback = callback;
437   timer->data = data;
438   timer->cont = 1;
439   timer->thread = 0;
440   timer->auto_destroy = auto_destroy;
441
442   if (new_thread) {
443     if (pthread_create(&timer->thread, NULL, aubio_timer_start, (void*) timer)) {
444       AUBIO_ERR( "Failed to create the timer thread");
445       AUBIO_FREE(timer);
446       return NULL;
447     }
448   } else {
449     aubio_timer_start((void*) timer);
450   }
451   return timer;
452 }
453
454 int 
455 delete_aubio_timer(aubio_timer_t* timer)
456 {
457   timer->cont = 0;
458   aubio_timer_join(timer);
459   AUBIO_DBG( "Deleted player thread\n");
460   AUBIO_FREE(timer);
461   return AUBIO_OK;
462 }
463
464 int 
465 aubio_timer_join(aubio_timer_t* timer)
466 {
467   int err = 0;
468
469   if (timer->thread != 0) {
470     err = pthread_join(timer->thread, NULL);
471   } else
472     AUBIO_DBG( "Joined player thread\n");
473   return (err == 0)? AUBIO_OK : AUBIO_FAIL;
474 }
475
476
477 /***************************************************************
478  *
479  *               Time
480  */
481
482 static double aubio_cpu_frequency = -1.0;
483
484 double rdtsc(void);
485 double aubio_estimate_cpu_frequency(void);
486
487 void aubio_time_config(void)
488 {
489   if (aubio_cpu_frequency < 0.0) {
490     aubio_cpu_frequency = aubio_estimate_cpu_frequency() / 1000000.0;  
491   }
492 }
493
494 unsigned int aubio_curtime()
495 {
496   struct timeval now;
497   gettimeofday(&now, NULL);
498   return now.tv_sec * 1000 + now.tv_usec / 1000;
499 }
500
501 double aubio_utime(void)
502 {
503   return (rdtsc() / aubio_cpu_frequency);
504 }
505
506 #if !defined(__i386__)
507
508 double rdtsc(void)
509 {
510   return 0.0;
511 }
512
513 double aubio_estimate_cpu_frequency(void)
514 {
515   return 1.0;
516 }
517
518 #else
519
520 double rdtsc(void)
521 {
522   unsigned int a, b;
523
524   __asm__ ("rdtsc" : "=a" (a), "=d" (b));
525   return (double)b * (double)0x10000 * (double)0x10000 + a;
526 }
527
528 double aubio_estimate_cpu_frequency(void)
529 {
530   double start, stop;
531   unsigned int a0, b0, a1, b1;
532   unsigned int before, after;
533
534   before = aubio_curtime();  
535   __asm__ ("rdtsc" : "=a" (a0), "=d" (b0));
536
537   sleep(1);
538   
539   after = aubio_curtime();
540   __asm__ ("rdtsc" : "=a" (a1), "=d" (b1));
541
542
543   start = (double)b0 * (double)0x10000 * (double)0x10000 + a0;
544   stop = (double)b1 * (double)0x10000 * (double)0x10000 + a1;
545
546   return 1000 * (stop - start) / (after - before);
547 }
548
549 #endif
550
551 #endif