PyAudio Input overflowed

后端 未结 9 1551
长发绾君心
长发绾君心 2020-11-30 04:04

I\'m trying to make real-time plotting sound in python. I need to get chunks from my microphone.

Using PyAudio, try to use

import pyaudio
import wav         


        
相关标签:
9条回答
  • 2020-11-30 04:39

    For me this helped: https://stackoverflow.com/a/46787874/5047984

    I used multiprocessing to write the file in parallel to recording audio. This is my 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 讨论(0)
  • 2020-11-30 04:40

    I worked this on OS X 10.10, Got the same error while trying to get audio from the microphone in a SYBA USB card (C Media chipset), and process it in real time with fft's and more:

    IOError: [Errno Input overflowed] -9981
    

    The overflow was completely solved when using a Callback Mode, instead of the Blocking Mode, as written by libbkmz.(https://www.python.org/dev/peps/pep-0263/)

    Based on that, the bit of the working code looked like this:

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

    This code will create a callback function, then create a stream object, start it and then loop in any function. A separate thread streams audio, and that stream is closed when the main loop is stopped. self.audio is used in any function. I also had problems with the thread running forever if not terminated.

    Since Pyaudio runs this stream in a separate thread, and this made the audio stream stable, the Blocking mode might have been saturating depending on the speed or timing of the rest of the processes in the script.

    Note that the chunk size is 2^12, but smaller chunks work just as well. There are other parameters I considered and played around with to make sure they all made sense:

    • Chunk size larger or smaller(no effect)
    • Number and format of bits for the words in the buffer, signed 16 bit in this case.
    • signedness of variables(tried with unsigned and got saturation patterns)
    • Nature of mic input, and selection as default in the system, gain etc.

    Hope that works for someone!

    0 讨论(0)
  • 2020-11-30 04:40

    My other answer solved the problem in most cases. However sometimes the error still occurs.

    That was the reason why I scrapped pyaudio and switched to pyalsaaudio. My Raspy now smoothly records any sound.

    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')
    
    0 讨论(0)
提交回复
热议问题