【问题标题】:Best practice to async play separate MIDI messages?异步播放单独 MIDI 消息的最佳实践?
【发布时间】:2020-05-28 09:56:17
【问题描述】:

我已将 MIDI 文件解析为一组音符(键、速度、时间,还有 MIDI 文件的速度及其变化事件)。我需要在 GUI (LCL) 应用程序中异步播放它们(我不能使用 MCISendString,因为我需要处理这些消息)。问题是,在 MIDI 中通常有数千个音符。您认为播放它们的最佳方式是什么?

我有一些想法,但它们速度慢且不切实际:

  • 使用等待(SleepDelay)指定时间量并播放音符的函数一次调用一堆BeginThreads(线程有限制,它真的很不稳定)。
  • 对时间戳进行排序,然后通过单个线程运行它们,该线程将休眠/延迟currentNoteTime-previousNoteTime 并播放音符。可能会很慢,尤其是在尝试对所有内容进行排序时。
  • 编写另一个应用程序作为后台进程并完成工作(不专业的 bodging)。

我正在使用 Lazarus (Object Pascal),但如果需要,我也可以使用 Delphi 代码。感谢您的宝贵时间。

【问题讨论】:

    标签: delphi pascal midi lazarus


    【解决方案1】:

    所有线程方法(睡眠、延迟等)在 Windows 上都将失败,因为您无法获得优于 16 毫秒(在最佳情况下)的精度,这将导致您的数据播放不正确,并且延迟很大。已知问题,可以在网上搜索。

    我是DryWetMIDI C# 库的作者,该库具有播放功能。我的做法是:

    1. 按时间排序所有事件并将指针设置为 MIDI 数据的开始
    2. 使用Windows Multimedia Timers API 运行高精度计时器,每 1 毫秒计时一次
    3. 在每个滴答声中查看当前时间应播放哪些事件并将这些事件发送到输出设备
    4. 根据播放的事件向前移动指针

    但请注意,此方法仅适用于 Windows。对于其他系统,您需要使用特定于操作系统的 API 来运行高精度计时器。

    【讨论】:

    • 非常感谢。我会检查一下并尝试您的方法。顺便说一句,过去将您的图书馆用于一些个人项目。好东西!
    • 谢谢 :) 您可以从 DWM 播放的OnClockTicked 方法开始您的调查:github.com/melanchall/drywetmidi/blob/develop/DryWetMidi/…
    • 工作就像一个魅力,即使在后台发生半重性能负载的事情。现在剩下的就是对东西进行分类,我认为这很容易。非常感谢。
    • @Maxim 有几个可用于 Delphi 的高精度计时器组件。有些甚至允许在执行期间更改延迟间隔,因此您无需检查是否存在某些事件调度胖当前计时器间隔,您可以简单地跳转到下一个事件。这种计时器经常用于游戏开发,尤其是在处理物理模拟等时。
    • @SilverWarior 你能说出这些组件的名字吗?他们是否像 WinMM 那样使用HPET 硬件计时器?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2010-10-09
    • 1970-01-01
    • 1970-01-01
    • 2010-10-12
    • 2011-08-12
    • 2013-02-02
    • 1970-01-01
    相关资源
    最近更新 更多