diff options
Diffstat (limited to 'portmidi/porttime')
| -rwxr-xr-x | portmidi/porttime/porttime.c | 3 | ||||
| -rwxr-xr-x | portmidi/porttime/porttime.h | 103 | ||||
| -rw-r--r-- | portmidi/porttime/pthaiku.cpp | 88 | ||||
| -rwxr-xr-x | portmidi/porttime/ptlinux.c | 139 | ||||
| -rwxr-xr-x | portmidi/porttime/ptmacosx_cf.c | 140 | ||||
| -rwxr-xr-x | portmidi/porttime/ptmacosx_mach.c | 204 | ||||
| -rwxr-xr-x | portmidi/porttime/ptwinmm.c | 70 |
7 files changed, 747 insertions, 0 deletions
diff --git a/portmidi/porttime/porttime.c b/portmidi/porttime/porttime.c new file mode 100755 index 0000000..71b06f4 --- /dev/null +++ b/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/portmidi/porttime/porttime.h b/portmidi/porttime/porttime.h new file mode 100755 index 0000000..0a61c5c --- /dev/null +++ b/portmidi/porttime/porttime.h @@ -0,0 +1,103 @@ +/** @file 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 + */ + +#ifndef PORTMIDI_PORTTIME_H +#define PORTMIDI_PORTTIME_H + +/* Should there be a way to choose the source of time here? */ + +#ifdef WIN32 +#ifndef INT32_DEFINED +// rather than having users install a special .h file for windows, +// just put the required definitions inline here. portmidi.h uses +// these too, so the definitions are (unfortunately) duplicated there +typedef int int32_t; +typedef unsigned int uint32_t; +#define INT32_DEFINED +#endif +#else +#include <stdint.h> // needed for int32_t +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef PMEXPORT +#ifdef _WINDLL +#define PMEXPORT __declspec(dllexport) +#else +#define PMEXPORT +#endif +#endif + +/** @defgroup grp_porttime PortTime: Millisecond Timer + @{ +*/ + +typedef enum { + ptNoError = 0, /* success */ + ptHostError = -10000, /* a system-specific error occurred */ + ptAlreadyStarted, /* cannot start timer because it is already started */ + ptAlreadyStopped, /* cannot stop timer because it is already stopped */ + ptInsufficientMemory /* memory could not be allocated */ +} PtError; /**< @brief @enum PtError PortTime error code; a common return type. + * No error is indicated by zero; errors are indicated by < 0. + */ + +/** real time or time offset in milliseconds. */ +typedef int32_t PtTimestamp; + +/** a function that gets a current time */ +typedef void (PtCallback)(PtTimestamp timestamp, void *userData); + +/** start a real-time clock service. + + @param resolution the timer resolution in ms. The time will advance every + \p resolution ms. + + @param callback a function pointer to be called every resolution ms. + + @param userData is passed to \p callback as a parameter. + + @return #ptNoError on success. See #PtError for other values. +*/ +PMEXPORT PtError Pt_Start(int resolution, PtCallback *callback, void *userData); + +/** stop the timer. + + @return #ptNoError on success. See #PtError for other values. +*/ +PMEXPORT PtError Pt_Stop(void); + +/** test if the timer is running. + + @return TRUE or FALSE +*/ +PMEXPORT int Pt_Started(void); + +/** get the current time in ms. + + @return the current time +*/ +PMEXPORT PtTimestamp Pt_Time(void); + +/** pauses the current thread, allowing other threads to run. + + @param duration the length of the pause in ms. The true duration + of the pause may be rounded to the nearest or next clock tick + as determined by resolution in #Pt_Start(). +*/ +PMEXPORT void Pt_Sleep(int32_t duration); + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif // PORTMIDI_PORTTIME_H diff --git a/portmidi/porttime/pthaiku.cpp b/portmidi/porttime/pthaiku.cpp new file mode 100644 index 0000000..9d8de14 --- /dev/null +++ b/portmidi/porttime/pthaiku.cpp @@ -0,0 +1,88 @@ +// pthaiku.cpp - portable timer implementation for Haiku + +#include "porttime.h" +#include <Looper.h> +#include <MessageRunner.h> +#include <OS.h> + +namespace { + const uint32 timerMessage = 'PTTM'; + + struct TimerLooper : BLooper { + TimerLooper() : BLooper() { + } + + + virtual void MessageReceived(BMessage *message) + { + PtCallback *callback; + void *userData; + if (message->what == timerMessage && message->FindPointer("callback", (void**)&callback) == B_OK && message->FindPointer("userData", &userData) == B_OK) { + (*callback)(Pt_Time(), userData); + } + BLooper::MessageReceived(message); + } + }; + + bool time_started_flag = false; + bigtime_t time_offset; + TimerLooper *timerLooper; + BMessageRunner *timerRunner; +} + +extern "C" { + PtError Pt_Start(int resolution, PtCallback *callback, void *userData) + { + if (time_started_flag) return ptAlreadyStarted; + time_offset = system_time(); + if (callback) { + timerLooper = new TimerLooper; + timerLooper->Run(); + BMessenger target(timerLooper); + BMessage message(timerMessage); + message.AddPointer("callback", (void*)callback); + message.AddPointer("userData", userData); + bigtime_t interval = resolution * 1000; + timerRunner = new BMessageRunner(target, &message, interval); + if(timerRunner->InitCheck() != B_OK) { + delete timerRunner; + timerRunner = NULL; + timerLooper->PostMessage(B_QUIT_REQUESTED); + timerLooper = NULL; + return ptHostError; + } + } + time_started_flag = true; + return ptNoError; + } + + + PtError Pt_Stop() + { + if (!time_started_flag) return ptAlreadyStopped; + time_started_flag = false; + delete timerRunner; + timerRunner = NULL; + timerLooper->PostMessage(B_QUIT_REQUESTED); + timerLooper = NULL; + return ptNoError; + } + + + int Pt_Started() + { + return time_started_flag; + } + + + PtTimestamp Pt_Time() + { + return (system_time() - time_offset) / 1000; + } + + + void Pt_Sleep(int32_t duration) + { + snooze(duration * 1000); + } +} diff --git a/portmidi/porttime/ptlinux.c b/portmidi/porttime/ptlinux.c new file mode 100755 index 0000000..c4af5c1 --- /dev/null +++ b/portmidi/porttime/ptlinux.c @@ -0,0 +1,139 @@ +/* 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. + +*/ +/* stdlib, stdio, unistd, and sys/types were added because they appeared + * in a Gentoo patch, but I'm not sure why they are needed. -RBD + */ +#include <stdlib.h> +#include <stdio.h> +#include <unistd.h> +#include <sys/types.h> +#include "porttime.h" +#include "time.h" +#include "sys/resource.h" +#include "pthread.h" + +#define TRUE 1 +#define FALSE 0 + +#ifndef CLOCK_MONOTONIC_RAW +#define CLOCK_MONOTONIC_RAW CLOCK_MONOTONIC +#endif + +static int time_started_flag = FALSE; +static struct timespec time_offset = {0, 0}; +static pthread_t pt_thread_pid; +static int pt_thread_created = FALSE; + +/* 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; + /* need this set before process runs: */ + clock_gettime(CLOCK_MONOTONIC_RAW, &time_offset); + 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; + pt_thread_created = TRUE; + } + time_started_flag = TRUE; + return ptNoError; +} + + +PtError Pt_Stop() +{ + /* printf("Pt_Stop called\n"); */ + pt_callback_proc_id++; + if (pt_thread_created) { + pthread_join(pt_thread_pid, NULL); + pt_thread_created = FALSE; + } + time_started_flag = FALSE; + return ptNoError; +} + + +int Pt_Started() +{ + return time_started_flag; +} + + +PtTimestamp Pt_Time() +{ + long seconds, ms; + struct timespec now; + clock_gettime(CLOCK_MONOTONIC_RAW, &now); + seconds = now.tv_sec - time_offset.tv_sec; + ms = (now.tv_nsec - time_offset.tv_nsec) / 1000000; /* round down */ + return seconds * 1000 + ms; +} + + +void Pt_Sleep(int32_t duration) +{ + usleep(duration * 1000); +} diff --git a/portmidi/porttime/ptmacosx_cf.c b/portmidi/porttime/ptmacosx_cf.c new file mode 100755 index 0000000..a174c86 --- /dev/null +++ b/portmidi/porttime/ptmacosx_cf.c @@ -0,0 +1,140 @@ +/* ptmacosx.c -- portable timer implementation for mac os x */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <pthread.h>
+#include <CoreFoundation/CoreFoundation.h>
+
+#import <mach/mach.h>
+#import <mach/mach_error.h>
+#import <mach/mach_time.h>
+#import <mach/clock.h>
+
+#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);
+}
+
+
+void Pt_Sleep(int32_t duration)
+{
+ usleep(duration * 1000);
+}
diff --git a/portmidi/porttime/ptmacosx_mach.c b/portmidi/porttime/ptmacosx_mach.c new file mode 100755 index 0000000..1390af8 --- /dev/null +++ b/portmidi/porttime/ptmacosx_mach.c @@ -0,0 +1,204 @@ +/* ptmacosx.c -- portable timer implementation for mac os x */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <CoreAudio/HostTime.h>
+
+#import <mach/mach.h>
+#import <mach/mach_error.h>
+#import <mach/mach_time.h>
+#import <mach/clock.h>
+#include <unistd.h>
+#include <AvailabilityMacros.h>
+
+#include "porttime.h"
+#include "sys/time.h"
+#include "pthread.h"
+
+#ifndef NSEC_PER_MSEC
+#define NSEC_PER_MSEC 1000000
+#endif
+#define THREAD_IMPORTANCE 63
+
+// QOS headers are available as of macOS 10.10
+#if MAC_OS_X_VERSION_MAX_ALLOWED >= 101000
+#include "sys/qos.h"
+#define HAVE_APPLE_QOS 1
+#else
+#undef HAVE_APPLE_QOS
+#endif
+
+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);
+ }
+
+ // Most important, set real-time constraints.
+
+ // Define the guaranteed and max fraction of time for the audio thread.
+ // These "duty cycle" values can range from 0 to 1. A value of 0.5
+ // means the scheduler would give half the time to the thread.
+ // These values have empirically been found to yield good behavior.
+ // Good means that audio performance is high and other threads won't starve.
+ const double kGuaranteedAudioDutyCycle = 0.75;
+ const double kMaxAudioDutyCycle = 0.85;
+
+ // Define constants determining how much time the audio thread can
+ // use in a given time quantum. All times are in milliseconds.
+
+ // About 128 frames @44.1KHz
+ const double kTimeQuantum = 2.9;
+
+ // Time guaranteed each quantum.
+ const double kAudioTimeNeeded = kGuaranteedAudioDutyCycle * kTimeQuantum;
+
+ // Maximum time each quantum.
+ const double kMaxTimeAllowed = kMaxAudioDutyCycle * kTimeQuantum;
+
+ // Get the conversion factor from milliseconds to absolute time
+ // which is what the time-constraints call needs.
+ mach_timebase_info_data_t tb_info;
+ mach_timebase_info(&tb_info);
+ double ms_to_abs_time =
+ ((double)tb_info.denom / (double)tb_info.numer) * 1000000;
+
+ thread_time_constraint_policy_data_t time_constraints;
+ time_constraints.period = (uint32_t)(kTimeQuantum * ms_to_abs_time);
+ time_constraints.computation = (uint32_t)(kAudioTimeNeeded * ms_to_abs_time);
+ time_constraints.constraint = (uint32_t)(kMaxTimeAllowed * ms_to_abs_time);
+ time_constraints.preemptible = 0;
+
+ error = thread_policy_set(mach_thread_self(),
+ THREAD_TIME_CONSTRAINT_POLICY,
+ (thread_policy_t)&time_constraints,
+ THREAD_TIME_CONSTRAINT_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();
+ PtTimestamp timestamp;
+ if (delay < 0) delay = 0;
+ wait_time = AudioConvertNanosToHostTime((UInt64)delay * NSEC_PER_MSEC);
+ wait_time += AudioGetCurrentHostTime();
+ mach_wait_until(wait_time);
+ timestamp = Pt_Time();
+ (*(parameters->callback))(timestamp, parameters->userData);
+ }
+ 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;
+
+#ifdef HAVE_APPLE_QOS
+ pthread_attr_t qosAttribute;
+ pthread_attr_init(&qosAttribute);
+ pthread_attr_set_qos_class_np(&qosAttribute,
+ QOS_CLASS_USER_INTERACTIVE, 0);
+
+ res = pthread_create(&pt_thread_pid, &qosAttribute, Pt_CallbackProc,
+ parms);
+#else
+ res = pthread_create(&pt_thread_pid, NULL, Pt_CallbackProc, parms);
+#endif
+
+ struct sched_param sp;
+ memset(&sp, 0, sizeof(struct sched_param));
+ sp.sched_priority = sched_get_priority_max(SCHED_RR);
+ if (pthread_setschedparam(pthread_self(), SCHED_RR, &sp) == -1) {
+ return ptHostError;
+ }
+
+ if (res != 0) return ptHostError;
+ }
+
+ time_started_flag = TRUE;
+ return ptNoError;
+}
+
+
+PtError Pt_Stop(void)
+{
+ /* printf("Pt_Stop called\n"); */
+ pt_callback_proc_id++;
+ pthread_join(pt_thread_pid, NULL);
+ time_started_flag = FALSE;
+ return ptNoError;
+}
+
+
+int Pt_Started(void)
+{
+ return time_started_flag;
+}
+
+
+PtTimestamp Pt_Time(void)
+{
+ UInt64 clock_time, nsec_time;
+ clock_time = AudioGetCurrentHostTime() - start_time;
+ nsec_time = AudioConvertHostTimeToNanos(clock_time);
+ return (PtTimestamp)(nsec_time / NSEC_PER_MSEC);
+}
+
+
+void Pt_Sleep(int32_t duration)
+{
+ usleep(duration * 1000);
+}
diff --git a/portmidi/porttime/ptwinmm.c b/portmidi/porttime/ptwinmm.c new file mode 100755 index 0000000..5204659 --- /dev/null +++ b/portmidi/porttime/ptwinmm.c @@ -0,0 +1,70 @@ +/* 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_PTR dwUser,
+ DWORD_PTR dw1, DWORD_PTR dw2)
+{
+ (*time_callback)(Pt_Time(), (void *) dwUser);
+}
+
+
+PMEXPORT 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_PTR) userData, TIME_PERIODIC | TIME_CALLBACK_FUNCTION);
+ if (!timer_id) return ptHostError;
+ }
+ return ptNoError;
+}
+
+
+PMEXPORT 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;
+}
+
+
+PMEXPORT int Pt_Started()
+{
+ return time_started_flag;
+}
+
+
+PMEXPORT PtTimestamp Pt_Time()
+{
+ return timeGetTime() - time_offset;
+}
+
+
+PMEXPORT void Pt_Sleep(int32_t duration)
+{
+ Sleep(duration);
+}
|
