连续波形音频合成器

时间:2012-01-26 20:48:38

标签: c++ audio synthesis

我开始编写一个具有独特特性的软合成器:振荡器将具有“连续波形”旋钮,允许用户以连续的方式选择正弦波,方波和锯齿波。也就是说,如果旋钮一直向左,输出将是一个正弦波,如果它在中间它将是一个锯齿波,如果它一直向右,它将是一个方波然后中间位置将输出经典波的“插值”版本的波。 - 可以改变旋钮位置和波浪类型,但需要有一种连续的方式来改变波形 -

我想到了几种实现振荡器的方法:

  1. 提出一个功能,它采用旋钮位置并计算实际信号的频谱(幅度和频率阵列),然后使用一串正弦函数和一个和块来实现输出信号。

  2. 与1.类似,但应用反向傅立叶变换而不是正弦和求和(好的,此时我不确定它们实际上是否相同。)

  3. 为每个可能的旋钮位置生成波形表,并使用波表合成技术生成输出信号。

  4. 从2个锯齿波开始(它们包含偶数和奇数谐波),反转一个并求它们,并用旋钮控制每个齿的振幅。波形不会是

  5. 我有几个问题:

    一个。我已经读过,1号技术是处理器密集型的,并不是真的可行。这适用于ARM处理器,例如iPad上的处理器吗?

    B中。无论我最终选择哪种技术,只需将低通滤波器连接到振荡器的输出就可以解决混叠问题?

    ℃。关于如何实现这种振荡器的任何其他建议?

    d。有关使用哪个C ++工具包的建议?我一直在看CCRMA的STK,但我不知道是否还有其他更合适的库。

    祝你好运! ;)

    编辑:有人昨晚指示我din。贝塞尔曲线是另一个需要考虑的选择。

4 个答案:

答案 0 :(得分:5)

我不确定你是不是太复杂了。如果我理解正确的话,你用连续波形旋钮做的所有事情都可以有效地将3个波形的不同数量混合在一起。因此,只需始终生成所有3个波形,然后根据您描述的波形混合将它们与不同的增益相加。

对于带宽限制波形合成以避免混叠,您可能会找到所需的大部分内容here

希望有所帮助。

答案 1 :(得分:2)

这是B的答案(简单地通过将低通滤波器连接到输出来解决混叠的问题吗?),这触及了其他一些点。

不幸的是,答案是'不'。混叠是由于存在高于奈奎斯特频率的谐波频率(即采样率的一半)。如果振荡器的波形中存在这些谐波,则滤波无效。 (适当的积极过滤会破坏你生成的波浪的特征。)过采样(另一个答案提到这个)可以,但它很昂贵。

为避免这种情况,您必须生成“带限”波形。也就是说,没有高于某个选定值的谐波的波形<1。奈奎斯特。这样做并非易事。本文here值得一读。解决这个问题有两种既定的实用方法:BLIT(Band Limited Impulse Train)和MinBLEPs。两种方法都试图通过在波形中的适当点插入“填充物”来消除产生谐波的不连续性。

考虑到这一点,你的选择开始缩小。轻松和声音之间的最佳折衷可能是产生一系列带限波形表。但是,您仍然需要研究某种形式的抗锯齿来处理插值波。

iDevice ARM非常能够实时执行DSP。一般建议:编写严密的代码,使用内联函数并避免划分。你的渲染循环将被称为每秒44,100次,所以,只要你的代码在1/44100秒(0.023ms)内完成,你就没有问题。在实践中,您应该能够同时运行多个振荡器而不会出现任何问题。应用程序商店中所有这些音乐应用程序的存在证明了这一点。

STK是一个很棒的介绍库。 (Perry Cook的书“交互式应用的实时音频合成”也是一个很好的基础,值得一读。)STK故意没有优化,我不确定它能够很好地生成你的'连续'波形。 kvraudio.commusicdsp.org应该在您的阅读列表中。

答案 2 :(得分:1)

