在 C# 中创建正弦波或方波

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/203890/
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-03 17:54:47  来源:igfitidea点击:

Creating sine or square wave in C#

c#audiosignal-processing

提问by johnc

How do I generate an audio sine or square wave of a given frequency?

如何生成给定频率的音频正弦波或方波?

I am hoping to do this to calibrate equipment, so how precise would these waves be?

我希望这样做是为了校准设备,那么这些波的精确度如何?

采纳答案by Mark Heath

You can use NAudioand create a derived WaveStream that outputs sine or square waves which you could output to the soundcard or write to a WAVfile. If you used 32-bit floating point samples you could write the values directly out of the sin function without having to scale as it already goes between -1 and 1.

您可以使用NAudio并创建一个派生的 WaveStream 来输出正弦波或方波,您可以将其输出到声卡或写入WAV文件。如果您使用 32 位浮点样本,您可以直接从 sin 函数中写入值,而无需缩放,因为它已经在 -1 和 1 之间。

As for accuracy, do you mean exactly the right frequency, or exactly the right wave shape? There is no such thing as a true square wave, and even the sine wave will likely have a few very quiet artifacts at other frequencies. If it's accuracy of frequency that matters, you are reliant on the stability and accuracy of the clock in your sound card. Having said that, I would imagine that the accuracy would be good enough for most uses.

至于准确性,您是指准确的频率,还是完全正确的波形?没有真正的方波这样的东西,即使是正弦波,在其他频率下也可能会有一些非常安静的伪影。如果重要的是频率的准确性,则您依赖于声卡中时钟的稳定性和准确性。话虽如此,我认为准确性对于大多数用途来说已经足够了。

Here's some example code that makes a 1 kHz sample at a 8 kHz sample rate and with 16 bit samples (that is, not floating point):

下面是一些示例代码,它以 8 kHz 采样率和 16 位采样(即非浮点)生成 1 kHz 采样:

int sampleRate = 8000;
short[] buffer = new short[8000];
double amplitude = 0.25 * short.MaxValue;
double frequency = 1000;
for (int n = 0; n < buffer.Length; n++)
{
    buffer[n] = (short)(amplitude * Math.Sin((2 * Math.PI * n * frequency) / sampleRate));
}

回答by Edward

This lets you give frequency, duration, and amplitude, and it is 100% .NET CLR code. No external DLL's. It works by creating a WAV-formatted MemoryStreamwhich is like creating a file in memory only, without storing it to disk. Then it plays that MemoryStreamwith System.Media.SoundPlayer.

这让你可以给出频率、持续时间和幅度,它是 100% .NET CLR 代码。没有外部DLL。它的工作原理是创建一个 WAV 格式MemoryStream,就像只在内存中创建一个文件,而不将它存储到磁盘。然后它MemoryStreamSystem.Media.SoundPlayer.

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Windows.Forms;

public static void PlayBeep(UInt16 frequency, int msDuration, UInt16 volume = 16383)
{
    var mStrm = new MemoryStream();
    BinaryWriter writer = new BinaryWriter(mStrm);

    const double TAU = 2 * Math.PI;
    int formatChunkSize = 16;
    int headerSize = 8;
    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 samples = (int)((decimal)samplesPerSecond * msDuration / 1000);
    int dataChunkSize = samples * frameSize;
    int fileSize = waveSize + headerSize + formatChunkSize + headerSize + dataChunkSize;
    // var encoding = new System.Text.UTF8Encoding();
    writer.Write(0x46464952); // = encoding.GetBytes("RIFF")
    writer.Write(fileSize);
    writer.Write(0x45564157); // = encoding.GetBytes("WAVE")
    writer.Write(0x20746D66); // = encoding.GetBytes("fmt ")
    writer.Write(formatChunkSize);
    writer.Write(formatType);
    writer.Write(tracks);
    writer.Write(samplesPerSecond);
    writer.Write(bytesPerSecond);
    writer.Write(frameSize);
    writer.Write(bitsPerSample);
    writer.Write(0x61746164); // = encoding.GetBytes("data")
    writer.Write(dataChunkSize);
    {
        double theta = frequency * TAU / (double)samplesPerSecond;
        // 'volume' is UInt16 with range 0 thru Uint16.MaxValue ( = 65 535)
        // we need 'amp' to have the range of 0 thru Int16.MaxValue ( = 32 767)
        double amp = volume >> 2; // so we simply set amp = volume / 2
        for (int step = 0; step < samples; step++)
        {
            short s = (short)(amp * Math.Sin(theta * (double)step));
            writer.Write(s);
        }
    }

    mStrm.Seek(0, SeekOrigin.Begin);
    new System.Media.SoundPlayer(mStrm).Play();
    writer.Close();
    mStrm.Close();
} // public static void PlayBeep(UInt16 frequency, int msDuration, UInt16 volume = 16383)

回答by Aleks

Try from Creating sine and save to wave file in C#

尝试在 C# 中创建正弦并保存到波形文件

private void TestSine()
{
    IntPtr format;
    byte[] data;
    GetSineWave(1000, 100, 44100, -1, out format, out data);
    WaveWriter ww = new WaveWriter(File.Create(@"d:\work\sine.wav"),
        AudioCompressionManager.FormatBytes(format));
    ww.WriteData(data);
    ww.Close();
}

private void GetSineWave(double freq, int durationMs, int sampleRate, short decibel, out IntPtr format, out byte[] data)
{
    short max = dB2Short(decibel);//short.MaxValue
    double fs = sampleRate; // sample freq
    int len = sampleRate * durationMs / 1000;
    short[] data16Bit = new short[len];
    for (int i = 0; i < len; i++)
    {
        double t = (double)i / fs; // current time
        data16Bit[i] = (short)(Math.Sin(2 * Math.PI * t * freq) * max);
    }
    IntPtr format1 = AudioCompressionManager.GetPcmFormat(1, 16, (int)fs);
    byte[] data1 = new byte[data16Bit.Length * 2];
    Buffer.BlockCopy(data16Bit, 0, data1, 0, data1.Length);
    format = format1;
    data = data1;
}

private static short dB2Short(double dB)
{
    double times = Math.Pow(10, dB / 10);
    return (short)(short.MaxValue * times);
}

回答by Declan Taylor

Using Math.NET Numerics

使用Math.NET 数字

https://numerics.mathdotnet.com/Generate.html

https://numerics.mathdotnet.com/Generate.html

Sinusoidal

Generates a Sine wave array of the given length. This is equivalent to applying a scaled trigonometric Sine function to a periodic sawtooth of amplitude 2π.

s(x)=A?sin(2πνx+θ)

Generate.Sinusoidal(length,samplingRate,frequency,amplitude,mean,phase,delay)

正弦

生成给定长度的正弦波阵列。这等效于将缩放三角正弦函数应用于幅度为 2π 的周期性锯齿波。

s(x)=A?sin(2πνx+θ)

Generate.Sinusoidal(length,samplingRate,frequency,amplitude,mean,phase,delay)

e.g

例如

 Generate.Sinusoidal(15, 1000.0, 100.0, 10.0);

returns array { 0, 5.9, 9.5, 9.5, 5.9, 0, -5.9, ... }

返回数组 { 0, 5.9, 9.5, 9.5, 5.9, 0, -5.9, ... }

and there's also

还有

Generate.Square(...

which will

这将

create a periodic square wave...

创建一个周期性方波...

can't speak about precision.

不能谈精度。