【问题标题】:How to generate sounds according to frequency? [duplicate]如何根据频率产生声音? [复制]
【发布时间】:2012-12-12 03:10:21
【问题描述】:

可能重复:
Creating sine or square wave in C#

我想产生声音。要么是这样的:

MakeSound(frequency, duration);

或者:

MakeSound(MyArrayOfSamples);

我找到了一个名为:Microsoft.Directx.DirectSound 的东西,但读到它已停产。而且我在 Visual Studio (2010) 中找不到它作为参考的选项。我找到了this link,根据我读过的内容,它应该包含它,但我对使用 2006 年的东西犹豫不决,因为它可能不再受支持。 this one 说它适用于 C/C++(尽管也说:“托管代码”),我不想浪费数周时间试图了解如何将其包装到托管代码中,只是为了发现我做不到.我找到的最有希望的链接是WaveFormat,但我找不到如何使用它。

不是询问如何获得声波的数学表示。我也不是在问如何播放 mp3 文件等。我也不是在寻找第三方软件或包装器。仅针对特定目标的 C# / .net 解决方案。

【问题讨论】:

  • 您不是在尝试以指定的频率和持续时间播放音调吗?
  • @ispiro:不过,我认为这可能就是这样做的方式;使用 NAudio 制作 WAV,然后播放。
  • 太棒了。即使在拼写出我要寻找的内容之后 - 我仍然会为与该问题重复的问题获得密切的投票!
  • @JüriRuut 来自我的问题:我也不是在问如何播放 mp3 文件等。

标签: c# .net audio


【解决方案1】:

无论你怎么看,除非你想使用非托管代码,否则你将不得不构建一个 WAV 来播放它。但是,下面是来自Eric Lippert's blog 的代码 sn-p,它将向您展示如何使用频率滚动您自己的 WAV 文件。

namespace Wave
{
   using System;
   using System.IO;
   class MainClass {
      public static void Main() {
         FileStream stream = new FileStream("test.wav", FileMode.Create);
         BinaryWriter writer = new BinaryWriter(stream);
         int RIFF = 0x46464952;
         int WAVE = 0x45564157;
         int formatChunkSize = 16;
         int headerSize = 8;
         int format = 0x20746D66;
         short formatType = 1;
         short tracks = 1;
         int samplesPerSecond = 44100;
         short bitsPerSample = 16;
         short frameSize = (short)(tracks * ((bitsPerSample + 7)/8));
         int bytesPerSecond = samplesPerSecond * frameSize;
         int waveSize = 4;
         int data = 0x61746164;
         int samples = 88200 * 4;
         int dataChunkSize = samples * frameSize;
         int fileSize = waveSize + headerSize + formatChunkSize + headerSize + dataChunkSize;
         writer.Write(RIFF);
         writer.Write(fileSize);
         writer.Write(WAVE);
         writer.Write(format);
         writer.Write(formatChunkSize);
         writer.Write(formatType);
         writer.Write(tracks); 
         writer.Write(samplesPerSecond);
         writer.Write(bytesPerSecond);
         writer.Write(frameSize);
         writer.Write(bitsPerSample); 
         writer.Write(data);
         writer.Write(dataChunkSize);
         double aNatural = 220.0;
         double ampl = 10000;
         double perfect = 1.5;
         double concert = 1.498307077;
         double freq = aNatural * perfect;
         for (int i = 0; i < samples / 4; i++) {
            double t = (double)i / (double)samplesPerSecond;
            short s = (short)(ampl * (Math.Sin(t * freq * 2.0 * Math.PI)));
            writer.Write(s);
         }
         freq = aNatural * concert;
         for (int i = 0; i < samples / 4; i++) {
            double t = (double)i / (double)samplesPerSecond;
            short s = (short)(ampl * (Math.Sin(t * freq * 2.0 * Math.PI)));
            writer.Write(s);
         }
         for (int i = 0; i < samples / 4; i++) {
            double t = (double)i / (double)samplesPerSecond;
            short s = (short)(ampl * (Math.Sin(t * freq * 2.0 * Math.PI) + Math.Sin(t * freq * perfect * 2.0 * Math.PI)));
            writer.Write(s);
         }
         for (int i = 0; i < samples / 4; i++) {
            double t = (double)i / (double)samplesPerSecond;
            short s = (short)(ampl * (Math.Sin(t * freq * 2.0 * Math.PI) + Math.Sin(t * freq * concert * 2.0 * Math.PI)));
            writer.Write(s);
         }
         writer.Close();
         stream.Close();
      }
   }
}

根据您的需要将其分开,但请注意 aNatural 变量 - 它是一个频率 - 就像您正在寻找的一样。

现在,您可以将其放入MemoryStream,然后根据需要与SoundPlayer 一起播放。

【讨论】:

  • “不管你怎么看,除非你想使用非托管代码,否则你将不得不构建一个 WAV 来播放它” - 不一定。似乎DirectSound 应该做我正在寻找的东西。但正如我所写 - 我很犹豫是否使用它,除非有人能告诉我如何让它运行(并且:如果它会运行!)。
  • @ispiro,我提供的代码是raw .NET 解决方案,它完全符合您的要求。 此外,DirectSound使用非托管代码与声卡和任何其他较低级别的设备通信.我想说的是,使用上述代码滚动一个简单的 WAV 文件将产生您想要的结果,没有开销,也没有您需要担心的依赖关系。
【解决方案2】:

这里是内核中Beep 函数的封装,包含持续时间和频率。现在Beep使用声卡;在我的日子里,它使用了一些粘在主板上的压电设备。

using System;
using System.Runtime.InteropServices;

class BeepSample
{
    [DllImport("kernel32.dll", SetLastError=true)]
    static extern bool Beep(uint dwFreq, uint dwDuration);

    static void Main()
    {
        Console.WriteLine("Testing PC speaker...");
        for (uint i = 100; i <= 20000; i++)
        {
            Beep(i, 5);
        }
        Console.WriteLine("Testing complete.");
    }
}

在我的 Win10 机器上,我需要将持续时间(最后一个参数)设置为比此处的 5 毫秒大得多,最多可达 50 毫秒,但为了得到合理的值,我必须将其设置为 100 毫秒。

如果您想采取简单的方法,或者使用Console.Beep(Int32, Int32) 方法。该方法是在 .Net 2.0 中引入的。

【讨论】:

  • 哔声在 x64 系统上不起作用。
  • @KvanTTT 你能用证据支持这个说法吗? Msdn 说它是从 win xp x64 和 vista 一起删除的(x86 和 x64),但在 Windows 7 中使用默认声卡完全重新实现。我粗略地引用了该功能的实现者Larry Osterman
  • 不,哔声在我的 Win 7 x64 和 Win 8 x64 上不起作用。 Here 是解释,here 是关于 SO 的问题。
  • 有趣的是,我们都引用同一个博客来证明这一点:-)
  • 我刚刚在我的 win7 x64 上验证了它,这确实像宣传的那样工作。我想我必须支持拉里·奥斯特曼。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-08-29
  • 2021-05-13
  • 1970-01-01
  • 2023-03-10
  • 2011-06-10
  • 1970-01-01
  • 2011-09-17
相关资源
最近更新 更多