我目前正致力于一种易于使用的音频捕获设备,用于数字化旧的盒式磁带(即低保真度)。这个设备基于一个带有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究竟失败了什么?答案 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大容量存储都应该能够处理这个问题。如上所示,缓冲音频流没有帮助。