在Python/PyGame上使用MIDI,Ubuntu 12.04
我在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 个回答
我在使用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的仓库里还有不少包是因为这个原因而坏掉的。)
如果你想现在就解决这个问题,可以去查看最新版本的 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
你的应用现在应该可以正常工作了...
虽然这不完全能回答你的问题,但可能会帮助你自己调试这个问题。
错误是这样的:
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