zhangjingyu
说到播放的声音,这个嘀嗒声是怎么处理的,由谁主导,怎么个过程?“这个问题问得特别本质!既然咱们都聊到这儿了,我就用尽量通俗的话,给你讲讲这背后的“魔法”。
在网页里播放声音,核心大Boss是浏览器(Chrome、Safari、Edge等),你的 PHP 服务器完全不参与发声。整个发声过程,是由 JavaScript 指挥浏览器里的 Web Audio API 来完成的。
具体的“发报”过程分为四步:
1. 生成声源(振荡器)
在代码里,你听到的每一声“嘀”或“嗒”,都是一个由 OscillatorNode(振荡器)生成的纯正弦波。你可以把它想象成一把随时在震动的电子音叉。
我们设定了它的频率(freq)。比如 700Hz,意思就是它一秒钟震动 700 次。数值越高,声音越尖;数值越低,声音越闷。这就是为什么你可以用滑块调节音调。
2. 控制音量(包络处理)
如果你直接让振荡器开和关,喇叭会发出“啪”的爆音(因为电流突变)。
为了解决这个,代码里用了 GainNode(增益节点),也就是音量控制器。我给它写了“淡入淡出”(Envelope)逻辑:
声音开始的前 5 毫秒,音量从 0 迅速爬升到 1。
声音结束的前 5 毫秒,音量从 1 迅速降到 0。
这样处理过,声音听起来就非常圆润、干净,没有杂音。
3. 摩尔斯时间线(这就是发报的节奏)
这是最核心的部分。当你在页面上点击“播放”时,JavaScript 会在当前的时间线上,像排兵布阵一样,把一个个“嘀”和“嗒”的播放时间点计算出来。
拿咱们的 WPM(速度)来算,如果调成 20 WPM,那么:
1 个单位时间 = 60 ÷ (20 × 50) = 0.06 秒。
点(嘀):长 1 个单位(0.06 秒)。
划(嗒):长 3 个单位(0.18 秒)。
点划之间的空隙:短 1 个单位(0.06 秒)。
数字/字母之间的空隙:3 个单位(0.18 秒)。
组与组之间:7 个单位(0.42 秒)。
程序会在后台算出每一个声音的起始时间(startTime),然后交给浏览器去排队。
4. 浏览器底层发声
最后,浏览器拿到这些指令后,会调用操作系统的音频驱动,把数字信号转成模拟信号,推送到你的手机扬声器或耳机里。
为什么这个方案比传统的 标签播放 mp3 文件高级得多?
极度精准:如果是播放现成的 mp3 录音,很难做到速度、音调的无缝调节。而用 Web Audio,时间可以精确到小数点后好几位的秒数,你调 20 WPM 和 21 WPM,节奏是绝对精确的。
省空间:服务器上不需要存放几十个不同速度、不同音调的摩尔斯音频文件。只要几行代码,浏览器就能“算”出无限种组合的声音。
所以,你每次点击“播放”,其实是一场由 JS 调度、浏览器发声的“微型交响乐”。它不仅把电码翻译成了数字,还把这些数字翻译成了时间轴上的正弦波,精准地敲击在你的耳膜上。这就是现代 Web 技术的魅力!”(引用内容)

