Solved

Timing Procedures in C++

Posted on 1998-07-17
26
377 Views
Last Modified: 2013-12-03
    I am writing some MIDI sequencing software, and have found the standard Timer component for Visuall C++ to be too slow, and it skips beats.  I know that you can implement your own timing code into your program, which is extremely accurate (milisecond intervals).  You do this with the SetTimer and TimerProc functions.  Can you show me an example *.cpp file which illustrates how to write your own callback function TimerProc, and how to call the SetTimer function to use the callback function every time the interval has expired?  Basicly, I need some kind of very accurate timing mechanism that will execute a block of code every time a timer message is recieved.  Can you Help?  I use Borland C++ Builder.
0
Comment
Question by:bitmask
  • 10
  • 7
  • 3
  • +4
26 Comments
 
LVL 22

Expert Comment

by:nietod
Comment Utility
First of all, do you understand that the SetTimer timers and the TimerProc will function only if your program has a windows message loop operating at the same time.  This is because the timer procedure is called after a timer message has been handled by the default window procedure.  Is that going to work for you?
0
 

Author Comment

by:bitmask
Comment Utility
Please, I need simple responses.  I just want to know how to get an accurate timer going.  Step by step, what to put in the *.h and what to put in the *.cpp.  I already know that I am doing things wrong, so telling me that doesn't help me!!!!!
0
 
LVL 22

Expert Comment

by:nietod
Comment Utility
You missunderstood me.  I'm not saying you're doing anything wrong.  I'm trying to determine whethor or not a timer will function for your case.  Window's timers are a bit missleading.  But I'll post the sample code next and we'll see.
0
 
LVL 22

Expert Comment

by:nietod
Comment Utility
VOID CALLBACK TimPrc(HWND hwnd, UINT uMsg, UINT idEvent,DWORD dwTime)
{
}

   *    *    *
{
   UINT TimHnd = SetTimer( NULL,0,1000,TimPrc);


   *    *    *

   KillTimer(NULL,TimHnd);

}
0
 
LVL 2

Expert Comment

by:duneram
Comment Utility
I haven't looked at this topic in a while, but I seem to remember the multimedia timer is the way to go for fine timing of things.

Also I believe there is a limit to the number of timers you can set.  An alternative that will let you have unlimited timers is to set one timer and then build a class that allows multiple instances and each instance to have its own timestamp.

Essentially at creation of the first one you install your timerproc (settimer)
At each time thereafter you simply get the time off the multimedia timer,  then when you are done you collect the finish time off the multimedia timer and you have an elapsed time.

I have old code that does this, I just have to find it.


0
 
LVL 22

Expert Comment

by:nietod
Comment Utility
In the example, the timer procedure called TimPrc() will be called every second  (I set the interval to 1000 milliseconds which is 1 second).  

The parameters passed to TimPrc will probably be ignored.  They must be there however.  The last parameter is the current time, of sorts, and might be useful, but the rest probably not.

The SetTimer() procedure creates a timer and stores a handle to it in TimHnd.   Whent he timer is not needed KillTimer() is used to destroy it.  You may want to make TimHnd a global varialbe depending on your needs.  (since SetTimer() and KillTimer()) will probably be in different procedures).

That's all there is to it except for one detail.  You must have a windows message loop runing or the timer procedure won't get called.  That is your program must be doing GetMessage() and DispatchMessage() or the procedure doesn't get called.  
0
 
LVL 22

Expert Comment

by:nietod
Comment Utility
I also should mention that there is no gaurantee that your procedure will be called as frequently as you request.  If you set the interval very small it may be called irregularly.  Usually 10 times a second is not a problem when your program is in the foreground AND is not taking a long time to process messages.  Note that when you are processing a non timer message (like WM_PAINT) you can't be processing timer messages, so the response of the timer depends in large part on your application.
0
 
LVL 11

Expert Comment

by:alexo
Comment Utility
Because timers use windows messages, they are NOT accurate.
For timing purposes, use either multimedia timers (e.g., timeSetEvent() etc.) or the performance monitoring functions (QueryPerformanceCounter() etc.) which give the best resolution.
0
 
LVL 22

Expert Comment

by:nietod
Comment Utility
Okay where were you guys when I was trying get across that this might not be what he wants?
0
 

Author Comment

