Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Using Multimedia Timer API - timeSetEvent

690 views
Skip to first unread message

Donovan J. Edye

unread,
Mar 29, 2004, 10:11:06 AM3/29/04
to
G'Day,

One of the paramaters to this API is a callback which is declared as follows:

procedure TimeCallBack(TimerID, Msg: Uint; dwUser, dw1, dw2: DWORD); pascal;

Is there any way I could have the callback referencce a method of a particular class
instance. ie:

MyObjectInstance1.CallBack
MyOtherObjectInstance2.CallBack

etc.

TIA

--
-- Donovan J. Edye
----------------------------------------------------------------------
SetiStats - Get your SETI statistics delivered to your mailbox daily.
http://www.edye.wattle.id.au/p.php?page=/delphi/setistats
----------------------------------------------------------------------

Kurt Barthelmess (TeamB)

unread,
Mar 29, 2004, 11:17:10 AM3/29/04
to
"Donovan J. Edye" <don...@nospam.edye.wattle.id.au> wrote:

>One of the paramaters to this API is a callback which is declared as follows:
>
>procedure TimeCallBack(TimerID, Msg: Uint; dwUser, dw1, dw2: DWORD); pascal;
>
>Is there any way I could have the callback referencce a method of a particular class
>instance. ie:
>
>MyObjectInstance1.CallBack
>MyOtherObjectInstance2.CallBack

Not exactly. The callback routine will be passed the parameters shown
in the docs, and those do not match what a method expects. What you
can do is use the dwUser parameter to timeSetEvent to pass the
MyObjectInstance1 (or 2...) and have the callback routine typecast
that back to a TMyObjectInstance to invoke the method.

Good luck.

Kurt

Donovan J. Edye

unread,
Mar 29, 2004, 11:40:53 AM3/29/04
to
K,

Great idea!!! Now why did I not think of that. ;-)

Kurt Barthelmess (TeamB) wrote:

--

Peter Haas

unread,
Mar 29, 2004, 2:07:26 PM3/29/04
to
Hi Donovan,

Donovan J. Edye wrote in <4067f63a$1...@newsgroups.borland.com>:


> One of the paramaters to this API is a callback which is declared as follows:
>
> procedure TimeCallBack(TimerID, Msg: Uint; dwUser, dw1, dw2: DWORD); pascal;

For 32 bit this is a wrong conversion. In the 32 bit Platform SDK PASCAL
is defined as __stdcall:

| procedure TimeCallBack(TimerID, Msg: Uint; dwUser, dw1, dw2: DWORD); stdcall;

> Is there any way I could have the callback referencce a method of a particular class
> instance. ie:
>
> MyObjectInstance1.CallBack
> MyOtherObjectInstance2.CallBack
>
> etc.

Not at all. A method have a hidden first parameter, which contain a
pointer to the instance.

You can use the dwUser parameter to get this instance pointer:

timeSetEvent(.., .., .., DWord(Self), ...)

