在没有外部库的情况下在C#中播放动态创建的简单声音

我需要能够使用C#动态生成波形并播放它,无需任何外部库,也无需将声音文件存储在硬盘上。 延迟不是问题; 声音将在应用程序需要之前生成。

实际上,如果不是因为微软表示在64位版本的Windows中不支持它,Console.Beep()方法可能会满足我的需求。

如果我动态地生成自己的声音,我可以得到一个比简单的嘟嘟声更精彩的声音。 例如,我可以从三角波制作波形,其频率从2 KHz增加到4 KHz,同时衰减音量。 我不需要花哨的16位立体声,只需8位单声道即可。 我不需要动态控制音量和音高,只需在内存中生成一个声音文件并播放它而不存储它。

许多年前,我需要在Apple II,惠普工作站和我的旧Amiga计算机上生成声音。 从那时起就不需要这样做,而且我所描述的简单似乎变得更加复杂。 我很难相信这么简单的东西看起来很难。 我看到的大多数答案都是指NAudio或类似的库,这不是这个项目的选项(除了拉动整个库只是为了播放音调这一事实似乎是浪费)。

基于我收到的答案中的一个链接,以及我发现的.wav标题格式的其他一些页面,这是我的工作代码,用于生成8位“ding!”的小类。 用户指定的频率和持续时间的声音。 它基本上是一个蜂鸣声,在指定的持续时间内在幅度上线性衰减到零。

public class AlertDing { private SoundPlayer player = null; private BinaryWriter writer = null; ///  /// Dynamically generate a "ding" sound and save it to a memory stream ///  /// Frequency in Hertz, eg 880 /// Duration in multiple of 1/10 second public AlertDing(double freq, uint tenthseconds) { string header_GroupID = "RIFF"; // RIFF uint header_FileLength = 0; // total file length minus 8, which is taken up by RIFF string header_RiffType = "WAVE"; // always WAVE string fmt_ChunkID = "fmt "; // Four bytes: "fmt " uint fmt_ChunkSize = 16; // Length of header in bytes ushort fmt_FormatTag = 1; // 1 for PCM ushort fmt_Channels = 1; // Number of channels, 2=stereo uint fmt_SamplesPerSec = 14000; // sample rate, eg CD=44100 ushort fmt_BitsPerSample = 8; // bits per sample ushort fmt_BlockAlign = (ushort)(fmt_Channels * (fmt_BitsPerSample / 8)); // sample frame size, in bytes uint fmt_AvgBytesPerSec = fmt_SamplesPerSec * fmt_BlockAlign; // for estimating RAM allocation string data_ChunkID = "data"; // "data" uint data_ChunkSize; // Length of header in bytes byte [] data_ByteArray; // Fill the data array with sample data // Number of samples = sample rate * channels * bytes per sample * duration in seconds uint numSamples = fmt_SamplesPerSec * fmt_Channels * tenthseconds / 10; data_ByteArray = new byte[numSamples]; //int amplitude = 32760, offset=0; // for 16-bit audio int amplitude = 127, offset = 128; // for 8-audio double period = (2.0*Math.PI*freq) / (fmt_SamplesPerSec * fmt_Channels); double amp; for (uint i = 0; i < numSamples - 1; i += fmt_Channels) { amp = amplitude * (double)(numSamples - i) / numSamples; // amplitude decay // Fill with a waveform on each channel with amplitude decay for (int channel = 0; channel < fmt_Channels; channel++) { data_ByteArray[i+channel] = Convert.ToByte(amp * Math.Sin(i*period) + offset); } } // Calculate file and data chunk size in bytes data_ChunkSize = (uint)(data_ByteArray.Length * (fmt_BitsPerSample / 8)); header_FileLength = 4 + (8 + fmt_ChunkSize) + (8 + data_ChunkSize); // write data to a MemoryStream with BinaryWriter MemoryStream audioStream = new MemoryStream(); BinaryWriter writer = new BinaryWriter(audioStream); // Write the header writer.Write(header_GroupID.ToCharArray()); writer.Write(header_FileLength); writer.Write(header_RiffType.ToCharArray()); // Write the format chunk writer.Write(fmt_ChunkID.ToCharArray()); writer.Write(fmt_ChunkSize); writer.Write(fmt_FormatTag); writer.Write(fmt_Channels); writer.Write(fmt_SamplesPerSec); writer.Write(fmt_AvgBytesPerSec); writer.Write(fmt_BlockAlign); writer.Write(fmt_BitsPerSample); // Write the data chunk writer.Write(data_ChunkID.ToCharArray()); writer.Write(data_ChunkSize); foreach (byte dataPoint in data_ByteArray) { writer.Write(dataPoint); } player = new SoundPlayer(audioStream); } ///  /// Call this to clean up when program is done using this sound ///  public void Dispose() { if (writer != null) writer.Close(); if (player != null) player.Dispose(); writer = null; player = null; } ///  /// Play "ding" sound ///  public void Play() { if (player != null) { player.Stream.Seek(0, SeekOrigin.Begin); // rewind stream player.Play(); } } } 

希望这应该有助于其他试图动态生成简单警报声音而不需要声音文件的人。

这可能会有所帮助: http : //channel9.msdn.com/coding4fun/articles/Generating-Sound-Waves-with-C-Wave-Oscillators

以下文章解释了如何使用SoundPlayer生成和播放* .wav文件。 请注意,SoundPlayer可以将流作为参数,因此您可以在MemoryStream中生成wav文件内容并避免保存到文件。

http://blogs.msdn.com/b/dawate/archive/2009/06/24/intro-to-audio-programming-part-3-synthesizing-simple-wave-audio-using-c.aspx

我尝试了从Anachronist(2012-10)剪下的代码 – 它对我有用

对我来说最大的障碍:摆脱“AlertDing”wav末尾的系统性“咔嗒声”。

这是由代码剪切中的“软错误”引起的:

for (uint i = 0; i < numSamples - 1; i += fmt_Channels)

需要转变为

for (uint i = 0; i < numSamples; i += fmt_Channels)

如果不改变,则在每次“播放”结束时将产生系统的“零”,从而产生尖锐的咔嗒声 。 (=幅度跳跃0-> min-> 0)

原来的问题暗示“当然没有点击噪音”:)