2012-05-24 6 views
21

Ich versuche Echtzeit-Plotten Sound in Python zu machen. Ich muss Stücke von meinem Mikrofon bekommen.PyAudio Eingang übergelaufen

PyAudio, versuchen

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() 

Nach verwenden, ich habe die followin Fehler bekommen:

* 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 

Ich kann nicht diesen Puffer verstehen. Ich möchte, blockierenden IO-Modus zu verwenden, also wenn Chunks nicht verfügbar sind, möchte ich auf diese Chunks warten. Aber wenn ich versuche, außer Segment oder Schlaf (0,1), ich höre Klicks, so ist dies nicht das, was ich will.

Bitte schlagen Sie die beste Lösung für mein Ploblem vor?

+2

Vielleicht ist Ihr Chunkgröße zu klein ist. Vielleicht erhält es mehr Daten im Puffer, als Sie herausziehen, weil die Chunk-Größe klein genug ist, dass der Python-Code nicht mithalten kann. – Demolishun

+0

Hallo. Frage mich nur, ob es Updates zu diesem Thema gibt? Ich bekomme den Fehler "[Errno Input overflowed] -9981" intermittierend. Ich habe überprüft, dass "p.is_format_supported" für das verwendete Format zutrifft. –

Antwort

8

Ich habe den gleichen Fehler, wenn ich Ihren Code ausgeführt habe. Ich schaute auf die Standard-Abtastrate meines Standard-Audiogerätes, das interne Mikrofon meines Macbooks, es war 48000Hz, nicht 44100Hz.

p.get_device_info_by_index(0)['defaultSampleRate'] 
Out[12]: 48000.0 

Wenn ich RATE auf diesen Wert änderte, funktionierte es.

+1

Ich habe den gleichen Fehler, und Ihre Lösung (bis 48000) funktioniert. Aber ich hatte den Code ausführen: wenn p.is_format_supported (44.100,0, # Samplerate input_device = devinfo [ "Index"], input_channels = devinfo [ 'maxInputChannels'], input_format = pyaudio.paInt16): print ‚Yay! " ... und es hat funktioniert! Ich bin also verwirrt, was das Problem ist. Irgendeine Einsicht? – user426364

+0

Versuchen Sie, Portaudio zu aktualisieren, dies behebt einige Ratenprobleme für mich. Ich habe "brew install portaudio --HEAD" benutzt. – velotron

+0

das funktionierte für mich, ich wusste nicht, Soundkarte Standard Abtastrate war 48kHz, danke! – Jeff

2
FORMAT = pyaudio.paInt16 

Achten Sie darauf, das richtige Format einzustellen, mein internes Mikrofon wurde auf 24 Bit eingestellt (siehe Audio-Midi-Setup-Anwendung).

5

Es scheint, als ob viele Leute dieses Problem begegnen. Ich habe ein bisschen hinein gegraben und ich denke, es bedeutet, dass zwischen dem vorherigen Anruf zu stream.read() und diesem aktuellen Anruf, Daten aus dem Strom verloren wurden (d. H. Der Puffer füllte sich schneller als Sie es löschten).

Vom doc für Pa_ReadStream() (die Portaudio-Funktion, die stream.read() schließlich Aufruf endet):

@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 dann ein IOError in dem pyaudio Wrapper verursacht).

Wenn es für Sie in Ordnung ist, nicht jeden einzelnen Frame zu erfassen, können Sie diesen Fehler ignorieren. Wenn es absolut wichtig für Sie ist, jeden Frame zu haben, dann müssen Sie einen Weg finden, um die Priorität Ihrer Anwendung zu erhöhen. Ich bin nicht vertraut genug mit Python, um eine pythonische Art zu wissen, dies zu tun, aber es lohnt sich, einen einfachen Befehl nice zu versuchen, oder ändern Sie die Planungsrichtlinie zu SCHED_DEADLINE.

Edit:

Ein Problem im Moment ist, dass, wenn IOError geworfen wird, verlieren Sie alle in diesem Anruf gesammelt Frames. Um stattdessen den Überlauf zu ignorieren und einfach das zurückzugeben, was wir haben, können Sie den folgenden Patch anwenden, der bewirkt, dass stream.read() Ausgabeunterlauf und Eingabeüberlauffehler von PortAudio ignoriert (aber immer noch etwas auswirft, wenn ein anderer Fehler aufgetreten ist). Ein besserer Weg wäre, dieses Verhalten (werfen/nicht werfen) je nach Ihren Bedürfnissen anzupassen.

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

