Tone.js 是一个用于在浏览器中创建、播放和处理音频的 JavaScript 框架。本技能面向在项目中添加音频、声音设计、音乐编排或音频响应式动画的场景,并重点说明如何将 Tone.js 与 GSAP 动画时间线同步。
主要用途与适用场景
- 在 GSAP 动画中同时播放音频文件(音效、旁白、音乐)。
- 实现节拍同步或 BPM 锁定的动画,例如按节拍切换场景。
- 制作音频响应式视觉:由波形或频率数据驱动 DOM/SVG 元素动画。
- 以编程方式生成声音,例如合成器、振荡器、界面音效。
- 为任意声源添加混响、延迟、失真等音频效果。
安装与初始化
- 通过 CDN 引入:<script src="https://cdnjs.cloudflare.com/ajax/libs/tone/14.8.49/Tone.js"></script>
- 通过 npm / bun 安装:bun add tone,然后 import * as Tone from 'tone';
- 受浏览器自动播放策略限制,必须在用户手势处理器(如 click、keydown)内调用 await Tone.start(),否则音频上下文不会恢复。示例中在按钮点击事件中调用 Tone.start() 并启动 Tone.getTransport().start(),且使用 { once: true } 仅触发一次。
核心架构
- 信号图结构为:声源(Synth、Player、Analyser)→ 效果器(Reverb、Delay、Distortion)→ 目标(toDestination())。
- 所有节点通过 .connect() 或 .toDestination() 连接。
常用能力
- 播放音调:new Tone.Synth().toDestination().triggerAttackRelease("C4", "8n")
- 加载并播放文件:new Tone.Player(url).toDestination(),再调用 player.start()
- 添加混响:const rev = new Tone.Reverb(2).toDestination(); synth.connect(rev)
- 按节拍调度:Tone.getTransport().scheduleRepeat(cb, "4n")
- 读取波形:new Tone.Analyser("waveform", 64).getValue()
- 读取频率:new Tone.Analyser("fft", 32).getValue()
- 设置 BPM:Tone.getTransport().bpm.value = 120
- 将视觉同步到音频:Tone.getDraw().schedule(() => { /* gsap here */ }, time)
- 停止并清空调度:Tone.getTransport().stop(); Tone.getTransport().cancel()
与 GSAP 同步的正确方式
- Tone 回调运行在音频线程,直接在回调中调用 gsap.to() 会造成抖动。应使用 Tone.getDraw().schedule() 将音频事件桥接到视觉帧。
- 示例:在 Tone.getTransport().scheduleRepeat 回调中通过 Tone.getDraw().schedule 调用 gsap.fromTo,而不是直接调用 gsap.to。
音频响应式动画
- 将 Tone.Analyser 接入 GSAP ticker,每帧读取波形数据并驱动 DOM 元素。示例使用 gsap.ticker.add 读取 analyser.getValue()(Float32Array,值域 [-1, 1]),再用 gsap.set 设置元素 scaleY。
- 在 ticker.add 内应使用 gsap.set() 而非 gsap.to(),避免每帧创建新补间带来开销。
BPM 锁定场景切换
- 设置 bpm 后,使用 Tone.getTransport().scheduleRepeat 按小节("1m")触发,并通过 Tone.getDraw().schedule 执行 gsap.fromTo 切换场景透明度。
播放音频文件与效果器链
- 使用 Tone.Player 加载音效或旁白,设置 autostart: false,在 GSAP 事件(如 onStart)中调用 player.start()。
- 效果器链示例:Reverb 接 toDestination(),FeedbackDelay 连接 Reverb,Synth 连接 FeedbackDelay,再触发音符。
常见错误与修复
- 音频不启动:先在 click 或 keydown 处理器中调用 await Tone.start()。
- 视觉抖动:不要在 Tone 回调中直接调用 gsap.to(),改用 Tone.getDraw().schedule()。
- ticker 中使用 gsap.to():改用 gsap.set()。
- Transport 事件触发两次:重新调度前先调用 Tone.getTransport().cancel()。
- Player 未就绪:在 player.load() 的 Promise 中或 onsuccess 内调用 player.start()。
- Analyser 占用 CPU 高:使用较小缓冲区(32 至 64),波形足够时避免使用 FFT。
最小可运行示例(原生 HTML)
- 页面引入 Tone.js 与 gsap.min.js,在 body 点击事件中 await Tone.start(),创建 Analyser 与 Synth,通过 gsap.ticker.add 读取波形并设置 .bar 元素 scaleY,最后触发音符。该示例同样使用 { once: true }。
限制与注意事项
- 必须依赖用户手势触发音频初始化,否则无法播放。
- 资料未提供关于收费、价格、平台兼容范围或性能指标的更多信息,暂未提供。