【发布时间】:2017-02-09 18:40:44
【问题描述】:
短版
我需要将一个音频信号划分另一个(幅度方面)。在不使用ScriptProcessorNode 的情况下,如何在 Web Audio API 中完成此操作? (使用 ScriptProcessorNode 任务是微不足道的,但由于固有的性能问题,它完全无法用于生产)
加长版
考虑两个音频源,例如两个OscillatorNodes,oscA 和oscB:
var oscA = audioCtx.createOscillator();
var oscB = audioCtx.createOscillator();
现在,考虑这些振荡器是低频振荡器,都具有低(即 控制单个目的地AudioParam,例如,获得 GainNode。通过各种路由设置,我们可以定义这两个信号之间的数学运算。
加法
如果 oscA 和 oscB 都直接连接到目标 AudioParam,则它们的输出添加在一起:
var dest = audioCtx.createGain();
oscA.connect(dest.gain);
oscB.connect(dest.gain);
减法
如果oscB的输出首先通过增益为-1的anotherGainNode,然后连接到目标AudioParam,那么oscB的输出实际上是从oscA 中减去,因为我们实际上是在执行oscA + -oscB 操作。使用这个技巧,我们可以从另一个信号中减去一个信号:
var dest = audioCtx.createGain();
var inverter = audioCtx.createGain();
oscA.connect(dest.gain);
oscB.connect(inverter);
inverter.gain = -1;
inverter.connect(dest.gain);
乘法
类似地,如果oscA的输出连接到另一个 GainNode,而oscB的输出连接到的gain AudioParam GainNode,那么oscB就是乘以oscA的信号:
var dest = audioCtx.createGain();
var multiplier = audioCtx.createGain();
oscA.connect(multiplier);
oscB.connect(multiplier.gain);
multiplier.connect(dest.gain);
部门(?)
现在,我想将oscB 的输出除 oscA 的输出。 我该如何做到这一点,不使用 ScriptProcessorNode?
编辑
我之前非常荒谬尝试解决这个问题的尝试是:
- 使用 PannerNode 控制
positionZ参数,确实产生的结果随着信号 B (oscB) 的增加而减少,但它完全关闭(例如,它产生了12/1 = 8.5和12/2 = 4.2)——现在这个值可以通过使用增益设置为12 / 8.48528099060058593750(近似值)的GainNode来补偿,但它只支持>=1 - 使用 AnalyserNode 快速采样音频信号,然后使用该值 (LOL)
编辑 2
ScriptProcessorNode 对于比技术演示更复杂的应用程序基本上无用的原因是:
- 它在主线程 (!) 上执行音频处理,繁重的 UI 工作会引入音频故障
- 一个简单的 ScriptProcessorNode 将在现代设备上占用 5% 的 CPU 功率,因为它使用 JavaScript 执行处理,并且需要在音频线程(或渲染线程)和主线程(或 UI 线程)之间传递数据
【问题讨论】:
-
ti.com.cn/cn/lit/an/snoa641b/snoa641b.pdf 这是一份关于使用运算放大器对交流信号进行乘法/除法的文档,但我相信它将为您提供足够的信息来创建等效代码。希望对您有所帮助。
-
需要注意的重要一点是对数,除法变成减法,所以 Log(sig1) - Log(Sig2) 是 Log(sig1/sig2),反之亦然。如果我错了,请有人大喊大叫,这样我就不会把 OP 弄错了。 :D
-
@ChrisCaviness -- 这里的问题是(AFAIK)
Log将再次需要 ScriptProcessorNode。我认为不可能在 Web Audio API 中实现。 -
我没有使用过网络音频 api,而且我的交流信号电路教育是 30 年前的,所以除了我上面介绍的一般内容之外,我不会提供太多帮助。对不起。如果您确实使用了 Log 方法,那么您当然必须对输出进行反日志才能获得真实的结果。
-
如果将一个值乘以 0.5,它与将一个值除以 2 相同。增益节点既可以乘也可以除。当 gain.value