Ich arbeitete dies auf OS X 10.10, erhielt die gleiche Störung, während Ton vom Mikrofon in einer SYBA USB-Karte (C Media-Chipsatz), und verarbeitet sie in Echtzeit mit FFTs und mehr zu erhalten versuchen:

IOError: [Errno Input overflowed] -9981 

Der Überlauf wurde vollständig gelöst bei der Verwendung von a. Rückrufmodus, als anstelle des Blocking-Modus, durch libbkmz geschrieben (https://www.python.org/dev/peps/pep-0263/)

auf dieser Basis sah das Bit des Arbeits Code wie folgt:

""" 
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() 

Dieser Code wird eine Callback-Funktion erstellen , dann erstellen Sie ein Stream-Objekt, starten Sie es und dann in irgendeiner Funktion Schleife. Ein separater Thread streamt Audio, und dieser Stream wird geschlossen, wenn die Hauptschleife gestoppt wird. self.audio wird in jeder Funktion verwendet. Ich hatte auch Probleme damit, dass der Thread für immer lief, wenn er nicht beendet wurde.

Da Pyaudio diesen Stream in einem separaten Thread ausführt und dadurch den Audio-Stream stabil hält, könnte der Blocking-Modus abhängig von der Geschwindigkeit oder dem Timing der übrigen Prozesse im Skript gesättigt sein.

Beachten Sie, dass die Chunk-Größe 2^12 ist, aber kleinere Chunks funktionieren genauso gut. Es gibt noch andere Parameter I betrachtet und spielte mit, dass sie alles einen Sinn zu machen:

  • Chunk Größe größer oder kleiner ist (kein Effekt)
  • Anzahl und Format der Bits für die Worte in dem Puffer, signiert 16 Bit in diesem Fall.
  • Signedness von Variablen (versucht mit unsigned und bekamen Sättigungsmuster)
  • Art des Mikrofoneingangs und die Auswahl als Standard im System, gewinnen usw.

Hoffnung, dass jemand arbeitet!

1

Ich hatte das gleiche Problem auf der wirklich langsamen Raspberry Pi, aber ich war in der Lage, es zu lösen (für die meisten Fälle) mit dem schnelleren array Modul zum Speichern der Daten.

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") 

Der Inhalt data ist eher danach binär. Aber Sie können numpy.array(data, dtype='i') verwenden, um ein numpy Array von Intergers zu erhalten.

1

Mein other answer löste das Problem in den meisten Fällen. Manchmal tritt der Fehler jedoch immer noch auf.

Das war der Grund, warum ich Pyaudio verschrottet und zu pyalsaudio wechselte. Mein Raspy nimmt jetzt sanft jeden Ton auf.

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') 
10

pyaudio.Stream.read() hat ein Schlüsselwort Parameter exception_on_overflow, setzen Sie diese auf False.

Für Ihre Beispielcode, der wie folgt aussehen würde:

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() 

Siehe PyAudio documentation für weitere Details.

+4

Ich bekomme: TypeError: read() hat ein unerwartetes Schlüsselwortargument 'exception_on_overflow' –

0

für mich diesen geholfen: https://stackoverflow.com/a/46787874/5047984

I Multiprozessing die Datei parallel zur Aufzeichnung von Audio zu schreiben verwendet. Dies ist mein Code:

recordAudioSamples.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) 

config.py

### configuration file for assos_listen 
# upload 
upload = False 

# config for this sensor 
sensorID = "al_01" 

# sampling rate & chunk size 
chunkSize = 8192 
samplingRate = 44100 # 44100 needed for Aves sampling 
# choices=[4000, 8000, 16000, 32000, 44100] :: default 16000 

# sample length in seconds 
sampleLength = 10 

# configuration for assos_store container 
ftp_server_ip = "192.168.0.157" 
username = "sensor" 
password = "sensor" 

# storage on assos_listen device 
storagePath = "/home/pi/assos_listen_pi/storage/"