マルチメディアタイマ


マルチメディアタイマを使えば1ミリ秒程度のインターバルで比較的正確にイベント発生させることができる. マルチメディアタイマを設定するにはtimeSetEvent関数を用いる. この関数のプロトタイプは以下のようになっている.

function timeSetEvent( uDelay, uResolution: UINT;
  lpFunction: TFNTimeCallBack; dwUser: DWORD; uFlags: UINT ): MMRESULT; stdcall;

uDelayはタイマイベントのインターバルであり,uResolutionは時間の精度を指定する. uResolutionにあまり小さな値を指定するとシステムのオーバーヘッドが大きくなるので 注意が必要である. lpFunctionはイベントが発生するたびに呼び出されるコールバック関数のアドレスである. コールバック関数はstdcallで宣言しておく必要がある. dwUserはコールバック関数に渡すアプリケーション定義の変数である. uFlagsはイベントが発生する頻度を指定するもので,TIME_PERIODICを指定すれば タイマが解除されるまでuDelayで指定した時間ごとにコールバック関数が呼び出される. 一方,TIME_ONESHOTを指定すればuDelayで指定した時間が経過した後,一度だけ コールバック関数が呼び出される. 設定したタイマを解除するにはtimeKillEventを用いる.

なお,マルチメディアタイマに関する一連のAPIはmmsystem.pasで 宣言されているので,このユニットをuses節に追加する必要がある.

VCLのTimerとマルチメディアタイマの精度を比較するため 以下のようなプログラムを作ってみた. timeSetEventの2番目の引数には timeGetDevCaps関数で取得したマルチメディアタイマの最小分解能を渡した.

var
  Count: Integer;
  Started, Terminated: DWORD;

procedure MMTimer_TimerProc( uTimer, uMessage: UINT;
                     dwUser, dw1, dw2: DWORD ); stdcall;
begin
   if Count = 0 then
      Started := timeGetTime;
   Inc( Count );
   if Count = 1000 then
   begin
      Terminated := timeGetTime;
      timeKillEvent( uTimer );
      Form1.Label1.Caption
          := 'Total Milliseconds = ' + IntToStr( Terminated - Started );
   end;
end;

procedure TForm1.MMTimerStartBtnClick(Sender: TObject);
var
  TC: TIMECAPS;
begin
   timeGetDevCaps( @TC, SizeOf( TC ) );
   Count := 0;
   timeSetEvent( 1, TC.wPeriodMin, MMTimer_TimerProc,
                 0, TIME_PERIODIC );
end;

procedure TForm1.VCLTimerStartBtnClick(Sender: TObject);
begin
   Count := 0;
   VCLTimer.Interval := 1;
   VCLTimer.Enabled := True;
end;

procedure TForm1.VCLTimerTimer(Sender: TObject);
begin
   if Count = 0 then
      Started := timeGetTime;
   Inc( Count );
   if Count = 1000 then
   begin
      Terminated := timeGetTime;
      VCLTimer.Enabled := False;
      Label1.Caption := 'Total Milliseconds = '
                        + IntToStr( Terminated - Started );
   end;
end;

このプログラムでは,はじめ整数型変数Countに0を代入しておき, 1ミリ秒ごとにCountに1を加算し,Countが1000になるまでの時間を計測するものである. もし正確に1ミリ秒ごとにイベントが発生していれば, Countが1000になるまでちょうど1秒かかるはずである.

実行結果は以下のようになった.

VCL Timer
MM Timer

VCLのTimerでは,Intervalプロパティを1に設定しているにもかかわらず約10000ミリ秒(=10秒)かかっている. つまり,平均して10ミリ秒に1回程度しかイベントが発生していないことになる. いろいろ試してみると,Intervalに10以下の値を設定した場合の結果は常に10000ミリ秒程度であった. したがって,VCLのTimer,すなわちシステム標準のタイマでは10ミリ秒以下の制御は事実上できないことになる. 一方,マルチメディアタイマではほぼ1000ミリ秒かかっており, 1ミリ秒ごとに正確にイベントが発生している(=コールバック関数が呼ばれている)ことがわかる.

なお,上で示したプログラムと全く同じ動作をするプログラムをVBでも作成したので, ソースコードをここに置いておく.


お問い合わせはメールにて: akasaka@klc.ac.jp

戻る
SEO [PR] 爆速!無料ブログ 無料ホームページ開設 無料ライブ放送