VoiceFox 0.5.0:频谱、歌单互通与桌面媒体控制

VoiceFox 这一轮更新的重点,不是继续增加一个音源,而是把终端音乐播放器里几个长期缺失的能力补完整。

0.5.0 主要加入了频谱可视化、睡眠定时器、Windows SMTC、歌单导入导出、网易云只追加推送,以及远程歌单缓存,同时修复了拖拽列宽和频谱断流等影响日常使用的问题。

频谱可视化

按 w 可以打开频谱。

Linux 下优先从 PipeWire 的默认输出 monitor 流采集系统实际声音,没有时回退到 PulseAudio monitor。采集和 FFT 分析放在独立线程,UI 每帧只读取最新的频谱快照。

分析链路大致是:

系统输出 PCM
    ↓
4096 点 FFT
    ↓
50Hz–12kHz 对数频带
    ↓
dB 归一化
    ↓
相邻频带平滑
    ↓
attack / decay + 峰值保持
    ↓
ratatui 柱状渲染

底层使用 realfft 做 FFT、colorgrad 做颜色插值。

这里还有一个容易被忽略的细节:频谱采集进程退出并不会让界面永久冻结。PipeWire 重启、切换输出设备等情况发生后会自动重连;超过 1 秒没有新数据时也不会继续画最后一帧。

睡眠定时器

按 t 可以选择 15、30、45、60、90、120 分钟,或者关闭定时器。

到时间后不会直接切断声音,而是复用 libmpv 的音量淡出,在最长约 10 秒的窗口内逐渐降低音量,然后暂停。恢复播放时音量会恢复。

Windows SMTC

Windows 现在通过 System Media Transport Controls 接入系统媒体控制。

因此硬件媒体键、蓝牙耳机按键和系统媒体浮层可以控制播放、暂停、上一首、下一首和进度,同时显示当前歌曲和封面。

媒体控制代码也从原先散落在主循环和平台实现里的逻辑抽成统一的 media_controls / media_session 层,Linux MPRIS 与 Windows SMTC 分别负责协议适配。

歌单互通

这一版开始,VoiceFox 的歌单已经不再局限于程序自己的数据库。

导入

支持:

  • M3U / M3U8
  • LX Music JSON
  • 网易云歌单 JSON

导出

自建歌单可以导出 M3U8。

本地歌曲写绝对路径,在线歌曲则写 voicefox:: 标识,让外部工具至少能够识别 VoiceFox 的来源和歌曲 ID。

推送网易云

自建歌单和收藏可以推送到网易云。

这里采用的是只追加策略:

登录预检
   ↓
选择远端目标
   ↓
五级匹配
   ↓
生成追加 Diff
   ↓
用户确认
   ↓
分批写入

已经存在的远端歌曲不会删除,无法可靠匹配的歌曲也不会强行写入,而是明确列出原因。

网易云远程歌单缓存

这是这一轮里另一个比较重要的架构调整。

网易云歌单现在作为远程集合的只读镜像保存,而不是复制成本地歌单。

缓存保存:

  • 歌单 ID
  • 歌单信息
  • 歌曲元数据
  • 「我喜欢的音乐」特殊歌单标识

播放时仍然走网易云音源自己的地址解析。

远端请求出现部分失败时,缓存按歌单 ID 增量合并。这样即使网易云因为频控导致某一个歌单暂时拉取失败,也不会把之前已经缓存好的其它歌单一起清空。

缓存跨进程落盘,所以 VoiceFox 重启后仍然能够看到自己的远程歌单。

交互修复

这一版也处理了两个很明显的手感问题。

第一是表头列宽拖拽。

以前队列处在左右分栏布局时,拖动列边界有机会被错误判断成「拖动表头换列」,导致相邻列卡顿或意外切换。现在命中测试使用表头实际宽度,不再把整个内容区域当成表头。

第二是频谱断流冻结。

采集子进程结束后现在会自动重新建立采集连接;没有新帧超过 1 秒也不会继续显示旧频谱。

当前 VoiceFox

现在的 VoiceFox 已经形成比较明确的结构:

ratatui
   ↓
application / services
   ↓
core
   ├─ player
   ├─ lyric
   └─ sync
   ↓
source providers
   ├─ 在线音源
   ├─ JS 自定义音源
   └─ local

media
   ├─ Linux MPRIS
   └─ Windows SMTC

同步层独立于具体音源,通过 SyncProvider 扩展新的平台;播放器仍然由 libmpv 负责实际音频输出。

项目主页:VoiceFox

继续阅读

源码:GitHub