Solved

Timing Procedures in C++

Posted on 1998-07-17
26
384 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
ID: 1410456
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
ID: 1410457
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
ID: 1410458
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
Live: Real-Time Solutions, Start Here

Receive instant 1:1 support from technology experts, using our real-time conversation and whiteboard interface. Your first 5 minutes are always free.

 
LVL 22

Expert Comment

by:nietod
ID: 1410459
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
ID: 1410460
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
ID: 1410461
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
ID: 1410462
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
ID: 1410463
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
ID: 1410464
Okay where were you guys when I was trying get across that this might not be what he wants?
0
 

Author Comment

by:bitmask
ID: 1410465
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
ID: 1410466
>> 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
ID: 1410467
>> 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
ID: 1410468
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
 

Expert Comment

by:cleck
ID: 1410469
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
ID: 1410470
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
ID: 1410471
If I am not wrong, Borland C++ Builder has a TTimer Component. Why don't you use it?
0
 

Author Comment

by:bitmask
ID: 1410472
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
ID: 1410473
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
ID: 1410474
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
ID: 1410475
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
ID: 1410476
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
ID: 1410477
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
ID: 1410478
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
ID: 1410479
If thats the case couldn't I use assembler code then?
0
 
LVL 22

Expert Comment

by:nietod
ID: 1410480
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
ID: 1410481
>> 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

Courses: Start Training Online With Pros, Today

Brush up on the basics or master the advanced techniques required to earn essential industry certifications, with Courses. Enroll in a course and start learning today. Training topics range from Android App Dev to the Xen Virtualization Platform.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Suggested Solutions

Entering time in Microsoft Access can be difficult. An input mask often bothers users more than helping them and won't catch all typing errors. This article shows how to create a textbox for 24-hour time input with full validation politely catching …
Whether you've completed a degree in computer sciences or you're a self-taught programmer, writing your first lines of code in the real world is always a challenge. Here are some of the most common pitfalls for new programmers.
This Micro Tutorial demonstrates using Microsoft Excel pivot tables, how to reverse engineer competitors' marketing strategies through backlinks.
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…

776 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