在 Raspberry Pi 上使用 Python,我无法通过 Thonny/终端使用 PyAudio 录制音频

时间:2021-03-13 03:30:33

标签: python multithreading pyaudio pi

使用以下示例:https://realpython.com/playing-and-recording-sound-python/#python-sounddevice_1,我在使用 Thonny 时收到以下错误:“后端终止或断开连接。使用‘停止/重新启动’重新启动。”。当我在终端中运行程序时,出现错误:“OSError: [Errno -9981] Input overflowed”。示例代码(不是线程的)可以在终端和 Thonny 中工作,如果我修改它以在溢出时不抛出异常“data = stream.read(chunk,exception_on_overflow = False)”但在新的线。我还尝试将块大小更改为更大或更小,但无济于事。当我有线程版本的溢出异常时,我在终端中收到一个不同的错误:“分段错误”。我正在运行 Raspbian 10 Buster 和 Python 3.7.3,如果有人可以测试/看看它是否有效,谢谢。

import time
import board
import busio
import digitalio
from adafruit_mcp230xx.mcp23017 import MCP23017
from adafruit_debouncer import Debouncer
i2c = busio.I2C(board.SCL, board.SDA)
mcp = MCP23017(i2c)

import threading
import pyaudio
import wave
import sys
import subprocess

record = False

def background_audio_recording():
    
    #chunk = 1024  # Record in chunks of 1024 samples
    chunk = 1024
    sample_format = pyaudio.paInt16  # 16 bits per sample
    channels = 2
    fs = 44100  # Record at 44100 samples per second
    #seconds = 3
    filename = "output.wav"
    
    p = pyaudio.PyAudio()  # Create an interface to PortAudio
    
    stream = p.open(format=sample_format,
        channels=channels,
        rate=fs,
        frames_per_buffer=chunk,
        #input_device_index = 2,
        input=True)
    
    frames = []  # Initialize array to store frames
    
    while record:
        #data = stream.read(chunk, exception_on_overflow = False)
        data = stream.read(chunk)
        frames.append(data)
    '''
    for i in range(0, int(fs / chunk * seconds)):
        data = stream.read(chunk)
        frames.append(data)
    '''
    # Stop and close the stream 
    stream.stop_stream()
    stream.close()
    # Terminate the PortAudio interface
    p.terminate()
    
    print('Finished recording')
    
    # Save the recorded data as a WAV file
    wf = wave.open(filename, 'wb')
    wf.setnchannels(channels)
    wf.setsampwidth(p.get_sample_size(sample_format))
    wf.setframerate(fs)
    wf.writeframes(b''.join(frames))
    wf.close()

    print("File Saved")

    return

button1PinSetup = mcp.get_pin(0) # GPA0
button1PinSetup.direction = digitalio.Direction.INPUT
button1PinSetup.pull = digitalio.Pull.UP
button1Pin = Debouncer(button1PinSetup)

button2PinSetup = mcp.get_pin(1) # GPA1
button2PinSetup.direction = digitalio.Direction.INPUT
button2PinSetup.pull = digitalio.Pull.UP
button2Pin = Debouncer(button2PinSetup)

while True:
    button1Pin.update()
    button2Pin.update()
    if button1Pin.fell:
        print("Record")
        if record == True:
            print("Already Recording")
        else:
            record = True
            threading.Thread(target=background_audio_recording).start()
    if button2Pin.fell:
        print("Recording Stopped")
        record = False

1 个答案:

答案 0 :(得分:0)

似乎,我需要将 PyAudio 对象创建为全局对象,以及在线程内(对于每次额外的录制尝试)。我用下面的代码让它工作

import pyaudio
import wave
import time
import threading

import board
import busio
import digitalio
from adafruit_mcp230xx.mcp23017 import MCP23017
from adafruit_debouncer import Debouncer
i2c = busio.I2C(board.SCL, board.SDA)
mcp = MCP23017(i2c)

form_1 = pyaudio.paInt16 # 16-bit resolution
chans = 2 # 1 channel
samp_rate = 44100 # 44.1kHz sampling rate
chunk = 4096 # 2^12 samples for buffer
#record_secs = 3 # seconds to record
dev_index = 2 # device index found by p.get_device_info_by_index(ii)
wav_output_filename = 'test1.wav' # name of .wav file

audio = pyaudio.PyAudio() # create pyaudio instantiation

record = False

def background_audio_recording():
    audio = pyaudio.PyAudio() # create pyaudio instantiation
    # create pyaudio stream
    stream = audio.open(format = form_1,rate = samp_rate,channels = chans, \
                    input_device_index = dev_index,input = True, \
                    frames_per_buffer=chunk)
    print("recording")
    frames = []

    # loop through stream and append audio chunks to frame array
    #for ii in range(0,int((samp_rate/chunk)*record_secs)):
    while record == True:
        data = stream.read(chunk)
        frames.append(data)

    print("finished recording")

    # stop the stream, close it, and terminate the pyaudio instantiation
    stream.stop_stream()
    stream.close()
    audio.terminate()
    
    # save the audio frames as .wav file
    wavefile = wave.open(wav_output_filename,'wb')
    wavefile.setnchannels(chans)
    wavefile.setsampwidth(audio.get_sample_size(form_1))
    wavefile.setframerate(samp_rate)
    wavefile.writeframes(b''.join(frames))
    wavefile.close()
    return


button1PinSetup = mcp.get_pin(0) # GPA0
button1PinSetup.direction = digitalio.Direction.INPUT
button1PinSetup.pull = digitalio.Pull.UP
button1Pin = Debouncer(button1PinSetup)

button2PinSetup = mcp.get_pin(1) # GPA1
button2PinSetup.direction = digitalio.Direction.INPUT
button2PinSetup.pull = digitalio.Pull.UP
button2Pin = Debouncer(button2PinSetup)

while True:
    button1Pin.update()
    button2Pin.update()
    if button1Pin.fell:
        print("Record")
        if record == True:
            print("Already Recording")
        else:
            record = True
            threading.Thread(target=background_audio_recording).start()
    if button2Pin.fell:
        print("Recording Stopped")
        record = False