ref: 06156a6d73195b8d9f66902f12b2ee6ea7171c93
dir: /ext/midi/timer.c/
/*
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public License
* as published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the Free
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
* 02111-1307, USA
*/
/* this file originally taken from FluidSynth - A Software Synthesizer
* Copyright (C) 2003 Peter Hanappe and others.
*/
#include "aubio_priv.h"
#include "timer.h"
#if defined(WIN32)
/*=============================================================*/
/* */
/* Win32 */
/* */
/*=============================================================*/
/***************************************************************
*
* Timer
*
*/
#include <windef.h>
#if 0
#include <winbase.h>
struct _aubio_timer_t
{
long msec;
aubio_timer_callback_t callback;
void* data;
HANDLE thread;
DWORD thread_id;
int cont;
int auto_destroy;
};
static int aubio_timer_count = 0;
DWORD WINAPI aubio_timer_run(LPVOID data);
aubio_timer_t*
new_aubio_timer(int msec, aubio_timer_callback_t callback, void* data,
int new_thread, int auto_destroy)
{
aubio_timer_t* timer = AUBIO_NEW(aubio_timer_t);
if (timer == NULL) {
AUBIO_ERR( "Out of memory");
return NULL;
}
timer->cont = 1;
timer->msec = msec;
timer->callback = callback;
timer->data = data;
timer->thread = 0;
timer->auto_destroy = auto_destroy;
if (new_thread) {
timer->thread = CreateThread(NULL, 0, aubio_timer_run, (LPVOID) timer, 0, &timer->thread_id);
if (timer->thread == NULL) {
AUBIO_ERR( "Couldn't create timer thread");
AUBIO_FREE(timer);
return NULL;
}
SetThreadPriority(timer->thread, THREAD_PRIORITY_TIME_CRITICAL);
} else {
aubio_timer_run((LPVOID) timer);
}
return timer;
}
DWORD WINAPI
aubio_timer_run(LPVOID data)
{
int count = 0;
int cont = 1;
long start;
long delay;
aubio_timer_t* timer;
timer = (aubio_timer_t*) data;
if ((timer == NULL) || (timer->callback == NULL)) {
return 0;
}
SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_HIGHEST);
/* keep track of the start time for absolute positioning */
start = aubio_curtime();
while (cont) {
/* do whatever we have to do */
cont = (*timer->callback)(timer->data, aubio_curtime() - start);
count++;
/* to avoid incremental time errors, I calculate the delay between
two callbacks bringing in the "absolute" time (count *
timer->msec) */
delay = (count * timer->msec) - (aubio_curtime() - start);
if (delay > 0) {
Sleep(delay);
}
cont &= timer->cont;
}
AUBIO_DBG( "Timer thread finished");
if (timer->auto_destroy) {
AUBIO_FREE(timer);
}
ExitThread(0);
return 0;
}
int
delete_aubio_timer(aubio_timer_t* timer)
{
timer->cont = 0;
aubio_timer_join(timer);
AUBIO_FREE(timer);
return AUBIO_OK;
}
int
aubio_timer_join(aubio_timer_t* timer)
{
DWORD wait_result;
if (timer->thread == 0) {
return AUBIO_OK;
}
wait_result = WaitForSingleObject(timer->thread, INFINITE);
return (wait_result == WAIT_OBJECT_0)? AUBIO_OK : AUBIO_FAIL;
}
/***************************************************************
*
* Time
*/
double rdtsc(void);
double aubio_estimate_cpu_frequency(void);
static double aubio_cpu_frequency = -1.0;
void aubio_time_config(void)
{
if (aubio_cpu_frequency < 0.0) {
aubio_cpu_frequency = aubio_estimate_cpu_frequency() / 1000000.0;
}
}
double aubio_utime(void)
{
return (rdtsc() / aubio_cpu_frequency);
}
double rdtsc(void)
{
LARGE_INTEGER t;
QueryPerformanceCounter(&t);
return (double) t.QuadPart;
}
double aubio_estimate_cpu_frequency(void)
{
#if 0
LONGLONG start, stop, ticks;
unsigned int before, after, delta;
double freq;
start = rdtsc();
stop = start;
before = aubio_curtime();
after = before;
while (1) {
if (after - before > 1000) {
break;
}
after = aubio_curtime();
stop = rdtsc();
}
delta = after - before;
ticks = stop - start;
freq = 1000 * ticks / delta;
return freq;
#else
unsigned int before, after;
LARGE_INTEGER start, stop;
before = aubio_curtime();
QueryPerformanceCounter(&start);
Sleep(1000);
after = aubio_curtime();
QueryPerformanceCounter(&stop);
return (double) 1000 * (stop.QuadPart - start.QuadPart) / (after - before);
#endif
}
#endif
#elif defined(MACOS9)
/*=============================================================*/
/* */
/* MacOS 9 */
/* */
/*=============================================================*/
/***************************************************************
*
* Timer
*/
struct _aubio_timer_t
{
TMTask myTmTask;
long msec;
unsigned int start;
unsigned int count;
int isInstalled;
aubio_timer_callback_t callback;
void* data;
int auto_destroy;
};
static TimerUPP myTimerUPP;
void
_timerCallback(aubio_timer_t *timer)
{
int cont;
cont = (*timer->callback)(timer->data, aubio_curtime() - timer->start);
if (cont) {
PrimeTime((QElemPtr)timer, timer->msec);
} else {
timer->isInstalled = 0;
}
timer->count++;
}
aubio_timer_t*
new_aubio_timer(int msec, aubio_timer_callback_t callback, void* data,
int new_thread, int auto_destroy)
{
aubio_timer_t* timer = AUBIO_NEW(aubio_timer_t);
if (timer == NULL) {
AUBIO_ERR( "Out of memory");
return NULL;
}
if (!myTimerUPP)
myTimerUPP = NewTimerProc(_timerCallback);
/* setup tmtask */
timer->myTmTask.tmAddr = myTimerUPP;
timer->myTmTask.qLink = NULL;
timer->myTmTask.qType = 0;
timer->myTmTask.tmCount = 0L;
timer->myTmTask.tmWakeUp = 0L;
timer->myTmTask.tmReserved = 0L;
timer->callback = callback;
timer->msec = msec;
timer->data = data;
timer->start = aubio_curtime();
timer->isInstalled = 1;
timer->count = 0;
timer->auto_destroy = auto_destroy;
InsXTime((QElemPtr)timer);
PrimeTime((QElemPtr)timer, msec);
return timer;
}
int
delete_aubio_timer(aubio_timer_t* timer)
{
if (timer->isInstalled) {
RmvTime((QElemPtr)timer);
}
AUBIO_FREE(timer);
return AUBIO_OK;
}
int
aubio_timer_join(aubio_timer_t* timer)
{
if (timer->isInstalled) {
int count = timer->count;
/* wait until count has incremented */
while (count == timer->count) {}
}
return AUBIO_OK;
}
/***************************************************************
*
* Time
*/
#define kTwoPower32 (4294967296.0) /* 2^32 */
void aubio_time_config(void)
{
}
unsigned int aubio_curtime()
{
/* could be optimized by not going though a double */
UnsignedWide uS;
double mSf;
unsigned int ms;
Microseconds(&uS);
mSf = ((((double) uS.hi) * kTwoPower32) + uS.lo)/1000.0f;
ms = mSf;
return (ms);
}
#else
/*=============================================================*/
/* */
/* POSIX */
/* */
/*=============================================================*/
#include <pthread.h>
#include <unistd.h>
#include <sys/time.h>
/***************************************************************
*
* Timer
*/
struct _aubio_timer_t
{
long msec;
aubio_timer_callback_t callback;
void* data;
pthread_t thread;
int cont;
int auto_destroy;
};
void*
aubio_timer_start(void *data)
{
int count = 0;
int cont = 1;
long start;
long delay;
aubio_timer_t* timer;
timer = (aubio_timer_t*) data;
/* keep track of the start time for absolute positioning */
start = aubio_curtime();
while (cont) {
/* do whatever we have to do */
cont = (*timer->callback)(timer->data, aubio_curtime() - start);
count++;
/* to avoid incremental time errors, calculate the delay between
two callbacks bringing in the "absolute" time (count *
timer->msec) */
delay = (count * timer->msec) - (aubio_curtime() - start);
if (delay > 0) {
usleep(delay * 1000);
}
cont &= timer->cont;
}
AUBIO_DBG( "Timer thread finished");
if (timer->thread != 0) {
pthread_exit(NULL);
}
if (timer->auto_destroy) {
AUBIO_FREE(timer);
}
return NULL;
}
aubio_timer_t*
new_aubio_timer(int msec, aubio_timer_callback_t callback, void* data,
int new_thread, int auto_destroy)
{
aubio_timer_t* timer = AUBIO_NEW(aubio_timer_t);
if (timer == NULL) {
AUBIO_ERR( "Out of memory");
return NULL;
}
timer->msec = msec;
timer->callback = callback;
timer->data = data;
timer->cont = 1;
timer->thread = 0;
timer->auto_destroy = auto_destroy;
if (new_thread) {
if (pthread_create(&timer->thread, NULL, aubio_timer_start, (void*) timer)) {
AUBIO_ERR( "Failed to create the timer thread");
AUBIO_FREE(timer);
return NULL;
}
} else {
aubio_timer_start((void*) timer);
}
return timer;
}
int
delete_aubio_timer(aubio_timer_t* timer)
{
timer->cont = 0;
aubio_timer_join(timer);
AUBIO_DBG( "Deleted player thread\n");
AUBIO_FREE(timer);
return AUBIO_OK;
}
int
aubio_timer_join(aubio_timer_t* timer)
{
int err = 0;
if (timer->thread != 0) {
err = pthread_join(timer->thread, NULL);
} else
AUBIO_DBG( "Joined player thread\n");
return (err == 0)? AUBIO_OK : AUBIO_FAIL;
}
/***************************************************************
*
* Time
*/
static double aubio_cpu_frequency = -1.0;
double rdtsc(void);
double aubio_estimate_cpu_frequency(void);
void aubio_time_config(void)
{
if (aubio_cpu_frequency < 0.0) {
aubio_cpu_frequency = aubio_estimate_cpu_frequency() / 1000000.0;
}
}
unsigned int aubio_curtime()
{
struct timeval now;
gettimeofday(&now, NULL);
return now.tv_sec * 1000 + now.tv_usec / 1000;
}
double aubio_utime(void)
{
return (rdtsc() / aubio_cpu_frequency);
}
#if !defined(__i386__)
double rdtsc(void)
{
return 0.0;
}
double aubio_estimate_cpu_frequency(void)
{
return 1.0;
}
#else
double rdtsc(void)
{
unsigned int a, b;
__asm__ ("rdtsc" : "=a" (a), "=d" (b));
return (double)b * (double)0x10000 * (double)0x10000 + a;
}
double aubio_estimate_cpu_frequency(void)
{
double start, stop;
unsigned int a0, b0, a1, b1;
unsigned int before, after;
before = aubio_curtime();
__asm__ ("rdtsc" : "=a" (a0), "=d" (b0));
sleep(1);
after = aubio_curtime();
__asm__ ("rdtsc" : "=a" (a1), "=d" (b1));
start = (double)b0 * (double)0x10000 * (double)0x10000 + a0;
stop = (double)b1 * (double)0x10000 * (double)0x10000 + a1;
return 1000 * (stop - start) / (after - before);
}
#endif
#endif