delphi - 异步播放单独 MIDI 消息的最佳实践?
问题描述
我已经将一个 MIDI 文件解析为一组音符(键、速度、时间,还有 MIDI 文件的速度及其变化事件)。我需要异步播放它们的 GUI (LCL) 应用程序(我不能使用MCISendString
,因为我需要处理这些消息)。问题是,在 MIDI 中通常有数千个音符。您认为播放它们的最佳方式是什么?
我有一些想法,但它们缓慢且不切实际:
- 使用等待(或)指定时间量并播放音符
BeginThread
的函数一次调用一堆s (线程有限制,它真的很不稳定)。Sleep
Delay
- 对时间戳进行排序,然后通过单个线程运行它们,该线程将睡眠/延迟
currentNoteTime-previousNoteTime
并播放音符。可能会很慢,尤其是在尝试对所有内容进行排序时。 - 编写另一个应用程序作为后台进程并完成工作(不专业的 boding)。
我正在使用 Lazarus (Object Pascal),但如果需要,我也可以使用 Delphi 代码。感谢您的时间。
解决方案
所有线程方法(睡眠、延迟等)在 Windows 上都将失败,因为您的精度不会超过 16 毫秒(在最佳情况下),这将导致您的数据播放不正确,延迟很大。已知问题,可以在网上搜索。
我是具有播放功能的DryWetMIDI C# 库的作者。我的做法是:
- 按时间排序所有事件并将指针设置为 MIDI 数据的开始
- 使用Windows Multimedia Timers API运行高精度计时器,每 1 毫秒计时一次
- 在每个刻度上查看当前时间应该播放哪些事件并将这些事件发送到输出设备
- 通过播放的事件向前移动指针
但请注意,这种方法仅适用于 Windows。对于其他系统,您需要使用特定于操作系统的 API 来运行高精度计时器。
推荐阅读
- numpy - 如何在模型构建期间将 kerastensor 转换为 numpy 数组,反之亦然
- arrays - 如何仅快速删除数组的 5 个特定项目中的 3 个
- apache - Web 服务器“内容类型”未在 Apache 上正确配置
- node.js - NodeJS如何在不同的文件中使用connect obj
- gradle - Unity Gradle Build Fail: processReleaseManifest 由于属性冲突
- google-cloud-platform - Redis 是否可以从其 RDB 备份过程中使用多个内核中受益?
- flutter - 在 Flutter 上,我想从硬盘驱动器获取图像并随机显示
- pandas-groupby - 用groupby中的2个变量计算滚动总和
- rust - 如何在函数中调用 FLTK 代码?
- json - 如何将虚拟数据添加到嵌套的 JSON 结构