Python PyAudio在线程中播放连续流,并允许更改频率
我根本没有穿线的经验 我想做的就是播放一个声音,并能够同时使用GUI更改音调(频率) 此代码播放连续流,没有任何峰值或失真:Python PyAudio在线程中播放连续流,并允许更改频率,python,audio,python-multithreading,pyaudio,Python,Audio,Python Multithreading,Pyaudio,我根本没有穿线的经验 我想做的就是播放一个声音,并能够同时使用GUI更改音调(频率) 此代码播放连续流,没有任何峰值或失真: class Stream: def __init__(self, sample_rate): self.p = pyaudio.PyAudio() self.sample_rate = sample_rate # for paFloat32 sample values must be in range [-1.0
class Stream:
def __init__(self, sample_rate):
self.p = pyaudio.PyAudio()
self.sample_rate = sample_rate
# for paFloat32 sample values must be in range [-1.0, 1.0]
self.stream = self.p.open(format=pyaudio.paFloat32,
channels=1,
rate=sample_rate,
output=True)
self.samples = 0.
def create_sine_tone(self, frequency, duration):
# generate samples, note conversion to float32 array
self.samples = (np.sin(2 * np.pi * np.arange(self.sample_rate * duration) * frequency
/ self.sample_rate)).astype(np.float32)
def play_sine_tone(self, volume=1.):
"""
:param frequency:
:param duration:
:param volume:
:param sample_rate:
:return:
"""
# play. May repeat with different volume values (if done interactively)
while 1:
self.stream.write(volume * self.samples)
def terminate(self):
self.p.terminate()
def finish(self):
self.stream.stop_stream()
self.stream.close()
此代码创建GUI。在左键单击
和右键单击
中,创建正弦音()。但是,据我所知,它修改了play\u sine\u tone
中threading
使用的内存,程序崩溃
def main():
window = Tk()
window.title("Piano reference")
window.geometry('350x200')
s = Stream(44100)
lbl = Label(window, text="A4")
lbl.grid(column=2, row=1)
def left_click(frequency):
s.create_sine_tone(frequency, 1.)
t = threading.Thread(target=s.play_sine_tone, args=(1,))
t.start()
lbl.configure(text=frequency)
def right_click(frequency):
s.create_sine_tone(frequency, 1.)
t = threading.Thread(target=s.play_sine_tone, args=(1,))
t.start()
lbl.configure(text=frequency)
btn1 = Button(window, text="<<", command=lambda: left_click(100))
btn2 = Button(window, text=">>", command=lambda: right_click(200))
btn1.grid(column=0, row=0)
btn2.grid(column=1, row=0)
window.mainloop()
def main():
window=Tk()
窗口标题(“钢琴参考”)
窗口几何(“350x200”)
s=流量(44100)
lbl=标签(窗口,text=“A4”)
lbl.grid(列=2,行=1)
def左键单击(频率):
s、 创建正弦音调(频率,1.)
t=threading.Thread(target=s.play\u sine\u tone,args=(1,))
t、 开始()
lbl.configure(文本=频率)
def右键单击(频率):
s、 创建正弦音调(频率,1.)
t=threading.Thread(target=s.play\u sine\u tone,args=(1,))
t、 开始()
lbl.configure(文本=频率)
btn1=按钮(窗口,文本=”,命令=lambda:右键单击(200))
btn1.网格(列=0,行=0)
btn2.网格(列=1,行=0)
window.mainloop()
如何修改wave,使程序不会崩溃?也许我可以在更改频率之前关闭线程?我找不到答案。据我所知:
循环声音中有“咔哒”声。必须生成信号的整个周期
您可以将流
与回调一起使用
,这样线程将移动到PyAudio
的引擎盖下。使用它,我能够以公认的方式运行程序
我有一些关于创建两个线程对象的想法,它们将成为Stream
类的字段。然后他们可以使用2个不同的流和线程来启动和停止。但是我没能让它工作-我认为线程没有等待finish()
如果您所要做的只是播放可以使用GUI控制的不同音调,那么您可能不需要线程
提供基于Tkinter(和其他工具)的超级易于使用的GUI生成器。最重要的是,它提供了基于GUI组件驱动的事件的操作
另一方面,使用的给了我们创建不同音调并播放它们的简单方法。
pydub\u play\u with_simpleudio
方法允许我们以非阻塞方式使用simpleudio播放音调
GUI控件:
- “>>”以200 Hz的倍数选择下一个频率
- 这不是一个答案,你可能想把这些评论添加到你的问题中,或者在你的问题下单独发布为“评论”。谢谢。我会留下它,因为已经有一些其他的评论和答案了,我不想把事情搞得一团糟,但我肯定会记得下次当你在正确的轨道上时,你可以在选择新频率后和播放新频率前关闭现有的播放声音的线程。或者,根本不使用线程,跟踪峰值,让现有频率在启动新频率之前完成峰值。这样你就不会在频移时听到咔哒声。我不确定这是否是我问题的答案,但它解决了我的问题。下一次,我将寻找更好的工具,而不是与几乎长时间工作的代码作斗争。我能够消除休眠,并且工作没有问题。这对点击没有帮助。这看起来像是“停止”呼叫,因为如果我删除停止呼叫,我就听不到一声咔嗒声。这些音调都是在自己的上方播放的,但它们都是在没有点击的情况下开始播放的。我也尝试过不使用淡入淡出,这似乎改善了点击率。也许它会通过立即开始下一个音调来掩盖它?是的,我也观察到了同样的情况。停止呼叫会突然停止提示音,重新启动时出现延迟,导致咔嗒声。尽管它在彼此的基础上演奏得很优美,产生了谐波。也许在开始下一个后尝试停止上一个可能会起作用。可能需要两个play_obj。
import PySimpleGUI as sg
from pydub.generators import Sine
from pydub import AudioSegment
from pydub.playback import _play_with_simpleaudio
import time
sr = 44100 # sample rate
bd = 16 # bit depth
l = 10000.0 # duration in millisec
sg.ChangeLookAndFeel('BluePurple')
silent = AudioSegment.silent(duration=10000)
FREQ = 200
def get_sine(freq):
#create sine wave of given freq
sine_wave = Sine(freq, sample_rate=sr, bit_depth=bd)
#Convert waveform to audio_segment for playback and export
sine_segment = sine_wave.to_audio_segment(duration=l)
return sine_segment
# Very basic window. Return values as a list
layout = [
[sg.Button('<<'), sg.Button('>>')],
[sg.Text('Processing Freq [Hz]:'), sg.Text(size=(15,1), justification='center', key='-OUTPUT-')]
]
window = sg.Window('Piano reference', layout)
count = 0
play_obj = _play_with_simpleaudio(silent)
while 100 <= FREQ <= 20000 : # Event Loop
count += 1
event, values = window.Read()
if event in (None, 'Exit'):
break
if event == '<<':
if not FREQ < 100:
FREQ -= 100
window['-OUTPUT-'].update(FREQ)
if event == '>>':
if not FREQ > 20000:
FREQ += 200
window['-OUTPUT-'].update(FREQ)
print(event, FREQ)
sound = get_sine(FREQ)
try:
play_obj.stop()
time.sleep(0.1)
sound = sound.fade_in(100).fade_out(100)
play_obj = _play_with_simpleaudio(sound)
time.sleep(0.1)
except KeyboardInterrupt:
play_obj.stop_all()
window.close()
$ python3 pygui3.py
Playing >> 400 Hz
Playing >> 600 Hz
Playing >> 800 Hz
Playing << 700 Hz
Playing << 600 Hz