MIDI 音序器以微秒分辨率触发事件
有没有办法在 C# 中以几微秒的分辨率触发事件?
我正在构建一个 MIDI 音序器,它需要每个 MIDI 滴答声触发一个事件,然后播放当时注册的任何音符。
在每分钟 120 次节拍和 120 ppqn(每节拍/四分音符脉冲)的分辨率下,该事件应每 4.16666 毫秒触发一次。现代定序器具有更高的分辨率,例如 768ppqn,这要求每 651 微秒触发该事件。
我发现短时事件的最佳分辨率是 1 毫秒。我怎样才能超越这个范围?
这个问题肯定已经被任何 C# MIDI 音序器或 MIDI 文件播放器解决了。 也许我只是没有从正确的角度看待问题。
感谢您的帮助。
Is there a way to fire events in C# at a resolution of a few microseconds?
I am building a MIDI sequencer, and it requires an event to be fired every MIDI tick, which will then play any note registered at that time.
At 120 beats per minute and at a resolution of 120 ppqn (pulses per beat/quarter note), that event should fire every 4.16666 milliseconds. Modern sequencers have higher resolutions such as 768ppqn which would require that event to be fired every 651 microseconds.
The best resolution for short-timed events I have found is of 1 millisecond. How can I go beyond that?
This problem must have already been solved by any C# MIDI sequencer or MIDI file player.
Maybe am I just not looking at the problem through the right angle.
Thank you for your help.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
大多数 MIDI 音序器/MIDI 播放器要么将大块时间转换为波形(用于通过计算机扬声器播放),要么采用大块 MIDI 指令(用于连接到 MIDI 端口的外部设备)。无论哪种方式,数据块都会被复制到声卡,并且声卡会负责精确的计时。
您可能想查看多媒体控制 API。
请参阅 Microsoft 论坛上的此帖子
Most midi sequencers/midi players will either convert large blocks of time to waveform (for playing through computer speakers) or take a large block of MIDI instructions (for an external device attached to a MIDI port). Either way, a block of data is copied to the sound card, and the sound card takes care of exact timing.
You might want to look at the Multimedia Control APIs.
See this post over at the Microsoft discussion forum
我认为你不太可能从计时器中获得完全正确的分辨率。更好的方法是使用 1 毫秒精确的计时器,当它触发时,检查哪些 MIDI 事件正在等待并触发它们。
因此,MIDI 事件进入排序队列,您查看第一个事件,并将计时器设置为尽可能接近该时间。当计时器触发时,消耗队列中已过去的所有事件,直到遇到未来的事件。计算该事件的时间。重新安排计时器。
当然,如果您要输出到声卡,则方法根本不同,您应该计算所有计时的样本。
I think you are unlikely to get exactly the correct resolution from a timer. A better approach would be to use the 1ms accurate timer, and when it fires, to check which MIDI events are pending and to fire them.
So, the MIDI events go in a sorted queue, you peek the first one, and set the timer to fire as close as possible to that time. When the timer fires, consume all events from the queue that have elapsed, until you encounter a future event. Calculate time to this event. Reschedule timer.
Of course, if you are outputting to your soundcard, the approach is fundamentally different, and you should be counting samples for all your timings.
在 .NET 中不可能以微秒间隔准确触发事件。
事实上,由于 Windows 本身不是实时操作系统,因此在用户模式软件中以 100% 精确度执行某些微秒的操作几乎是不可能的。
有关为什么这如此困难的更多信息,请参阅 MSDN 杂志文章:实施连续正在更新适用于 Windows 的高分辨率时间提供程序。虽然它谈论的是 Windows NT,但这通常仍然适用于更高版本的 Windows。
这篇文章的结论总结得很好:
It is not possible to have events accurately fired on microsecond intervals in .NET.
In fact because Windows itself is not a real time OS, performing anything with 100% accuracy to certain microseconds, in user mode software, is pretty much impossible.
For more information on why this is so difficult see the MSDN magazine article: Implement a Continuously Updating, High-Resolution Time Provider for Windows. While it talks about Windows NT, this still generally applies to later versions of Windows.
The conclusion of this article sums it up well:
而不是使用计时器,
请使用秒表
示例,10x 1 秒
将输出:
看起来还不错
instead of using timer
use stopwatch
example, for 10x 1 second
will output:
which seem kind of ok