网页钢琴与 Web Audio 合成
用振荡器与 GainNode 包络合成钢琴音,支持键盘演奏、延音踏板与内置乐谱自动播放。
网页钢琴与 Web Audio 合成
Web Audio 不只能分析已有音频——用 振荡器(Oscillator) 也能从零合成声音。下面 demo 实现了一个 3 个八度的网页钢琴:按住琴键持续发声,松手渐弱;空格键控制延音踏板;还可点击内置乐谱自动演奏。若你读过 Web Audio 音乐可视化,那篇讲的是 AnalyserNode 分析播放,本篇则走 合成发声 路线。
核心链路
1. 音高:音符名 → 频率
每个琴键对应如 C4、F#5 的音符名。通过 MIDI 公式换算频率(A4 = 440Hz):
function noteToFreq(note) {
const match = note.match(/^([A-G]#?)(\d)$/)
const [, name, octaveStr] = match
const midi = (Number(octaveStr) + 1) * 12 + NOTE_INDEX[name]
return 440 * Math.pow(2, (midi - 69) / 12)
}
2. 发声:振荡器 + ADSR 包络
每次按键创建一个 OscillatorNode(三角波)和 GainNode:
Oscillator → GainNode → destination
按下时 gain 从极小值指数爬升到 PEAK_GAIN(attack ≈ 20ms);松手时指数衰减到 0 再 stop 振荡器。多音同奏用 Map<note, voice> 管理,每个音符独立一条链路。
3. 延音踏板
踩下踏板(空格或点击踏板按钮)时,松开的键不会立刻 releaseVoice,声音会保持到抬踏板。抬踏板后,所有 keyHeld === false 的 voice 才进入释放包络。
4. 三路输入
| 输入 | 处理方式 |
|---|---|
| 鼠标 / 触摸 | pointerdown 捕获 → pressNote;pointerup → releaseNote |
| 物理键盘 | KEY_MAP 映射 QWERTY 键到音符 |
| 内置乐谱 | 按 BPM 计算节拍时长,playNoteTimed 定时发声 |
乐谱播放用 playToken 取消机制:切换曲目或点停止时递增 token,异步循环检测到 token 变化即退出。
在线体验
点击或键盘演奏(需用户手势后 AudioContext 才会 resume)。也可 全屏预览。
小结
网页钢琴的核心是 振荡器合成 + 包络塑形 + 多 voice 管理。和音乐可视化的 AnalyserNode 不同,这里完全在「生成」声音。真实钢琴音色需要更复杂的采样或物理建模,但三角波 + 简单 ADSR 已足够演示 Web Audio 的合成路径。想继续深入,可以试试换波形、加滤波器,或接入 SoundFont 采样。