by:bitmask
Comment Utility
I am trying this just to see if the timer stuff works, and I am having no success.  Also, once this is written, how can I use variable names, and object names for stuff on my main form from within the TimerProc?  At the very least, how can I call other functions on the same form/*.cpp?

//---------------------------------------------------------------------------
#include <vcl\vcl.h>
#pragma hdrstop

#include "Unit1.h"
#include "mmsystem.h"
//---------------------------------------------------------------------------
#pragma resource "*.dfm"
TForm1 *Form1;
//---------------------------------------------------------------------------
void CALLBACK TimerProc(HWND hwnd, UINT uMsg, UINT idEvent,DWORD dwTime)
{
}
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
      : TForm(Owner)
{
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
MMRESULT timeSetEvent(100, 0, TimerProc, NULL, TIME_PERIODIC);
}
//---------------------------------------------------------------------------
0
 
LVL 11

Expert Comment

by:alexo
Comment Utility
>> Okay where were you guys when I was trying get across that this might not be what he wants?

Probably off line.
0
 
LVL 22

Expert Comment

by:nietod
Comment Utility
>> I am trying this just to see if the timer stuff works, and I am having no success.  
This probably isn't the right way to go because the timing isn't accurate enough.  But it will work and you should be able to access variables,objects, and functions as usual.  

0
 
LVL 3

Expert Comment

by:BudVVeezer
Comment Utility
There is a MAJOR problem with using the TimerProc function.  It is of the LEAST priority in the messaging scheme.  If there is another message, then the WM_TIMER message gets pushed down in the message queue.  It is USUALLY fairly acurate, but if your program processes many messages, then I would NOT suggest using the WM_TIMER message.  I dunno if this is of any use to you, but I figured that you should know about it.

~Aaron
0
How your wiki can always stay up-to-date

Quip doubles as a “living” wiki and a project management tool that evolves with your organization. As you finish projects in Quip, the work remains, easily accessible to all team members, new and old.
- Increase transparency
- Onboard new hires faster
- Access from mobile/offline

 

Expert Comment

by:cleck
Comment Utility
I am currently working on a real-time test system for use in the Win32 environment.  Using a fairly small callback module, I am seeing timing problems at 50Hz.  At slower speeds, the timing does become more accurate, but keep in mind that any action that queues messages will kill your determinism (i.e. moving the window, resizing, opening menus, etc.)  One option I can think of that might work:
Using Borland C++ 5.0, I was able to use the new WinNT timing function SetWaitableTimer with WaitForSingleObjectEx to get a fairly accurate timer system (and it doesn't rely on messaging).
0
 

Author Comment

by:bitmask
Comment Utility
It would be greatly appreciated to have not only suggestions, but also some code to go with it.
0
 
LVL 5

Expert Comment

by:tuvi
Comment Utility
If I am not wrong, Borland C++ Builder has a TTimer Component. Why don't you use it?
0
 

Author Comment

by:bitmask
Comment Utility
I cant use the Timer component that comes with visual c++ development environment because it is way too slow.  And it ends up skipping beats.  I need accuracy - not ease of use!
0
 
LVL 5

Accepted Solution

by:
tuvi earned 100 total points
Comment Utility
Bitmask, here is how you implement a Timer in Borland C++ Builder without using the TTimer:

The form is named "TestForm"
Header file: "Main.h"
--------------------
//---------------------------------------------------------------------------
#ifndef MainH
#define MainH
//---------------------------------------------------------------------------
#include <vcl\Classes.hpp>
#include <vcl\Controls.hpp>
#include <vcl\StdCtrls.hpp>
#include <vcl\Forms.hpp>
//---------------------------------------------------------------------------
class TTestForm : public TForm
{
__published:    // IDE-managed Components
  void __fastcall FormDestroy(TObject *Sender);
private:           // User declarations
protected:
  void __fastcall WMTimer(TWMTimer TimeMsg);
public:            // User declarations
  __fastcall TTestForm(TComponent* Owner);
// these are needed for message trapping in C++ Builder
BEGIN_MESSAGE_MAP
  MESSAGE_HANDLER(WM_TIMER, TWMTimer, WMTimer)
END_MESSAGE_MAP(TForm)
};
//---------------------------------------------------------------------------
extern TTestForm *TestForm;
//---------------------------------------------------------------------------
#endif

And the implementation file: "Main.cpp"
------------
//---------------------------------------------------------------------------
#include <vcl\vcl.h>
#pragma hdrstop

#include "Main.h"

#define MYTIME     10      // your ID event
#define MSEC        5000  // intervals in milliseconds (1000 = 1 second)
//---------------------------------------------------------------------------
#pragma resource "*.dfm"
TTestForm *TestForm;
//---------------------------------------------------------------------------
__fastcall TTestForm::TTestForm(TComponent* Owner) : TForm(Owner)
{
  SetTimer (Handle, MYTIME, MSEC, NULL);
}
//---------------------------------------------------------------------------
void __fastcall TTestForm::WMTimer(TWMTimer TimeMsg)
{
  if (TimeMsg.TimerID == MYTIME)
    {
// do your processing right here.
// I set timer to 5 seconds so I have time to close and test the next Msg Dialog
// delete next line and insert your code
      Application->MessageBox ("Timer running", "Timer", IDOK);
    }
}
//---------------------------------------------------------------------------
void __fastcall TTestForm::FormDestroy(TObject *Sender)
{
  KillTimer (Handle, MYTIME);
}
//---------------------------------------------------------------------------

0
 
LVL 5

Expert Comment

by:tuvi
Comment Utility
Bitmask, I forgot to mention the TWMTimer structure (wrapper for WM_TIME message) as defined in <Messages.hpp>

struct TWMTimer
{
  Cardinal Msg;
  long TimerID;
  void *TimerProc;
  long Result;
} ;
0
 

Author Comment

by:bitmask
Comment Utility
Kudos to tuvi!!!!!!!!!!!!!!!!!!!!!  I wrote a little timer app with the source code provided by tuvi and it works very well.  I am anxious to try implementing it into my MIDI program.  It seems like very solid timing code.  VERY MUCH APPRECIATED.  I will post an update detailing my success or failure.  THANK YOU!!!!
0
 
LVL 22

Expert Comment

by:nietod
Comment Utility
If VC's timer component is too slow this will be as well.  They are based on the same mechansim.  This is what I was trying to warn you of.
0
 

Author Comment

by:bitmask
Comment Utility
nietod --
if that is the case can you suggest an alternate method.  I know it can be done, as many people write sequencing software.  What other means of building timers are available?  Code examples would be great!
0
 
LVL 22

Expert Comment

by:nietod
Comment Utility
As alexo suggested, you need to be using the multimedia timers.  I don't have any source code, but most likely no one has builder type source code for this.  You are going to have to learn how to combine ordinary C++ with your builder code.
0
 

Author Comment

by:bitmask
Comment Utility
If thats the case couldn't I use assembler code then?
0
 
LVL 22

Expert Comment

by:nietod
Comment Utility
You could, but I see no reason why you should.  You can use ordinary C++.  Builder is a C++ compiler.  It has neat framework that hides some of the C++ details from you.  In order to make some things work, like the code I originaly posted, you are going to have to learn how to use ordinary C++ code in your project (like what file to stick it in and where) or you going to have to learn how to convert the C++ code so it fits into the framework.
0
 
LVL 11

Expert Comment

by:alexo
Comment Utility
>> If thats the case couldn't I use assembler code then?
You could also deep fry your privates.  However, I see no reason for both activities.

bitmask, let me summarize:
1. Windows timers (SetTimer() etc.) are extremely unaccurate.
2. Multimedia timers (timeSetEvent() etc.) are better.
3. Performance monitoring functions (QueryPerformanceCounter() etc.) give good resolution but cannot schedule events.
4. Pentium counters have even better resolution than #4 but are non-portable and require deep-frying your privates..., err..., Assembly coding.

Now, a WDJ column came up with an interesting solution.
Basically, you schedule an event (using multimedia timers) a bit before it must occur, then busy wait (using performance monitoring) until the exact time.
0

Featured Post

Top 6 Sources for Identifying Threat Actor TTPs

Understanding your enemy is essential. These six sources will help you identify the most popular threat actor tactics, techniques, and procedures (TTPs).

Join & Write a Comment

zlib is a free compression library (a DLL) on which the popular gzip utility is built.  In this article, we'll see how to use the zlib functions to compress and decompress data in memory; that is, without needing to use a temporary file.  We'll be c…
As more and more people are shifting to the latest .Net frameworks, the windows presentation framework is gaining importance by the day. Many people are now turning to WPF controls to provide a rich user experience. I have been using WPF controls fo…
This is Part 3 in a 3-part series on Experts Exchange to discuss error handling in VBA code written for Excel. Part 1 of this series discussed basic error handling code using VBA. http://www.experts-exchange.com/videos/1478/Excel-Error-Handlin…
This video explains how to create simple products associated to Magento configurable product and offers fast way of their generation with Store Manager for Magento tool.

763 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

6 Experts available now in Live!

Get 1:1 Help Now