procedure TimeCallBack(...
...
TMyClass(dwUser).Callback(...)


But there is a other serious problem.

From the WinSDK:
: Applications should not call any system-defined functions from inside a
: callback function, except for PostMessage, timeGetSystemTime,
: timeGetTime, timeSetEvent, timeKillEvent, midiOutShortMsg,
: midiOutLongMsg, and OutputDebugString.

I suggest to use PostMessage and a mechanism to avoid message queue
overflow. Few weeks ago I have posted a example:

Newsgroups: borland.public.delphi.nativeapi.win32
Subject: Re: timeSetEvent
Date: Thu, 19 Feb 2004 23:57:12 +0100
Message-ID: <40353efb$1...@newsgroups.borland.com>

or online in the archive:
http://216.101.185.148/scripts/isapi.dll/article?id=4328A7C3&article=5077475

Bye Peter.
--
JEDI+ API, the active JEDI Header Conversions Project:
http://jediplus.pjh2.de/api

Donovan J. Edye

unread,
Mar 29, 2004, 9:55:07 PM3/29/04
to
P,

> From the WinSDK:
> : Applications should not call any system-defined functions from inside a
> : callback function, except for PostMessage, timeGetSystemTime,
> : timeGetTime, timeSetEvent, timeKillEvent, midiOutShortMsg,
> : midiOutLongMsg, and OutputDebugString.

I am not making any direct API calls from within the callback method of the class I
intend to invoke. So you must be suggesting that I might be doing this inadvertantly?
ie Delphi might be doing it behind the scenes? Can you elaborate on this?

This address returns a server error 500. Anywhere else I can look for this article?
You can email it to me via my website listed below.

Donovan J. Edye

unread,
Mar 29, 2004, 10:42:46 PM3/29/04
to
P,

> I suggest to use PostMessage and a mechanism to avoid message queue
> overflow. Few weeks ago I have posted a example:

Just been thinking about your suggestion to use a message to trigger
the callback in the class. This to me seems to be a poor design choice
as you are then bound by the speed of the processing of the message
loop to get the callback to fire. Simplistically if we are firing the
timer every 10ms and we have the following scenario:

- Callback Invoked (After 10ms by WinAPI)
- PostMessage (1ms to place onto message queue)
- Message serviced 5ms later (Assume app heaps busy)

Then we have a total round trip of 16ms. So we are 60% over our
requested interval. Also the 16ms can vary depending on how busy the
machine is. Seems to me we have taken the hight precision timer and
hobbled it rather badlyy. One of the issues with the WM_TIMER approach
is eactly this - You are bound to the processing of the message loop so
are not going to get accurate timings.

Your comments?

--
--Donovan

Kurt Barthelmess (TeamB)

unread,
Mar 30, 2004, 1:34:27 AM3/30/04
to
"Donovan J. Edye" <donovan...@namsys.com.au> wrote:

>Just been thinking about your suggestion to use a message to trigger
>the callback in the class. This to me seems to be a poor design choice
>as you are then bound by the speed of the processing of the message
>loop to get the callback to fire.

[clip]


>Seems to me we have taken the hight precision timer and
>hobbled it rather badlyy.

Not "we" - Microsoft. The underlying problem is that Windows can't
handle any requests except the ones that MS mentions in the docs - at
least it can not in the context of this timer interrupt. There are
probably some good reasons for that, but it doesn't make any
difference whether there are or are not - we're stuck with the
implementation.

If you need the ability to respond to a timer at extremely small
intervals - and exactly on those intervals, Windows is not the best
choice for a platform because it was designed with other goals in
mind.

Good luck.

Kurt

Peter Haas

unread,
Mar 30, 2004, 2:06:42 PM3/30/04
to
Hi Donovan,

Donovan J. Edye wrote in <4068...@newsgroups.borland.com>:


> I am not making any direct API calls from within the callback method of the class I
> intend to invoke. So you must be suggesting that I might be doing this inadvertantly?
> ie Delphi might be doing it behind the scenes? Can you elaborate on this?

What do you want to do in the callback? E.g. writing to a file, draw
anything to the screen call functions from the Windows API.

> > or online in the archive:
> > http://216.101.185.148/scripts/isapi.dll/article?id=4328A7C3&article=5077475
> This address returns a server error 500. Anywhere else I can look for this article?

:-(

Unfortunately this newsgroup is 'too new', Google Groups don't archive
it. I think the message is still available on the news server, therefore
a good newsreader can find it by message id. But unfortunately XanaNews
don't have such a function, at least I have not found it.

A other way:
- visit http://www.tamaracka.com/search.htm
- search for timeSetEvent
- call the (currently third) article "Re: timeSetEvent" "Peter Haas"
"borland.public.delphi.nativeapi.win32" "2/19/2004 10:57:12 PM"

Peter Haas

unread,
Mar 30, 2004, 2:06:42 PM3/30/04
to
Hi Donovan,

Donovan J. Edye wrote in <4068...@newsgroups.borland.com>:


> > I suggest to use PostMessage and a mechanism to avoid message queue
> > overflow. Few weeks ago I have posted a example:
> Just been thinking about your suggestion to use a message to trigger
> the callback in the class. This to me seems to be a poor design choice
> as you are then bound by the speed of the processing of the message
> loop to get the callback to fire. Simplistically if we are firing the
> timer every 10ms and we have the following scenario:
>
> - Callback Invoked (After 10ms by WinAPI)
> - PostMessage (1ms to place onto message queue)
> - Message serviced 5ms later (Assume app heaps busy)
>
> Then we have a total round trip of 16ms. So we are 60% over our
> requested interval.

Firstly, how you have measure this periods?

Do you need really the exact moment? Do you need really intervals with
very small differences? Windows is not a real time OS! Under Windows you
can guarantee maybe a precision of one minute.

> Also the 16ms can vary depending on how busy the machine is.

For what do you need 10 ms intervals and WinAPI calls?

A other calculation. Can you guarantee, that your callback function
don't exceed the 10 ms - the needed time for calling the callback and
other processes?

> Seems to me we have taken the hight precision timer and hobbled it
> rather badlyy.

timeSetEvent is part of the multimedia timer, it is not a high precision
timer. It is not possible to guarantee a high precision on Windows.

The multimedia timer is designed for multimedia purposes, e.g. for
drawing movie frames to the screen. For this purpose intervals of 40-80
ms are sufficiently, a offset of 20 ms between the timer event and the
drawing of the frame is not important.

You can use the callback, if you don't call any WinAPI function
(directly or indirectly) except the functions posted before and if you
can guarantee, that your callback function don't exceed the interval.
If not, you risk a serious crash on the computer. Please note, even if a
program work for some minutes on your computer, it can crash on a other
computer.


In the most PCs there exist a high-resolution timer, but with a other
design. QueryPerformanceCounter return the current value of a continuous
counter, the interval you can get from QueryPerformanceFrequency. Note,
that there are two, probably different counters in a two processor
system.

With this timer you don't get a callback or a event, you need to poll
the time in a loop. Usually this will executed in a own thread, if you
execute it in the main thread the application is froozen for any
messages. Among others because the VCL is not threadsafe, you need to
synchronize your VCL and WinAPI calls with the main thread, a good way
is to use PostMessage.


> One of the issues with the WM_TIMER approach is eactly this - You are
> bound to the processing of the message loop so are not going to get
> accurate timings.

WM_TIMER is designed for other purposes. It have a resolution of 53 ms,
with the multimedia timer you can choose a resolution down to 1 ms.


However, you should describe, what you want to do. Then we can either
try to find a practically solution or tell you, that you can not solve
your problem under Windows.

Colin Wilson

unread,
Mar 31, 2004, 7:10:00 PM3/31/04
to
Peter Haas wrote:

> timeSetEvent is part of the multimedia timer, it is not a high
> precision timer. It is not possible to guarantee a high precision on
> Windows.
>
> The multimedia timer is designed for multimedia purposes, e.g. for
> drawing movie frames to the screen. For this purpose intervals of
> 40-80 ms are sufficiently, a offset of 20 ms between the timer event
> and the drawing of the frame is not important.

In my experience you can use it to get better than 10ms. The trick is
to set your application's priority to real-time. Of course it's not
generally recommended that you do this because you can lock up NT if
your program stalls, but it may be necessary if you want (nearly)
real-time performance.

Internally, when you call timeSetEvent, NT creates a separate thread to
do the work. It would be nice if you could just set that thread's
priority - but there's no way of getting it's handle (that I know of).

You need about 10ms or better to do midi playback using the low level
midi functions without it sounding strange.


> You can use the callback, if you don't call any WinAPI function
> (directly or indirectly) except the functions posted before and if you
> can guarantee, that your callback function don't exceed the interval.
> If not, you risk a serious crash on the computer. Please note, even
> if a program work for some minutes on your computer, it can crash on
> a other computer.

That list of APIs is not comprehensive on Win 32. It was a hangover
from 16-bit days, and they couldn't be bothered to re-asses it. Of
course you must follow the usual re-entrancy things, and almost
certainly not do any GUI stuff from within the callback.

There's a sample free-with-source (d7) MIDI sequencer available on my
website which is driven by a timeSetEvent timer...


--
Colin
e-mail :co...@wilsonc.demon.co.uk
web: http://www.wilsonc.demon.co.uk/delphi.htm

Posted with XanaNews 1.16.1.13

Donovan J. Edye

unread,
Apr 2, 2004, 10:21:05 PM4/2/04
to
G'Day,

Thanks Peter, Kurt, Colin for your comments and insight. I realise that Win32 is not
the place to do real time work. I was however just "stirring the pot" with my comment
that the limited amount of API calls available in the callback seemed "disappointing".
Especially the fact that you would have to use PostMessage and be at the mercy of Windows
message handling once more. ;-)


Donovan J. Edye wrote:

> P,
>
> > I suggest to use PostMessage and a mechanism to avoid message queue
> > overflow. Few weeks ago I have posted a example:

--
-- Donovan J. Edye

Andrew Rybenkov

unread,
Apr 3, 2004, 8:03:23 PM4/3/04
to
> Windows is not a real time OS!

while people repeat this constantly, I can assure you, that
there was implemented some data aquisition software in Delphi 1,
that was successfully used for electrocardiagramming (for example),
under Win 3.11 on P166 with some S3 video card it was able to work properly with
2ms resolution (enough for ECG) - acquire data, normalize it, remove noise etc., draw ~ 8 plots for
corresponding channels and store the data. Moreover drawing was not optimized -
just Delphi canvas methods.


--
Andrew Rybenkov.

Kurt Barthelmess (TeamB)

unread,
Apr 3, 2004, 11:47:18 PM4/3/04
to
"Andrew Rybenkov" <aryb...@hotmail.com> wrote:

One of the differences between Windows 16 and Windows 32 is that under
Windows 16, an application could retain control of the CPU without
being preempted by another. If a Win16 application did not call
GetMessage (or an equivalent), the system would lock up. A Win32 app
can and will get preempted if it behaves like that.

You generally need to write a device driver if you have time critical
operations under Win32.

Good luck.

Kurt

Andrew Rybenkov

unread,
Apr 4, 2004, 8:25:28 AM4/4/04
to
> One of the differences between Windows 16 and Windows 32 is that under
> ..

U-hu, "co-operative" multitasking.

(As Colin already mentioned) in Win32 you need just to manipulate with process' priority.
Actually, by assigning to your process the highest priority you grab all the resources, -
even the mouse is frozen.

>You generally need to write a device driver if you have time critical operations under Win32.

... with resolution less than 1ms.


--
Andrew Rybenkov.

0 new messages