2

我需要计算一个三角形和锯齿波,但由于我的模型和我能够使用的数据,它有点复杂(但也许我只是感到困惑)。

我能够计算出我的正弦波,但我并没有真正使用帧计数器。我所做的是,计算一个theta_increment变量,下次我需要计算样本时可以使用它。这像这样工作:

float x = note.frequency / AppSettings::sampleRate;
float theta_increment = 2.0f * M_PI * x;
float value = 0;

if(waveType == SINE){
    value = sin(note.theta) * fixedAmplitude;
}

现在我有了存储theta_incrementnote.theta成员中的当前帧/样本的值,因此我可以将其用于下一个样本:

note.theta += theta_increment;

我已经查看了大量关于如何计算锯子或三角形的示例,但我无法弄清楚。(我只有上面提到的数据可供我使用)这是我最后一次尝试,但它不起作用并给我带来了大量的故障:

value = 1.0f - (2.0f * ((float)note.theta / (float)44100));
4

2 回答 2

4

如果您有一个循环生成您的值,如下所示:

for (size_t frame=0; frame!=n_frames; ++frame) {
  float pos = fmod(frequency*frame/sample_rate,1.0);
  value[frame] = xFunc(pos)*fixedAmplitude;
}

然后您可以将这些函数用于不同类型的波:

float sinFunc(float pos)
{
  return sin(pos*2*M_PI);
}

float sawFunc(float pos)
{
  return pos*2-1;
}

float triangleFunc(float pos)
{
  return 1-fabs(pos-0.5)*4;
}

基本思想是您需要一个在每个周期内从 0.0 到 1.0 的值 (pos)。然后你可以随心所欲地塑造它。

对于正弦波,sin() 函数可以完成这项工作,您只需乘以 2*PI 即可将 0.0 到 1.0 范围转换为 0.0 到 2*PI 范围。

对于锯齿波,您只需要将 0.0 到 1.0 的范围转换为 -1.0 到 1.0 的范围。乘以 2 并减去 1 即可。

对于三角波,可以使用绝对值函数来引起方向的突变。首先,我们通过减去 -0.5 将 0.0 到 1.0 的范围映射到 -0.5 到 0.5 的范围。然后我们通过取绝对值把它变成0.5到0.0到0.5的形状。通过乘以 4,我们将其转换为 2.0 到 0.0 到 2.0 的形状。最后通过从 1 中减去它,我们得到一个 -1.0 到 1.0 到 -1.0 的形状。

于 2012-08-18T14:41:39.780 回答
2

锯齿波可以这样计算:

value = x - floor(x);

三角形可以这样计算:

value = 1.0 - fabs(fmod(x,2.0) - 1.0);

其中 x 是note.theta

于 2012-08-18T14:32:39.430 回答