2016-03-05 46 views
1

我的目標是在按下按鈕時錄製聲音。在「if」條件下錄製音頻導致靜態

第一步實際上是錄製音頻。下面的腳本就像一個魅力:

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() 

任何人都可以指出我正確的方向來解決這個問題嗎?我無法弄清楚這一點。

測試: 這些行動導致相同的靜態音頻文件:

  • 而按鈕已經按下了按鈕一次
  • 終止後按下
  • 終止腳本終止腳本按下按鈕後的腳本兩次
  • 用循環計數器替換按鈕並記錄循環計數是否在20到40之間以確保該按鈕是不是問題。

錯誤與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 

「打印L」,而在與numpy的註釋掉

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

什麼測試都做了些什麼?您是否嘗試過按下按鈕,然後按下按鈕時終止腳本?您是否嘗試按下按鈕並釋放它(一次),然後終止腳本? ... ... ...我不知道Python的,所以我不知道這是否是顯著,但:你按下按鈕,第二次,腳本調用'INP = alsaaudio.PCM(...)'和'W =波。打開('test.wav','w')'第二次,沒有從第一次初始化清理。 ...... ... ......另外,你有兩個'hasRecorded = True'語句;看起來你只需要一個。 – Scott

+0

也許讀取按鈕狀態需要很長時間,音頻會被超出。你可以通過調用'time.time()'前後調用多長時間來進行民意調查,並且採取差異。這是秒數的浮點數。 – meuh

+0

您可能會在[樹莓派具體](http://raspberrypi.stackexchange.com/)stackexchange網站的更多幫助。 – meuh

回答

1

環路你是不是叫讀取速度不夠快。 -32是unix錯誤代碼 - EPIPE*Alsa docs說:

-EPIPE

此錯誤xrun(溢進行播放或溢出捕獲)。 ...當應用程序沒有及時從alsa-lib中獲取新捕獲的樣本時,可能會發生溢出。

因此,聲音設備生成的樣本更快,然後您正在使用它們。將按鈕digitalRead添加到您的工作循環已經減慢了太多。您已經設置了ALSA以44100樣本/秒的速度生成1024個樣本的塊,這意味着您需要每23毫秒調用一次read 。我會花時間閱讀按鈕的空循環,看看需要多長時間。

根據按鈕代碼的速度,有幾種可能的解決方案。降低採樣率肯定會降低您需要撥打read的頻率,但也會降低音頻質量。增加週期將會填充更大的緩衝區,這意味着你需要不經常讀取它們。缺點是對按鈕按下的反應較少。使用8位樣本也可以降低質量成本的處理負荷。

一個結構性的解決辦法是擺脫在這個循環中讀取按鈕,只是監控的事件,你可以在中斷處理程序,或獨立線程用於監視的I/O設置。

*順便說一下,這似乎是pyalsaaudio documentation中的缺口,或者是實施中的缺陷。沒有提到read函數可以返回錯誤代碼。

+0

太棒了,非常感謝!這給了我一些新的研究。 – JohnHeroHD

+1

@JohnHeroHD可以找到的使用[覆盆子PI手冊]的132頁上的'threading'庫在單獨的線程讀取GPIO一個例子(http://downloads.raspberrypi.org/Raspberry_Pi_Education_Manual.pdf) – meuh

+1

我剛使它工作!我正在產生一個處理記錄的新過程,並且只要按鈕不再被按下,就簡單地終止過程。我甚至添加了一些LED用於視覺指示。非常感謝你指引我朝這個方向發展!對於任何有興趣的人來說,這裏是最後的工作腳本:https://gist.github.com/JohnHeroHD/c53efdae55faf780f79b – JohnHeroHD