2012-05-24 29 views
21

Próbuję renderować w czasie rzeczywistym dźwięk w python. Muszę zdobyć kawałki z mojego mikrofonu.Przepełnienie wejścia PyAudio

Korzystanie PyAudio, spróbuj użyć

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

Po, ja coraz followin błąd:

* 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 

nie mogę zrozumieć tego bufora. Chcę, aby użyć trybu blokowania IO, więc jeśli porcje nie są dostępne, chcę poczekać na te porcje. Ale kiedy tworzę spróbuj z wyjątkiem segmentu lub snu (0.1), słyszę kliknięcia, więc nie jest to to, czego chcę.

Proszę zaproponować najlepsze rozwiązanie dla mojego ploblem?

+2

Być może twój rozmiar kawałek jest zbyt mała. Może dostaje więcej danych w buforze, niż wyciągasz, ponieważ rozmiar kawałka jest na tyle mały, że kod Pythona nie nadąża. – Demolishun

+0

Witam. Zastanawiasz się, czy są jakieś aktualizacje dotyczące tego problemu? Otrzymuję sporadycznie błąd "[Errno Input overflowed] -9981'. Sprawdziłem "p.is_format_supported" jest prawdziwe dla formatu, którego używam. –

Odpowiedz

8

Ten sam błąd wystąpił podczas uruchamiania kodu. Spojrzałem na domyślną częstotliwość próbkowania mojego domyślnego urządzenia audio, wewnętrznego mikrofonu mojego komputera MacBook, to był 48000 Hz, a nie 44100 Hz.

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

Po zmianie wartości na tę wartość działało.

+1

Wystąpił ten sam błąd, a Twoje rozwiązanie (zwiększenie do 48000) działało. Ale ja uruchomić kod: if p.is_format_supported (44100,0, # Częstotliwość próbkowania input_device = devinfo [ "index"], input_channels = devinfo [ 'maxInputChannels'], input_format = pyaudio.paInt16): print „Yay! " ... i zadziałało! Tak więc jestem zdezorientowany co do problemu. Jakiś wgląd? – user426364

+0

Spróbuj uaktualnić portaudio, co naprawiło dla mnie pewne problemy z szybkością. Użyłem "brew install portaudio - HEAD". – velotron

+0

to działało dla mnie, nie zdawałem sobie sprawy, że domyślna częstotliwość próbkowania karty dźwiękowej to 48 kHz, dzięki! – Jeff

2
FORMAT = pyaudio.paInt16 

Upewnij się, aby ustawić odpowiedni format, mój wewnętrzny mikrofon został ustawiony na 24-bitowy (patrz aplikacji audio-Midi-setup).

5

Wygląda na to, że wiele osób napotyka ten problem. Wkopałem się w to i myślę, że oznacza to, że pomiędzy poprzednim połączeniem do stream.read() a bieżącym połączeniem, dane ze strumienia zostały utracone (tj. Bufor wypełnił się szybciej, niż go wyczyściłeś).

Z dokumentu na Pa_ReadStream() (funkcja PortAudio że stream.read() ostatecznie kończy wywołanie)

@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 następnie powoduje IOError w owijce pyaudio).

Jeśli nie możesz przechwycić każdej klatki, możesz zignorować ten błąd. Jeśli posiadanie każdej klatki jest absolutnie niezbędne, musisz znaleźć sposób na zwiększenie priorytetu swojej aplikacji. Nie jestem wystarczająco obeznany z Pythonem, aby znać w tym celu pyton, ale warto wypróbować proste polecenie nice lub zmienić zasady planowania na SCHED_DEADLINE.

Edit:

Jednym z problemów jest to, że teraz, kiedy IOError jest generowany, tracisz wszystkie klatki zebrane w tej rozmowy. Aby zamiast tego zignorować przepełnienie i po prostu zwrócić to, co mamy, możesz zastosować poniższą łatę, która spowoduje, że stream.read() zignoruje błędy wyjścia i błędy przepełnienia wejścia z PortAudio (ale nadal będzie coś rzucać, jeśli wystąpi inny błąd). Lepszym sposobem jest dostosowanie tego zachowania (rzut/brak) w zależności od potrzeb.

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

Pracowałem nad tym w OS X 10.10, Mam ten sam błąd, starając się uzyskać dźwięk z mikrofonu w SYBA karty USB (C chipset mediów), i przetwarza je w czasie rzeczywistym z FFT-tych i więcej:

IOError: [Errno Input overflowed] -9981 

Przelew został całkowicie rozwiązany przy użyciu a. Tryb oddzwaniania, zamiast trybu blokowanie, jak napisane przez libbkmz (https://www.python.org/dev/peps/pep-0263/)

podstawie, że bit kodu roboczego wyglądał następująco:

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

Kod ten będzie utworzyć funkcję oddzwonienia , a następnie utwórz obiekt strumienia, uruchom to, a następnie pętli w dowolnej funkcji. Oddzielny wątek przesyła dźwięk, a strumień jest zamykany po zatrzymaniu pętli głównej. self.audio jest używane w dowolnej funkcji. Miałem też problemy z wątkiem działającym wiecznie, jeśli nie zakończono go.

Ponieważ Pyaudio uruchamia ten strumień w osobnym wątku, co spowodowało, że strumień audio jest stabilny, tryb blokowania mógł zostać nasycony w zależności od szybkości lub czasu pozostałych procesów w skrypcie.

Należy zauważyć, że rozmiar porcji to 2^12, ale mniejsze porcje działają równie dobrze. Istnieją inne parametry Uważałem i bawił się, aby upewnić się, że wszystko miało sens:

  • rozmiar Chunk większe lub mniejsze (brak efektu)
  • ilość i format bitów dla słowa w buforze, podpisany 16 bit w tym przypadku.
  • signedness zmiennych (próbowałem z unsigned i dostał wzory nasycenie)
  • Nature wejścia MIC i wybór jako domyślny w systemie, zdobyć itd

nadzieję, że pracuje dla kogoś!

1

Miałem ten sam problem w bardzo powolnym Raspberry Pi, ale udało mi się go rozwiązać (dla większości przypadków) używając szybszy moduł array do przechowywania danych.

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

Zawartość pliku data jest raczej binarna. Ale można użyć numpy.array(data, dtype='i'), aby uzyskać szereg tablic interweniantów.

1

My other answer rozwiązał problem w większości przypadków. Jednak czasami błąd nadal występuje.

To był powód, dla którego usunąłem pyaudio i przełączyłem się na pyalsaaudio. Mój Raspy teraz płynnie rejestruje każdy dźwięk.

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() ma parametr słowa kluczowego exception_on_overflow, ustaw wartość False.

Dla Państwa przykładowy kod, który wyglądałby następująco:

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

zobaczyć PyAudio documentation więcej szczegółów.

+4

Otrzymuję: TypeError: read() otrzymałem nieoczekiwany argument słowa kluczowego "exception_on_overflow" –

0

dla mnie to pomogło: https://stackoverflow.com/a/46787874/5047984

użyłem wieloprocesorowe napisać plik równolegle do nagrywania dźwięku. To jest mój kod:

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/" 
Powiązane problemy