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

Ace编辑器运行Tone.js重复播放致音效叠加失真如何解决

问题根源

每次点击播放按钮触发go()函数时,会重复执行编辑器内的Tone.js代码,导致两个核心问题:

  • 重复向Tone.Transport注册调度回调,旧的回调没有被清除,多个回调同时触发音符播放
  • 重复创建Synth等音频节点,多个节点同时输出信号造成音量叠加、声音失真

之前尝试的editor.setValue('')方法是操作Ace编辑器的文本内容,和已执行的JS上下文、Tone.js内部注册的事件完全无关,所以会误删编辑器内的代码,却解决不了声音叠加的问题。

修复方案

不需要修改编辑器内容,只需要在每次运行新代码、点击停止按钮时,重置Tone.js的运行上下文即可,核心操作包括:

  • 停止Transport播放
  • 清空Transport上所有已注册的调度事件
  • 重置播放位置到起始点
  • 做短暂静音避免清理时产生爆音

修改后的完整JS逻辑

const editor = ace.edit("editor");
editor.setTheme("ace/theme/monokai");
editor.session.setMode("ace/mode/javascript");
editor.setOptions({fontSize:"14pt"});

// 重置Tone运行上下文,不影响编辑器内的代码内容
const resetToneContext = () => {
    // 停止播放
    Tone.Transport.stop();
    // 清除所有通过scheduleRepeat、scheduleOnce注册的调度事件
    Tone.Transport.cancel();
    // 重置播放进度到开头
    Tone.Transport.position = 0;
    // 短暂静音避免清理瞬间产生爆音
    Tone.Master.mute = true;
    setTimeout(() => {
        Tone.Master.mute = false;
    }, 50);
}

const go = () => {
    // 每次运行用户代码前,先清理上一次的运行状态
    resetToneContext();
    const userCode = editor.getSession().getValue();
    try {
        new Function(userCode)();
        console.log(userCode);
    } catch (err) {
        console.error(err);
    }
    Tone.Transport.start();
}

const stop = () => {
    resetToneContext();
}

效果说明

  • 编辑器内的用户代码会完整保留,不会被清空
  • 每次点击播放只会存在一组调度事件、不会重复叠加声音
  • 点击停止按钮会立即终止播放,再次点击播放会从头开始运行

如果需要更严格的上下文隔离,可以进一步改造new Function的执行作用域,避免用户代码声明的全局变量残留,但对于入门教程场景,上述逻辑已经完全可以解决声音叠加失真的问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.30 15:27:23