我正在尝试在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()
之后,我收到了以下错误:
* 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
我无法理解这个缓冲区。我想,使用阻止IO模式,所以如果没有块,我想等待那些块。但是当我创建try除了segment或sleep(0.1)之外,我听到了点击,所以这不是我想要的。
请为我的问题建议最佳解决方案?
答案 0 :(得分:15)
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()
有关详细信息,请参阅PyAudio documentation。
答案 1 :(得分:9)
运行代码时遇到同样的错误。我查看了我的默认音频设备的默认采样率,我的macbook的内置麦克风,它是48000Hz而不是44100Hz。
p.get_device_info_by_index(0)['defaultSampleRate']
Out[12]: 48000.0
当我将RATE更改为此值时,它可以正常工作。
答案 2 :(得分:6)
似乎很多人都遇到了这个问题。我挖了一下它,我认为这意味着在之前调用stream.read()
和当前调用之间,来自流的数据丢失了(即缓冲区填满的速度比你清除它的速度快)。
来自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.
(PaInputOverflowed
然后在pyaudio包装器中导致IOError
。
如果您没有捕获每一帧,那么您可以忽略此错误。如果您拥有每一帧绝对至关重要,那么您需要找到一种方法来提高应用程序的优先级。我不熟悉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;
答案 3 :(得分:3)
FORMAT = pyaudio.paInt16
确保设置正确的格式,我的内置麦克风设置为24位(参见Audio-Midi-Setup应用程序)。
答案 4 :(得分:3)
我在OS X 10.10上工作,尝试从SYBA USB卡(C媒体芯片组)中的麦克风获取音频时出现同样的错误,并使用fft&#39及更多实时处理:< / p>
IOError: [Errno Input overflowed] -9981
当使用回调模式而不是阻止模式时,溢出完全解决,如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()
此代码将创建一个回调函数,然后创建一个流对象,启动它然后在任何函数中循环。一个单独的线程流音频,当主循环停止时该流被关闭。 self.audio用于任何函数。如果没有终止,我也遇到了永远运行的线程问题。
由于Pyaudio在一个单独的线程中运行此流,并且这使得音频流稳定,因此阻塞模式可能已经饱和,具体取决于脚本中其余进程的速度或时间。
请注意,块大小为2 ^ 12,但较小的块也可以。我还考虑了其他一些参数,以确保它们都有意义:
希望对某人有用!
答案 5 :(得分:2)
我在真正慢的覆盆子pi上遇到了同样的问题,但我能够通过使用更快的array
模块来存储数据来解决它(大多数情况下 )。 / p>
import array
import pyaudio
FORMAT = pyaudio.paInt16
CHANNELS = 1
INPUT_CHANNEL=2
RATE = 48000
CHUNK = 512
p = pyaudio.PyAudio()
stream = p.open(format=FORMAT,
channels=CHANNELS,
rate=RATE,
input=INPUT_CHANNEL,
frames_per_buffer =CHUNK)
print("* recording")
try:
data = array.array('h')
for i in range(0, int(RATE / CHUNK * RECORD_SECONDS)):
data.fromstring(stream.read(CHUNK))
finally:
stream.stop_stream()
stream.close()
p.terminate()
print("* done recording")
之后data
的内容相当二元。
但是你可以使用numpy.array(data, dtype='i')
来获得一大堆整数。
答案 6 :(得分:2)
我的other answer在大多数情况下解决了这个问题。但是,有时错误仍然会发生。
这就是为什么我取消了pyaudio并切换到pyalsaaudio的原因。我的Raspy现在可以顺畅地录制任何声音。
declare module UUID {
// ...
};
declare function UUID(seed?: number): string;
declare module "UUID" {
export = UUID;
}
答案 7 :(得分:0)
对我来说这有帮助: https://stackoverflow.com/a/46787874/5047984
我使用多处理来并行编写文件来录制音频。这是我的代码:
<强> recordAudioSamples.py 强>
ax.set_xlim(-20, 20)
ax.set_ylim(0, 40)
<强> config.py 强>
import pyaudio
import wave
import datetime
import signal
import ftplib
import sys
import os
# configuration for assos_listen
import config
# run the audio capture and send sound sample processes
# in parallel
from multiprocessing import Process
# CONFIG
CHUNK = config.chunkSize
FORMAT = pyaudio.paInt16
CHANNELS = 1
RATE = config.samplingRate
RECORD_SECONDS = config.sampleLength
# HELPER FUNCTIONS
# write to ftp
def uploadFile(filename):
print("start uploading file: " + filename)
# connect to container
ftp = ftplib.FTP(config.ftp_server_ip, config.username, config.password)
# write file
ftp.storbinary('STOR '+filename, open(filename, 'rb'))
# close connection
ftp.quit()
print("finished uploading: " +filename)
# write to sd-card
def storeFile(filename,frames):
print("start writing file: " + filename)
wf = wave.open(filename, 'wb')
wf.setnchannels(CHANNELS)
wf.setsampwidth(p.get_sample_size(FORMAT))
wf.setframerate(RATE)
wf.writeframes(b''.join(frames))
wf.close()
print(filename + " written")
# abort the sampling process
def signal_handler(signal, frame):
print('You pressed Ctrl+C!')
# close stream and pyAudio
stream.stop_stream()
stream.close()
p.terminate()
sys.exit(0)
# MAIN FUNCTION
def recordAudio(p, stream):
sampleNumber = 0
while (True):
print("* recording")
sampleNumber = sampleNumber +1
frames = []
startDateTimeStr = datetime.datetime.now().strftime("%Y_%m_%d_%I_%M_%S_%f")
for i in range(0, int(RATE / CHUNK * RECORD_SECONDS)):
data = stream.read(CHUNK)
frames.append(data)
fileName = str(config.sensorID) + "_" + startDateTimeStr + ".wav"
# create a store process to write the file in parallel
storeProcess = Process(target=storeFile, args=(fileName,frames))
storeProcess.start()
if (config.upload == True):
# since waiting for the upload to finish will take some time
# and we do not want to have gaps in our sample
# we start the upload process in parallel
print("start uploading...")
uploadProcess = Process(target=uploadFile, args=(fileName,))
uploadProcess.start()
# ENTRYPOINT FROM CONSOLE
if __name__ == '__main__':
p = pyaudio.PyAudio()
stream = p.open(format=FORMAT,
channels=CHANNELS,
rate=RATE,
input=True,
frames_per_buffer=CHUNK)
# directory to write and read files from
os.chdir(config.storagePath)
# abort by pressing C
signal.signal(signal.SIGINT, signal_handler)
print('\n\n--------------------------\npress Ctrl+C to stop the recording')
# start recording
recordAudio(p, stream)
答案 8 :(得分:0)
这对我有帮助:
input_ = stream.read(chunk, exception_on_overflow=False)
exception_on_overflow = False