简体   繁体   English

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

[英]Capturing audio with python on the raspberry pi fails

I am currently working on an easy-to-use audio capturing device for digitizing old casette tapes (ie low fidelity). 我目前正在开发一种易于使用的音频捕获设备,用于将旧的盒式录音带数字化(即低保真度)。 This device is based on a raspberry pi with an usb sound card, which does nothinge else than starting the listed python script on bootup. 该设备基于带有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()

According to the documentation pyaudio, the routine inp.read() or alsaaudio.PCM.read() respectively should usually wait until a full period of 1024 samples has been captured. 根据pyaudio文档,例程inp.read()或alsaaudio.PCM.read()通常应等待,直到捕获了1024个样本为止。 It then should return the number of captured samples as well as the samples itself. 然后,它应返回捕获的样本数以及样本本身。 Most of the time it returns exactly one period of 1024 samples. 大多数情况下,它恰好返回一个周期为1024个样本。 I don't think that I have a performance problem, since I would expect it to return several periods then. 我认为我没有性能问题,因为我希望它会在之后恢复几个周期。

THE VERY MYSTERIOUS BEHAVIOR: After 01:30 of recording, inp.read() takes some milliseconds longer than normal to process (this is a useful information in my ignorant opinion) and then returns -32 and faulty data. 极其神秘的行为:记录01:30之后,inp.read()比正常处理要花费几毫秒的时间(在我无知的情况下,这是有用的信息),然后返回-32和错误数据。 Then the stream continues. 然后流继续。 After half a minute at 02:00 it takes about a second (ie longer than the first time) to process and returns -32 and faulty data again. 在02:00半分钟后,大约需要一秒钟(即,比第一次更长)来处理并再次返回-32和错误数据。 This procedere repeats then every minute (02:30-03:00, 03:30-04:00, 04:30-05:00). 然后,此过程每分钟重复一次(02:30-03:00、03:30-04:00、04:30-05:00)。 This timing specification was roughly taken by hand. 该时序规范大致是手工完成的。

-32 seems to result from the following code line in /pyalsaaudio-0.7/alsaaudio.c -32似乎是/pyalsaaudio-0.7/alsaaudio.c中的以下代码行导致的

return -EPIPE;

Some words about how this expresses: If the data stream is directly written into the wave file, ie including the faulty period, the file contains sections of white noise. 关于此表示方式的一些说法:如果将数据流直接写入wave文件,即包括故障时段,则该文件包含部分白噪声。 These sections last 30 seconds. 这些部分持续30秒。 This is because the samples usually consist of 2 bytes. 这是因为样本通常由2个字节组成。 When the faulty period (1 byte) is written, the byte order gets inverted. 当写入故障时段(1个字节)时,字节顺序被反转。 With the next faulty period it gets inverted again and therefore is correct. 在下一个故障时段,它将再次反转,因此是正确的。 If faulty data is refused and only correct data is written into the wave file, the file 'jumps' every 30 seconds. 如果拒绝错误数据,并且仅将正确的数据写入wave文件,则文件每30秒“跳转”一次。

I think the problem can either be found in 1. the sound card (but I tested 2 different) 2. the computing performance of the raspberry pi 3. the lib pyaudio 我认为问题可以在1.声卡中找到(但我测试了2种不同)2.树莓派的计算性能3. lib pyaudio

Further note: I am pretty new to the linux and python topic. 进一步的注意:我对linux和python话题还很陌生。 If you need any logs or something, please describe how I can find them. 如果您需要任何日志或其他东西,请说明我如何找到它们。

To cut a long story short: Could someone please help me? 简而言之:有人可以帮我吗? How can I solve this error? 我该如何解决这个错误?

EDIT: I already did this usb firmware updating stuff, which is needed, since the usb can be overwhelmed. 编辑:我已经做了这个USB固件更新,这是必需的,因为USB可能会不堪重负。 BTW: What exactly is this EPIPE failure? 顺便说一句:此EPIPE失败到底是什么?

Upon further inverstigation, I found out, that this error is not python/pyaudio specific. 经过进一步的调查,我发现此错误不是特定于python / pyaudio的。 When I try to record a wave file with arecord , I get the following output. 当我尝试使用arecord记录wave文件时,得到以下输出。 The overrun messages are sent according to the timing described above. 根据上述时序发送溢出消息。

    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)

Referring to this thread at raspberrypi.org , the problem seems to be the (partly) limited write speed to the SD card or the usb storage device with a raspberry pi. 引用raspberrypi.org上的该线程 ,问题似乎是(部分)对带有raspberry pi的SD卡或USB存储设备的写入速度受到限制。 Recording to RAM (with tmpfs) or compressing the audio data (eg to mp3 with lame) before writing it somewhere else could be a good solution in some cases. 在某些情况下,在将其写入其他位置之前,先将其记录到RAM(使用tmpfs)或压缩音频数据(例如,使用lame压缩到mp3)可能是一个不错的解决方案。

I can't say why the write speed is to low. 我不能说为什么写速度这么低。 In my opinion, the data stream is 192 kByte/s for 48 kSamples/s, 16 Bit, stereo. 我认为,对于48 kSamples / s,16位,立体声,数据流为192 kByte / s。 Any SD card or usb mass storage should be able to handle this. 任何SD卡或USB大容量存储设备都应该能够处理此问题。 As seen above, buffering the audio stream doesn't help. 如上所示,缓冲音频流没有帮助。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM