使用PyAudio和TK在关键持有上演奏音符

时间:2016-12-18 19:22:28

标签: python tk pyaudio

我希望使用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()

2 个答案:

答案 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]