在从事一个项目时,我发现需要准确地生成各种波浪。我认为简单的正弦波是最容易开始的,但看来我错了。我制作了一个简单的程序,它生成样本的 vector
,然后播放这些样本,以便用户听到波形,作为测试。相关代码如下:
vector<short> genSineWaveSample(int nsamples, float freq, float amp) {
vector<short> samples;
for(float i = 0; i <= nsamples; i++) {
samples.push_back(amp * sinx15(freq*i));
}
return samples;
}
我不确定这是什么问题。我知道由 short
组成的 vector 可能存在一些问题,但这正是我的音频框架想要的,而且我对这种库没有经验,所以不知道会发生什么。
症状如下:
- 频率不正确
- 即:给定 freq=440,A4 不是播放的音符
- 奇怪的扭曲
- 大多数频率不会产生干净的波。 220、440、880都是干净的,其他大部分都是失真的
- 大部分频率都大幅上移
任何人都可以就我可能做错的地方提出建议吗?
这是我到目前为止尝试过的:
- 制作我自己的正弦函数,以获得更高的准确性。
- 我对 sin(x) 使用了 15 次泰勒级数展开
- 更改了采样率,从 256 到 44100 之间的任何值,考虑到上述错误,听不到任何变化,波形只是更加失真。
谢谢。如果有任何信息可以帮助您,我将有义务提供。
最佳答案
我怀疑您向 sin15x 函数传递了不正确的值。如果您熟悉信号处理的基础知识 Nyquist frequency是您可以忠实地重建(或在您的情况下构造)采样信号的最小频率。定义为信号中存在的最高频率分量的 2 倍。
这对您的程序意味着,您需要在每个循环中为您想要重现的最高频率至少提供 2 个值。在 20Khz 下,您每秒需要 40,000 个样本。看起来您只是在用值打包一个 vector ,然后让回放程序整理时间。
我们假设您使用 44.1Khz 作为播放采样频率。这意味着产生一秒钟 1kHz 波的代码片段看起来像
DataStructure wave = new DataStructure(44100) // creates some data structure of 44100 in length
for(int i = 0; i < 44100; i++)
{
wave[i] = sin(2*pi * i * (frequency / 44100) + pi / 2) // sin is in radians, frequency in Hz
}
您需要除以频率,而不是乘法。要看到这一点,请以传递 22,050 Hz 频率值的情况为例。对于 i = 0,您得到 sin(0) = 1。对于 i = 1,sin(3pi/2) = -1 等等。这为您提供了 1、-1、1、-1... 的重复序列,这是以 44.1Khz 采样的 22,050Hz 波的正确表示。这在您降低频率时起作用,但每个周期获得越来越多的样本。有趣的是,这并没有什么不同。每个周期采样 2 个样本的正弦波与每秒采样 1000 次的正弦波一样准确。这没有考虑噪音,但对于大多数用途来说效果很好。
我建议研究数字信号处理的基础知识,因为它是一个非常有趣的领域并且非常有助于理解。
编辑:这假设所有这些参数都被评估为 float 。
关于C++数学函数生成,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36962650/