在 "if" 条件下录制音频会导致静态

Recording audio in "if" condition results in static

我的目标是在按下按钮时录制声音。

第一步实际上是录制音频。以下脚本非常有效:

import alsaaudio, wave, numpy

inp = alsaaudio.PCM(alsaaudio.PCM_CAPTURE, alsaaudio.PCM_NORMAL, "default:CARD=C525")
inp.setchannels(1)
inp.setrate(44100)
inp.setformat(alsaaudio.PCM_FORMAT_S16_LE)
inp.setperiodsize(1024)

w = wave.open('test.wav', 'w')
w.setnchannels(1)
w.setsampwidth(2)
w.setframerate(44100)

while True:
    l, data = inp.read()
    a = numpy.fromstring(data, dtype='int16')
    print numpy.abs(a).mean()
    w.writeframes(data)

test.wav 文件播放得很好,声音正在正确录制。

现在我只想在按下按钮时录制音频。我正在使用带有按钮的 GrovePi。这个按钮很好用。它检测到按钮被按下,它生成 .wav 文件,但它生成的音频文件包含纯静态。

import time
import grovepi
import alsaaudio
import os
import wave
import numpy

button = 4 #grovepi D4
grovepi.pinMode(button,"INPUT")
inputSoundDevice = "default:CARD=C525"
path = os.path.realpath(__file__).rstrip(os.path.basename(__file__))

def start():
    print "started"

    while True:
        if grovepi.digitalRead(button) == 1:
            inp = alsaaudio.PCM(alsaaudio.PCM_CAPTURE, alsaaudio.PCM_NORMAL, inputSoundDevice)
            inp.setchannels(1)
            inp.setrate(44100)
            inp.setformat(alsaaudio.PCM_FORMAT_S16_LE)
            inp.setperiodsize(1024)
            time.sleep(.5)
            print "inp setup"

            w = wave.open('test.wav', 'w')
            w.setnchannels(1)
            w.setsampwidth(2)
            w.setframerate(44100)
            print "wave setup"

            while(grovepi.digitalRead(button) == 1):
                l, data = inp.read()
                a = numpy.fromstring(data, dtype='int16')
                print numpy.abs(a).mean()
                w.writeframes(data)

            time.sleep(.5)
            w.close()
            inp = None
            print "closed"

start()

任何人都可以指出正确的方向来解决这个问题吗?我想不通这个。

测试中: 这些操作会产生相同的静态音频文件:

numpy 出错

File "buttonWhilePressedLight.py", line 43, in <module>
start()
File "buttonWhilePressedLight.py", line 34, in start
a = numpy.fromstring(data, dtype='int16')
ValueError: string size must be a multiple of element size

"print l" 在循环中用 numpy 注释掉

started
inp setup
wave setup
940
-32
940
-32
940
<-etc,etc,etc->
closed

您调用 read 的速度不够快。 -32 是 unix 错误代码 -EPIPE.* Alsa docs 表示:

-EPIPE

This error means xrun (underrun for playback or overrun for capture). ... The overrun can happen when an application does not take new captured samples in time from alsa-lib.

因此声音设备生成样本的速度比您使用它们的速度更快。将按钮 digitalRead 添加到您的工作循环中会减慢它的速度。您已将 ALSA 设置为在 44100 samples/second 处生成 1024 个样本块,这意味着您需要调用 read 每 23 毫秒。我会计时一个空循环读取按钮,看看需要多长时间。

根据按钮代码的速度,有几种可能的解决方案。降低采样率肯定会降低你需要调用的频率read,但也会降低音频质量。增加 periodsize 将填充更大的缓冲区,这意味着您需要减少读取它们的频率。缺点是对按钮按下的响应较差。使用 8 位样本还可以以质量为代价来减少处理负荷。

一个结构性的解决方案是去掉这个循环中的按钮读取,只监视一个事件,你可以在中断处理程序中设置这个事件,或者在监视 I/O 的独立线程中设置。

*顺便说一句,这似乎是 pyalsaaudio documentation 中的一个漏洞,或者是实现中的一个错误。没有提到 read 函数可以 return 错误代码。