【问题标题】:How can i synthesize and output simple sound waves in C#?如何在 C# 中合成和输出简单的声波?
【发布时间】:2010-10-30 08:04:15
【问题描述】:

如果你口齿不清,请不要试图说出我的标题。

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

【问题讨论】:

    标签: c# windows audio


    【解决方案1】:

    根据我的经验,.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 用于锯齿。为了获得额外的乐趣,您可以编写合成函数来加速或减慢波浪、放大它、合并其他波浪等。当然,文件生成器不需要知道这些。任何。它只需要 single IWave 并对其进行适当的采样次数,将 [-1, 1] 范围适当地缩放到 [0, 255]。

    【讨论】:

      【解决方案2】:

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

      【讨论】:

        【解决方案3】:

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

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

        【讨论】:

          【解决方案4】:

          有一篇 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();
          

          Mike 的 ToneSource 继承了他的 BaseSource,而后者又继承了 MediaStreamSource 并覆盖了它的几个方法:OpenMediaAsyncGetSampleAsyncSeekAsyncCloseMediaGetDiagnosticAsync 和 @987654 .在the MSDN documentation 中有更多关于它们的信息; Mike 的代码本身并不长,但涉及到位移和写入内存流,值得在the source provided in Mike's blog post 中查看。

          Mike 的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;
          }
          

          Mike 还提供的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)
              };
          }
          

          【讨论】:

            猜你喜欢
            • 2013-12-24
            • 1970-01-01
            • 2011-01-08
            • 2012-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2023-01-18
            • 1970-01-01
            相关资源
            最近更新 更多