音乐

网页钢琴与 Web Audio 合成

用振荡器与 GainNode 包络合成钢琴音,支持键盘演奏、延音踏板与内置乐谱自动播放。

#web-audio #piano #synthesis

网页钢琴与 Web Audio 合成

Web Audio 不只能分析已有音频——用 振荡器(Oscillator) 也能从零合成声音。下面 demo 实现了一个 3 个八度的网页钢琴:按住琴键持续发声,松手渐弱;空格键控制延音踏板;还可点击内置乐谱自动演奏。若你读过 Web Audio 音乐可视化,那篇讲的是 AnalyserNode 分析播放,本篇则走 合成发声 路线。

核心链路

1. 音高:音符名 → 频率

每个琴键对应如 C4F#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 捕获 → pressNotepointerupreleaseNote
物理键盘KEY_MAP 映射 QWERTY 键到音符
内置乐谱按 BPM 计算节拍时长,playNoteTimed 定时发声

乐谱播放用 playToken 取消机制:切换曲目或点停止时递增 token,异步循环检测到 token 变化即退出。

在线体验

点击或键盘演奏(需用户手势后 AudioContext 才会 resume)。也可 全屏预览

正在加载网页钢琴…

小结

网页钢琴的核心是 振荡器合成 + 包络塑形 + 多 voice 管理。和音乐可视化的 AnalyserNode 不同,这里完全在「生成」声音。真实钢琴音色需要更复杂的采样或物理建模,但三角波 + 简单 ADSR 已足够演示 Web Audio 的合成路径。想继续深入,可以试试换波形、加滤波器,或接入 SoundFont 采样。