Entrée PyAudio débordée

j'essaie de faire du son de traçage en temps réel en python. J'ai besoin d'obtenir des morceaux de mon micro.

utilisez PyAudio, essayez d'utiliser

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

Après, j'obtiens ce qui suit erreur:

* 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

je ne peux pas comprendre ce tampon. Je veux, pour utiliser le mode IO de blocage, donc si les morceaux ne sont pas disponibles, je veux attendre ces morceaux. Mais quand je crée essayer sauf segment ou sommeil (0.1), j'entends des clics, donc ce n'est pas ce que je veux.

s'il vous Plaît suggérer la meilleure solution pour mon ploblem?

23
demandé sur libbkmz 2012-05-24 12:36:11

8 réponses

pyaudio.Stream.read() a un paramètre de mot-clé exception_on_overflow, Mettez à False.

Pour ton exemple de code qui pourrait ressembler à:

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

voir le PyAudio documentation pour plus de détails.

12
répondu Jesquik 2016-02-16 20:38:55

j'ai eu la même erreur quand j'ai lancé votre code. J'ai regardé le taux d'échantillon par défaut de mon périphérique audio par défaut, le microphone interne de mon macbook, c'était 48000Hz pas 44100Hz.

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

quand j'ai changé le taux à cette valeur, ça a marché.

8
répondu velotron 2012-12-08 05:10:12

Il semble que beaucoup de gens rencontrent ce problème. J'ai creusé un peu et je pense que cela signifie qu'entre l'appel précédent stream.read() et cet appel courant, les données du flux ont été perdues (c'est-à-dire que le buffer s'est rempli plus vite que vous ne l'avez effacé).

Dans la doc de Pa_ReadStream() (la fonction PortAudio qui stream.read() finalement finit par appeler):

@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 cause alors un IOError dans le papier pyaudio).

si vous êtes D'accord pas de capturer chaque image, alors vous pouvez ignorer cette erreur. Si c'est absolument essentiel pour vous d'avoir chaque image, alors vous aurez besoin de trouver un moyen d'augmenter le niveau de priorité de votre demande. Je ne suis pas assez familier avec Python pour connaître une façon pythonique de faire cela, mais cela vaut la peine d'essayer un simple nice commande, ou changer la Politique de planification en SCHED_DEADLINE.

Edit:

un problème en ce moment est que quand IOError est lancé, vous perdez tous les cadres collectés dans cet appel. Pour ignorer le débordement et simplement retourner ce que nous avons, vous pouvez appliquer le patch ci-dessous, ce qui causera stream.read () pour ignorer les erreurs output underrun et input overflow de PortAudio (mais quand même jeter quelque chose si une erreur différente s'est produite). Une meilleure façon serait de rendre ce comportement (Lancer/pas lancer) personnalisable en fonction de vos besoins.

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;
6
répondu Meta 2015-02-18 15:23:03
FORMAT = pyaudio.paInt16

assurez-vous de régler le bon format, mon microphone interne a été réglé à 24 bits (voir application Audio-Midi-Setup).

3
répondu w-m 2013-01-15 15:48:02

j'ai travaillé sur OS X 10.10, J'ai eu la même erreur en essayant d'obtenir l'audio à partir du microphone dans une carte USB SYBA (C Media chipset), et le traiter en temps réel avec fft et plus:

IOError: [Errno Input overflowed] -9981

le débordement a été complètement résolu en utilisant un Mode de rappel, au lieu du Mode de blocage, comme écrit par libbkmz.(https://www.python.org/dev/peps/pep-0263/)

basé sur cela, le morceau du code de travail ressemblait à ceci:

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

ce code va créer une fonction de rappel, puis créer un objet stream, le démarrer et ensuite boucler n'importe quelle fonction. Un thread séparé diffuse l'audio, et ce flux est fermé lorsque la boucle principale est arrêtée. auto.l'audio est utilisé dans n'importe quelle fonction. J'ai aussi eu des problèmes avec le thread tournant à jamais si ce n'est terminé.

puisque Pyaudio exécute ce flux dans un thread séparé, et cela a rendu le flux audio stable, le mode de blocage a pu être saturé en fonction de la vitesse ou du timing du reste des processus dans le script.

notez que la taille des morceaux est 2^12, mais les plus petits morceaux fonctionnent tout aussi bien. Il y a d'autres paramètres que j'ai pris en compte et avec lesquels j'ai joué pour m'assurer qu'ils avaient tous un sens:

  • taille des morceaux plus grand ou plus petit (aucun effet)
  • nombre et format des bits pour les mots dans le tampon, signé 16 bits dans ce cas.
  • signification des variables (essayé avec non signé et a obtenu la saturation des modèles)
  • la Nature de l'entrée micro, et la sélection par défaut dans le système, le gain etc.

j'Espère que fonctionne pour quelqu'un!

3
répondu Roberto Becerra 2015-10-02 06:24:45

Mon réponse résolu le problème dans la plupart des cas. Toutefois, l'erreur persiste parfois.

C'est la raison pour laquelle j'ai abandonné pyaudio et je suis passé à pyalsaaudio. Mon râpeur enregistre en douceur n'importe quel son.

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')
2
répondu Harald Thomson 2016-01-14 18:23:02

j'ai eu le même problème sur le pi à la framboise vraiment lent, mais j'ai pu le résoudre (pour la plupart des cas) en utilisant le plus rapide array module de stockage des données.

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

Le contenu data est plutôt binaire par la suite. Mais vous pouvez utiliser numpy.array(data, dtype='i') pour obtenir un tableau numpy d'entiers.

1
répondu Harald Thomson 2016-01-14 18:27:35

pour moi, cela a aidé: https://stackoverflow.com/a/46787874/5047984

j'ai utilisé le multiprocessing pour écrire le fichier en parallèle à l'enregistrement audio. C'est mon 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/"
0
répondu gannebamm 2017-10-17 10:38:21