【发布时间】:2012-01-27 13:22:56
【问题描述】:
对于 MIDI 播放器来说,尽可能精确地播放音符很重要。我从来没有成功过,总是责怪计时器(参见之前的帖子:How to prevent hints interrupting a timer)。最近我收购了 ProDelphi 并开始测量究竟是什么消耗了这么多时间。结果非常令人惊讶,请参见下面的示例代码。
procedure TClip_View.doMove (Sender: TObject; note, time, dure, max_time: Int32);
var x: Int32;
begin
{$IFDEF PROFILE}Profint.ProfStop; Try; Profint.ProfEnter(@self,1572 or $58B20000); {$ENDIF}
Image.Picture.Bitmap.Canvas.Pen.Mode := pmNot;
Image.Picture.Bitmap.Canvas.MoveTo (FPPos, 0);
Image.Picture.Bitmap.Canvas.LineTo (FPPos, Image.Height);
x := time * GPF.PpM div MIDI_Resolution;
Image.Picture.Bitmap.Canvas.Pen.Mode := pmNot;
Image.Picture.Bitmap.Canvas.MoveTo (x, 0);
Image.Picture.Bitmap.Canvas.LineTo (x, Image.Height);
FPPos := x;
// Bevel.Left := time * GPF.PpM div MIDI_Resolution;
{$IFDEF PROFILE}finally; Profint.ProfExit(1572); end;{$ENDIF}
end; // doMove //
测量结果是(在 Intel i7-920、2.7Ghz 上没有调试代码):
- 如图所示的代码需要 95 微秒
- 5.609 毫秒,除了现在注释掉的语句 (
Bevel.Left :=) 之外的所有内容都被注释掉了 - 0.056 微秒,当所有代码被
x := time * GPF.PpM div MIDI_Resolution;替换时
仅在 Bevel 上移动所消耗的 CPU 是在 Canvas 上绘图的 60 倍。这让我很惊讶。测量 1 的结果非常好听(还有更多的事情发生),但 2 和 3 不是。我需要某种形式的反馈给用户,因为玩家现在正在处理什么,钢琴卷上的某种线条是公认的方式。在我对减少定时事件循环中 CPU 周期的永无止境的追求中,我有一些问题:
- 为什么绕斜角移动要花费这么多时间?
- 有没有办法比在位图上绘图减少更多的 CPU 周期?
- 有没有办法减少绘图时的闪烁?
【问题讨论】:
-
Windows 不是一个实时操作系统,但您真的不应该将实时方面的行为(如您的 MIDI 排序)与您的 UI 绘画联系起来。
-
@WarrenP MIDI 不期望真正的“实时”。它本身具有几毫秒的延迟(特别是对于 DIN 外部外围设备 - 它是 32000 波特 AFAIR 的串行链路)。今天的 Windows 反应灵敏,足以处理这个问题。
-
但如果您在代码中插入随机暂停则不会,因为它是单线程且低效的。 :-)