You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

ConstantSourceNode的offset属性为何不反映更新后的值?

问题原因

你遇到的核心问题是:AudioParam的value属性并不是实时反映音频线程中的当前值——它只是该参数的初始静态配置值。当你调用setValueAtTime这类调度方法时,参数变化只会在独立的音频处理线程中生效,不会同步更新主线程里的value属性,所以你打印的始终是创建时的初始值0.5。

解决办法

方法1:自己维护参数值(简单直接)

如果只是需要跟踪你主动设置的参数数值,完全可以自己同步维护一个变量,不用依赖AudioParam的value属性:

function log(message) {
  const d = document.createElement('div');
  d.innerText = message;
  document.body.appendChild(d);
}

const b = document.createElement('button');
b.textContent = 'Test';
b.addEventListener('click', (e) => {
  log('Started.');
  const ctx = new AudioContext();
  let currentOffset = 0.5;
  const cNode = new ConstantSourceNode(ctx, {offset: currentOffset});
  // 设置新值时同步更新变量
  currentOffset = 1.0;
  cNode.offset.setValueAtTime(currentOffset, ctx.currentTime);
  log(`Value: ${currentOffset}`);
  setTimeout(() => {log(`Value: ${currentOffset}`);}, 1000);
});
document.body.appendChild(b);

方法2:获取音频线程实时值

如果你需要获取音频处理线程中的实际参数值,要用AudioParam.getValueAtTime()方法,传入音频上下文的当前时间(注意必须用ctx.currentTime,不能依赖主线程的时间)。另外别忘启动ConstantSourceNode,否则参数调度不会生效:

function log(message) {
  const d = document.createElement('div');
  d.innerText = message;
  document.body.appendChild(d);
}

const b = document.createElement('button');
b.textContent = 'Test';
b.addEventListener('click', (e) => {
  log('Started.');
  const ctx = new AudioContext();
  const cNode = new ConstantSourceNode(ctx, {offset: 0.5});
  // 必须启动节点,否则参数变化不会被音频线程处理
  cNode.start();
  cNode.offset.setValueAtTime(1.0, ctx.currentTime);
  // 用getValueAtTime获取音频线程当前的参数值
  log(`Value: ${cNode.offset.getValueAtTime(ctx.currentTime)}`);
  setTimeout(() => {
    // 这里依旧要用ctx.currentTime获取音频线程的当前时间
    log(`Value: ${cNode.offset.getValueAtTime(ctx.currentTime)}`);
  }, 1000);
});
document.body.appendChild(b);

运行这段代码就能得到你预期的输出:

Started.
Value: 1
Value: 1
实现你的原始需求:用单个参数控制多个节点

顺便给你实现最初的需求——用一个AudioParam控制两个振荡器的频率(一个用原值,一个用2倍值):

const ctx = new AudioContext();
// 创建统一的频率控制源
const freqControl = new ConstantSourceNode(ctx, {offset: 440});
freqControl.start();

// 创建两个振荡器
const osc1 = new OscillatorNode(ctx);
const osc2 = new OscillatorNode(ctx);

// 直接连接控制源到第一个振荡器的频率
freqControl.offset.connect(osc1.frequency);

// 用GainNode实现2倍增益,连接到第二个振荡器的频率
const doubleGain = new GainNode(ctx, {gain: 2});
freqControl.offset.connect(doubleGain).connect(osc2.frequency);

// 后续修改控制源的offset,两个振荡器的频率会自动同步更新
freqControl.offset.setValueAtTime(880, ctx.currentTime);

内容的提问来源于stack exchange,提问作者MattD

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.25 23:24:58