Python 使用PyAudio和TK在按住键时播放备忘

Python 使用PyAudio和TK在按住键时播放备忘,python,tk,pyaudio,Python,Tk,Pyaudio,我希望使用python在按住键时播放一个音符。我目前正在实现和修改找到的代码。然而,我面临的问题是,当按住键时,会重复调用keydown函数,导致每次调用keydown函数时都会出现音频插入和输出 我正在寻找一种保持和弦弹奏能力的方法,但在对同一个键调用keyup之前,不要对同一个键调用keydown,以消除这种进进出出的剪切。我一直在研究的代码的具体部分如下所示 提前谢谢 p = pyaudio.PyAudio() chord = Chord() gen = NoteGen() def ca

我希望使用python在按住键时播放一个音符。我目前正在实现和修改找到的代码。然而,我面临的问题是,当按住键时,会重复调用keydown函数,导致每次调用keydown函数时都会出现音频插入和输出

我正在寻找一种保持和弦弹奏能力的方法,但在对同一个键调用keyup之前,不要对同一个键调用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()
p=pyaudio.pyaudio()
chord=chord()
gen=NoteGen()
def回调(帧内数据、帧计数、时间信息、状态):
波浪=弦(帧计数)
data=wave.astype(numpy.float32).tostring()
返回(数据,pyaudio.paccontinue)
溪流=p.打开(
format=pyaudio.paFloat32,
通道=1,
费率=44100,
输出=真,
stream_callback=回调
)
stream.start_stream()
def按键关闭(事件):
k=gen(event.char)
打印(“添加注释:+event.char”)
和弦。加上音符(k)
为和弦中的n个音符打印[(n.名称,n.频率]
def keyup(事件):
k=gen(event.char)
打印(“删除注释:+event.char”)
和弦。删除注释(k)
打印[n.和弦中n的名称.注释]
root=Tk()
框架=框架(根,宽度=100,高度=100)
frame.bind_all(“,向下键)
frame.bind_all(“,keyup)
frame.pack()
root.mainloop()
stream.stop_stream()
stream.close()
p、 终止()

您可以使用一些全局变量来检查是否已经触发了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]

拥有一个字典,其中包含一个键代码作为键,该键的状态(例如布尔值)作为值

因此,当调用key down时,检查key代码是否在dict中,如果不是,只需将其与值1相加。然后开始演奏音符。 如果存在,请检查该键的状态,如果按下,则忽略该事件。否则就去演奏这个音符。 在设置键时,将键的状态设置为0

而且,也不要使用回调来播放音频,打断这样播放的音符会让你做噩梦

最好将线程中的注释写入流

分块写入数据并检查停止标志

调用“向上键”时,设置标志并执行以下操作:

stream.stop_stream(); stream.start_stream()
准确地切断声音

将编写部分放入try-except块,这样当您强制流从线程外部停止时,就不会发生任何错误

如果您希望有更好的方式使用pyaudio来实现这些功能,这将允许您一次播放多个声音,请在PyPI中搜索SWmixer模块。你还需要numpy。然后使用SWMixer将每个声音加载到它自己的对象中,并根据需要启动和停止它。它的用法与pygame.mixer模块非常相似

顺便说一句,如果您尝试并行使用多个PyAudio流,我不确定这将如何工作

我的意思是,我知道您可以并行使用一个输出流和一个输入流,而不会有太多麻烦,但是超过2个输出流可能会导致一些问题。这就是我提到SWMixer的原因。我从来没有尝试过使用多个,所以我可能是错的


但我确实尝试过使用PyAudio本身的多个实例。它的工作原理是减少以前称之为的数量。因此,我的想法也适用于溪流。因此,您将听到最后一个音符的声音比之前开始的要大,或者您可能会听到一些奇怪的声音。

正如您所看到的,变量名为chord。所以最终的目标是能够同时演奏多个音符。如果我没有大错特错的话。因此,一个变量不行。@Dalen,这就是一个例子。我们可以制作一个变量数组,或者一个具有不同键的字典并检查它。正如我所看到的,目前只有一个音符(44100赫兹)在任何键上播放。是的,是的,就这样!