ToneJS:如何实现键盘触发多音高同时播放
嘿,这个问题我熟!要实现多音同时播放,核心问题就是原来的单个Tone.Synth一次只能输出一个音轨的声音,咱们换成ToneJS专门的复音合成器Tone.PolySynth就能轻松搞定,同时还要加个状态记录来避免重复触发。我给你改好代码,再一步步讲清楚逻辑:
核心修改思路
- 改用PolySynth处理复音:
Tone.PolySynth内部会自动管理多个Synth实例,支持同时播放多个不同音符,不用咱们手动创建和维护多个Synth对象。 - 记录激活的音符状态:新增一个
activeNotes对象,用来跟踪当前按住的按键对应的音符,避免同一个按键按住时多次触发keydown事件导致重复发声。 - 完善按键事件逻辑:在
keydown时检查按键是否合法且未激活,再触发音符;keyup时找到对应音符并停止播放。
修改后的完整代码
// 键盘到音高的映射不变 const keyToPitch = { "z":"C3", "s":"C#3", "x":"D3", "d":"D#3", "c":"E3", "v":"F3", "g":"F#3", "b":"G3", "h":"G#3", "n":"A3", "j":"A#3", "m":"B3", ",":"C4" }; // 替换单个Synth为PolySynth,指定内部使用的合成器类型和参数 const polySynth = new Tone.PolySynth(Tone.Synth).toMaster(); // 设置振荡器类型,和原来一致 polySynth.set({ oscillator: { type: "sawtooth" } }); // 记录当前激活(按住)的音符,避免重复触发 const activeNotes = {}; function onKeyDown(e) { const pitch = keyToPitch[e.key.toLowerCase()]; // 检查按键是否在映射里,且该音符未被激活 if (pitch && !activeNotes[pitch]) { // 触发音符播放,第二个参数可以设置音量(可选) polySynth.triggerAttack(pitch, Tone.now(), 0.5); activeNotes[pitch] = true; } } function onKeyUp(e) { const pitch = keyToPitch[e.key.toLowerCase()]; if (pitch && activeNotes[pitch]) { // 停止该音符播放 polySynth.triggerRelease(pitch, Tone.now()); delete activeNotes[pitch]; } } // 绑定键盘事件 window.addEventListener('keydown', onKeyDown); window.addEventListener('keyup', onKeyUp);
额外说明
- 如果想调整复音的最大数量(比如最多同时播放8个音),可以在创建PolySynth时指定:
new Tone.PolySynth({ maxPolyphony: 8 }, Tone.Synth) - 你也可以给PolySynth设置其他参数,比如滤波器、包络等,和单个Synth的设置方式类似,用
polySynth.set()方法即可。
内容的提问来源于stack exchange,提问作者drenl
相关产品推荐
相关产品推荐

