我希望使用python播放关键持有音符。我目前正在实施和修改找到的here代码。但是,我遇到的问题是,当按住键时会重复调用keydown函数,导致每次调用keydown函数时音频切入和切出。
我正在寻找一种方法来保持弹奏和弦的能力,但是通过不在同一个键上调用keydown来删除此内外切换,直到在所述键上调用了键盘。我一直在研究的代码的具体部分如下所示。
提前致谢。
p = pyaudio.PyAudio()
chord = Chord()
gen = NoteGen()
def callback(in_data, frame_count, time_info, status):
wave = chord(frame_count)
data = wave.astype(numpy.float32).tostring()
return (data, pyaudio.paContinue)
stream = p.open(
format=pyaudio.paFloat32,
channels=1,
rate=44100,
output=True,
stream_callback=callback
)
stream.start_stream()
def keydown(event):
k = gen(event.char)
print("add note: " + event.char)
chord.add_note(k)
print [(n.name, n.frequency) for n in chord.notes]
def keyup(event):
k = gen(event.char)
print("remove note: " + event.char)
chord.remove_note(k)
print [n.name for n in chord.notes]
root = Tk()
frame = Frame(root, width=100, height=100)
frame.bind_all("<KeyPress>", keydown)
frame.bind_all("<KeyRelease>", keyup)
frame.pack()
root.mainloop()
stream.stop_stream()
stream.close()
p.terminate()
答案 0 :(得分:1)
有一个字典,其中包含一个键代码作为键,并将该键的状态(例如布尔值)作为值。
因此,当调用key down时,检查键码是否在dict中,如果不是只是添加值1.并开始播放音符。 如果存在,请检查该键的状态,如果按下则忽略该事件。否则去玩这个音符。 在键上,将键的状态设置为0。
另外,不要使用回调来播放音频,打断这样的播放音符会让你做恶梦。
最好在流中写入一个内容中的注释。
以块的形式写入数据并检查停止标志。
当调用key up时设置标志并执行:
stream.stop_stream(); stream.start_stream()
准确切断声音。
将写入部分放入try-except块中,这样当你强制流从线程外部停止时,没有任何不好的事情发生。
如果您希望更好地使用pyaudio进行此类操作,这将允许您一次播放多个声音,请搜索PyPI for SWmixer模块。你还需要numpy。然后使用SWMixer将每个声音加载到自己的对象中,然后根据需要启动和停止它。它的用法与pygame.mixer模块非常相似。
顺便说一句,如果你尝试并行使用多个PyAudio流,我不确定这是如何工作的。
我的意思是,我知道你可以平行地使用一个输出和一个输入流而没有太多麻烦,但是超过2个输出流可能会导致一些输出流。这就是我提到SWMixer的原因。我从未尝试使用过多个,所以我可能错了。
但我确实尝试过使用PyAudio的多个实例。它的工作原理是减少以前调用的音量。所以我也发生了溪流。所以你会听到最后一个音符比之前开始的声音更大,或者你可能会发出有趣的声音。
答案 1 :(得分:0)
您可以使用一些全局变量来检查是否已经触发了keydown事件。
key_pressed = False
def keydown(event):
if key_pressed:
return
key_pressed = True
k = gen(event.char)
print("add note: " + event.char)
chord.add_note(k)
print [(n.name, n.frequency) for n in chord.notes]
def keyup(event):
key_pressed = False
k = gen(event.char)
print("remove note: " + event.char)
chord.remove_note(k)
print [n.name for n in chord.notes]