以midi音序器的微秒分辨率发射事件

时间:2010-08-04 00:40:39

标签: c# timer precision midi

有没有办法以几微秒的分辨率在C#中激活事件?

我正在构建一个MIDI音序器,它需要在每个MIDI音符时触发一个事件,然后播放当时注册的任何音符。

每分钟120次,分辨率为120 ppqn(每拍脉冲数/四分音符),该事件应每隔4.16666毫秒发射一次。现代音序器具有更高的分辨率,例如768ppqn,这将要求每651微秒触发一次事件。

我发现的短时间事件的最佳分辨率是1毫秒。我怎样才能超越它?

任何C#MIDI音序器或MIDI文件播放器都必须已经解决了这个问题。 也许我只是没有通过正确的角度来看问题。

感谢您的帮助。

4 个答案:

答案 0 :(得分:6)

大多数midi音序器/ midi播放器要么将大块时间转换为波形(用于通过计算机扬声器播放),要么采用大块MIDI指令(用于连接到MIDI端口的外部设备)。无论哪种方式,都会将一块数据复制到声卡中,并且声卡会处理准确的时间。

您可能希望查看多媒体控制API。

请参阅this post over at the Microsoft discussion forum

答案 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)

而不是使用计时器

使用stopwatch

例如,为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

看起来很好