我正在开发一个从 Kivy 应用程序中接受 MIDI 键盘输入(使用 Mido)的应用程序。目标是让一个线程不断轮询 MIDI 输入并将事件路由到 pyfluidsynth,同时并行运行传统的 Kivy 应用程序。我需要某种并行进程,否则只要循环运行时 MIDI 轮询,Kivy UI 就会冻结。
经过多次摆弄,我让它工作了,但我有点担心代码。我尝试在 [if name == " main "]下启动线程,但只能运行一个进程,然后运行另一个进程。
然后不小心留下了mido_midi.py的最后两行代码,本来只是为了测试,我得到了想要的效果。现在,当我运行 main.py 时,我得到了应用程序和键盘输入。除了关闭应用程序时的一些丑陋行为外,事情似乎按我想要的方式工作。
我担心的是,我似乎无法通过从 main 调用所有内容来使线程工作。由于一切正常,我不明白为什么,这对我来说是错误的。我想我会把它扔给更聪明的人以获得洞察力。
我做得对吗?如果没有,我需要改变什么?谢谢。
主要.py:
from kivy.app import App
from kivy.uix.widget import Widget
from mido_midi import start_synth, KeyboardInput
class MyApp(App):
def build(self):
return GameWidget()
class GameWidget(Widget):
def __init__(self, **kwargs):
super().__init__(**kwargs)
...
self.midikeyboard = KeyboardInput()
...
if __name__ == "__main__":
app = MyApp()
app.run()
mido_midi.py:
import mido
import fluidsynth
import threading
def start_synth(driver, sound, channel=0):
fs = fluidsynth.Synth(samplerate=24000, gain=0.8)
fs.start(driver)
sfid = fs.sfload(sound)
fs.program_select(channel, sfid, 0, 0)
# print("Midi loaded...")
return fs
class KeyboardInput(threading.Thread):
def __init__(self, device='Keystation 88 Port 1', driver='coreaudio', sound='sounds/Wii_Grand_Piano.sf2', channel=0):
super(KeyboardInput, self).__init__()
self.played_notes = []
self.device = device
self.driver = driver
self.sound = sound
self.channel = channel
self.inport = mido.open_input(self.device)
self.fs = start_synth(self.driver, self.sound)
def run(self):
for msg in self.inport:
print(msg)
note = msg.note
velocity = msg.velocity
self.fs.noteon(self.channel, note, velocity)
# Code outside of the class, intended for testing
m = KeyboardInput()
m.start()
KeyboardInput
当您执行from mido_midi import start_synth, KeyboardInput
“测试”行时,您的代码正在启动线程。该if __name__ == "__main__":
构造旨在防止在导入包含该构造的文件时发生这种情况。另请注意,您有两个不同的KeyboardInput
. 不确定这是否是您的意图。
您应该能够通过在if __name__ == "__main__":
块内添加相同的两行来启动块内的线程:
m = KeyboardInput()
m.start()
如果你真的只想要一个实例KeyboardInput
,你应该能够做到
self.midikeyboard.start()
在你的__init__()
方法里面GameWidget
。
此外,如果您想更轻松地关闭,请添加daemon=True
到构造函数调用中,或者:
m = KeyboardInput(daemon=True)
要么
self.midikeyboard = KeyboardInput(daemon=True)
这daemon=True
意味着该线程将在应用程序完成后立即终止。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句