如何在C#中合成和输出简单的声波?

时间:2009-06-01 05:03:19

标签: c# windows audio

如果你有口齿不清,请不要试着说出我的头衔。

但是,是的,最简单的方法是为更复杂的锯齿和其他波浪生成简单或奖励。

4 个答案:

答案 0 :(得分:3)

根据我的经验,.wav file formatWikipedia entry列出了提供文件格式的其他文档;使用您认为最好的文件格式)是最简单的广泛使用的文档格式。编写未压缩的PCM非常容易。

对于像正弦波和锯齿一样的东西,我将任务分为采样和文件制作。所以你可能有一个界面,如:

public interface IWave
{       
    double Sample(double time);
}

其中Sample将被赋予大于0的时间(但可能大于1)并且应该返回介于-1和1之间的值。(您可以使用委托代替。)然后写一个文件生成器根据采样持续时间(例如“100000波”)和采样频率(例如50000 Hz)创建wav文件。

然后,这只是适当实施IWave的情况 - 例如对于简单的正弦波返回sin(time / (2 * pi))的版本,或对于锯齿返回(time % 1.0) * 2 - 1的版本。为了奖励娱乐,您可以编写合成功能来加速或减慢波形,放大波形,组合其他波浪等。文件生成器当然不需要知道任何。它只需要采用 IWave并对其进行适当的采样,将[-1,1]范围适当地缩放到[0,255]。

答案 1 :(得分:1)

只是详细说明Jon已经说过 - 你要做的就是创建一个8位(即字节[1024])或16位缓冲区并将其填满(即对于方波,它是[255 255 255 255 0] 0 0 0 255 255 255 255 0 0 0 0])。

答案 2 :(得分:1)

有关如何在C#中生成正弦波的示例代码,请查看this question。将其扩展到方波或锯齿波将非常容易。您可以通过将简单波形混合在一起来生成更复杂的波形。

如果需要,您还可以使用NAudio WaveFileWriter类将生成的数据写入WAV文件。

答案 3 :(得分:0)

有一篇Charles Petzold的文章Simple Electronic Music Sequencer for Silverlight基于Gilles Khouzam的博客文章Playing back Wave files in Silverlight和Pete Brown的Creating Sound using MediaStreamSource in Silverlight 3 Beta。 Mike Hodnick有一篇有用的博客文章,其中包含基于Petzold文章Digital Audio Synthesis on Windows Phone 7的示例代码。

在主窗口的XAML中,Mike介绍了一个媒体元素

<MediaElement x:Name="media"/>

然后使用SetSource方法将媒体元素源设置为他正在构建的wave

this.media.SetSource(new TonesSource());
this.media.Play();

迈克ToneSource将他的BaseSource子类化,后者依次为MediaStreamSource子类并覆盖其中的几个方法:OpenMediaAsyncGetSampleAsyncSeekAsyncCloseMediaGetDiagnosticAsyncSwitchMediaStreamAsyncthe MSDN documentation中有更多关于它们的内容;迈克的代码本身并不长,但涉及到位移和写入内存流,值得在the source provided in Mike's blog post中查看。

然后,迈克的ToneSource班级提供立体声样本

protected override StereoSample GetSample()
{
    short left = 0;
    short right = 0;

    foreach (var oscillator in this.leftOscillators)
        left += oscillator.GetNextSample();

    foreach (var oscillator in this.rightOscillators)
        right += oscillator.GetNextSample();

    return new StereoSample() { Left = left, Right = right };
}

使用他的Oscillator

public short GetNextSample()
{
    ushort wholePhaseAngle = (ushort)(phaseAngle >> 16);
    short amplitude = 0;
    amplitude = (short)(short.MaxValue * Math.Sin(2 * Math.PI * wholePhaseAngle / ushort.MaxValue));
    amplitude = (short)((amplitude * multiplier) >> 16);
    phaseAngle += phaseAngleIncrement;

    return amplitude;
}

迈克提供的NoiseSource甚至比ToneSource

更简单
protected override StereoSample GetSample()
{
    return new StereoSample()
    {
        Left = (short)random.Next(short.MinValue, short.MaxValue),
        Right = (short)random.Next(short.MinValue, short.MaxValue)
    };
}