From 90d5b8b4a064420d74678654e94ea4755b377f21 Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Thu, 15 Dec 2005 00:57:02 +0000 Subject: checking in missing files on behalf of Miller (cleared it with him first). The files are from portmidi17nov04.zip svn path=/trunk/; revision=4216 --- pd/portmidi/porttime/porttime.c | 3 + pd/portmidi/porttime/porttime.dsp | 104 +++++++++++++++++++++++++++ pd/portmidi/porttime/porttime.h | 36 ++++++++++ pd/portmidi/porttime/ptlinux.c | 120 +++++++++++++++++++++++++++++++ pd/portmidi/porttime/ptmacosx_cf.c | 135 +++++++++++++++++++++++++++++++++++ pd/portmidi/porttime/ptmacosx_mach.c | 123 +++++++++++++++++++++++++++++++ pd/portmidi/porttime/ptwinmm.c | 65 +++++++++++++++++ 7 files changed, 586 insertions(+) create mode 100644 pd/portmidi/porttime/porttime.c create mode 100644 pd/portmidi/porttime/porttime.dsp create mode 100644 pd/portmidi/porttime/porttime.h create mode 100644 pd/portmidi/porttime/ptlinux.c create mode 100644 pd/portmidi/porttime/ptmacosx_cf.c create mode 100644 pd/portmidi/porttime/ptmacosx_mach.c create mode 100644 pd/portmidi/porttime/ptwinmm.c (limited to 'pd/portmidi/porttime') diff --git a/pd/portmidi/porttime/porttime.c b/pd/portmidi/porttime/porttime.c new file mode 100644 index 00000000..71b06f4a --- /dev/null +++ b/pd/portmidi/porttime/porttime.c @@ -0,0 +1,3 @@ +/* porttime.c -- portable API for millisecond timer */ + +/* There is no machine-independent implementation code to put here */ diff --git a/pd/portmidi/porttime/porttime.dsp b/pd/portmidi/porttime/porttime.dsp new file mode 100644 index 00000000..364373c9 --- /dev/null +++ b/pd/portmidi/porttime/porttime.dsp @@ -0,0 +1,104 @@ +# Microsoft Developer Studio Project File - Name="porttime" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Static Library" 0x0104 + +CFG=porttime - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "porttime.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "porttime.mak" CFG="porttime - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "porttime - Win32 Release" (based on "Win32 (x86) Static Library") +!MESSAGE "porttime - Win32 Debug" (based on "Win32 (x86) Static Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "porttime - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "porttime - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "_LIB" /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "USE_DLL_FOR_CLEANUP" /YX /FD /GZ /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ENDIF + +# Begin Target + +# Name "porttime - Win32 Release" +# Name "porttime - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=.\porttime.c +# End Source File +# Begin Source File + +SOURCE=.\ptwinmm.c +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=.\porttime.h +# End Source File +# End Group +# End Target +# End Project diff --git a/pd/portmidi/porttime/porttime.h b/pd/portmidi/porttime/porttime.h new file mode 100644 index 00000000..029ea777 --- /dev/null +++ b/pd/portmidi/porttime/porttime.h @@ -0,0 +1,36 @@ +/* porttime.h -- portable interface to millisecond timer */ + +/* CHANGE LOG FOR PORTTIME + 10-Jun-03 Mark Nelson & RBD + boost priority of timer thread in ptlinux.c implementation + */ + +/* Should there be a way to choose the source of time here? */ + +#ifdef __cplusplus +extern "C" { +#endif + + +typedef enum { + ptNoError = 0, + ptHostError = -10000, + ptAlreadyStarted, + ptAlreadyStopped, + ptInsufficientMemory +} PtError; + + +typedef long PtTimestamp; + +typedef void (PtCallback)( PtTimestamp timestamp, void *userData ); + + +PtError Pt_Start(int resolution, PtCallback *callback, void *userData); +PtError Pt_Stop(); +int Pt_Started(); +PtTimestamp Pt_Time(); + +#ifdef __cplusplus +} +#endif diff --git a/pd/portmidi/porttime/ptlinux.c b/pd/portmidi/porttime/ptlinux.c new file mode 100644 index 00000000..c99abf04 --- /dev/null +++ b/pd/portmidi/porttime/ptlinux.c @@ -0,0 +1,120 @@ +/* ptlinux.c -- portable timer implementation for linux */ + + +/* IMPLEMENTATION NOTES (by Mark Nelson): + +Unlike Windows, Linux has no system call to request a periodic callback, +so if Pt_Start() receives a callback parameter, it must create a thread +that wakes up periodically and calls the provided callback function. +If running as superuser, use setpriority() to renice thread to -20. +One could also set the timer thread to a real-time priority (SCHED_FIFO +and SCHED_RR), but this is dangerous for This is necessary because +if the callback hangs it'll never return. A more serious reason +is that the current scheduler implementation busy-waits instead +of sleeping when realtime threads request a sleep of <=2ms (as a way +to get around the 10ms granularity), which means the thread would never +let anyone else on the CPU. + +CHANGE LOG + +18-Jul-03 Roger Dannenberg -- Simplified code to set priority of timer + thread. Simplified implementation notes. + +*/ + +#include "porttime.h" +#include "sys/time.h" +#include "sys/resource.h" +#include "sys/timeb.h" +#include "pthread.h" + +#define TRUE 1 +#define FALSE 0 + +static int time_started_flag = FALSE; +static struct timeb time_offset = {0, 0, 0, 0}; +static pthread_t pt_thread_pid; + +/* note that this is static data -- we only need one copy */ +typedef struct { + int id; + int resolution; + PtCallback *callback; + void *userData; +} pt_callback_parameters; + +static int pt_callback_proc_id = 0; + +static void *Pt_CallbackProc(void *p) +{ + pt_callback_parameters *parameters = (pt_callback_parameters *) p; + int mytime = 1; + /* to kill a process, just increment the pt_callback_proc_id */ + /* printf("pt_callback_proc_id %d, id %d\n", pt_callback_proc_id, + parameters->id); */ + if (geteuid() == 0) setpriority(PRIO_PROCESS, 0, -20); + while (pt_callback_proc_id == parameters->id) { + /* wait for a multiple of resolution ms */ + struct timeval timeout; + int delay = mytime++ * parameters->resolution - Pt_Time(); + if (delay < 0) delay = 0; + timeout.tv_sec = 0; + timeout.tv_usec = delay * 1000; + select(0, NULL, NULL, NULL, &timeout); + (*(parameters->callback))(Pt_Time(), parameters->userData); + } + printf("Pt_CallbackProc exiting\n"); +// free(parameters); + return NULL; +} + + +PtError Pt_Start(int resolution, PtCallback *callback, void *userData) +{ + if (time_started_flag) return ptNoError; + ftime(&time_offset); /* need this set before process runs */ + if (callback) { + int res; + pt_callback_parameters *parms = (pt_callback_parameters *) + malloc(sizeof(pt_callback_parameters)); + if (!parms) return ptInsufficientMemory; + parms->id = pt_callback_proc_id; + parms->resolution = resolution; + parms->callback = callback; + parms->userData = userData; + res = pthread_create(&pt_thread_pid, NULL, + Pt_CallbackProc, parms); + if (res != 0) return ptHostError; + } + time_started_flag = TRUE; + return ptNoError; +} + + +PtError Pt_Stop() +{ + printf("Pt_Stop called\n"); + pt_callback_proc_id++; + time_started_flag = FALSE; + return ptNoError; +} + + +int Pt_Started() +{ + return time_started_flag; +} + + +PtTimestamp Pt_Time() +{ + long seconds, milliseconds; + struct timeb now; + ftime(&now); + seconds = now.time - time_offset.time; + milliseconds = now.millitm - time_offset.millitm; + return seconds * 1000 + milliseconds; +} + + + diff --git a/pd/portmidi/porttime/ptmacosx_cf.c b/pd/portmidi/porttime/ptmacosx_cf.c new file mode 100644 index 00000000..c0c22a32 --- /dev/null +++ b/pd/portmidi/porttime/ptmacosx_cf.c @@ -0,0 +1,135 @@ +/* ptmacosx.c -- portable timer implementation for mac os x */ + +#include +#include +#include +#include + +#import +#import +#import +#import + +#include "porttime.h" + +#define THREAD_IMPORTANCE 30 +#define LONG_TIME 1000000000.0 + +static int time_started_flag = FALSE; +static CFAbsoluteTime startTime = 0.0; +static CFRunLoopRef timerRunLoop; + +typedef struct { + int resolution; + PtCallback *callback; + void *userData; +} PtThreadParams; + + +void Pt_CFTimerCallback(CFRunLoopTimerRef timer, void *info) +{ + PtThreadParams *params = (PtThreadParams*)info; + (*params->callback)(Pt_Time(), params->userData); +} + +static void* Pt_Thread(void *p) +{ + CFTimeInterval timerInterval; + CFRunLoopTimerContext timerContext; + CFRunLoopTimerRef timer; + PtThreadParams *params = (PtThreadParams*)p; + //CFTimeInterval timeout; + + /* raise the thread's priority */ + kern_return_t error; + thread_extended_policy_data_t extendedPolicy; + thread_precedence_policy_data_t precedencePolicy; + + extendedPolicy.timeshare = 0; + error = thread_policy_set(mach_thread_self(), THREAD_EXTENDED_POLICY, + (thread_policy_t)&extendedPolicy, + THREAD_EXTENDED_POLICY_COUNT); + if (error != KERN_SUCCESS) { + mach_error("Couldn't set thread timeshare policy", error); + } + + precedencePolicy.importance = THREAD_IMPORTANCE; + error = thread_policy_set(mach_thread_self(), THREAD_PRECEDENCE_POLICY, + (thread_policy_t)&precedencePolicy, + THREAD_PRECEDENCE_POLICY_COUNT); + if (error != KERN_SUCCESS) { + mach_error("Couldn't set thread precedence policy", error); + } + + /* set up the timer context */ + timerContext.version = 0; + timerContext.info = params; + timerContext.retain = NULL; + timerContext.release = NULL; + timerContext.copyDescription = NULL; + + /* create a new timer */ + timerInterval = (double)params->resolution / 1000.0; + timer = CFRunLoopTimerCreate(NULL, startTime+timerInterval, timerInterval, + 0, 0, Pt_CFTimerCallback, &timerContext); + + timerRunLoop = CFRunLoopGetCurrent(); + CFRunLoopAddTimer(timerRunLoop, timer, CFSTR("PtTimeMode")); + + /* run until we're told to stop by Pt_Stop() */ + CFRunLoopRunInMode(CFSTR("PtTimeMode"), LONG_TIME, false); + + CFRunLoopRemoveTimer(CFRunLoopGetCurrent(), timer, CFSTR("PtTimeMode")); + CFRelease(timer); + free(params); + + return NULL; +} + +PtError Pt_Start(int resolution, PtCallback *callback, void *userData) +{ + PtThreadParams *params = (PtThreadParams*)malloc(sizeof(PtThreadParams)); + pthread_t pthread_id; + + printf("Pt_Start() called\n"); + + // /* make sure we're not already playing */ + if (time_started_flag) return ptAlreadyStarted; + startTime = CFAbsoluteTimeGetCurrent(); + + if (callback) { + + params->resolution = resolution; + params->callback = callback; + params->userData = userData; + + pthread_create(&pthread_id, NULL, Pt_Thread, params); + } + + time_started_flag = TRUE; + return ptNoError; +} + + +PtError Pt_Stop() +{ + printf("Pt_Stop called\n"); + + CFRunLoopStop(timerRunLoop); + time_started_flag = FALSE; + return ptNoError; +} + + +int Pt_Started() +{ + return time_started_flag; +} + + +PtTimestamp Pt_Time() +{ + CFAbsoluteTime now = CFAbsoluteTimeGetCurrent(); + return (PtTimestamp) ((now - startTime) * 1000.0); +} + diff --git a/pd/portmidi/porttime/ptmacosx_mach.c b/pd/portmidi/porttime/ptmacosx_mach.c new file mode 100644 index 00000000..935d99bb --- /dev/null +++ b/pd/portmidi/porttime/ptmacosx_mach.c @@ -0,0 +1,123 @@ +/* ptmacosx.c -- portable timer implementation for mac os x */ + +#include +#include +#include + +#import +#import +#import +#import + +#include "porttime.h" +#include "sys/time.h" +#include "pthread.h" + +#define NSEC_PER_MSEC 1000000 +#define THREAD_IMPORTANCE 30 + +static int time_started_flag = FALSE; +static UInt64 start_time; +static pthread_t pt_thread_pid; + +/* note that this is static data -- we only need one copy */ +typedef struct { + int id; + int resolution; + PtCallback *callback; + void *userData; +} pt_callback_parameters; + +static int pt_callback_proc_id = 0; + +static void *Pt_CallbackProc(void *p) +{ + pt_callback_parameters *parameters = (pt_callback_parameters *) p; + int mytime = 1; + + kern_return_t error; + thread_extended_policy_data_t extendedPolicy; + thread_precedence_policy_data_t precedencePolicy; + + extendedPolicy.timeshare = 0; + error = thread_policy_set(mach_thread_self(), THREAD_EXTENDED_POLICY, + (thread_policy_t)&extendedPolicy, + THREAD_EXTENDED_POLICY_COUNT); + if (error != KERN_SUCCESS) { + mach_error("Couldn't set thread timeshare policy", error); + } + + precedencePolicy.importance = THREAD_IMPORTANCE; + error = thread_policy_set(mach_thread_self(), THREAD_PRECEDENCE_POLICY, + (thread_policy_t)&precedencePolicy, + THREAD_PRECEDENCE_POLICY_COUNT); + if (error != KERN_SUCCESS) { + mach_error("Couldn't set thread precedence policy", error); + } + + + /* to kill a process, just increment the pt_callback_proc_id */ + printf("pt_callback_proc_id %d, id %d\n", pt_callback_proc_id, parameters->id); + while (pt_callback_proc_id == parameters->id) { + /* wait for a multiple of resolution ms */ + UInt64 wait_time; + int delay = mytime++ * parameters->resolution - Pt_Time(); + if (delay < 0) delay = 0; + wait_time = AudioConvertNanosToHostTime((UInt64)delay * NSEC_PER_MSEC); + wait_time += AudioGetCurrentHostTime(); + error = mach_wait_until(wait_time); + (*(parameters->callback))(Pt_Time(), parameters->userData); + } + printf("Pt_CallbackProc exiting\n"); + free(parameters); + return NULL; +} + + +PtError Pt_Start(int resolution, PtCallback *callback, void *userData) +{ + if (time_started_flag) return ptAlreadyStarted; + start_time = AudioGetCurrentHostTime(); + + if (callback) { + int res; + pt_callback_parameters *parms; + + parms = (pt_callback_parameters *) malloc(sizeof(pt_callback_parameters)); + if (!parms) return ptInsufficientMemory; + parms->id = pt_callback_proc_id; + parms->resolution = resolution; + parms->callback = callback; + parms->userData = userData; + res = pthread_create(&pt_thread_pid, NULL, Pt_CallbackProc, parms); + if (res != 0) return ptHostError; + } + + time_started_flag = TRUE; + return ptNoError; +} + + +PtError Pt_Stop() +{ + printf("Pt_Stop called\n"); + pt_callback_proc_id++; + time_started_flag = FALSE; + return ptNoError; +} + + +int Pt_Started() +{ + return time_started_flag; +} + + +PtTimestamp Pt_Time() +{ + UInt64 clock_time, nsec_time; + clock_time = AudioGetCurrentHostTime() - start_time; + nsec_time = AudioConvertHostTimeToNanos(clock_time); + return (PtTimestamp)(nsec_time / NSEC_PER_MSEC); +} + diff --git a/pd/portmidi/porttime/ptwinmm.c b/pd/portmidi/porttime/ptwinmm.c new file mode 100644 index 00000000..bbfebb0e --- /dev/null +++ b/pd/portmidi/porttime/ptwinmm.c @@ -0,0 +1,65 @@ +/* ptwinmm.c -- portable timer implementation for win32 */ + + +#include "porttime.h" +#include "windows.h" +#include "time.h" + + +TIMECAPS caps; + +static long time_offset = 0; +static int time_started_flag = FALSE; +static long time_resolution; +static MMRESULT timer_id; +static PtCallback *time_callback; + +void CALLBACK winmm_time_callback(UINT uID, UINT uMsg, DWORD dwUser, + DWORD dw1, DWORD dw2) +{ + (*time_callback)(Pt_Time(), (void *) dwUser); +} + + +PtError Pt_Start(int resolution, PtCallback *callback, void *userData) +{ + if (time_started_flag) return ptAlreadyStarted; + timeBeginPeriod(resolution); + time_resolution = resolution; + time_offset = timeGetTime(); + time_started_flag = TRUE; + time_callback = callback; + if (callback) { + timer_id = timeSetEvent(resolution, 1, winmm_time_callback, + (DWORD) userData, TIME_PERIODIC | TIME_CALLBACK_FUNCTION); + if (!timer_id) return ptHostError; + } + return ptNoError; +} + + +PtError Pt_Stop() +{ + if (!time_started_flag) return ptAlreadyStopped; + if (time_callback && timer_id) { + timeKillEvent(timer_id); + time_callback = NULL; + timer_id = 0; + } + time_started_flag = FALSE; + timeEndPeriod(time_resolution); + return ptNoError; +} + + +int Pt_Started() +{ + return time_started_flag; +} + + +PtTimestamp Pt_Time() +{ + return timeGetTime() - time_offset; +} + -- cgit v1.2.1