有个开发者在Chrome标签页里造了一架印度手风琴(Harmonium)。不是视频,不是游戏引擎,是纯网页——你按键盘,风箱动画跟着动,声音从AudioContext里流出来,延迟低得不像浏览器能做的事。我更好奇的是:他们怎么让"真实乐器"的幻觉成立,而CPU几乎不喘气。
采样派 vs 合成派:这场仗早就打完了
页面写着"三个八度、九个采样点"。这句话是破案关键。
如果是物理建模合成,需要实时计算簧片振动、气流湍流、箱体共振——CPU风扇该转了。但"采样点"暗示另一条路:提前录好WAV,用重采样(Resampling)改变音高。每个音名对应一个AudioBuffer,加载一次,用playbackRate拉伸。
手风琴的簧片有个特性:音色相对稳定,不像小提琴有丰富的弓法变化。所以每个八度塞3-4个采样,中间音高靠算法插值,25音分(cent)一档的微调足够骗过耳朵。这是正方观点:采样派赢了,用空间换时间,用内存换CPU。
反方会质疑:27个采样文件(3八度×9音),每个300-500KB,离线安装时怎么不卡?ServiceWorker缓存这么多音频,首次加载是灾难。但原文提到"带宽沉重"却没说解决方式——可能用了分块加载,或者把高频采样压缩得更狠。这里存疑,但采样派的主逻辑成立。
我的判断:采样派确实赢了,但赢法比表面精巧。他们不是简单堆文件,而是在浏览器音频架构的缝隙里做了大量减法。
风箱的平滑欺骗:GainNode的隐形工作
手风琴的灵魂是风箱。推风箱,音量起;停住,音衰减。网页版复刻了这个——但最危险的是音量跳变时的爆音(Pop)。
直接改AudioBufferSourceNode的音量?每次调整都是一次音频时钟的硬切换,爆音几乎不可避免。他们的解法更底层:所有声音先流进一个共享的GainNode,风箱UI只改变目标振幅值,实际音量用短指数斜坡(Exponential Ramp)过渡。
这样CPU在做什么?几乎不做。指数斜坡是Web Audio API的原生功能,浏览器底层用线性插值搞定,主线程只发一个目标值。原文说的"CPU stays quiet"在这里兑现——不是算法多聪明,是选对了API的抽象层级。
力度感应(Velocity Sensitive)更有意思。真手风琴没有"力度"概念,只有气压。他们很可能把按键力度映射到全局风箱增益:敲得重=模拟气压大。但没有复音触后(Polyphonic Aftertouch),长音会僵住——我猜他们在持续平滑gain.value,伪造空气被压缩的质感。这是数字对物理的妥协,也是聪明的妥协。
MIDI的浏览器政治:Chrome的特权与Safari的补丁
navigator.requestMIDIAccess是网页接硬件键盘的入口。但Safari支持得晚,且有各种权限陷阱。低延迟表现暗示他们押注Chrome的直接MIDI路径,其他浏览器"尽力而为"(Best-effort)。
这里有个未解之谜:用了什么Polyfill?原文说"想知道"但没给答案。可能用了WebMIDIAPIShim,也可能自己封装。无论如何,这是浏览器生态分裂的缩影——同一个API,不同内核的表现差出一个数量级。开发者选择了务实:不追求公平,追求能用的那部分体验。
无人机的无缝切换:预解码与循环接缝
手风琴有持续音(Drone),页面还提供坦布拉琴(Tanpura)循环。切换瞬间完成,没有浏览器重新缓冲的停顿。
这暴露另一个技术选择:所有循环音频预解码为AudioBuffer,不是实时流。坦布拉的周期约5秒,他们用Looping AudioBufferSourceNode,接缝处做小幅交叉淡入淡出(Crossfade)。 harmonium的Drone更简单——同一采样叠低通滤波器,省一个文件。
录音功能也基于此。混音进MediaStreamDestination,再喂给MediaRecorder,全程客户端。WebM格式、2分钟上限,恰好卡在Chrome默认内存限制上;再长,延迟飙升。这不是设计选择,是浏览器实现的硬边界。
一小时链接的压缩魔术:JSON的极限瘦身
最精巧的可能是分享功能。"一小时有效链接"不存音频,只传状态。
原文测试:短录音的链接约40字符。什么概念?原始JSON描述乐器设置(采样选择、滤波参数、风箱位置、录音元数据)轻松超500字节。40字符意味着强压缩——LZ算法把重复模式压掉,再Base64编码塞进URL查询参数。
接收方拿到链接,客户端重建完全相同的乐器状态。音频?本地采样重新渲染。这是"状态即链接"的极致:不碰服务器存储,不付CDN流量,链接过期后零残留。隐私和成本的双赢,代价是链接长度随复杂度膨胀——但40字符说明他们的状态描述极度精简。
离线安装的体积困境:ServiceWorker的未解之谜
PWA(渐进式网页应用)能离线运行,靠ServiceWorker缓存核心资源。但27个采样文件、总计可能8-13MB的音频,首次安装是道坎。
原文在这里断了:"Either Cloudf"——推测想说Cloudflare或CDN分片,但未完。我们只知道带宽沉重,不知道具体策略。可能按需加载(只缓存当前调式的采样),可能用WebCodecs API做浏览器端解压,也可能硬扛首次加载的流失率。
这是采样派胜利的代价:空间换时间的账单,在离线场景下到期。
为什么这件事值得技术人盯着
这个风琴不是玩具,是一组技术决策的标本。它展示了Web Audio API的边界:什么能原生做,什么要绕路,什么必须接受平台差异。采样vs合成的选择、GainNode的平滑技巧、状态链接的压缩——这些不是音乐技术,是资源受限环境下的工程权衡。
更深一层:它证明了"浏览器原生体验"的可能性。不用Electron,不用WASM音频引擎,标准API+聪明架构就能做到低延迟、可离线、可分享。这对想做轻量交互产品的团队是参考:先榨干平台,再考虑堆技术。
最后,那个断掉的"Cloudf"像故意留下的钩子——作者知道答案,但选择停在谜面。或许下次更新,我们会看到采样流式加载的方案。届时CPU可能还是安静的,但网络面板会讲故事。
热门跟贴