【问题标题】:Dividing one audio signal by another one将一个音频信号除以另一个
【发布时间】:2017-02-09 18:40:44
【问题描述】:

短版

我需要将一个音频信号划分另一个(幅度方面)。在不使用ScriptProcessorNode 的情况下,如何在 Web Audio API 中完成此操作? (使用 ScriptProcessorNode 任务是微不足道的,但由于固有的性能问题,它完全无法用于生产

加长版

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

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

现在,考虑这些振荡器是低频振荡器,都具有低(即 控制单个目的地AudioParam,例如,获得 GainNode。通过各种路由设置,我们可以定义这两个信号之间的数学运算。

加法

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

var dest = audioCtx.createGain();

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

减法

如果oscB的输出首先通过增益为-1anotherGainNode,然后连接到目标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.512/2 = 4.2)——现在这个值可以通过使用增益设置为12 / 8.48528099060058593750(近似值)的GainNode来补偿,但它只支持>=1
  • 使用 AnalyserNode 快速采样音频信号,然后使用该值 (LOL)

编辑 2

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

  1. 它在主线程 (!) 上执行音频处理,繁重的 UI 工作会引入音频故障
  2. 一个简单的 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

标签: javascript web-audio-api


【解决方案1】:

需要注意的是,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。如果您从音频链中删除.connect(distortion),您会看到一个简单的正弦波。可视化代码来自sonoport

【讨论】:

  • 您可能只需要曲线数组中的 3 个点,因为该节点对中间值使用线性插值。
  • 谢谢,解释清楚了。因此,这将有效地允许以音频信号作为操作数来执行大多数任意数学运算。
  • 然而,我不太明白的是,这将如何处理[-1, 1] 范围之外的值。据我所知,曲线值不是外推的。
  • @JohnWeisz 据我所知,网络音频中的信号幅度不能超过 1。
  • 当然可以,我正在使用音频信号来转发来自 MIDI 控制器的值,通过任意数学运算,目前正在测试音频信号以控制频率,并且 Web 音频 API 处理值 022050 完美无缺(它可能完美支持整个 float32 范围,尽管我还没有尝试)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-10-27
  • 2017-05-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-06-13
相关资源
最近更新 更多