Page 1 of 1

Danilo's PBOSL Hi-res Timer as PB source include

Posted: Wed May 21, 2008 7:00 pm
by netmaestro
I hope Danilo won't mind this, but srod did the same with the ToolBarPro library some months ago and he hasn't been assassinated afaik. Libs written in C have the drawback of only being usable in compiled form and at the rate the team is releasing new versions of PB, compiled userlibs have a shelf life of about 3 months.

I'm not sure why the timeBeginPeriod code is there, I can't see the need for it as TimeSetEvent covers all that ground but he's got it in there and this is a faithful translation so in it stays.

Code: Select all

;===============================================================================
; Program:          PBOSL_Timer Clone
; Author:           Lloyd Gallant (netmaestro) based on work by Danilo Krahn 
; Date:             November 26, 2007
; Target Compiler:  PureBasic 4.0 and later
; Target OS:        Windows XP/Vista 
; License:          Free, unrestricted, no warranties expressed or implied
;
; This code was originally conceived and written in C by Danilo Krahn
; and released as part of the PureBasic Open Source Libraries collection.
; Its functions are reproduced here in PureBasic sourcecode for use
; as a PB Include file for those who prefer not to use compiled libraries in 
; their projects. All functions in this library are fully compatible in name
; and functionality with those in the compiled PBOSL version.
;
; If you have programs that use the compiled PBOSL_Timer library and you would 
; prefer a .pbi include alternative, you may safely include this file in your
; projects and all the hi-res timer functions will work as expected.
; (that's an opinion, not a warranty)
;
;===============================================================================

Global timer_res.TIMECAPS
Global Dim timer_handles(16)
Global Dim timer_procedures(16)

timeGetDevCaps_( timer_res, SizeOf(TIMECAPS) )

Procedure Timer_Init()
  timeBeginPeriod_( timer_res\wPeriodMin )
  For i=1 To 16
    timer_handles(i)    = 0
    timer_procedures(i) = 0
  Next
EndProcedure

Procedure GetMinTimerResolution()
  ProcedureReturn timer_res\wPeriodMin
EndProcedure

Procedure GetMaxTimerResolution()
  ProcedureReturn timer_res\wPeriodMax
EndProcedure

Procedure Timer_CallBack( timer_handle, msg, timer_number, dw1, dw2)
  If timer_procedures(timer_number)
    CallFunctionFast( timer_procedures(timer_number) )
  EndIf
EndProcedure

Procedure StartTimer( timer_number, delay, *timer_proc_address )
  If timer_number > 15
    ProcedureReturn 0
  EndIf
  If timer_handles(timer_number)
    timeKillEvent_( timer_handles(timer_number) )
  EndIf
  timer_procedures(timer_number) = *timer_proc_address
  timer_handles(timer_number) = timeSetEvent_( delay, 0, @Timer_CallBack(), timer_number, #TIME_PERIODIC )
  ProcedureReturn timer_handles(timer_number)
EndProcedure

Procedure EndTimer( timer_number )
  If timer_number > 15
    ProcedureReturn 0
  EndIf
  If timer_handles(timer_number)
    timeKillEvent_( timer_handles(timer_number) )
    ProcedureReturn 1
  EndIf
  ProcedureReturn 0
EndProcedure

Procedure Timer_End()
  For i=1 To 16
    If timer_handles(i)
      timeKillEvent_(timer_handles(i))
    EndIf
  Next
  timeEndPeriod_( timer_res\wPeriodMin )
EndProcedure

Posted: Wed May 21, 2008 8:07 pm
by IceSoft
See what MSDN says:

Code: Select all

timeBeginPeriod
The timeBeginPeriod function sets the minimum timer resolution for an application or device driver. 

MMRESULT timeBeginPeriod(
  UINT uPeriod  
);
Parameters

uPeriod

Minimum timer resolution, in milliseconds, for the application or device driver.

Return Values

Returns TIMERR_NOERROR if successful or TIMERR_NOCANDO if the resolution specified in uPeriod is out of range. 

Remarks

Call this function immediately before using timer services, and call the timeEndPeriod function immediately after you are finished using the timer services.

You must match each call to timeBeginPeriod with a call to timeEndPeriod, specifying the same minimum resolution in both calls. An application can make multiple timeBeginPeriod calls as long as each call is matched with a call to timeEndPeriod.

Posted: Wed May 21, 2008 9:05 pm
by netmaestro
TimeSetEvent doesn't need it.

Posted: Wed May 21, 2008 9:12 pm
by ts-soft
here is my old translation on the german board

Posted: Wed May 21, 2008 9:28 pm
by netmaestro
I can't speak German so I don't get to the German board much, but thanks for posting that. If I'd known it existed I wouldn't have written mine.

On the timeBeginPeriod subject, if it were required for TimeSetEvent then this code would be debugging a value much smaller than 1000 but here it's debugging exactly 1000 every time:

Code: Select all

Global x=0

Procedure Test(uID, uMsg, dwUser, dw1, dw2)
  x+1
EndProcedure

TEvent = timeSetEvent_(1,0,@Test(),0,#TIME_PERIODIC)

Delay (1000) ; Allow 1 second for the timer proc to increment x

timeKillEvent_(TEvent)

Debug x

Posted: Sat May 31, 2008 9:48 am
by Psychophanta
Sorry, but as long as i know Danilo and you are wrong.
MS does not recognize that stuff as "HI-RES timing", but just as "Multimedia timing".
"HI-RES timing" belongs to other different Winapi stuff.

HI-RES timers are usually below 1 millisecond for PCs since about year 2000 until now.

When a user search for hi-res timers in this forum he will be led up to a wrong info due to threads like this. :?

Posted: Sun Jun 01, 2008 4:09 pm
by Rescator
Yeah! QueryPerformanceCounter_() if I remember correctly is a HI-RES timer.

As to timeBeginPeriod_() and timeEndPeriod_() they may not be needed for setEvent etc. But they are needed (at least on XP, not sure on Vista) to get close to 1ms when using Delay() or Sleep_() otherwise you get only as fine grained as 10ms or such. Win 9x has 1ms by default though.
ElapsedMilliseconds() is not as accurate as timeGetTime_()

Vista is supposedly normalizing all timers to all use HI-RES timers "under the hood" but only on hardware that actually provides a good HI-RES timer crystal etc.

In summary, timing on Windows is a pain in the ass :P