3

我正在查看这个关于 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)因此也非常欢迎对此进行任何解释。

4

2 回答 2

0

我想它会以你的方式工作得很好(但不要忘记乘以幅度):

buffer[frame] = sin(theta_increment * frame) * amplitude;

只是表达相同数学的两种不同方式。看起来编写原始代码的人想要保留 0 <= theta < 2pi,但这可能没有必要(除非 sin() 调用以我不知道的方式很奇怪)。此外,他们可能希望保持“数学”部分独立于帧变量,以防相同的片段出现在其他地方的其他循环中,但这只是猜测。

于 2012-03-06T02:47:23.737 回答
0

您的方法可用于创建相同的结果,但表达方式不同。但是,theta += theta_increment;这将是一个比您建议的更简单的表达式(计算)。

阶段的域被包装到sin'逻辑参数域。对于短样本,这一步实际上是不必要的。由于浮点存储的限制,您的频率最终可能会发生变化,并且如果该值未包装,则最终永远不会增加,这取决于您生成的样本数量以及您是否使用floatdouble. 这样想:如果你有一个巨大的正浮点数(你的相位累加器的值)并且你尝试添加会发生什么0.000004给它?浮点误差会将其舍入以适应浮点数或双精度数,并且该误差将导致相位不稳定并最终导致音高不稳定。对于短样本(例如某些周期),在这种情况下不需要回绕,但对于许多许多周期,它用于随着时间的推移稳定音高和相位累加器。

最后,theta 将用于存储相位渐变的最后一个值,以便在随后的渲染调用中从中断处恢复生成。否则,输出将在渲染调用边界处从 0 重新开始,从而产生非常令人不快的噪音和错误的频率。

考虑所有因素:这可能是因为它是一个简单的演示,并且是在该上下文中生成正弦的快速方法。你的方法有一些“昂贵”的转换,但它是无分支的——它可能比原来的更快,尤其是对于更高的频率。

于 2012-03-06T03:02:06.947 回答