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

Jas*_*n O 1 .net c#

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

System.Console.Beep(440, 500);
System.Console.Beep(460, 500);
System.Console.Beep(480, 500);
Run Code Online (Sandbox Code Playgroud)

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

Zen*_*xer 6

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

    public static void Beep(int frequency, int duration)
    {
        ConsolePal.Beep(frequency, duration);
    }
Run Code Online (Sandbox Code Playgroud)

有两种实现ConsolePal:一种用于Windows,另一种用于类似Unix的系统。假设您使用的是Windows,我们来看看中Beep实现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);
    }
Run Code Online (Sandbox Code Playgroud)

这里的关键是呼叫Interop.Kernel32.Beep。这是我们即将调用本机Windows API的有力指标,但让我们验证一下。 Interop.Kernel32劈了过来一堆文件 --normally这可能会造成一些困难,对我们来说,但它只是恰巧,在列表中的第一个是Interop.Beep.cs--convenient!

打开文件,证实了我们对本地调用的怀疑:

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

这是使用一种称为Platform Invoke的技术,通常缩写为P / Invoke。有一个很棒的网站pinvoke.net,其中提供了常见的P / Invoke代码片段以及一些随附的实现。让我们来看看pinvoke.net在kernel32.dll中对Beep怎么说

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

由于您的代码中没有别的东西,否则Console.Beep会导致延迟,这意味着Windows API可能是罪魁祸首。幸运的是,pinvoke.net提供了一种可能可行的解决方法。为了确保这一点,让我们查看一下Windows上的MSDN文档Beep,pinvoke.net可以方便地链接到该文档。它附带了一些令人着迷的历史Beep,并推荐改用MessageBeep

不幸的是,有关MSDN的文档MessageBeep令人失望:我们不能使用它来产生任意音调。

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

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