如何根据频率产生声音

本文关键字:声音 频率 何根 | 更新日期: 2023-09-27 17:49:30

可能重复:
在C#中创建正弦波或方波

我想发出声音。或者类似于:

MakeSound(frequency, duration);

或者:

MakeSound(MyArrayOfSamples);

我发现了一种名为:Microsoft.Directx.DirectSound的东西,但读到它已经停产了。我在Visual Studio(2010(中找不到它作为参考选项。我发现了这个链接,根据我读到的内容,它应该包括它,但我很犹豫是否使用2006年的东西,因为它可能不再得到支持。这个说它是针对C/C++的(尽管也说:"托管代码"(,我不想浪费几个星期的时间试图了解如何将其封装到托管代码中,只是发现我做不到。我发现最有希望的链接是WaveFormat,但我找不到如何使用它。

我不是在问如何得到声波的数学表示。我也没有问如何播放mp3文件之类的东西。我也没有在寻找第三方软件或包装。只是针对一个非常具体的目标的C#/.net解决方案。

如何根据频率产生声音

不管怎么看,除非你想使用非托管代码,否则你必须构建一个WAV才能播放它。然而,下面是Eric Lippert博客中的一段代码片段,它将向你展示如何使用频率滚动你自己的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进行播放

这是内核中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毫秒。

或者使用控制台。Beep(Int32,Int32(方法,如果你想走简单的路线。该方法是在中引入的。Net 2.0。