【发布时间】:2010-10-30 08:04:15
【问题描述】:
如果你口齿不清,请不要试图说出我的标题。
但是,是的,为更复杂的锯齿波和其他波生成简单或奖励的最简单方法是什么。
【问题讨论】:
如果你口齿不清,请不要试图说出我的标题。
但是,是的,为更复杂的锯齿波和其他波生成简单或奖励的最简单方法是什么。
【问题讨论】:
根据我的经验,.wav file format(Wikipedia 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]。
【讨论】:
只是为了详细说明 Jon 已经说过的内容 - 您所做的只是创建一个 8 位(即字节 [1024])或 16 位缓冲区并将其填充(即对于方波,它是 [255 255 255 255 0 0 0 0 255 255 255 255 0 0 0 0])。
【讨论】:
查看this question 以获取有关如何在 C# 中生成正弦波的示例代码。将其扩展到方波或锯齿波将非常容易。您可以通过将简单波形混合在一起来生成更复杂的波形。
如果需要,您还可以使用NAudio WaveFileWriter 类将生成的数据写入WAV文件。
【讨论】:
有一篇 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 并覆盖了它的几个方法:OpenMediaAsync、GetSampleAsync、SeekAsync、CloseMedia、GetDiagnosticAsync 和 @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)
};
}
【讨论】: