Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/357.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python PyAudio在线程中播放连续流,并允许更改频率_Python_Audio_Python Multithreading_Pyaudio - Fatal编程技术网

Python PyAudio在线程中播放连续流,并允许更改频率

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

我根本没有穿线的经验

我想做的就是播放一个声音,并能够同时使用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, 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