【发布时间】: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