电视秒变 K 歌房 + MTV 频道:NASMusicTV v2.16 全新进化

电视秒变 K 歌房 + MTV 频道:NASMusicTV v2.16 全新进化

电视秒变 K 歌房 + MTV 频道:NASMusicTV v2.16 全新进化

上次聊 NASMusicTV 还是 v2.6.2 -- 那时候它只是一个"电视上能好好显示歌词的 NAS 播放器"。现在它能把人声消掉让你在家 K 歌,还能自动搜索 B 站 MV 把电视变成音乐频道。

一、从"能听"到"能唱"

如果你看过上一篇文章,应该记得那个核心卖点:电视上逐字变色歌词。播一首《晴天》,右侧歌词跟着进度逐字亮起 -- 体验确实不错。

但听久了你会发现一个问题:光看歌词不过瘾,想跟着唱

手机上的音乐 App 早就有"伴奏模式"了 -- 消掉人声,只留背景音乐。但电视上?几乎没人做。

原因很简单:人声消除是 DSP(数字信号处理)活,吃 CPU、吃延迟、吃音频管线设计。手机上做这个已经够麻烦了,电视上还要兼顾遥控器操作和低版本设备兼容 -- 大多数开发者懒得碰。

但 v2.13 做了。而且做得比你想的更深。

人声消除:不是"挖空",是"深度衰减"

最简单的人声消除算法是左右声道相减(Mid/Side 分离)。人声通常在正中间(左右声道相同),相减后人声归零,伴奏保留。

但问题是:很多乐器也在正中间。主旋律吉他、贝斯、底鼓 -- 这些和人声同频段的居中乐器会被一并抹掉。结果就是:人声没了,音乐也塌了,听感像从水管里传出来的。

NASMusicTV 的方案是参考 Audacity 的官方建议:

  • 人声频段不是完全挖空,而是深度衰减保留 15% -- 留一点人声残影,不至于太空洞
  • Side 声道(立体声宽度信息)只轻度削减,保留 50% -- 保住混响和立体声宽度
  • 高通截止 8kHz -- 保留镲片和空气感
  • 补偿增益 1.25x -- 衰减处理后电平会掉,适度补偿避免削波

实际效果:人声大幅减弱但背景音乐完整不塌方。不会像专业伴奏那么干净,但在电视音响上 K 歌完全够用。

K 歌模式:全屏沉浸 + 逐字"前快后慢"

有了人声消除,下一步就是 K 歌体验。

播放页点「K歌」按钮 -> 进入全屏沉浸 K 歌页。双行歌词窗口逐行滚动 + 逐字变色推进。底部工具栏随时切换"原唱/伴奏"、退出返回播放页。

这里有个细节值得一提:逐字变色的节奏

最初版本是线性推进 -- 每个字均匀亮起,50% 进度时正好亮一半。但真实唱歌不是这样的:句首唱得快,句尾有拖音。所以后来改成了幂曲线 progress^0.6 -- 行内时间过半时已经覆盖约 2/3 的字,剩余的字在后半段慢慢亮起。这种"前快后慢"的节奏更接近真实演唱的呼吸感。

歌词框下缘还有一条 2dp 的青色渐变进度细线,实时指示整曲进度。纯视觉指示,不参与焦点和 seek -- 但那种"一条线慢慢走完一整首歌"的感觉,意外地治愈。


二、MTV:把电视变成音乐频道

K 歌做完了,下一个想法很自然:既然能搜到歌,能不能搜到 MV?

B 站:唯一现实选项

调研了一圈免费 MV 接口:

候选国内可用免登录播放可行性结论
B 站非官方 API直连免登录直链 mp4选用
网易云 MV可用需登录公共端点挡 MV 接口弃用
YouTube不可达需 API Key需爬 playerResponse排除
Archive.org可用免登录无中文歌 MV排除

B 站成了唯一选项。但 B 站的 API 有几个坑:

