You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Delphi中实现快速声音播放?解决节拍器低Timer间隔异常

Delphi节拍器声音截断/延迟问题解决方案

问题根源

  1. TTimer精度不足:TTimer基于Windows消息队列,默认精度约10-15ms,当主线程繁忙时,定时器事件会被延迟触发,导致节拍不准。
  2. PlaySound的SND_ASYNC模式缺陷:该模式下新的PlaySound调用会直接终止上一个未完成的播放,造成声音截断;同时每次从磁盘加载WAV文件的耗时,在短间隔场景下会放大延迟问题。

具体解决方法

1. 替换TTimer为高精度多媒体定时器

使用Windows多媒体定时器timeSetEvent,它能提供最低1ms的定时精度,且基于回调而非消息队列,不受主线程繁忙状态影响。

示例代码:

unit TestForm;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, ExtCtrls, MMSystem;

type
  TTestForm = class(TForm)
  private
    FTimerID: UINT;
    FWaveResource: THandle; // 预加载的WAV资源句柄
    procedure MetronomeCallback(uTimerID, uMsg: UINT; dwUser, dw1, dw2: DWORD); stdcall;
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
    procedure StartMetronome(BPM: Integer);
    procedure StopMetronome;
  end;

var
  TestForm: TTestForm;

implementation

{$R *.dfm}

constructor TTestForm.Create(AOwner: TComponent);
begin
  inherited;
  // 预加载WAV文件到内存(替换为你的WAV文件路径)
  FWaveResource := LoadLibrary(PChar('100ms_sound.wav'));
end;

destructor TTestForm.Destroy;
begin
  StopMetronome;
  if FWaveResource <> 0 then
    FreeLibrary(FWaveResource);
  inherited;
end;

procedure TTestForm.MetronomeCallback(uTimerID, uMsg: UINT; dwUser, dw1, dw2: DWORD);
begin
  // 使用预加载的内存资源播放,避免磁盘IO延迟
  PlaySound(PChar(FWaveResource), 0, SND_MEMORY or SND_ASYNC or SND_NODEFAULT);
end;

procedure TTestForm.StartMetronome(BPM: Integer);
var
  Interval: UINT;
begin
  StopMetronome;
  // 计算节拍间隔(毫秒):60000ms / BPM
  Interval := 60000 div BPM;
  // 启动多媒体定时器:定时间隔、精度、回调函数、用户数据、重复模式
  FTimerID := timeSetEvent(Interval, 1, @MetronomeCallback, DWORD(Self), TIME_PERIODIC);
end;

procedure TTestForm.StopMetronome;
begin
  if FTimerID <> 0 then
  begin
    timeKillEvent(FTimerID);
    FTimerID := 0;
  end;
end;

2. 优化声音播放逻辑

  • 预加载声音资源:将WAV文件提前加载到内存,避免每次播放时的磁盘读取操作,减少延迟。
  • 避免声音截断:如果需要确保前一段声音播放完成后再触发下一个,可改用SND_SYNC模式,但注意不能在定时器回调中直接使用(会阻塞线程),此时可使用WaveOut系列API管理播放缓冲区,实现有序播放。

3. 避免主线程阻塞

确保主线程无耗时操作,否则即使使用高精度定时器,回调的执行也会被延迟。若有UI相关的耗时任务,建议放在单独线程中处理。


内容的提问来源于stack exchange,提问作者user21138890

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.02 19:44:59