我写了一个音乐播放器(2022)

Lobsters Hottest 工具

摘要

一位开发者分享了构建“amused”的历程,这是一个极简音乐播放器,采用守护进程/客户端架构,利用Unix管道进行播放列表操作,强调简洁性和组合性。

<p><a href="https://lobste.rs/s/gtsgzs/i_wrote_music_player_2022">评论</a></p>
查看原文
查看缓存全文

缓存时间: 2026/07/27 15:46

# 我写了一个音乐播放器 来源:https://www.omarpolo.com/post/amused.html 2024/02/29 编辑:修正了一些拼写和链接,改进了标记。[这是前几天我发表在意大利语胶囊上那篇同题文章的局部不准确翻译。](gemini://it.omarpolo.com/articoli/amused.gmi) 出于好奇,我写了一个小音乐播放器。想法是看看能否在严格沙箱化的进程中解码音频文件。长话短说:这是个错误。最终我写了一个自己喜欢的东西,现在还得维护它! amused (https://git.omarpolo.com/?action=summary&path=amused.git) 这是一个小程序,在后台播放音乐,并通过一个非常简单的命令行界面进行控制: `` $ amused add *.mp3 # 将所有mp3文件加入队列 $ amused play playing /path/to/music.mp3 $ amused pause $ amused status paused /path/to/music.mp3 `` 就这些。好吧,说实话还有一点点内容。它在管道方面有一种独特的行为(我是说在其类别中),但在展示它如何与 Shell 配合之前,我想先描述一下我的思考过程。 最初的想法是有一个守护进程(“amused”)负责播放音乐,一个客户端(“playlistctl”?)负责控制。类似于 mpd/mpc 那样的模式。我很快就放弃了这个想法,转而采用单个可执行文件——amused——它既是守护进程又是客户端,并且在需要时自动启动守护进程。我想这样用起来更方便。 最早实现的命令之一是‘show’,用于打印所有已入队的文件。Amused 是一个简单的程序,只有当前播放队列的概念,我想尽可能保持简单。特别是我不想添加任何状态持久化机制。所有状态都通过命令行操作,并且是临时的:一旦你杀死它,一切就消失了。 然后我想,可以用‘show’命令将状态转储到磁盘,所以我写了‘load’命令来从文件重新导入: `` $ amused show > amused.dump $ # 然后,稍后…… $ amused load < amused.dump `` 可以说相当酷。到了这一步,我手头已经有一个自己开始真正喜欢的程序了,于是我想再加一些功能,这样我就可以每天实际使用它了。最先想到的功能之一就是操作播放队列:排序、打乱、删除重复项或特定歌曲……嗯,这并不难实现,但是否需要我自己编写这些功能呢?(最近我越来越多地思考这类问题。) 然后我有了一次“UNIX 启示”:我可以用 Shell! `` $ amused show > list $ sort -R < list > list.shuffled $ amused load < list.shuffled `` 这样可以工作,但输入起来相当繁琐。我可以做得更好。我可以使用管道! `` $ amused show | sort -R | amused load `` 非常感谢 Douglas McIlroy 提出管道的想法!这么多年过去了,它们依然如此重要。 老实说,要像这样使用管道,需要在客户端上做一些小改动以避免竞态:‘load’原本是‘flush’(清空播放列表)和每个文件一个‘add’的别名。如果由于管道的随机性以及时序问题,‘load’命令在‘show’之前执行,那么结果可不会好。不过,使其“无竞态”实际上非常简单,并且让‘load’命令更加健壮。 再举几个例子,以展示它如何很好地组合: - 从当前队列中移除所有 Guccini 的歌曲:`` $ amused show | grep -vi guccini | amused load `` - 加载 Dream Theater 全集:`` $ find ~/music/dream-theater | amused load `` - 用 fzf 选择一首歌:`` $ amused jump "$(amused show | fzf)" `` - ……或者用 dmenu!`` $ amused jump "$(amused show | dmenu)" `` 代码量也相当适中: `` % wc -l *.c | tail -1 2902 total `` 其中大约 500~1000 行是从其他 OpenBSD 程序中“借”来的,还有大约 500 行是各种音频格式的解码“后端”。 最困难的部分实际上是音频解码。我以前从未写过“音频代码”。好吧,我曾经为 Godot 提交过一个 sndio 后端 PR,但那一次引擎本身负责解码,驱动只需要播放给定的样本数组,所以有点作弊。我天真地以为每种格式都有自己的库和 API,这倒是合理。但不合理的是,这些库完全没有像样的文档!我指的是 libvorbisfile、libopusfile、libflac 和 libmad。这四个库没有一个提供 man 手册。不,我不认为 doxygen 生成的页面算是“文档”,那些充满 HTML 的头文件更不算!(谁,谁他妈觉得把 HTML 放在头文件里是个好主意?)当然,这些库的所有函数都在网页上有详细描述,但缺乏的是某种全局视图。(另外,示例代码大多很糟糕。) 幸运的是,它们用起来并不太难,一个毫无经验的人也能在几个小时内写出一个解码器。不过,我要特别提一下 libflac:它在我个人的“史上最烂 API 命名”列表中击败了 openssl。 我忘了一件事:amused 只针对 OpenBSD。这是我唯一使用的操作系统,我也只知道如何使用 sndio,所以……不过最终我可能会尝试制作一个可移植版本。 它是一个相当稳定的程序,我认为基本已经完成了,除了一些 bug 以及将来可能添加对更多音频格式的支持。这就引出了缺少的功能列表: - 某种“监视器”,用于记录事件:这可能有助于需要监控播放器状态的东西(例如配合 lemonbar 使用)。 - 快进和快退:我并不真的想实现,因为我再也不想碰音频代码了。 - 元标签:我喜欢元标签,但根据上一点,我尽可能不想再碰 lib\{vorbis,opus,flac,mad\} 的代码。 - 修复任何可能的 bug。:)

相似文章

现代应用

Lobsters Hottest

对现代代码编辑器的讽刺性观察,嘲弄过于复杂的AI功能、基于Electron的臃肿以及当代软件开发中的挫败感。

Jam-Pod

Product Hunt

Jam-Pod 是一款专为维护个人音乐收藏的用户设计的播放器。