傅立叶变换是线性的,因此采用例如FFT的FFT。通过iFFT或求和正弦,方波和锯波以及每个谐波线性交叉然后将其带回到时域,应该提供与直接交叉渐变锯和方波信号完全相同的输出。我不确定这是否是您想要做的,但如果没有必要进行FFT或计算中间表。

当然还有很多其他方法可以在波形之间平滑地“淡化” - 你可以使用相位失真,例如,由线性段组成的失真曲线,从生成正方形的位置移动到产生锯的位置。以固有的带限制的方式实现这可能非常棘手。

实际上,别名通常可以使用过采样和过滤来解决,或者只是过滤。使用带限技术会更好,因为混叠总是会产生一些噪音,但你经常可以将它过滤得足够低,以便听不见,这对于音频合成很重要。

答案 3 :(得分:1)

  

一个。我已经读过,1号技术是处理器密集型的,并不是真的可行。这适用于ARM处理器,例如iPad上的处理器吗?

这使得一个简单的问题变得复杂(双关语)。 Accelerate.framework提供了这些功能的优化变体(fwiw),但它仍然使一个简单的问题复杂化。一般说明:设备上的浮点计算很慢。浮点实现可能会大大损害您的程序。它可能会导致功能,复音或质量受损。在不知道需求的情况下,很难说你是否可以使用浮点计算。

  

B中。无论我最终选择哪种技术,只需将低通滤波器连接到振荡器的输出就可以解决混叠问题?

除非您进行过采样,否则对时域中生成的信号不起作用。

  

℃。关于如何实现这种振荡器的任何其他建议?

见下文

  

d。有关使用哪个C ++工具包的建议?我一直在看CCRMA的STK,但我不知道是否还有其他更合适的库。

STK更像是一种教学工具,而不是为嵌入式合成器设计的工具包。存在更合适的实现。

  

选项1.提出一个功能,它采用旋钮位置并计算实际信号的频谱(幅度和频率阵列),然后使用一串正弦函数和一个和块来实现输出信号。

     

选项2.类似于1.但应用反向傅立叶变换而不是正弦和求和(好的,此时我不确定它们实际上是否是同一个东西。)

台式机的速度相对较慢。

  

选项4.从2个锯齿波开始(它们包含偶数和奇数谐波),反转一个并求和,并用旋钮控制每个齿的振幅。波形不会是

您可以非常有效地(例如使用BLIT)进行别名自由生成。但是,BLIT仅限于少数波形(您可以将它用于Saw和Square)。您可以回顾历史并询问“他们如何在2000年的硬件和软件合成器中解决这个问题”。这是一个解决方案。另一个是:

  

选项3.为每个可能的旋钮位置生成波形表,并使用波表合成技术生成输出信号。

考虑到设备的功能,我建议使用这个或BLIT的int实现。

该表易于理解和实现,并提供良好的声音和CPU结果。它还可以高度配置CPU /内存/质量权衡。

如果你想要别名免费(或关闭),请选择BLIT(或其亲属)。原因是你需要一大块内存和大量的过采样,以便最小化到波表的声音混叠。

实现:

网上有很多BLIT(和家庭)实施。

这是一张用餐桌涂鸦的桌子:

enum { WF_Sine, WF_Saw, WF_Square, WF_COUNT };
enum { TableSize = SomePowerOfTwo };

struct sc_waveform {
    uint32_t at[TableSize];
};

enum { NPitches = Something };

sc_waveform oscs[WF_COUNT][NPitches];

初始化后,使用添加剂合成来填充oscs

播放期间,请使用:

  • 从表中读取的插值和过采样
  • 或对信号​​进行大量过采样,然后进行下采样(这是CPU效率)。

供参考:我估计表的线性插值消耗了不负责任的内存量(考虑到可用的数量)而没有过采样,如果你不,你应该将别名频率保持在-40 dB或低于-40 dB em>以可听见的方式阻尼最高部分,并以44.1kHz渲染。这是一种天真的蛮力方法!你可以通过一些额外的工作做得更好。

最后,如果你谷歌“矢量合成”,你也应该找到相关的信息 - 你所描述的是它的原始形式。