【问题标题】:Calculate saw and triangle wave from specific data根据特定数据计算锯齿波和三角波
【发布时间】:2012-08-18 14:18:45
【问题描述】:

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

我能够计算我的正弦波,但我并没有真正使用帧计数器。我要做的是,计算一个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_increment 存储在我的 note.theta 成员中,以便我可以将其用于下一个样本:

note.theta += theta_increment;

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

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

【问题讨论】:

    标签: c++ math waveform trigonometry


    【解决方案1】:

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

    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 的形状。

    【讨论】:

    • 知道如何将范围设置为介于 -1 和 1 之间的范围吗?我想正弦函数已经是这种情况了,但是其他两个呢?
    • @Sled:给定的函数范围为 -1 到 1。
    • 我通过绘制它们进行了尝试,我在图中得到的范围完全不同:jsfiddle.net/DsCXH 知道我做错了什么吗?
    • @Sled:那里的代码似乎与我所描述的不同。例如,它不使用模数。在您的代码中,theta 的范围从 0 到 2*PI,并且您使用 theta 就好像它等同于我的代码中的 pos,其中 pos 的范围从 0 到 1。
    • 我只是想知道,如果 sinFunc 产生的音调太高一个八度。它应该返回sin(pos * M_PI),而不是sin(pos * 2 * M_PI)。但是,我很高兴看到这个 triangleFunc ... :-)
    【解决方案2】:

    锯齿波可以这样计算:

    value = x - floor(x);
    

    三角形可以这样计算:

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

    其中 x 是 note.theta

    【讨论】:

    • 这些很好用。还有一个问题:你有没有机会知道反锯齿的公式?
    • 你可以通过1 - sawtooth(x);来翻转它。你是这个意思吗?或者也许你的意思更像value = sawtooth(-x);。可能有几种不同的方法,具体取决于您要查找的内容。
    • 嘿,还有一个关于此的问题:知道如何为每个函数指定介于 -1 和 1 之间的值范围吗?
    • 乘以 2 减去 1。
    • 对于我写的公式,是的。它们的输出始终在 0 到 1 的范围内。乘以 2 使输出在 0 到 2 的范围内。减去 1 将范围向下移动到 -1 到 1 之间。
    猜你喜欢
    • 1970-01-01
    • 2018-09-19
    • 2016-02-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多