使用 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 提供四种波形:

方波在这个场景下的优势:辨识度高、存在感强、但不吵。

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 });

注意事项

本文由 AI 辅助生成,可能存在错误或遗漏,请以实际资料和官方文档为准。