有没有办法以几微秒的分辨率在C#中激活事件?
我正在构建一个MIDI音序器,它需要在每个MIDI音符时触发一个事件,然后播放当时注册的任何音符。
每分钟120次,分辨率为120 ppqn(每拍脉冲数/四分音符),该事件应每隔4.16666毫秒发射一次。现代音序器具有更高的分辨率,例如768ppqn,这将要求每651微秒触发一次事件。
我发现的短时间事件的最佳分辨率是1毫秒。我怎样才能超越它?
任何C#MIDI音序器或MIDI文件播放器都必须已经解决了这个问题。 也许我只是没有通过正确的角度来看问题。
感谢您的帮助。
答案 0 :(得分:6)
大多数midi音序器/ midi播放器要么将大块时间转换为波形(用于通过计算机扬声器播放),要么采用大块MIDI指令(用于连接到MIDI端口的外部设备)。无论哪种方式,都会将一块数据复制到声卡中,并且声卡会处理准确的时间。
您可能希望查看多媒体控制API。
答案 1 :(得分:3)
我认为你不可能从计时器中获得完全正确的分辨率。更好的方法是使用1ms准确的计时器,当它触发时,检查哪些MIDI事件待处理并触发它们。
因此,MIDI事件进入排序队列,您查看第一个,并将计时器设置为尽可能接近该时间。当计时器触发时,消耗已经过去的队列中的所有事件,直到遇到未来事件。计算此事件的时间。重新安排计时器。
当然,如果您输出到声卡,方法根本不同,您应该计算所有时间的样本。
答案 2 :(得分:1)
在.NET中,无法在微秒间隔内准确触发事件。
事实上,由于Windows本身不是实时操作系统,因此在用户模式软件中以100%的精度执行任何操作几乎都是不可能的。
有关为何如此困难的详细信息,请参阅MSDN杂志文章:Implement a Continuously Updating, High-Resolution Time Provider for Windows。虽然它谈到了Windows NT,但这仍然普遍适用于Windows的更高版本。
本文的结论总结得很好:
如果你现在认为你可以获得 系统时间差不多了 这里任意精度,只是一个 轻微警告:别忘了 多任务处理的先发制人 系统如Windows NT。在最好的 案例,你得到的时间戳是关闭的 只需要阅读时间 性能计数器并改变这一点 读到一个绝对的时间。在里面 最糟糕的情况,时间过去了 很容易就是几十个 毫秒。
虽然这可能 表明你经历了这一切 什么都不做,请放心 没有。甚至执行调用 Win32 API GetSystemTimeAsFileTime(或 untime下的gettimeofday受制于 相同的条件,所以你是 实际上并没有比这更糟糕。在 大多数情况下,你会有 效果很好。只是不要表演 任何需要实时的东西 基于时间的可预测性 Windows NT中的邮票。
答案 3 :(得分:0)
而不是使用计时器
例如,为10x 1秒
static void Main(string[] args)
{
Stopwatch masterSW;
Stopwatch sw=null;
int count;
sw = Stopwatch.StartNew();
sw.Reset();
for (int i = 0; i < 10; i++)
{
count = 0;
masterSW = Stopwatch.StartNew();
while (count!=1536) //1537*651 microsecond is about a second (1.0005870 second)
{
if (!sw.IsRunning)
sw.Start();
if (sw.Elapsed.Ticks >= 6510)
{
count++;
sw.Reset();
}
}
Debug.WriteLine("Ticks: " + masterSW.Elapsed.Ticks.ToString());
}
}
将输出:
Ticks:10005392(即1.0005392秒)
蜱虫:10004792
蜱虫:10004376
蜱虫:10005408
蜱虫:10004398
蜱虫:10004426
蜱虫:10004268
蜱虫:10004427
蜱虫:10005161
蜱虫:10004306
看起来很好