三步取流:搜索拿到 bvid -> 调 view 接口拿 cid -> 调 playurl 接口拿直链。三步 HTTP 请求,每一步都可能失败。

风控:B 站搜索接口对未登录请求有风控,可能返回 412。代码里做了 wbi/legacy 双路径回退 -- 先试 wbi 签名接口,失败回退非 wbi 变体。最终还是失败?按钮置暗,不打扰用户。

防盗链:B 站直链校验 Referer 和 User-Agent。OkHttp 请求头必须带 Referer: https://www.bilibili.com + 浏览器 UA,否则返回 403。

直链过期:B 站直链有小时级有效期。缓存必须带时间戳,过期重建。

全屏视频页 + K 歌歌词联动

MTV 按钮在播放页「K歌」旁边。搜到 MV 则亮起可点击,没搜到则半透明不可点。点击进入全屏视频页:

  • 独立 ExoPlayer 播放视频(不碰主音频播放器的 DSP 管线)
  • 进入时暂停主播放器,退出时恢复 -- 两套播放器互不干扰
  • 暗色渐变遮罩保证底部控制条可读
  • 可选叠加 K 歌逐字歌词(按「歌词」按钮切换)
  • 上一首/下一首/播放暂停/切换 -- 完整控制条

控制条 5 秒无操作自动虚化至 0.15 透明度(几乎看不见,不挡视频),遥控器一操作就完全显化。这个交互在手机上很常见(视频播放器都这么做),但在 TV 上用 Compose 实现需要注意:D-pad 焦点变化也要触发显化,不只是按钮点击。

连播模式:预搜 + 无缝切换

MV 播完后怎么办?最初版本是停在最后一帧,用户手动按返回。体验很差。

后来做了"连播模式":当前 MV 播放时,后台预搜下一首歌的 MV。MV 播完 -> 用预搜结果直接切换 -> 无闪烁、无混音。

这里有个工程难点:主播放器的音频不能漏出来

切歌时如果调 next(),主播放器会加载新歌并开始播放 -- 但此时用户还在看 MV 视频页,主播放器的音频和 MV 视频的音频会混在一起。

解决方案是 suppressPlayback 标志:进入 MTV 模式时置 true,所有 play() 调用都被拦截。退出时置 false,恢复正常播放。

还有个细节:pause() 方法原来有 if (it.isPlaying) 守卫 -- 如果 ExoPlayer 恰好在 BUFFERING 状态,isPlaying 返回 false,pause() 被跳过,缓冲结束后自动恢复播放。改成无条件 pause() 才彻底解决。

MV 切换状态机:2 轮后自动找更多

B 站搜索一首歌可能返回多个 MV(不同 up 主上传的不同版本)。用户可以按「切换」按钮换一个看。

但这里有个设计问题:如果只搜到一个,按「切换」没反应 -- 用户不知道是程序卡了还是真的只有一个。

最终设计了这样一个状态机:

  1. 有多个候选:按「切换」循环播放(A -> B -> C -> A)
  2. 循环 2 轮后:用户明显不满意现有候选 -> 自动触发重搜,排除已展示的 bvid,降低相似度阈值,从 B 站找更多结果
  3. 只有一个结果:直接触发重搜
  4. 重搜上限 2 次:防止无限重搜。阈值递降 0.5 -> 0.3 -> 0.1,每次放宽条件
  5. 重搜不打断播放:后台搜索,当前 MV 继续播。搜到新结果才切换,搜不到就提示"未找到更多视频"

switchMv 失败(网络抖动/视频被删)也不再静默吞掉 -- 显示"切换失败,请重试"提示,回退切换计数。

MV 持久缓存:跨会话记住你喜欢的版本

每次切歌都搜一遍 B 站太浪费。但直链会过期,不能直接缓存 URL。

方案是缓存 bvid(B 站视频唯一 ID,不过期)而非直链。播放时先查缓存拿 bvid,再 resolveMv(bvid) 获取新鲜直链。

