从真实 MIDI 为 Game Boy “Wario Synth” 发布
发布: (2026年3月14日 GMT+8 21:32)
5 分钟阅读
原文: Dev.to
Source: Dev.to


Wario 合成引擎 8‑Bit Midi
把任何歌曲变成 Game Boy 版。
在线演示
关于
WAH! 🎮
随便输入一首歌。我们会在网上找到对应的 MIDI 文件,然后通过在浏览器中运行的自制 Game Boy 声音芯片把它彻底“炸”掉。
- 准确吗?有时是。
- 合法吗?大概吧。
- 酷炫吗?绝对酷。
四条辉煌的 chiptune 频道:
- 🟨 Pulse 1 — 尖叫的主旋律
- 🟨 Pulse 2 — Pulse 1 忘记的部分
- 🟩 Wave — 有种不同感觉的厚重低音
- ⬜ Noise — 打击乐(嘶嘶 pshh)
零采样。零服务器音频。只有原始振荡器在尽情嗨。
功能
- MIDI 搜索,来自 BitMidi 及其他来源
- 浏览器播放,带音色钢琴预览
- Wario 合成引擎:基于解析后的 MIDI 结构进行程序化 Game Boy 风格合成
- 分享链接,带动态社交预览
我们已交付的 MVP
- MIDI 搜索 + 排名(跨来源后端抓取/代理,带 SSRF 防护)
- 确定性的 MIDI 解析 + 元数据(稳定、可调试)
- 可靠的播放,使用 Web Audio + iOS “点击启用音频”交互
- Motif / 变体模式(角色映射:旋律/低音/和弦/纹理 → 合成层)
让我们卡住的功能:“下载 MP3”
我们添加了一个导出按钮,执行以下步骤:
- 离线渲染 (
OfflineAudioContext) - 在 JS 中编码 MP3 (
lamejs) - 触发 Blob 下载
当时体验很好:
- “渲染音频中…”
- “编码 MP3 中…”
- “MP3 已下载!”
随后浏览器开始阻止它。
真正的问题
现代浏览器经常 在长时间的异步工作(渲染/编码)后默默阻止下载,因为“用户手势”已经失效。没有错误提示,也没有文件,只有… 什么也没有。
我们尝试了常见的变通方案(导致复杂度爆炸):
- 打包编码器(避免 CDN 全局变量)
- 两次点击的 “准备 → 下载” 流程
- 在支持的情况下使用文件保存选择器 (
showSaveFilePicker) - 点击时预打开一个标签页/窗口,然后再导航到 Blob
最终,导出交互成为整个应用最不可靠的部分,于是我们 移除了下载 MP3 按钮,而不是交付一个不稳定的功能。
我们的收获
- 可靠性胜过巧妙:不可靠的按钮会破坏用户信任。
- 浏览器策略是产品约束:自动播放解锁 + 下载手势规则决定了你的用户体验。
- 确定性让迭代更有趣:稳定的解析/元数据让调试保持理性。
下一步提升方向
- 构建自己的 MIDI 库:爬取/缓存 “已知良好” 的 MIDI,统一元数据,去重,并按 “在我们的合成器中听起来好” 排序。
- 更好的音乐智能(仍保持轻量):改进角色映射、基本调式/音阶启发式、更加智能的鼓/噪声处理。
- 正式恢复导出功能:要么 服务器端渲染/导出,要么采用一种真正跨浏览器可靠的 “保存…” 流程。
把随机的 MIDI 变成酥脆的 Game Boy 表演简直是疯一样的有趣——它也是音频、MIDI 奇思妙想以及快速交付的绝佳练习场。