PyAudio输入溢出

lib*_*kmz 30 python audio pyaudio

我正试图在python中进行实时绘图声音.我需要从麦克风上取下块.

使用PyAudio,尝试使用

import pyaudio
import wave
import sys

chunk = 1024
FORMAT = pyaudio.paInt16
CHANNELS = 1
RATE = 44100
RECORD_SECONDS = 5
WAVE_OUTPUT_FILENAME = "output.wav"

p = pyaudio.PyAudio()

stream = p.open(format = FORMAT,
                channels = CHANNELS,
                rate = RATE,
                input = True,
                frames_per_buffer = chunk)

print "* recording"
all = []
for i in range(0, RATE / chunk * RECORD_SECONDS):
    data = stream.read(chunk)
    all.append(data)
print "* done recording"

stream.close()
p.terminate()
Run Code Online (Sandbox Code Playgroud)

之后,我得到了以下错误:

* recording
Traceback (most recent call last):
  File "gg.py", line 23, in <module>
    data = stream.read(chunk)
  File "/usr/lib64/python2.7/site-packages/pyaudio.py", line 564, in read
    return pa.read_stream(self._stream, num_frames)
IOError: [Errno Input overflowed] -9981
Run Code Online (Sandbox Code Playgroud)

我无法理解这个缓冲区.我想,使用阻止IO模式,所以如果没有块,我想等待那些块.但是当我创建尝试除了段或睡眠(0.1),我听到点击,所以这不是我想要的.

请为我的问题建议最好的解决方案?

小智 16

pyaudio.Stream.read()有一个关键字参数exception_on_overflow,将其设置为False.

对于您的示例代码,如下所示:

import pyaudio
import wave
import sys

chunk = 1024
FORMAT = pyaudio.paInt16
CHANNELS = 1
RATE = 44100
RECORD_SECONDS = 5
WAVE_OUTPUT_FILENAME = "output.wav"

p = pyaudio.PyAudio()

stream = p.open(format = FORMAT,
                channels = CHANNELS,
                rate = RATE,
                input = True,
                frames_per_buffer = chunk)

print "* recording"
all = []
for i in range(0, RATE / chunk * RECORD_SECONDS):
    data = stream.read(chunk, exception_on_overflow = False)
    all.append(data)
print "* done recording"

stream.close()
p.terminate()
Run Code Online (Sandbox Code Playgroud)

有关更多详细信息,请参阅PyAudio文档.

  • 我得到:TypeError:read()得到一个意外的关键字参数'exception_on_overflow' (4认同)

Jos*_*edy 9

我运行你的代码时遇到了同样的错误.我查看了我的默认音频设备的默认采样率,我的macbook的内置麦克风,它是48000Hz而不是44100Hz.

p.get_device_info_by_index(0)['defaultSampleRate']
Out[12]: 48000.0
Run Code Online (Sandbox Code Playgroud)

当我将RATE更改为此值时,它可以正常工作.


Met*_*eta 8

似乎很多人都遇到了这个问题.我挖了一下它,我认为这意味着在前一次调用stream.read()和当前调用之间,来自流的数据丢失了(即缓冲区填满的速度比你清除它的速度快).

从文档for Pa_ReadStream()(stream.read()最终调用的PortAudio函数):

@return On success PaNoError will be returned, or PaInputOverflowed if
input data was discarded by PortAudio after the previous call and
before this call.
Run Code Online (Sandbox Code Playgroud)

(PaInputOverflowed然后IOError在pyaudio包装器中导致一个).

如果您没有捕获每一帧,那么您可以忽略此错误.如果对每个帧都绝对至关重要,那么您需要找到一种方法来提高应用程序的优先级.我不太熟悉Python,知道这样做的pythonic方法,但是值得尝试一个简单的nice命令,或者将调度策略更改为SCHED_DEADLINE.

编辑:

现在的一个问题是,当抛出IOError时,您将丢失该调用中收集的所有帧.要改为忽略溢出并返回我们所拥有的内容,您可以应用下面的补丁,这将导致stream.read()忽略PortAudio的输出欠载和输入溢出错误(但如果发生了不同的错误,仍然会抛出一些东西).更好的方法是根据您的需要调整此行为(throw/no throw).

