简介与背景
当前 FeelUOwn 缺少听歌识曲(music recognition)功能,用户无法通过音频片段识别正在播放或周围环境中的歌曲。本提案计划实现该功能,让用户能够通过麦克风录音或捕获当前播放器输出进行歌曲识别。
方案概述
通过音频指纹服务(如 ACRCloud / AudD)识别歌曲,将结果匹配到已注册 provider 的歌曲并播放。实现分为两个阶段:Phase 1 支持麦克风模式(识别环境音乐),Phase 2 支持播放器输出捕获(识别当前播放的歌曲)。
Phase 1: 麦克风模式(MVP)
1.1 音频捕获
新增录音模块,使用跨平台库捕获麦克风输入:
- 方案:sounddevice(基于 PortAudio,跨平台)
- 录音时长:5-10 秒片段
- 格式:16-bit PCM,44100 Hz,单声道
- 输出:WAV 字节流 / base64 编码
- 抗噪:支持简单的录音前音量检测(避免空白片段)
# feeluown/recognizer/recorder.py
class Recorder:
def record(self, duration: float = 6) -> bytes:
"""Record from microphone, return WAV bytes."""
def has_signal(self) -> bool:
"""Check if there is audio signal above threshold."""
1.2 识别服务客户端
集成第三方音频指纹服务:
| 服务 |
免费额度 |
说明 |
| ACRCloud |
~1000次/月 |
成熟 SDK,支持 base64 音频片段,识别率高 |
| AudD |
~200次/月 |
简洁 REST API,支持文件/URL/麦克风 |
选择 ACRCloud 作为首选(成熟度最高),AudD 作为备选。
# feeluown/recognizer/service.py
class RecognizerService:
def __init__(self, config):
self.host = config.ACR_HOST
self.access_key = config.ACR_ACCESS_KEY
self.access_secret = config.ACR_ACCESS_SECRET
async def recognize(self, audio_data: bytes) -> RecognitionResult | None:
"""Send audio data to recognition service, return result."""
@dataclass
class RecognitionResult:
title: str
artists: list[str]
album: str | None
score: float # confidence 0~100
duration: int # ms
external_url: str # link to the service's result page
1.3 歌曲匹配
识别结果匹配到本地 provider 的歌曲:
# feeluown/recognizer/matcher.py
class SongMatcher:
def __init__(self, library):
self._library = library
async def match(self, result: RecognitionResult) -> list[SongModel]:
"""Search in all providers and return matched songs sorted by confidence."""
利用现有 app.library.a_search() 跨 provider 搜索,按标题/艺术家相似度排序。
1.4 配置管理
在设置中添加识别服务配置项(通过 config.deffield()):
| 配置项 |
说明 |
RECOGNIZER_ENABLED |
启用/禁用(bool,默认 false) |
RECOGNIZER_SERVICE |
服务商选择("acrcloud" / "audd") |
RECOGNIZER_ACR_HOST |
ACRCloud 主机地址 |
RECOGNIZER_ACR_ACCESS_KEY |
ACRCloud Access Key |
RECOGNIZER_ACR_ACCESS_SECRET |
ACRCloud Access Secret(加密存储) |
RECOGNIZER_RECORD_DURATION |
录音时长秒数(int,默认 6) |
RECOGNIZER_SHOW_NOTIFICATION |
识别成功后显示通知(bool,默认 true) |
1.5 UI 集成
在播放器控制栏添加"识别"按钮:
按钮行为:
- 点击后按钮变为红色脉冲动画,开始录音
- 录音完成后发送识别请求
- 成功:弹出结果对话框,显示匹配歌曲,可点击播放
- 失败:显示 msg("未识别" / "网络错误")
结果对话框(RecognizerResultDialog):
- 显示识别到的歌曲信息(封面、标题、艺术家、专辑)
- 匹配到的 provider 歌曲列表(可点击播放)
- "重新识别" 按钮
- 自动添加到播放历史的选项
1.6 键盘快捷键
新增全局快捷键:
Ctrl+Shift+R / Cmd+Shift+R:开始听歌识曲
- 可在设置中自定义
Phase 2: 播放器输出捕获(后续迭代)
难点:当前播放器基于 libmpv(feeluown/player/mpvplayer.py),不暴露原始 PCM 音频数据,无法直接获取当前播放的音频流。
方案探索(三选一):
| 方案 |
优势 |
劣势 |
| ① mpv ao_capture |
纯软件方案,无额外依赖 |
需扩展 python-mpv(feeluown/mpv.py),CFFI 绑定层改动大 |
| ② OS 级音频回环 |
通用方案,不依赖 mpv |
跨平台差异大:WASAPI/Win + PulseAudio/Linux + CoreAudio/macOS;实现复杂 |
| ③ 虚拟音频设备 |
稳定,音质无损 |
需用户安装驱动(如 VB-Cable、BlackHole),门槛高 |
建议优先探索 方案①(ao_capture),如不可行则转用 方案②(平台适配)。
Phase 2 的 UI 行为会有所不同:
- 识别当前正在播放的歌曲
- 按钮可显示"识别当前播放"
- 支持识别结果与当前歌曲对比(确认播放的是什么版本)
文件结构
feeluown/recognizer/ # 新建模块
├── __init__.py # 插件入口:enable/disable
├── recorder.py # 音频录制
├── service.py # 识别服务客户端
├── matcher.py # 歌曲匹配
├── models.py # RecognitionResult 等数据模型
└── ui.py # 按钮、对话框等 UI 组件
修改的现有文件:
feeluown/gui/uimain/player_bar.py — 添加识别按钮
feeluown/gui/components/btns.py — 新增识别按钮组件
feeluown/app/app.py — 注册 recognizer 模块(可选)
实现步骤(PR 拆分建议)
PR 1: 基础设施(~300 行)
PR 2: 识别服务集成(~250 行)
PR 3: UI 与交互(~200 行)
PR 4: 完善与优化
不在本次范围内
- 完整的离线音频指纹库(需要大量歌曲数据训练)
- 歌词自动滚动匹配(需要实时音频对齐)
- 翻唱/现场版识别(指纹服务能力有限)
- 跨平台音频回环捕获的完整实现(Phase 2 作为探索性工作)
参考
- ACRCloud API 文档
- AudD API 文档
feeluown/player/mpvplayer.py — 当前播放器实现
feeluown/mpv.py — python-mpv CFFI 绑定
feeluown/gui/uimain/player_bar.py — 播放器控制栏 UI
feeluown/gui/components/btns.py — 现有按钮组件
feeluown/utils/request.py — 网络请求工具
feeluown/plugin.py — 插件系统
feeluown/local/__init__.py — 参考插件实现
简介与背景
当前 FeelUOwn 缺少听歌识曲(music recognition)功能,用户无法通过音频片段识别正在播放或周围环境中的歌曲。本提案计划实现该功能,让用户能够通过麦克风录音或捕获当前播放器输出进行歌曲识别。
方案概述
通过音频指纹服务(如 ACRCloud / AudD)识别歌曲,将结果匹配到已注册 provider 的歌曲并播放。实现分为两个阶段:Phase 1 支持麦克风模式(识别环境音乐),Phase 2 支持播放器输出捕获(识别当前播放的歌曲)。
Phase 1: 麦克风模式(MVP)
1.1 音频捕获
新增录音模块,使用跨平台库捕获麦克风输入:
1.2 识别服务客户端
集成第三方音频指纹服务:
选择 ACRCloud 作为首选(成熟度最高),AudD 作为备选。
1.3 歌曲匹配
识别结果匹配到本地 provider 的歌曲:
利用现有
app.library.a_search()跨 provider 搜索,按标题/艺术家相似度排序。1.4 配置管理
在设置中添加识别服务配置项(通过
config.deffield()):RECOGNIZER_ENABLEDRECOGNIZER_SERVICERECOGNIZER_ACR_HOSTRECOGNIZER_ACR_ACCESS_KEYRECOGNIZER_ACR_ACCESS_SECRETRECOGNIZER_RECORD_DURATIONRECOGNIZER_SHOW_NOTIFICATION1.5 UI 集成
在播放器控制栏添加"识别"按钮:
按钮行为:
结果对话框(
RecognizerResultDialog):1.6 键盘快捷键
新增全局快捷键:
Ctrl+Shift+R/Cmd+Shift+R:开始听歌识曲Phase 2: 播放器输出捕获(后续迭代)
难点:当前播放器基于
libmpv(feeluown/player/mpvplayer.py),不暴露原始 PCM 音频数据,无法直接获取当前播放的音频流。方案探索(三选一):
python-mpv(feeluown/mpv.py),CFFI 绑定层改动大建议优先探索 方案①(
ao_capture),如不可行则转用 方案②(平台适配)。Phase 2 的 UI 行为会有所不同:
文件结构
修改的现有文件:
feeluown/gui/uimain/player_bar.py— 添加识别按钮feeluown/gui/components/btns.py— 新增识别按钮组件feeluown/app/app.py— 注册 recognizer 模块(可选)实现步骤(PR 拆分建议)
PR 1: 基础设施(~300 行)
feeluown/recognizer/模块和插件入口models.py(RecognitionResult 等)recorder.py(麦克风录音)PR 2: 识别服务集成(~250 行)
service.py(ACRCloud 客户端)matcher.py(跨 provider 匹配)PR 3: UI 与交互(~200 行)
PR 4: 完善与优化
不在本次范围内
参考
feeluown/player/mpvplayer.py— 当前播放器实现feeluown/mpv.py— python-mpv CFFI 绑定feeluown/gui/uimain/player_bar.py— 播放器控制栏 UIfeeluown/gui/components/btns.py— 现有按钮组件feeluown/utils/request.py— 网络请求工具feeluown/plugin.py— 插件系统feeluown/local/__init__.py— 参考插件实现