C# 如何根据频率产生声音?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/14042630/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-10 10:30:22  来源:igfitidea点击:

How to generate sounds according to frequency?

c#.netaudio

提问by ispiro

Possible Duplicate:
Creating sine or square wave in C#

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

I want to generate sounds. Either something like:

我想产生声音。要么像:

MakeSound(frequency, duration);

Or:

或者:

MakeSound(MyArrayOfSamples);

I've found something called: Microsoft.Directx.DirectSoundbut have read that it has been discontinued. And I couldn't find it as an option for a reference in Visual Studio (2010). I've found this linkwhich according to what I've read, is supposed to include it, but am hesitant to use something from 2006 since it might not be supported anymore. And this onesays it's for C/C++ (despite also saying: "managed code") and I don't want to waste weeks trying to understand how to wrap that into managed code, just to find out I can't do it. The most promising link I've found is WaveFormatbut I couldn't find how to use it.

我找到了一个叫做:Microsoft.Directx.DirectSound但读过它已经停产的东西。我找不到它作为 Visual Studio (2010) 中的参考选项。我找到了这个链接,根据我读过的内容,它应该包含它,但我对使用 2006 年的东西犹豫不决,因为它可能不再受支持。而这一次说,这是C / C ++(尽管也说:“托管代码”),我不想浪费几周试图了解如何来包装成托管代码,只是为了找出我不能这样做。我发现的最有前途的链接是WaveFormat,但我找不到如何使用它。

I'm notasking how to get the mathematical representation for the sound wave. Nor am I asking how to play an mp3 file or the like. Nor am I looking for third party software or wrappers. Just for a C# / .net solution for a very specific objective.

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

回答by Mike Perrenoud

Either way you look at it, unless you want to used unmanaged code, you're going to have to build a WAV to play it. However, below is a code snippet from Eric Lippert's blogthat will show you how to roll your own WAV file using frequencies.

不管你怎么看,除非你想使用非托管代码,否则你将不得不构建一个 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();
      }
   }
}

Break it apart for your needs, but notice the aNaturalvariable - it's a frequency - just like what you're looking for.

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

Now, you can place that into a MemoryStreamand then play it with SoundPlayerif you like.

现在,您可以将其放入 a 中MemoryStream,然后根据需要进行播放SoundPlayer

回答by rene

Here is a wrapper around the Beepfunction in the kernel, taking a duration and a frequency. Nowadays Beepuses the soundcard; in my days it used some piezo device glued on the motherboard.

这是内核中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.");
    }
}

On my Win10 box I need to set the duration (last parameter) much larger then the 5 ms here, more up to 50 ms but to get something reasonable I have to make it 100 ms.

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

Or use the Console.Beep(Int32, Int32)method if you want to take the easy route. That method was introduced in .Net 2.0.

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