2008-10-06 47 views
10

我正在编写一个软件合成器,需要以44.1 kHz采样率实时生成带限,别名自由波形。锯齿波形现在可以实现,因为我可以通过将两个锯齿混合在一起产生一个脉冲波,一个反相并移相。带限波形生成

到目前为止,我已经尝试以下方法:

  1. 在预先计算在启动不同的bandlimit频率一个周期完全限带波形采样,然后回放两个最接近的人混在一起。工作好吧我猜,但不觉得很优雅。需要大量的样品或者他们之间的“差距”会被听到。插值和混合也是CPU密集型的。

  2. 积分一串直流补偿sinc脉冲获得一个锯齿波。听起来很不错,只是如果你没有完全正确地获得DC补偿(我发现这非常棘手),则波会从零漂移。增加一点泄漏到积分器可以减少DC问题,但是你会失去低频。

所以,我的问题是:通常的做法是什么?任何建议的解决方案都必须在CPU方面高效,因为它必须实时完成,对于许多声音一次。

+0

我意识到这是一年前问过的,但对于其他任何人磕磕绊绊,我会推荐搜索友好和高度胜任的[DSP和插件开发](http://www.kvraudio.com/论坛/ viewforum.php?f = 33)论坛在[KVR](http://www.kvraudio.com/) – 2009-10-03 07:15:43

回答

4

有很多方法来处理带限波形生成。像往常一样,您将最终按照质量交易计算成本。

我建议你看看这个网站浏览:

http://www.musicdsp.org/

退房存档!它充满了很好的材料。我只是搜索关键字“bandlimited”。弹出的材料应该至少保持一周。

顺便说一句 - 不知道这是你在找什么,但几年前我做了别名减少(例如不是真正的频带有限)波形生成。我只是计算了最后一个样本位置和当前样本位置之间的积分。对于传统的合成器波形,如果以奇点分割积分间隔(例如锯齿得到他的复位),则可以很容易地进行。 CPU负载很低,质量可以满足我的需求。

我有相同的漂移问题,但在积分上应用具有非常低的截止频率的高通消除了这种效应。无论如何,真正的模拟合成器不会进入亚赫兹区域,所以你不会错过太多。

+0

“phase + =(sampleRate /(float TableSize)/频率;”不编译。 “(sampleRate /(float TableSize))/ frequency;”? – user877329 2014-07-06 17:17:15

2

这是我想出的,受到尼尔斯想法的启发。在这里粘贴它以防其他人使用。我简单地用最后一个采样的相位变化作为内核大小(或截止值)来分析滤波锯齿波。它工作得很好,在最高音符处有一些可听见的别名,但对于正常使用来说听起来很棒。

为了减少更多的混叠,内核大小可以增加一点,使得2 * phaseChange例如听起来不错,尽管你失去了一些最高频率。

另外,这里是我在浏览类似主题的SP时发现的另一个很好的DSP资源:The Synthesis ToolKit in C++ (STK)。这是一个拥有很多有用的DSP工具的类库。它甚至可以使用带限波形发生器。他们使用的方法是整合sinc,就像我在第一篇文章中所描述的那样(尽管我猜他们做得更好,然后我......)。

float getSaw(float phaseChange) 
{ 
    static float phase = 0.0f; 
    phase = fmod(phase + phaseChange, 1.0f); 
    return getBoxFilteredSaw(phase, phaseChange); 
} 

float getPulse(float phaseChange, float pulseWidth) 
{ 
    static float phase = 0.0f; 
    phase = fmod(phase + phaseChange, 1.0f); 
    return getBoxFilteredSaw(phase, phaseChange) - getBoxFilteredSaw(fmod(phase + pulseWidth, 1.0f), phaseChange); 
} 

float getBoxFilteredSaw(float phase, float kernelSize) 
{ 
    float a, b; 

    // Check if kernel is longer that one cycle 
    if (kernelSize >= 1.0f) { 
     return 0.0f; 
    } 

    // Remap phase and kernelSize from [0.0, 1.0] to [-1.0, 1.0] 
    kernelSize *= 2.0f; 
    phase = phase * 2.0f - 1.0f; 

    if (phase + kernelSize > 1.0f) 
    { 
     // Kernel wraps around edge of [-1.0, 1.0] 
     a = phase; 
     b = phase + kernelSize - 2.0f; 
    } 
    else 
    { 
     // Kernel fits nicely in [-1.0, 1.0] 
     a = phase; 
     b = phase + kernelSize; 
    } 

    // Integrate and divide with kernelSize 
    return (b * b - a * a)/(2.0f * kernelSize); 
} 
6

生成带限波形的一种快速方法是使用带限步骤(BLEPs)。您生成带限步骤本身:

enter image description here

,并存储在波表,然后更换了带限一步每一个过渡,创建波形看起来像这样的:

enter image description here

请参阅步骤Band-Limited Sound Synthesis。由于该BLEP是非因果性的(意味着它延伸到未来),为了生成实时波形,最好使用最小相位频带限制步骤,称为MinBLEP,它具有相同的频谱,但只延伸到了过去:

MinBLEPs采取进一步的想法和 采取一个窗口正弦,执行 最小相位重建,然后 整合的结果,并将其存储在一个 表。现在制作一个振荡器,您只需在波形中的每个 不连续处插入一个MinBLEP。因此,对于 方波,您插入一个MinBLEP ,其中波形反转,锯齿 您插入一个MinBLEP,其中 值反转,但您正常生成 斜坡。

1

来自blit的DC偏移 - 可以通过简单的高通滤波器来降低! - 就像一个真正的模拟电路一样,他们使用直流阻塞盖帽!