You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Windows11/64下如何让Python调用PortMidi C库?

Windows11 x64下Python对接PortMidi的问题解决指南

系统库路径配置

  • 将编译好的portmidi.dll放到以下任意位置:
    • Python安装目录下的DLLs文件夹
    • 系统C:\Windows\System32文件夹
    • 或把dll所在目录添加到系统环境变量PATH,添加后重启终端/IDE生效
  • 对于portmidi.lib,可将其放入VS默认库目录(如C:\Program Files (x86)\Microsoft Visual Studio\2022\BuildTools\VC\Tools\MSVC\[版本号]\lib\x64,路径根据你的VS版本调整),或在后续调用时手动指定lib路径。

ctypes方案:Pm_Write访问冲突排查

PortMidi的Pm_Write函数原型为:

PmError Pm_Write(PmStream *stream, const PmEvent *buffer, int32_t length);

按以下步骤排查问题:

  1. 确认PmEvent结构体定义正确
    x64下必须匹配PortMidi的类型定义,ctypes中应写为:

    class PmEvent(ctypes.Structure):
        _fields_ = [("message", ctypes.c_uint32),
                    ("timestamp", ctypes.c_uint32)]
    

    注意使用c_uint32,避免因类型大小不匹配导致指针越界。

  2. 检查调用参数的合法性

    • 确保stream是Pm_OpenOutput返回的有效指针,调用Pm_OpenOutput后需检查返回值是否为0(成功)
    • 传递事件数组时,直接传入数组对象即可,无需手动用byref或pointer转换:
      # 创建2个事件的数组
      events = (PmEvent * 2)()
      events[0].message = 0x904040  # 示例NoteOn消息
      events[0].timestamp = 0
      # 直接传数组,ctypes自动转为指针
      pm.Pm_Write(stream, events, 2)
      
  3. 指定正确的调用约定
    PortMidi默认使用cdecl调用约定,加载dll时需明确指定:

    pm = ctypes.CDLL("portmidi.dll", ctypes.CDECL)
    

    不要用ctypes.windll(默认stdcall),避免调用栈异常。

  4. 验证初始化流程
    确保Pm_Initialize()返回0(初始化成功),设备枚举、打开输出流的每一步都检查返回值,排除前置操作导致的非法指针。


Cython方案:编译错误修复

基于过时的pyportmidi修改,按以下步骤调整:

  1. 修正setup.py配置
    明确指定头文件、库文件路径,匹配x64编译选项:

    from setuptools import setup, Extension
    from Cython.Build import cythonize
    
    ext_modules = [
        Extension(
            "pyportmidi",
            sources=["pyportmidi.pyx"],
            include_dirs=["你的PortMidi头文件目录"],
            libraries=["portmidi"],
            library_dirs=["你的PortMidi库文件目录"],
            extra_compile_args=["/MD"],  # 与PortMidi编译时的多线程DLL选项一致
        )
    ]
    
    setup(
        name="pyportmidi",
        ext_modules=cythonize(ext_modules)
    )
    
  2. 修复pyx文件的类型与语法

    • 在pyx文件开头添加标准类型定义,适配x64:
      cdef extern from "<stdint.h>":
          ctypedef int int32_t
          ctypedef unsigned int uint32_t
      
    • 正确定义PmEvent结构体:
      cdef struct PmEvent:
          uint32_t message
          uint32_t timestamp
      
    • 确保函数声明与PortMidi原型完全一致,比如Pm_Write:
      cdef extern from "portmidi.h":
          int Pm_Write(void *stream, const PmEvent *buffer, int32_t length)
      
  3. 使用正确的编译环境
    打开VS的x64 Developer Command Prompt,执行编译命令:

    python setup.py build_ext --inplace
    

    必须用x64编译环境,确保与Python、PortMidi的位数一致,避免链接错误。

内容的提问来源于stack exchange,提问作者user1441998

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.31 17:45:27