使用 Web Audio API 实现浏览器插件的成功提示音效
NousSave 是一款 AI 对话管理浏览器插件,支持 ChatGPT、Claude、DeepSeek、Gemini 等平台的对话导出和快捷操作。插件在完成导出、复制等操作后会播放一段简短的成功提示音,实现方式是 Web Audio API 实时合成,无外部音频文件依赖。
核心实现
音效通过 AudioContext + OscillatorNode + GainNode 三件套实现:
function playSuccessSoundEffect(options) {
if (options?.muted) return;
const AudioCtx = window.AudioContext || window.webkitAudioContext;
if (!AudioCtx) return;
const ctx = new AudioCtx();
if (ctx.state === 'suspended') ctx.resume();
const frequency = Number(options?.frequency) || 1200;
const volume = Number(options?.volume) || 0.08;
const durationSec = (Number(options?.durationMs) || 300) / 1000;
const type = options?.type || 'square';
const oscillator = ctx.createOscillator();
const gainNode = ctx.createGain();
oscillator.connect(gainNode);
gainNode.connect(ctx.destination);
oscillator.frequency.value = frequency;
oscillator.type = type;
gainNode.gain.setValueAtTime(volume, ctx.currentTime);
gainNode.gain.exponentialRampToValueAtTime(
Math.max(0.001, volume * 0.125),
ctx.currentTime + durationSec
);
oscillator.onended = () => ctx.close();
oscillator.start(ctx.currentTime);
oscillator.stop(ctx.currentTime + durationSec);
}调用方式:
playSuccessSoundEffect({
frequency: 1200,
volume: 0.08,
durationMs: 300,
type: 'square'
});参数解析
| 参数 | 默认值 | 作用 |
|---|---|---|
frequency |
1200 Hz | 音调频率 |
volume |
0.08 | 响度(0~1) |
durationMs |
300 ms | 持续时长 |
type |
square |
波形类型 |
frequency = 1200 Hz
人耳对 1 kHz ~ 4 kHz 频段最敏感(等响曲线的谷底区域)。1200 Hz 踩在这个区间的起点,听感清脆但不刺耳。低于 800 Hz 会发闷,高于 2000 Hz 容易变成噪音。
type = 'square'
方波由基频和无穷多个奇次谐波(3f、5f、7f...)叠加而成。相比正弦波的"纯净",方波带有天然的泛音结构,听感上是经典的 8-bit 电子音色。Web Audio API 提供四种波形:
sine— 纯音,无谐波,像医用检测音square— 奇次谐波丰富,复古电子感sawtooth— 所有谐波都有,偏尖锐triangle— 奇次谐波但衰减快,比方波柔和
方波在这个场景下的优势:辨识度高、存在感强、但不吵。
volume = 0.08
提示音的职责是"告知状态",不是"引起注意"。0.08 的音量配合 300ms 的时长,刚好在潜意识层面完成信息传递,不会打断用户当前操作。
durationMs = 300 ms
人类对短促声音的感知阈值约 50ms,300ms 足够形成完整的"音节感"。超过 500ms 就从"提示"变成了"通知",性质不同。
指数衰减
gainNode.gain.exponentialRampToValueAtTime(
Math.max(0.001, volume * 0.125),
ctx.currentTime + durationSec
);音量从 0.08 线性起始,在 300ms 内指数衰减到 0.01(0.08 × 0.125)。exponentialRampToValueAtTime 模拟自然界声音的衰减曲线——声波能量按指数规律消散,所以听感自然,没有硬切的突兀感。
Math.max(0.001, ...) 是因为 exponentialRampToValueAtTime 的目标值不能为 0,否则会抛异常。
信号链路
OscillatorNode (1200Hz square)
│
▼
GainNode (0.08 → 0.01 exponential)
│
▼
AudioContext.destination (扬声器)OscillatorNode 产生原始波形,GainNode 控制音量包络,destination 是最终输出。整条链路在 oscillator.stop() 后通过 onended 回调关闭 AudioContext,释放系统资源。
复用
将上面的 playSuccessSoundEffect 函数复制到项目中即可使用。可选参数全部有默认值,零配置调用:
playSuccessSoundEffect(); // 使用全部默认参数需要不同音效时传入参数覆盖:
// 低沉的提示音
playSuccessSoundEffect({ frequency: 600, type: 'triangle', durationMs: 200 });
// 清脆的确认音
playSuccessSoundEffect({ frequency: 1800, type: 'sine', durationMs: 150 });注意事项
- 浏览器要求用户交互后才能创建 AudioContext(autoplay policy),首次调用需在点击事件中触发
ctx.close()释放资源,避免长时间运行的页面累积 AudioContext 实例- Safari 使用
webkitAudioContext,已做兼容处理 exponentialRampToValueAtTime的目标值必须大于 0
本文由 AI 辅助生成,可能存在错误或遗漏,请以实际资料和官方文档为准。