Web Audio API+SoundtouchJS:音频节点图构建问题求助
解决方案:针对指定AudioBufferSourceNode实现SoundTouchJS移调
正确的音频节点拓扑结构
仅为3个AudioBufferSourceNode添加SoundTouch移调处理器,将所有源(含未处理的MediaElementAudioSourceNode)通过合并器汇总后输出到扬声器,正确结构如下:
MS --------------------\ S1 --- SoundTouchWorklet --\\ S2 --- SoundTouchWorklet ---> Merger -- Destination S3 --- SoundTouchWorklet --/
分步实现代码
1. 注册Formant Correction Worklet
确保Worklet处理器代码无TypeScript残留语法,采用内联方式加载避免跨域问题:
// 内联Worklet处理器核心代码(TS转JS后版本) const workletCode = ` class FormantCorrectionProcessor extends AudioWorkletProcessor { // 此处放入SoundTouchJS提供的Worklet处理器逻辑,移除所有TypeScript类型注解 // 示例核心逻辑框架(需替换为官方转译后的完整代码) static get parameterDescriptors() { return [ { name: 'pitchShift', defaultValue: 0, minValue: -12, maxValue: 12 }, { name: 'rate', defaultValue: 1, minValue: 0.5, maxValue: 2 }, { name: 'formantShift', defaultValue: 0, minValue: -12, maxValue: 12 } ]; } process(inputs, outputs, parameters) { // 官方处理器核心处理逻辑 return true; } } registerProcessor('formant-correction-processor', FormantCorrectionProcessor); `; // 注册Worklet到音频上下文 async function setupWorklet(audioContext) { const blob = new Blob([workletCode], { type: 'application/javascript' }); const url = URL.createObjectURL(blob); await audioContext.audioWorklet.addModule(url); }
2. 初始化音频节点并建立连接
async function initAudio() { const audioContext = new (window.AudioContext || window.webkitAudioContext)(); await setupWorklet(audioContext); // 初始化媒体源(无需移调) const mediaElement = document.getElementById('your-media-element'); const mediaSource = audioContext.createMediaElementSource(mediaElement); // 初始化3个音频缓冲源(假设已加载audioBuffer1/2/3) const source1 = audioContext.createBufferSource(); source1.buffer = audioBuffer1; const source2 = audioContext.createBufferSource(); source2.buffer = audioBuffer2; const source3 = audioContext.createBufferSource(); source3.buffer = audioBuffer3; // 创建移调处理器工厂函数 const createPitchShifter = (context, pitchShift) => { const processor = new AudioWorkletNode(context, 'formant-correction-processor'); processor.parameters.get('pitchShift').value = pitchShift; // 设置半音移调值 return processor; }; const shifter1 = createPitchShifter(audioContext, 2); // 升2半音 const shifter2 = createPitchShifter(audioContext, -1); // 降1半音 const shifter3 = createPitchShifter(audioContext, 3); // 升3半音 // 创建4通道合并器(对应4个音频源) const merger = audioContext.createChannelMerger(4); // 建立节点连接 mediaSource.connect(merger, 0, 0); // 媒体源直接连合并器第0通道 source1.connect(shifter1); shifter1.connect(merger, 0, 1); // 处理后的源1连合并器第1通道 source2.connect(shifter2); shifter2.connect(merger, 0, 2); // 处理后的源2连合并器第2通道 source3.connect(shifter3); shifter3.connect(merger, 0, 3); // 处理后的源3连合并器第3通道 merger.connect(audioContext.destination); // 启动音频缓冲源(媒体源播放由DOM控制) source1.start(); source2.start(); source3.start(); }
常见问题排查
- Worklet注册失败:检查浏览器是否支持
AudioWorklet,处理器代码是否有语法错误,确保完全移除TypeScript类型注解。 - 移调无效果:确认
pitchShift参数设置在有效范围(-12~12半音),节点连接顺序为源→处理器→合并器,且AudioBufferSourceNode已调用start()。 - 音频不同步:若缓冲源与媒体源不同步,可通过
audioContext.currentTime指定启动时间,如source1.start(audioContext.currentTime)。 - 节点连接错误:禁止将
AudioBufferSourceNode连接到MediaElementAudioSourceNode(源节点无法作为输入节点),不要给媒体源添加移调处理器。
内容的提问来源于stack exchange,提问作者Mike Johnson Jr
相关产品推荐
相关产品推荐

