在Python/PyGame上使用MIDI,Ubuntu 12.04

6 投票
3 回答
1817 浏览
提问于 2025-04-17 13:29

我在Ubuntu 12.04上尝试让MIDI接口和pygame一起工作。我知道键盘是可以用的,因为它可以控制vkeybd,并且在OSX上也能和PyGame一起使用,所以问题出在Python的MIDI上。

$ python -m pygame.examples.midi --list

Traceback (most recent call last):
  File "/usr/lib/python2.7/runpy.py", line 162, in _run_module_as_main
    "__main__", fname, loader, pkg_name)
  File "/usr/lib/python2.7/runpy.py", line 72, in _run_code
    exec code in run_globals
  File "/usr/lib/python2.7/dist-packages/pygame/examples/midi.py", line 820, in <module>
    print_device_info()
  File "/usr/lib/python2.7/dist-packages/pygame/examples/midi.py", line 25, in     print_device_info
    pygame.midi.init()
  File "/usr/lib/python2.7/dist-packages/pygame/midi.py", line 71, in init
    import pygame.pypm
ImportError: /usr/lib/libportmidi.so.0: undefined symbol: snd_seq_event_input_pending

我通过软件包管理器安装了python-pygame,还有python-pm。

有什么想法吗? :)

3 个回答

1

我在使用Frescobaldi这个Python应用时,遇到了和你一样的问题(我用的是Ubuntu 12.04.1),比如在播放MIDI的时候。这之前是可以正常工作的,但现在不行了。

很明显,这是一个在2013年1月25日发布的portmidi包编译错误。你可以查看这个链接了解更多信息:https://launchpad.net/ubuntu/+source/portmidi/1:200-0ubuntu1.12.04.1。我把它降级到之前的1:200-0ubuntu1版本后,问题解决了。

我觉得正确的做法是去Launchpad上对1:200-0ubuntu1.12.04.1版本提交一个bug报告,链接是:https://bugs.launchpad.net/ubuntu/+source/portmidi/+bugs。如果这个问题没有被修复,我们也可以问问falkTX,看他是否愿意在他的KXStudio PPAs中提供一个正常工作的包。

顺便说一下,这是我系统上1:200-0ubuntu1的libportmidi通过ldd命令得到的结果:

linux-vdso.so.1 =>  (0x00007fffe9bff000)
libasound.so.2 => /usr/lib/x86_64-linux-gnu/libasound.so.2 (0x00007f26264cb000)
libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f26262ae000)
libporttime.so.0 => /usr/lib/libporttime.so.0 (0x00007f26260ab000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f2625cec000)
libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f26259f0000)
libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007f26257eb000)
librt.so.1 => /lib/x86_64-linux-gnu/librt.so.1 (0x00007f26255e3000)
/lib64/ld-linux-x86-64.so.2 (0x00007f26269f4000)

而坏掉的1:200-0ubuntu1.12.04.1版本的结果是:

linux-vdso.so.1 =>  (0x00007fff9e3ff000)
libporttime.so.0 => /usr/lib/libporttime.so.0 (0x00007fb84ac71000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fb84a8b2000)
libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007fb84a694000)
/lib64/ld-linux-x86-64.so.2 (0x00007fb84b0af000)

所以,任何没有自己链接libasound2的应用程序都会出问题。具体来说,Python的portmidi模块就是这样。(这种错误还因为从Ubuntu 12.04开始,gcc默认使用--as-needed链接器标志而变得更严重。我敢打赌,Ubuntu的仓库里还有不少包是因为这个原因而坏掉的。)

1

如果你想现在就解决这个问题,可以去查看最新版本的 portmidi,然后按照下面的步骤来构建这个库(假设你已经把portmidi下载或解压到一个叫做portmidi的文件夹里):

cd portmidi
make -f pm_linux/Makefile 

默认安装不会构建动态版本的库,所以你需要像下面这样来构建一个:

gcc -shared -Wl,-soname,libportmidi.so.0 -o  pm_linux/libportmidi.so.0 pm_common/pmutil.o pm_linux/pmlinuxalsa.o pm_linux/pmlinux.o pm_common/portmidi.o -lasound

接着,你可以先备份一下旧的库(以防万一),然后把这个新的库复制到旧库的位置:

sudo cp /usr/lib/libportmidi.so.0 /usr/lib/libportmidi.so.0.orig
sudo cp pm_linux/libportmidi.so.0 /usr/lib/libportmidi.so.0

你的应用现在应该可以正常工作了...

4

虽然这不完全能回答你的问题,但可能会帮助你自己调试这个问题。

错误是这样的:

ImportError: /usr/lib/libportmidi.so.0: undefined symbol: snd_seq_event_input_pending

这个undefined symbol的意思是动态链接器找不到snd_seq_event_input_pending这个函数所需的代码。

在一个32位的Oneiric系统上,我们可以这样查看libportmidi.so.0的一些符号。

nm -DC /usr/lib/libportmidi.so.0 | grep snd_seq_event_input_pending

U snd_seq_event_input_pending

这告诉我们libportmidi库需要snd_seq_event_input_pending的代码,但这个符号是未定义的。所以为了让libportmidi正常工作,它还必须加载一个包含这个函数的额外库。

在Oneiric上,我发现这个符号是在libasound2.so.2中定义的。

nm -DC /usr/lib/i386-linux-gnu/libasound.so.2 | grep snd_seq_event_input_pending

000a0fa0 T snd_seq_event_input_pending

T表示这个函数存在,并且在代码段中。

通常,相关库的链接是自动进行的,因为libportmidi应该会引用libasound.so.2。在同一个系统上。

ldd /usr/lib/libportmidi.so.0

....
libasound.so.2 => /usr/lib/i386-linux-gnu/libasound.so.2 (0x00e35000)

这显示了libmidi依赖于libasound。在你评论中的ldd输出列表中没有提到libasound,所以在加载时它不会尝试自动动态链接libasound.so.2,这就导致了你的错误。

可能出现错误的原因有几个:

  • libportmidi的链接方式可能在Oneiric和Precise之间发生了变化。例如,libportmidi可能会尝试自己寻找libasound的依赖。(不太可能)。
  • libportmidi的打包中可能存在一个错误,它没有正确引用libasound.so.2。这可能是特定于平台的(例如,仅在64位系统上出现错误)。

我建议你尝试找出你系统中包含snd_seq_event_input_pending函数的库,然后反向推理,看看为什么它没有和libportmidi链接。

以下的bash命令可以帮助你找到实现snd_seq_event_input_pending的库。如果你什么都没找到,那说明你机器上安装的库有问题。

find /lib /usr/lib -name "lib*.so.*" | while read f; do
    if nm -DC "$f" | grep -q 'T snd_seq_event_input_pending'; then
        echo "$f"
    fi
done

撰写回答