更有意思的是 markCompleted 机制:MV 播完时(STATE_ENDED)写入持久缓存,playCount++。如果用户切换过 MV 后播完了新版本,覆盖旧 bvid -- 说明用户更认可这个版本。下次播同一首歌,直接用用户认可的 bvid。

缓存上限 5000 条,LRU 淘汰。存在 app 的 filesDir 下的 JSON 文件里,跨会话持久。


三、可视化均衡器:电视屏幕上的频谱动画

这个功能没什么技术深度,但视觉效果意外地好。

实时 FFT 频谱分析,3 种视觉主题:

  • ColorFlow:彩色渐变柱状图,频率越高颜色越暖
  • NeonPulse:霓虹脉冲,节拍感强
  • ClassicalWave:经典波形,优雅柔和

播放页底部一排跳动的频谱柱,配合封面和歌词 -- 那种"音乐可视化了"的感觉,在电视大屏上特别有冲击力。

技术实现上用的是 Android 的 Visualizer 类(android.media.audiofx.Visualizer),从 ExoPlayer 的 audio session id 拿到频谱数据,20fps 刷新渲染成 Compose Canvas。没什么花哨的算法,就是 FFT 数据映射到矩形高度 + 颜色渐变。


四、完整备份/恢复:换设备不丢设置

电视盒子坏了或者换了新电视,重新配置一遍所有设置是很痛苦的。

v2.16 的备份功能现在覆盖了所有设置项

  • 服务器地址(不含密码/Token)
  • 全部 App 设置(主题、动画、播放模式、缓存、歌词偏移、端点配置等)
  • 网络收藏、本地歌单、播放队列
  • 播放次数、最近播放、搜索历史
  • 均衡器预设和频段
  • 天气设置(开关、城市、自动刷新,API Key 不备份)
  • 封面滤镜(模糊、暗色遮罩)
  • 歌词字号
  • MV 持久缓存(bvid 映射表,跨设备复用)

导出为 JSON 文件存在 Downloads/NASMusic/,可以通过文件管理器或扫码传输到新设备。恢复后服务器需重新输入密码连接(敏感字段不备份),其余设置一键恢复。

之前有几个版本遗漏了天气设置、封面滤镜、歌词字号等 8 项 -- 这次全部补上了。旧版备份文件恢复时新字段用默认值,向后兼容。


五、一些技术细节

suppressPlayback:一标志封堵所有混音

MTV 模式下主播放器必须保持静音。但 ExoPlayer 的播放路径有多条:

  • resume() -- 用户退出沉浸模式时恢复
  • playQueue() -- 网络歌曲 URL 解析完成后播放
  • next() REPEAT_ONE 模式 -- 显式调 play()

每条路径都可能因为异步回调(URL 解析、歌曲自动过渡)在 MTV 模式下意外触发播放。加了一个 suppressPlayback 布尔标志,在这三个方法的 play() 调用前检查 -- 一个标志封堵所有路径。

advanceIndexSilently:不碰 ExoPlayer 的切歌

MTV 连播切歌时,主播放器的队列索引需要推进(这样退出 MTV 后播的是下一首),但不能调 next()(因为 next() 会触发 ExoPlayer 加载新歌并播放)。

advanceIndexSilently 只更新 _currentIndex_currentSong 两个 StateFlow,完全不碰 ExoPlayer。退出 MTV 时用 syncAndPlayCurrent() 同步 -- 用 setMediaItems 恢复完整队列 + seek 到当前索引,而不是 setMediaItem 替换成单曲(那样 next()/previous() 会失效)。

endedHandled 绑定 videoUrl

MTV 无缝切歌时不走 Searching 状态,MvPlaybackScreen 不离开 Composition。endedHandled(标记 STATE_ENDED 是否已处理)如果用 remember 不带 key,第一首 MV 设 true 后后续 MV 的 STATE_ENDED 全被忽略 -- 表现为"播几首后停在最后一帧"。

改成 remember(mv.videoUrl) -- 新 URL 触发标志重置,每首 MV 都能正常触发 onPlaybackEnded


