使用Tone.js从数组创建振荡器及Buffer播放问题求助
使用Tone.js动态生成并播放音频的问题解答
核心疑问解答
1. 是否需要createBufferSource?
不需要。你使用的Tone.Player已经封装了原生Web Audio API的BufferSourceNode,内部会自动处理Buffer的加载与播放逻辑,无需手动创建createBufferSource。
2. 能否直接覆盖AudioBuffer的内容?
不能。原生AudioBuffer是不可变对象,一旦创建完成就无法修改其内部数据。如果需要更新音频内容,要么重新创建新的AudioBuffer,要么采用实时生成音频样本的方式(而非依赖静态Buffer)。
实现持续播放动态音频的解决方案
你的代码存在两个关键问题:
useEffect中的while(isPlaying)会阻塞主线程,导致页面无响应Tone.Player是为播放静态音频Buffer设计的,不适合动态更新音频数据
以下是修改后的代码,采用Tone.ScriptProcessor在音频线程中实时生成样本,实现持续播放:
import React, { useEffect, useState } from 'react'; import * as Tone from 'tone'; function AudioPlayer() { const [isPlaying, setIsPlaying] = useState(false); const sampleRate = 16384; let t = 0; // 样本计数 // 创建音频处理节点,每次处理1024个样本 const processor = new Tone.ScriptProcessor(1024); processor.connect(Tone.Destination); // 音频线程回调:实时生成样本 processor.onaudioprocess = (e) => { if (!isPlaying) return; const outputBuffer = e.outputBuffer.getChannelData(0); for (let i = 0; i < outputBuffer.length; i++) { // 生成440Hz正弦波样本 outputBuffer[i] = Math.sin(2 * Math.PI * 440 * (t / sampleRate)); t++; } }; const handlePlayClick = async () => { await Tone.start(); // 初始化音频上下文(必须在用户交互中调用) setIsPlaying(true); t = 0; // 重置样本计数 }; const handleStopClick = () => { setIsPlaying(false); }; return ( <div> {!isPlaying && ( <button onClick={handlePlayClick}>Play</button> )} {isPlaying && ( <button onClick={handleStopClick}>Stop</button> )} </div> ); } export default AudioPlayer;
代码说明
Tone.ScriptProcessor会在音频渲染线程中触发onaudioprocess回调,每次生成指定数量的音频样本,不会阻塞主线程- 必须在用户交互(如点击按钮)中调用
Tone.start(),这是浏览器的音频自动播放策略要求 - 通过控制
isPlaying状态,决定是否生成新的音频样本,实现播放/停止控制
内容的提问来源于stack exchange,提问作者merkwur
相关产品推荐
相关产品推荐

