Pygame 读取 MIDI 输入

Pygame read MIDI input

我参考了 Pygame MIDI documentation and this code 来尝试让 MIDI 输入工作。 MIDI 接口 (Avid Eleven Rack) 从我的 MIDI 控制器接收 MIDI 数据,在我的音频软件 (Pro Tools) 中效果很好。然而,使用Pygame,我似乎根本无法阅读任何信息。

源代码

import pygame
from pygame.locals import *
from pygame import midi

class MidiInput():
    def __init__(self):
        # variables
        self.elevenRackInID = 2

        # init methods
        pygame.init()
        pygame.midi.init()
        self.midiInput = pygame.midi.Input(self.elevenRackInID, 100)

    def run(self):
        # print(pygame.midi.Input(3, 100))
        # for i in range(10):
            # print(pygame.midi.get_device_info(i), i)
        self.read = self.midiInput.read(100)
        # self.convert = pygame.midi.midis2events(self.read, self.elevenRackInID)
        print(self.read)

test = MidiInput()
while True:
   test.run()

唯一打印到控制台的是空方括号:

[]

附加信息

刚刚又查了一下:输入的ID是对的,确实是一个输入

"self.midiInput.poll()" returns 错误。所以根据 Pygame 文档,没有数据进来。

您可以在下方查看数据、轮询和设备信息:

data: [] || poll: False || device info: (b'MMSystem', b'Eleven Rack', 1, 0, 1)

我所有 MIDI 设备的列表,根据 Pygame(带索引):

(b'MMSystem', b'Microsoft MIDI Mapper', 0, 1, 0) 0
(b'MMSystem', b'External', 1, 0, 0) 1
(b'MMSystem', b'Eleven Rack', 1, 0, 1) 2
(b'MMSystem', b'Maschine Mikro MK2 In', 1, 0, 0) 3
(b'MMSystem', b'Microsoft GS Wavetable Synth', 0, 1, 0) 4
(b'MMSystem', b'External', 0, 1, 0) 5
(b'MMSystem', b'Eleven Rack', 0, 1, 0) 6
(b'MMSystem', b'Maschine Mikro MK2 Out', 0, 1, 0) 7

非常感谢任何帮助或建议!

我在另一个论坛上得到了答案。事实证明,有一个示例文件显示了如何使代码工作。 所以如果其他人偶然发现了这个问题,这里是示例代码的有用部分:

import sys
import os

import pygame as pg
import pygame.midi


def print_device_info():
    pygame.midi.init()
    _print_device_info()
    pygame.midi.quit()


def _print_device_info():
    for i in range(pygame.midi.get_count()):
        r = pygame.midi.get_device_info(i)
        (interf, name, input, output, opened) = r

        in_out = ""
        if input:
            in_out = "(input)"
        if output:
            in_out = "(output)"

        print(
            "%2i: interface :%s:, name :%s:, opened :%s:  %s"
            % (i, interf, name, opened, in_out)
        )


def input_main(device_id=None):
    pg.init()
    pg.fastevent.init()
    event_get = pg.fastevent.get
    event_post = pg.fastevent.post

    pygame.midi.init()

    _print_device_info()

    if device_id is None:
        input_id = pygame.midi.get_default_input_id()
    else:
        input_id = device_id

    print("using input_id :%s:" % input_id)
    i = pygame.midi.Input(input_id)

    pg.display.set_mode((1, 1))

    going = True
    while going:
        events = event_get()
        for e in events:
            if e.type in [pg.QUIT]:
                going = False
            if e.type in [pg.KEYDOWN]:
                going = False
            if e.type in [pygame.midi.MIDIIN]:
                print(e)

        if i.poll():
            midi_events = i.read(10)
            # convert them into pygame events.
            midi_evs = pygame.midi.midis2events(midi_events, i.device_id)

            for m_e in midi_evs:
                event_post(m_e)

    del i
    pygame.midi.quit()

你可以在这个目录下自己找到文件: C:\Users\myUser\AppData\Roaming\Python\Python37\site-packages\pygame\examples\midi.py

'myUser' 替换为您的 Win 用户名。此外,'Python37' 可能因您安装的 Python 版本而异。

我不相信 Leonhard W 在下面发布的代码可用:pygame.midi poll() 方法和 pygame.midi read() 方法都没有阻塞。结果是 CPU 消费飙升 (~50%)。

当然,在实践中读取 MIDI 事件的代码将 运行 在单独的线程中,尽管这对 CPU 消耗没有帮助。

为了回应其他地方的另一个非常有用的评论,我查看了 Mido 库 (https://mido.readthedocs.io/en/latest/index.html#)。这提供了阻塞读取方法,只需几行代码,我就可以从 MIDI 控制器键盘查找消息并将它们传递到 MIDI 合成器。

import mido

names = mido.get_input_names()
print(names)
out_port = mido.open_output()

with mido.open_input(names[0]) as inport:
    for msg in inport:
        out_port.send(msg)

唯一的缺点是我在击键和听到音符之间有明显的延迟(可能是 1/4 秒)。哦,好吧,向前和向上。