六、版本历程

从 v2.6.2 到 v2.16.0,跨度虽然大,但核心就三件事:

  • v2.13.x:人声消除(DSP Mid/Side)+ K 歌全屏页 + 逐字"前快后慢"节奏 + 可视化均衡器
  • v2.14.0-v2.15.0:MTV 音乐视频搜索(B 站三步取流)+ 全屏视频页 + 连播预搜 + 上一首/下一首 + 多结果切换
  • v2.16.0:MV 持久缓存(bvid 跨会话 + markCompleted 追踪偏好)+ 切换状态机(2 轮重搜排除已展示)+ 控制条自动虚化 + 备份补全

测试用例从 89 条增长到 116 条(新增 MvSearchManagerTest 12 + BilibiliMvServiceTest 15,覆盖缓存/fallback/排除 bvid/阈值调整/解析)。


七、写在最后

从"能听歌看歌词"到"能 K 歌看 MV",NASMusicTV 走了 10 个版本。

老实说这些功能在手机 App 上不算新鲜 -- 网易云、QQ音乐都有 K 歌和 MV。但在 Android TV + NAS 这个组合上,能做到这个完成度的,目前可能就这一个。

电视大屏 + 音响 + 遥控器 + NAS 曲库 + B 站 MV -- 这套组合拼出来的体验,比想象中要好。播一首喜欢的歌,逐字歌词亮着,封面模糊做背景,频谱柱跳动,按一下 MTV 按钮切到 B 站 MV -- 那种"客厅变成了私人音乐空间"的感觉,真的会上瘾。

如果你有 Android TV 和 NAS,可以试试:

GitHub:github.com/hxzhang2000/

Release 页面有预编译 APK,下载装上就行。项目完全开源(GPL v3),欢迎 Star、Issue、PR。


本文介绍 NASMusicTV v2.16.0 的功能。项目遵循 GPL v3 开源协议。

编辑于 2026-08-09 · 著作权归作者所有
相关文章
开放式耳机首次拥有“安静权”:韶音OpenFit Pro用滤噪技术与自研超级单元重写品类规则百元价位能安心听歌DE大厂新品推荐?单边24单元的动铁耳机好听么? - 水月雨 Armature Art 24韶音OpenDots 2耳夹耳机使用体验:如何用「耳畔佩戴美学」将高质量音频融入日常生活?重新定义高端便携耳机新高度,蔚蓝北空MERNA耳机体验分享为什么越来越多人用通勤时间听播客?聊聊我从「随便听听」到认真选耳机的全过程,附韶音OpenDots 2耳夹式耳机测评体验音乐发烧友的无线之选:粤声HMpro2极光二代深度测评振翅于微毫之间:aune SR7000蝴蝶深度体验,硬核HiFi血统下的极致优雅有没有能替代迅雷和 IDM 的下载工具?聊聊我用了两个月的 FluxDown2026年挂耳式/开放式耳机选购指南,开放式耳机值得推荐吗?蛇圣、漫步者、南卡、韶音、小米开放式耳机怎么选择?2026年有什么戴着舒服又好用的耳夹式蓝牙耳机推荐?200以内的?终极对决:CD机 vs 数播,新手到底选哪个?2026年高性价比真无线蓝牙耳机推荐(6月更新)开放式耳机天花板?从"能听"到"好听"再到"恰到好处",韶音OpenFit Pro的进化之路索尼WF1000XM6降噪豆测评2026年8月最新HiFi有线耳机选购指南 | 高性价比hifi耳机横评,100~1500元价位有线HiFi机型全覆盖:森海塞尔/西圣/原道/铁三角等热门品牌机型全解析,百元入门到千元旗舰哪些值得买?复古仪式感,动听真实力:NAD C3030合并功放深度拆解评测这可能是世界上最硬核的iPod改造有没有可以替代 PotPlayer 的 PC 播放器软件推荐?深度用完几款AI录音卡后,讯飞让我理解什么叫真轻薄生产力