将一个音频信号除以另一个

Dividing one audio signal by another one

简短版

我需要将一个音频信号除以另一个音频信号(振幅方向)。我如何在不使用 ScriptProcessorNode 的情况下在网络音频 API 中完成此操作? (使用 ScriptProcessorNode 任务很简单,但由于固有的性能问题,它完全无法用于生产

长版

考虑两个音频源,例如两个 OscillatorNodesoscAoscB

var oscA = audioCtx.createOscillator();
var oscB = audioCtx.createOscillator();

现在,考虑这些振荡器是低频振荡器,它们的频率都很低(即 <20Hz),并且它们的信号用于控制 单个目标 AudioParam, for example, the gain of a GainNode .通过各种路由设置,我们可以定义这两个信号之间的数学运算。

加法

如果oscAoscB直接连接到目标AudioParam,它们的输出添加一起:

var dest = audioCtx.createGain();

oscA.connect(dest.gain);
oscB.connect(dest.gain);

减法

如果oscB的输出首先通过另一个增益为-1的GainNode,然后连接到目标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 of that 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


编辑

我早些时候绝对荒谬解决这个问题的尝试是:

编辑 2

ScriptProcessorNode 对于比技术演示更复杂的应用程序基本上无用的原因是:

  1. 它在主线程 (!) 上执行音频处理,繁重的 UI 工作会引入音频故障
  2. 一个简单的 ScriptProcessorNode 在现代设备上将占用 5% CPU 电源,因为它使用 JavaScript 执行处理并需要在音频线程(或渲染线程)之间传递数据) 和主线程(或 UI 线程)

需要注意的是,ScriptProcessorNodedeprecated

如果你需要A/B,那么你就需要1/B,反转信号。您可以使用 WaveShaperNode 进行反转。该节点需要一个对应值的数组。反转意味着 -1 变成 -1,-0.5 变成 -2 等

此外,请确保您了解被零除的知识。你必须处理它。在下面的代码中,我只取零后的下一个值并将其加倍。

function makeInverseCurve( ) {
  var n_samples = 44100,
      curve = new Float32Array(n_samples),
      x;
  for (var i = 0 ; i < n_samples; i++ ) {
    x = i * 2 / n_samples - 1;
    // if x = 0, let reverse value be twice the previous 
    curve[i] = (i * 2 == n_samples) ? n_samples : 1 / x;
  }
  return curve;
};

工作fiddle is here. If you remove .connect(distortion) out of the audio chain, you see a simple sine wave. Visualization code got from sonoport