在树莓派上用python捕获音频失败了

时间:2015-08-27 12:37:44

标签: python raspberry-pi capture alsa noise

我目前正致力于一种易于使用的音频捕获设备,用于数字化旧的盒式磁带(即低保真度)。这个设备基于一个带有usb声卡的覆盆子pi,除了在启动时启动列出的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究竟失败了什么?

1 个答案:

答案 0 :(得分:0)

经过进一步的调查,我发现,这个错误不是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卡或具有覆盆子pi的USB存储设备的写入速度。在某些情况下,在将其写入其他地方之前,将其录制到RAM(使用tmpfs)或压缩音频数据(例如,使用lame进行压缩)可能是一个很好的解决方案。

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