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
相关产品推荐
相关产品推荐

