Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/python-3.x/15.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 3.x 后台Python多进程音频_Python 3.x_Audio_Pyaudio_Multiprocess - Fatal编程技术网

Python 3.x 后台Python多进程音频

Python 3.x 后台Python多进程音频,python-3.x,audio,pyaudio,multiprocess,Python 3.x,Audio,Pyaudio,Multiprocess,我正在尝试编写一个带有基本用户界面的简单数字合成器。目前,它创建了一个具有所需频率和振幅的正弦波发生器,然后在发生器上无限循环,将块发送到音频流。这样做可以产生纯音,听起来不错。在我的简单UI上,是音符频率的滑块,而声音循环是无限的,显然我无法与UI交互来更改音符,因为控件是无限循环的。如果我试着在UI_更新循环中运行audiostream,而不是它自己的无限循环,它会变得很不稳定,因为它花费很短的时间来计算注释更改和UI渲染,听起来很糟糕 我的解决方案是简单地将音频渲染循环发送到多进程进程,并

我正在尝试编写一个带有基本用户界面的简单数字合成器。目前,它创建了一个具有所需频率和振幅的正弦波发生器,然后在发生器上无限循环,将块发送到音频流。这样做可以产生纯音,听起来不错。在我的简单UI上,是音符频率的滑块,而声音循环是无限的,显然我无法与UI交互来更改音符,因为控件是无限循环的。如果我试着在UI_更新循环中运行audiostream,而不是它自己的无限循环,它会变得很不稳定,因为它花费很短的时间来计算注释更改和UI渲染,听起来很糟糕

我的解决方案是简单地将音频渲染循环发送到多进程进程,并在后台运行无限循环。然后,当滑块移动时,终止进程并创建一个新进程来播放新音符。我制作了这个代码函数,我可以看到它创建过程来播放声音,调试我可以看到它执行声音创建功能,我可以更新UI并观察它循环过程,但是没有声音产生。我知道声音创建功能可以正常工作,因为我可以将其从进程中删除,并将其放置在主循环中,它会发出良好的声音,但由于无限循环,我无法与UI交互

我在MacCatalina10.15.6上使用Python3.8.5,pySimpleGUI是我使用的GUI库,pyaudio是我用来播放它的。有没有一种方法可以为我的电脑提供多进程的音频控制?有没有更好的设计,我可以使用,以获得平稳的声音,同时仍然能够改变声音不断

这是我代码的相关部分:

def sin_wave(frequency=440.0, samplerate=44100, amplitude=0.5):
  period = int(samplerate / frequency)
  amplitude = clip_amplitude(amplitude)
  lookup = [float(amplitude) * math.sin(2.0*math.pi*float(frequency)*(float(i%period)/float(samplerate))) for i in range(period)]
  return (lookup[i%period] for i in count(0))

def grouper(n, iterable, fillvalue=None):
  # "grouper(3, 'ABCDEFG', 'x') --> zip_longest((A,B,C), (D,E,F), (G,x,x))"
  args = [iter(iterable)] * n
  return zip_longest(fillvalue=fillvalue, *args)

def compute_samples(channels, nsamples=None):
  return islice(zip(*(map(sum, zip(*channel)) for channel in channels)), nsamples)

def update_samples(values):
  channel = ()
  for i in range(50):
    if f'Osc{i}Freq' in values and f'Osc{i}Vol' in values:
      # construct sound, then convert tuple to list, append our sound, back to tuple
      sound = sin_wave(frequency=values[f'Osc{i}Freq'], amplitude=values[f'Osc{i}Vol'])
      # operations cannot be combined or NoneType error
      channel = list(channel)
      channel.append(sound)
      channel = tuple(channel)

  # mono for now 
  channels = (
    channel,
    channel
  )
  return compute_samples(channels)

def write_audiostream(stream, samples, nchannels=2, sampwidth=2, framerate=44100, bufsize=2048):
  max_amplitude = float(int((2 ** (sampwidth * 8)) / 2) - 1) / 100

  logging.info('test')
  for chunk in grouper(bufsize, samples):
    frames = b''.join(b''.join(struct.pack('h', int(max_amplitude * sample)) for sample in channels) for channels in chunk if channels is not None)
    stream.write(frames)

def main():
  num_channels = 2
  sampwidth = 2
  framerate = 44100

  pya = pyaudio.PyAudio()
  stream = pya.open(format = pya.get_format_from_width(width=sampwidth), channels=num_channels, rate=framerate, output=True)
  ### GUI
  layout = [
    [
      sg.Text('Oscilator 1'), 
      sg.Slider(
        key="Osc1Freq",
        range=(20.0,500.0),
        default_value=440.0,
        orientation='h'), 
      sg.Slider(
        key="Osc1Vol",
        range=(0.0,1.0),
        default_value=0.5,
        resolution=0.01,
        orientation='h')
    ],
    [
      sg.Text('Oscilator 2'), 
      sg.Slider(
        key="Osc2Freq",
        range=(20.0,500.0),
        default_value=440.0,
        orientation='h'), 
      sg.Slider(
        key="Osc2Vol",
        range=(0.0,1.0),
        default_value=0.5,
        resolution=0.01,
        orientation='h')
    ],
    [sg.Output(size=(250,50))],
    [sg.Submit(), sg.Cancel()]
  ]

  window = sg.Window('Shit', layout)

  event_old, values_old = None, None
  while True:
    event, values = window.read(timeout = 50)
    if event in (None, 'Exit', 'Cancel'):
      break

    if values_old != values:
      print(event, values)
      event_old, values_old = event, values

      samples = update_samples(values)
      # sound functions here, it just takes control away while in infinite loop
      # write_audiostream(stream, samples)

      # no sound plays if executed in a Process
      if not 'audio_proc' in locals():
        audio_proc = multiprocess.Process(target=write_audiostream, args=(stream, samples), daemon=True)
        audio_proc.start()
      else:
        audio_proc.terminate()
        audio_proc = multiprocess.Process(target=write_audiostream, args=(stream, samples), daemon=True)
        audio_proc.start()