pygame.mixer.music.play() 无法识别 Fast Tracker(.xm 音乐格式)重复位置

Posted

技术标签:

【中文标题】pygame.mixer.music.play() 无法识别 Fast Tracker(.xm 音乐格式)重复位置【英文标题】:pygame.mixer.music.play() doesn't recognize Fast Tracker (.xm music format) repeat position 【发布时间】:2018-04-17 07:13:19 【问题描述】:

问题是:

我尝试无限循环播放 Fast Tracker 模块,但这样做只是从头开始重播音乐,而不是跟随重复位置。

示例: (这是模块https://api.modarchive.org/downloads.php?moduleid=153915#zeta_force_level_2.xm的来源)

import pygame

pygame.mixer.init()
pygame.mixer.music.load('/path/to/zeta_force_level_2.xm')
pygame.mixer.music.play(-1)

我想要实现的目标: 循环播放模块音乐,每次都在重复位置循环,而不是在轨道开始处循环。没有必要使用pygame:我使用它是因为我没有找到适合播放跟踪器音乐的东西

提前致谢。

【问题讨论】:

【参考方案1】:

更新:我在 cython 中编写了一个简单的演示,可以成功播放您链接的 .xm 文件。它基本上是this c demo code 的翻译。我的代码可以在this github page 上找到。为了让它在 Ubuntu 中工作,我必须安装 libxmp-dev 包。请注意,目前所有内容都是硬编码的,因此需要对其进行重构以更直接地在您的项目中使用。


这绝不是一个决定性的答案。在此过程中,我遇到了许多潜在的陷阱,这让我怀疑 pygame 是否适合这里的工作,但我将介绍到目前为止我发现的内容以及一些建议。

看起来.xm Fast Tracker MODule 格式与您典型的 wav/ogg/mp3 文件不同,它不仅可以播放一组样本数据,还可以组合不同的 MIDI乐器和样本一起创造你的音乐,就像问题中链接的(甜美的)chiptune。

事实证明,SDL/pygame 可以播放此类文件,但方式相当有限。查看pygame的music模块,有一个set_pos函数。但是,尝试使用它给了我一个pygame.error: set_pos unsupported for this codec。然而有趣的是,我可以通过使用pygame.mixer.music.play 和可选的start 关键字来解决这个问题。虽然大多数文件格式上的start 只是开始文件前几秒的偏移量(仅在歌曲的第一次播放时),但它对于MOD 文件(如问题中的.xm 文件)具有不同的含义。 Apparently,对应MOD文件中的pattern编号。因此,根据每个模式在文件中的起始位置,可以在 pygame 中使用的潜在起始点数量非常有限。

如果您想从一个特定的模式编号开始,那么下面的代码就足以循环。请注意,我使用 pygame 的事件系统来查看声音何时完成以使用适当的“模式偏移”“循环”声音文件:

import pygame

pygame.init()
pygame.mixer.music.load('zeta_force_level_2.xm')
pattern = 10
loop_event = pygame.USEREVENT + 1
pygame.mixer.music.set_endevent(loop_event)
pygame.mixer.music.play(start=pattern)

while True:
    for event in pygame.event.get():
        if event.type == loop_event:
            pygame.mixer.music.play(start=pattern)

此时,您可能想知道这些patterns 到底是什么?如果您的系统上安装了 ffmpeg,您可以在您的文件上运行 ffprobe 并获得以下输出:

Input #0, libmodplug, from 'zeta_force_level_2.xm':
  Metadata:
    name            : zeta force level 2
    instrument      : by zabutom --
                    : bye bye computer..
                    : see you in a week
    sample          : zeta force level 2
    extra info      : 20 patterns, 10 channels, 3/14 instruments, 1/14 sample
  Duration: 00:01:01.00, bitrate: 3 kb/s
    Stream #0:0: Audio: pcm_s16le, 44100 Hz, 2 channels, s16, 1411 kb/s

该文件中似乎有 20 种模式,您可以从中选择作为循环的起始位置。要获取有关您的特定文件的更多信息,您可以在 MilkyTracker 之类的工具中打开(并编辑!)您的文件并获得如下输出:

youtube 上有一些 MilkyTracker 的在线教程,但它看起来是一个相当复杂的软件。

似乎还有一个名为libxmp 的库及其对应的python binding。这应该处理将 MOD 文件数据“渲染”为简单 PCM 数组所需的转换,该数组可以在 pyaudio 或任何与 OpenAL 绑定的 python 库中播放。不管怎样,看起来你的工作已经完成了!

【讨论】:

libxmp-python 看起来很有趣,但我需要测试它是否正确重放。如果是,我会接受答案,无论如何谢谢你的回复。 @MaxLunar 我将在本周剩下的时间(再过 4 天)保持赏金开放,这将逐渐让您的问题更加清晰。考虑到未接受的问题也更有可能获得答案,我建议等待接受直到最后看看是否出现其他答案。 @MaxLunar 刚刚试用了我链接的库,想知道您使用的是什么操作系统平台和 python 版本?看起来 libxmp python 绑定可能是在考虑 python2 的情况下编写的...... @CodeSurgeon 我正在使用 python 3.5,实际上我想同时针对 Linux 和 Windows。我已经在 Win 上使用 pygame 测试了该解决方案,但似乎我搞砸了一些东西,或者它在这里不起作用(根本没有声音)。 @CodeSurgeon 在尝试播放跟踪器音乐时看起来也取决于系统。 Linux 也可以播放声音,但 Windows 不能。我也在努力实现可移植性,所以无论我在哪里开始我的脚本,它都应该播放声音。这有可能解决吗?谢谢。

以上是关于pygame.mixer.music.play() 无法识别 Fast Tracker(.xm 音乐格式)重复位置的主要内容,如果未能解决你的问题,请参考以下文章

如何在python中播放wav文件?