我正在看这个example about sound generation on iOS,因为我需要做类似的事情,但有些部分我不明白,我希望有人可以帮助我。
在这部分代码中:
double theta_increment = 2.0 * M_PI * viewController->frequency / viewController->sampleRate;
// Generate the samples
for (UInt32 frame = 0; frame < inNumberFrames; frame++)
{
buffer[frame] = sin(theta) * amplitude;
theta += theta_increment;
if (theta > 2.0 * M_PI)
{
theta -= 2.0 * M_PI;
}
}
我真的不明白theta += theta_increment;
部分的用途。对我来说,在for循环中做这样的事情更有意义:
buffer[frame] = sin(theta_increment * frame);
知道为什么那不起作用?另外,我不知道代码的这一部分是什么:if (theta > 2.0 * M_PI)
所以对此的任何解释都是非常受欢迎的。
答案 0 :(得分:0)
我想它会以你的方式工作(但不要忘记乘以振幅):
buffer[frame] = sin(theta_increment * frame) * amplitude;
表达相同数学的两种不同方式。看起来编写原始代码的人想要保持0&lt; = theta&lt; 2pi,但这可能没有必要(除非sin()调用以我不知道的方式很奇怪)。此外,他们可能想要保持&#34;数学&#34;部分独立于框架变量,以防相同的片段出现在其他地方的其他循环中,但这只是推测。
答案 1 :(得分:0)
您的方法可用于创建相同的结果,表达方式不同。但是,theta += theta_increment;
将比您建议的更简单(计算)。
阶段的域被包装到sin'
的逻辑参数域。对于短样品,此步骤实际上不是必需的。由于浮点存储的限制,您的频率最终可能会发生变化,并且如果未包装该值,最终永远不会增加,具体取决于您生成的样本数量以及是否使用float
或double
。可以这样想一想:如果你有一个巨大的正浮点数(相位累加器的值)并且你试图向它添加0.000004
,会发生什么?浮点误差将使其圆整以适合浮点数或双精度,并且误差将导致相位并最终导致音高不稳定。对于短样品(例如一些循环),在这种情况下不需要包裹,但是对于许多循环,它用于稳定节距和相位累加器随着时间的推移。
最后,theta将用于存储相位斜坡的最后一个值,以便在后续渲染调用中从中断处继续生成。如果没有这个,输出将在渲染调用边界处重新开始,产生非常令人不快的噪音和错误的频率。
考虑所有因素:可能是因为它是一个简单的演示,并且是在该环境中生成正弦的快速方法。你的方法有一些“昂贵的”转换,但它是无分支的 - 它可能比原始的更快,特别是对于更高的频率。