[英]Creating sine or square wave in C#
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?我希望这样做是为了校准设备,那么这些波的精确度如何?
You can use NAudio and create a derived WaveStream that outputs sine or square waves which you could output to the soundcard or write to a WAV file.您可以使用NAudio并创建一个派生的 WaveStream 来输出正弦波或方波,您可以将其输出到声卡或写入WAV文件。 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.
如果您使用 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));
}
This lets you give frequency, duration, and amplitude, and it is 100% .NET CLR code.这让你可以给出频率、持续时间和幅度,它是 100% .NET CLR 代码。 No external DLL's.
没有外部DLL。 It works by creating a WAV-formatted
MemoryStream
which is like creating a file in memory only, without storing it to disk.它通过创建一个 WAV 格式的
MemoryStream
,就像只在内存中创建一个文件,而不将它存储到磁盘。 Then it plays that MemoryStream
with System.Media.SoundPlayer
.然后它使用
System.Media.SoundPlayer
播放MemoryStream
。
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)
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);
}
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π.
这等效于将缩放三角正弦函数应用于幅度为 2π 的周期性锯齿波。
s(x)=A⋅sin(2πνx+θ)
s(x)=A⋅sin(2πνx+θ)
Generate.Sinusoidal(length,samplingRate,frequency,amplitude,mean,phase,delay)
Generate.Sinusoidal(length,samplingRate,frequency,amplitude,mean,phase,delay)
eg例如
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.不能谈精度。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.