我正在编写一个软件合成器,需要在44.1 kHz采样时实时生成带限、别名自由的波形。锯齿波现在可以用,因为我可以通过把两个锯齿混在一起产生一个脉冲波,一个倒移和相移。
到目前为止,我已经尝试了以下方法:
所以,我的问题是:通常的做法是什么?任何建议的解决方案都必须在CPU方面是有效的,因为它必须实时地对多个声音同时进行。
发布于 2008-10-06 17:49:42
带限波形的产生方法有很多种。你将结束交易的计算成本与质量与往常一样。
我建议你在这里看看这个网站:
http://www.musicdsp.org/
查查档案!里面全是好材料。我刚搜索了关键字“频限”。如果你忙碌了至少一周,弹出的材料就会弹出来。
顺便说一句--不知道这是不是你想要的,但几年前我确实减少了别名的波形生成(例如,并不是真正的波段限制)。我刚刚计算了最后一个样本位置和当前样本位置之间的积分。对于传统的合成器-波形,如果你在奇点处分裂你的积分间隔(例如锯齿得到他的重置),你可以很容易地做到这一点。CPU负载低,质量可以满足我的需要。
我也有同样的漂移问题,但是在积分上应用一个很低截止频率的高通可以消除这种影响。真正的模拟-合成器不会进入亚赫兹区域,所以你不会错过太多。
发布于 2010-04-28 19:10:14
一种快速产生带限波形的方法是使用带限步骤(BLEPs).您将生成带限制步骤本身:

并将其存储在一个可波形中,然后用一个带限步骤替换每个转换,以创建如下所示的波形:

请看带限声合成的穿行。
由于这种BLEP是非因果的(这意味着它延伸到未来),为了产生实时波形,最好使用最小相位带限步长,称为MinBLEP,它具有相同的频谱,但只扩展到过去:
MinBLEPs更进一步,采用加窗的正弦,执行最小相位重建,然后将结果集成到一个表中。现在,要制作一个振荡器,只需在波形中的每个不连续性处插入一个MinBLEP。所以对于方波,你插入一个波形倒置的MinBLEP,对于saw波,你插入一个值倒置的MinBLEP,但是你正常地生成斜坡。
发布于 2008-10-06 19:29:26
这就是我想到的,灵感来自尼尔斯的想法。把它贴在这里,以防对别人有用。我简单地用盒子过滤锯齿波,解析地使用最后一个样本的相位变化作为内核大小(或截止值)。这是相当好的工作,有一些可听到的别名在最高的音符,但对于正常使用,这听起来很棒。
为了更多地减少混叠,内核大小可以增加一点,例如,使2*相位变化听起来也不错,尽管你损失了一些最高频率。
此外,这里还有另一个很好的DSP资源,我在浏览SP时发现了类似的主题: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);
}https://stackoverflow.com/questions/175312
复制相似问题