连续调用Console.Beep()之间的延迟

时间:2019-08-25 23:43:45

标签: c# .net

我正在尝试制作一个简单的程序,该程序生成的音调可能会因输入值而异。我想起诉Console.Beep()函数,因为它似乎是最简单的解决方案,但却遇到了问题。我注意到,当我连续调用Console.beep()函数时,就像这样:

System.Console.Beep(440, 500);
System.Console.Beep(460, 500);
System.Console.Beep(480, 500);

从当前音调停止到下一个音调开始之间存在很小的延迟(大约100-200毫秒左右)。我想知道是否有任何方法可以减少此延迟,以便每当频率更新时音调都不会立即暂停?

1 个答案:

答案 0 :(得分:6)

当试图了解.NET为什么会以不期望的方式运行时,在GitHub上查看.NET Core的源代码通常会很有帮助。看着the source code for Console.Beep

    public static void Beep(int frequency, int duration)
    {
        ConsolePal.Beep(frequency, duration);
    }

ConsolePal有两种实现:一种用于Windows,另一种用于类似Unix的系统。假设您使用的是Windows,我们来看看the Beep implementation in ConsolePal.Windows.cs

    public static void Beep(int frequency, int duration)
    {
        const int MinBeepFrequency = 37;
        const int MaxBeepFrequency = 32767;

        if (frequency < MinBeepFrequency || frequency > MaxBeepFrequency)
            throw new ArgumentOutOfRangeException(nameof(frequency), frequency, SR.Format(SR.ArgumentOutOfRange_BeepFrequency, MinBeepFrequency, MaxBeepFrequency));
        if (duration <= 0)
            throw new ArgumentOutOfRangeException(nameof(duration), duration, SR.ArgumentOutOfRange_NeedPosNum);

        Interop.Kernel32.Beep(frequency, duration);
    }

这里的关键是呼叫Interop.Kernel32.Beep。这是我们即将调用本机Windows API的有力指标,但让我们验证一下。 Interop.Kernel32split over a bunch of files-通常这可能给我们带来一些困难,但碰巧的是,列表中的第一个是Interop.Beep.cs-方便!

打开文件,我们对本地调用are confirmed的怀疑:

    [DllImport(Libraries.Kernel32, SetLastError = true)]
    internal static extern bool Beep(int frequency, int duration);

这是使用一种称为“平台调用”的技术,通常缩写为P / Invoke。有一个很棒的网站pinvoke.net,其中提供了常见的P / Invoke代码片段以及一些随附的实现。让我们看看what pinvoke.net has to say about Beep in kernel32.dll

  

与MessageBeep不同,此功能是同步的。 (直到声音结束,它才将控制权返回给呼叫者。)

由于您的代码或Console.Beep中没有其他内容会导致延迟,因此这意味着Windows API可能是罪魁祸首。幸运的是,pinvoke.net提供了一种可能可行的解决方法。为了确保这一点,我们来看看MSDN's documentation on Windows' Beep,pinvoke.net可以方便地链接到该链接。它带有Beep上一些非常有趣的历史记录,并提供了切换到MessageBeep的建议。

不幸的是,the MSDN documentation for MessageBeep令人失望:我们不能用它来产生任意音调。

这使我们得出最终结论:kernel32的Beep并不是真的要产生奇特的声音。它既依赖于硬件,又依赖于平台,如果您想在各种设备上生成一致的声音,那么这两者都不是理想的选择。从本质上讲,它是过去的遗物。它甚至在Windows XP中被删除,尽管后来又随Windows 7一起添加了。这意味着.NET的Console.Beep(int, int)存在所有相同的问题,因为它只是kernel32的Beep的包装。

一个更强大的解决方案是研究各种音频框架,但是这些框架可能会复杂得多。现在,如果您只是从C#开始并想使事情保持简单,那么您可能会遇到诸如观察到的延迟之类的不一致性。

相关问题