【问题标题】:Capturing audio with python on the raspberry pi fails在树莓派上使用 python 捕获音频失败
【发布时间】:2015-11-21 20:24:35
【问题描述】:

我目前正在开发一种易于使用的音频捕获设备,用于数字化旧盒式磁带(即低保真度)。该设备基于带有 USB 声卡的树莓派,除了在启动时启动列出的 python 脚本之外,它什么也不做。

import alsaaudio
import wave
import os.path
import RPi.GPIO as GPIO
import key
import usbstick
import time

try:
    # Define storage
    path = '/mnt/usb/'
    prefix = 'Titel '
    extension = '.wav'

    # Configure GPIOs
    GPIO.setmode(GPIO.BOARD)
    button_shutdown = key.key(7)
    button_record = key.key(11)
    GPIO.setup(12, GPIO.OUT)
    GPIO.setup(15, GPIO.OUT)
    GPIO.output(12, GPIO.HIGH)

    # Start thread to detect external memory
    usb = usbstick.usbstick(path, 13)

    # Configure volume
    m = alsaaudio.Mixer('Mic', 0, 1)
    m.setvolume(100, 0, 'capture')

    # Only run until shutdown button gets pressed
    while not (button_shutdown.pressed()):

        # Only record if record button is pressed and memory is mounted
        if (button_record.pressed() and usb.ismounted()):

            # Create object to read input
            inp = alsaaudio.PCM(alsaaudio.PCM_CAPTURE, alsaaudio.PCM_NORMAL, 'sysdefault:CARD=Device')
            inp.setchannels(1)
            inp.setrate(44100)
            inp.setformat(alsaaudio.PCM_FORMAT_S16_LE)
            inp.setperiodsize(1024)

            # Find next file name
            i = 0
            filename = ''
            while (True):
                i += 1
                filename = path + prefix + str(i) + extension
                if not (os.path.exists(filename)):
                    break
            print 'Neue Aufnahme wird gespeichert unter ' + filename

            # Create wave file
            wavfile = wave.open(filename, 'w')
            wavfile.setnchannels(1)
            wavfile.setsampwidth(2)
            wavfile.setframerate(44100)

            # Record sound
            while (button_record.pressed()):
                l, data = inp.read()
                wavfile.writeframes(data)
                GPIO.output(15, GPIO.HIGH)

            # Stop record an save
            print 'Aufnahme beendet\n'
            inp.close()
            wavfile.close()
            GPIO.output(15, GPIO.LOW)

        # Record has been started but no memory is mounted
        elif (button_record.pressed() and not usb.ismounted()):
            print 'Massenspeichergeraet nicht gefunden'
            print 'Warte auf Massenspeichergeraet'

            # Restart after timeout 
            timestamp = time.time()
            while not (usb.ismounted()):
                if ((time.time() - timestamp) > 120):
                    time.sleep(5)
                    print 'Timeout.'
                    #reboot()
                    #myexit()

            print 'Massenspeichergeraet gefunden'
    myexit()

except KeyboardInterrupt:
    myexit()

根据文档 pyaudio,例程 inp.read() 或 alsaaudio.PCM.read() 通常应该等到完整的 1024 个样本被捕获。然后它应该返回捕获样本的数量以及样本本身。大多数情况下,它只返回一个包含 1024 个样本的周期。我不认为我有性能问题,因为我希望它会返回几个周期。

非常神秘的行为:在录制 01:30 后,inp.read() 的处理时间比正常情况多几毫秒(在我的无知中这是一个有用的信息),然后返回 -32 和错误数据。然后流继续。在 02:00 半分钟后,处理并再次返回 -32 和错误数据大约需要一秒钟(即比第一次长)。该过程每分钟重复一次(02:30-03:00、03:30-04:00、04:30-05:00)。这个时序规范大致是手工制作的。

-32 似乎来自 /pyalsaaudio-0.7/alsaaudio.c 中的以下代码行

return -EPIPE;

关于如何表达的一些话:如果数据流直接写入波形文件,即包括故障时段,则文件包含白噪声部分。这些部分持续 30 秒。这是因为样本通常由 2 个字节组成。当写入故障周期(1 个字节)时,字节顺序会反转。随着下一个故障周期,它再次反转,因此是正确的。如果错误数据被拒绝,只有正确的数据被写入波形文件,文件每 30 秒“跳转”一次。

我认为问题可以在 1.声卡(但我测试了2个不同的) 2.树莓派的计算性能 3. lib pyaudio

进一步说明:我对 linux 和 python 主题还很陌生。如果您需要任何日志或其他东西,请描述我如何找到它们。

长话短说:有人可以帮帮我吗?我该如何解决这个错误?

编辑:我已经做了这个 USB 固件更新的东西,这是必需的,因为 USB 可能不堪重负。顺便说一句:这个 EPIPE 故障到底是什么?

【问题讨论】:

  • 其他一些软件或驱动程序会占用 CPU,并阻止音频中断被足够快地处理。

标签: python raspberry-pi capture alsa noise


【解决方案1】:

经过进一步调查,我发现这个错误不是 python/pyaudio 特定的。当我尝试使用arecord 录制波形文件时,我得到以下输出。超限消息按照上述时序发送。

    pi@raspberrypi ~ $ sudo arecord -D sysdefault:CARD=Device -B buffersize=192000 -f cd -t wav /mnt/usb/test.wav
Recording WAVE '/mnt/usb/test.wav' : Signed 16 bit Little Endian, Rate 44100 Hz, Stereo
overrun!!! (at least -1871413807.430 ms long)
overrun!!! (at least -1871413807.433 ms long)
overrun!!! (at least -1871413807.341 ms long)
overrun!!! (at least -1871413807.442 ms long)

参考this thread at raspberrypi.org,问题似乎是(部分)对 SD 卡或带有树莓派的 USB 存储设备的写入速度有限。在将音频数据写入其他地方之前录制到 RAM(使用 tmpfs)或压缩音频数据(例如使用 lame 压缩到 mp3)在某些情况下可能是一个很好的解决方案。

我不能说为什么写入速度低。在我看来,对于 48 kSamples/s、16 位、立体声,数据流是 192 kByte/s。任何 SD 卡或 USB 大容量存储都应该能够处理这个问题。如上所示,缓冲音频流没有帮助。

【讨论】:

    猜你喜欢
    • 2020-02-20
    • 1970-01-01
    • 2017-01-22
    • 2015-11-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-07-21
    相关资源
    最近更新 更多