diff --git a/src/_portaudiomodule.c b/src/_portaudiomodule.c
index a8f053d..0878e74 100644
--- a/src/_portaudiomodule.c
+++ b/src/_portaudiomodule.c
@@ -2484,15 +2484,15 @@ pa_read_stream(PyObject *self, PyObject *args)
     } else {
       /* clean up */
       _cleanup_Stream_object(streamObject);
+
+      /* free the string buffer */
+      Py_XDECREF(rv);
+
+      PyErr_SetObject(PyExc_IOError,
+                       Py_BuildValue("(s,i)",
+                                     Pa_GetErrorText(err), err));
+      return NULL;
     }
-
-    /* free the string buffer */
-    Py_XDECREF(rv);
-
-    PyErr_SetObject(PyExc_IOError,
-                   Py_BuildValue("(s,i)",
-                                 Pa_GetErrorText(err), err));
-    return NULL;
   }

   return rv;
Run Code Online (Sandbox Code Playgroud)


Rob*_*rra 7

我在 OS X 10.10 上工作,尝试从 SYBA USB 卡(C Media 芯片组)中的麦克风获取音频时遇到同样的错误,并使用 fft 等实时处理它:

IOError: [Errno Input overflowed] -9981
Run Code Online (Sandbox Code Playgroud)

使用回调模式而不是 libbkmz 所写的阻塞模式完全解决了溢出问题。( https://www.python.org/dev/peps/pep-0263/ )

基于此,部分工作代码如下所示:

"""
Creating the audio stream from our mic
"""
rate=48000
self.chunk=2**12
width = 2

p = pyaudio.PyAudio()

# callback function to stream audio, another thread.
def callback(in_data,frame_count, time_info, status):
    self.audio = numpy.fromstring(in_data,dtype=numpy.int16)
    return (self.audio, pyaudio.paContinue)

#create a pyaudio object
self.inStream = p.open(format = p.get_format_from_width(width, unsigned=False),
                       channels=1,
                       rate=rate,
                       input=True,
                       frames_per_buffer=self.chunk,
                       stream_callback = callback)

"""
Setting up the array that will handle the timeseries of audio data from our input
"""
self.audio = numpy.empty((self.buffersize),dtype="int16")

    self.inStream.start_stream()

while True:
  try:
    self.ANY_FUNCTION() #any function to run parallel to the audio thread, running forever, until ctrl+C is pressed. 

  except KeyboardInterrupt:

    self.inStream.stop_stream()
    self.inStream.close()
    p.terminate()
    print("* Killed Process")
    quit()
Run Code Online (Sandbox Code Playgroud)

这段代码将创建一个回调函数,然后创建一个流对象,启动它,然后在任何函数中循环。一个单独的线程传输音频,当主循环停止时,该流将关闭。self.audio 用于任何功能。如果没有终止,我也遇到了线程永远运行的问题。

由于 Pyaudio 在一个单独的线程中运行这个流,这使得音频流稳定,阻塞模式可能已经饱和,这取决于脚本中其余进程的速度或时间。

请注意,块大小为 2^12,但较小的块也能正常工作。我考虑并使用了其他参数以确保它们都有意义:

  • 块大小更大或更小(无影响)
  • 缓冲区中字的位数和格式,在本例中为有符号 16 位。
  • 变量的符号性(尝试使用无符号并获得饱和模式)
  • 麦克风输入的性质,系统默认选择,增益等。

希望对某人有用!


Har*_*son 6

我的另一个答案在大多数情况下解决了问题。但有时仍然会出现该错误。

这就是我放弃 pyaudio 并改用 pyalsaaudio 的原因。我的 Raspy 现在可以顺利录制任何声音。

import alsaaudio   
import numpy as np
import array

# constants
CHANNELS    = 1
INFORMAT    = alsaaudio.PCM_FORMAT_FLOAT_LE
RATE        = 44100
FRAMESIZE   = 1024

# set up audio input
recorder=alsaaudio.PCM(type=alsaaudio.PCM_CAPTURE)
recorder.setchannels(CHANNELS)
recorder.setrate(RATE)
recorder.setformat(INFORMAT)
recorder.setperiodsize(FRAMESIZE)


buffer = array.array('f')
while <some condition>:
    buffer.fromstring(recorder.read()[1])

data = np.array(buffer, dtype='f')
Run Code Online (Sandbox Code Playgroud)