2017-07-03 69 views
9

我目前正在嘗試錄製一些話語,其中記錄會話應當在按下某個鍵時按下並在發佈時停止。我做了python腳本用於記錄和存儲數據..輸出音頻文件未正確創建,或者持續時間不明

from pynput import keyboard 
import time 
import pyaudio 
import wave 

CHUNK = 8192 
FORMAT = pyaudio.paInt16 
CHANNELS = 2 
RATE = 44100 
RECORD_SECONDS = 5 
WAVE_OUTPUT_FILENAME = "output.wav" 

p = pyaudio.PyAudio() 
frames = [] 

def callback(in_data, frame_count, time_info, status): 
    return (in_data, pyaudio.paContinue) 

class MyListener(keyboard.Listener): 
    def __init__(self): 
     super(MyListener, self).__init__(self.on_press, self.on_release) 
     self.key_pressed = None 

     self.stream = p.open(format=FORMAT, 
          channels=CHANNELS, 
          rate=RATE, 
          input=True, 
          frames_per_buffer=CHUNK, 
          stream_callback = self.callback) 
     print self.stream.is_active() 

    def on_press(self, key): 
     if key == keyboard.Key.cmd_l: 
      self.key_pressed = True 

    def on_release(self, key): 
     if key == keyboard.Key.cmd_l: 
      self.key_pressed = False 

    def callback(self,in_data, frame_count, time_info, status): 
     if self.key_pressed == True: 
      return (in_data, pyaudio.paContinue) 
     elif self.key_pressed == False: 
      return (in_data, pyaudio.paComplete) 
     else: 
      return (in_data,pyaudio.paAbort) 


listener = MyListener() 
listener.start() 
started = False 

while True: 
    time.sleep(0.1) 
    if listener.key_pressed == True and started == False: 
     started = True 
     listener.stream.start_stream() 
     print "start Stream" 

    elif listener.key_pressed == False and started == True: 
     print "Something coocked" 
     listener.stream.stop_stream() 
     listener.stream.close() 
     p.terminate() 

     wf = wave.open(WAVE_OUTPUT_FILENAME, 'wb') 
     wf.setnchannels(CHANNELS) 
     wf.setsampwidth(p.get_sample_size(FORMAT)) 
     wf.setframerate(RATE) 
     wf.writeframes(b''.join(frames)) 
     wf.close() 

     started = False 

問題的腳本是音頻文件似乎並沒有錄製任何文件的時間當我玩它是未知的?..

我不知道我明白這裏有什麼可能是錯的..?

更新:

新版本的輸出:

from pynput import keyboard 
import time 
import pyaudio 
import StringIO 
import multiprocessing 
from multiprocessing import Process, Queue, queues 
import wave 

CHUNK = 8192 
FORMAT = pyaudio.paInt16 
CHANNELS = 2 
RATE = 44100 
RECORD_SECONDS = 5 
WAVE_OUTPUT_FILENAME = "output.wav" 

p = pyaudio.PyAudio() 
frames = [] 

stream_queue = Queue() 



class MyListener(keyboard.Listener): 
    def __init__(self): 
     super(MyListener, self).__init__(on_press=self.on_press, on_release=self.on_release) 
     self.key_pressed = None 


     self.stream = p.open(format=FORMAT, 
          channels=CHANNELS, 
          rate=RATE, 
          input=True, 
          frames_per_buffer=CHUNK, 
          stream_callback = self.callback) 

     print ("Stream active? " + str(self.stream.is_active())) 

    def on_press(self, key): 
     if key == keyboard.Key.cmd_l: 
      self.key_pressed = True 

    def on_release(self, key): 
     if key == keyboard.Key.cmd_l: 
      self.key_pressed = False 

    def callback(self,in_data, frame_count, time_info, status): 
     print "callback" 
     if self.key_pressed == True: 
      #stream_queue.put(in_data) 
      frames.append(data) 
      return (in_data, pyaudio.paContinue) 

     elif self.key_pressed == False: 
      #stream_queue.put(in_data) 
      frames.append(data) 
      return (in_data, pyaudio.paComplete) 

     else: 
      return (in_data,pyaudio.paAbort) 


listener = MyListener() 
listener.start() 
started = False 

while True: 
    time.sleep(0.1) 
    if listener.key_pressed == True and started == False: 
     started = True 
     listener.stream.start_stream() 
     print ("Start stream - Key is down") 

    elif listener.key_pressed == True and started == True: 
     print("stream has started and key is still down") 
     print("Stream is active? " + str(listener.stream.is_active())) 
     print("Stream is stopped? " + str(listener.stream.is_stopped())) 
     print("Stream is time? " + str(listener.stream.get_time())) 

    elif listener.key_pressed == False and started == True: 
     print("Key has been released") 
     listener.stream.stop_stream() 
     listener.stream.close() 
     print("stream has been closed") 
     p.terminate() 

     wf = wave.open(WAVE_OUTPUT_FILENAME, 'wb') 
     wf.setnchannels(CHANNELS) 
     wf.setsampwidth(p.get_sample_size(FORMAT)) 
     wf.setframerate(RATE) 
     wf.writeframes(b''.join(frames)) 
     wf.close() 

     started = False 

輸出:

python File2.py 
Stream active? True 
callback 
Start stream - Key is down 
stream has started and key is still down 
Stream is active? False 
Stream is stopped? False 
Stream is time? 134638.797766 
stream has started and key is still down 
Stream is active? False 
Stream is stopped? False 
Stream is time? 134638.902259 
stream has started and key is still down 
Stream is active? False 
Stream is stopped? False 
Stream is time? 134639.006739 
stream has started and key is still down 
Stream is active? False 
Stream is stopped? False 
Stream is time? 134639.111282 
stream has started and key is still down 
Stream is active? False 
Stream is stopped? False 
Stream is time? 134639.215573 
stream has started and key is still down 
Stream is active? False 
Stream is stopped? False 
Stream is time? 134639.320448 
stream has started and key is still down 
Stream is active? False 
Stream is stopped? False 
Stream is time? 134639.424682 
stream has started and key is still down 
Stream is active? False 
Stream is stopped? False 
Stream is time? 134639.528631 
stream has started and key is still down 
Stream is active? False 
Stream is stopped? False 
Stream is time? 134639.633699 
stream has started and key is still down 
Stream is active? False 
Stream is stopped? False 
Stream is time? 134639.738129 
stream has started and key is still down 
Stream is active? False 
Stream is stopped? False 
Stream is time? 134639.842747 
Key has been released 
stream has been closed 
^CTraceback (most recent call last): 
    File "File2.py", line 67, in <module> 
    time.sleep(0.1) 
KeyboardInterrupt 
MacBook-Pro:~$ play output.wav 

output.wav: 

File Size: 44   
    Encoding: Signed PCM  
    Channels: 2 @ 16-bit 
Samplerate: 44100Hz  
Replaygain: off   
    Duration: unknown  

In:0.00% 00:00:00.00 [00:00:00.00] Out:0  [  |  ]  Clip:0  
Done. 

的事情,似乎不可思議,在我看來

  • listener.stream.start_stream()
  • 回調打印消息callback只打印一次,但應在每次回調將數據存儲到幀時打印,而這些幀只會顯示一次。
  • output.wav文件的持續時間未知?爲什麼?

回答

5

我有這個第一版的請求。對所有這一切都可以。global。我不熟悉pynput,所以我只是按照DOC,使用最簡單的例子pynput。所以這裏的代碼工作正常與win7和python3.holding space開始記錄,和esc退出腳本。

from pynput import keyboard 
import pyaudio 
import wave 
import time 

CHUNK = 8192 
FORMAT = pyaudio.paInt16 
CHANNELS = 2 
RATE = 44100 
RECORD_SECONDS = 5 
WAVE_OUTPUT_FILENAME = "output.wav" 

record_on = False 
complete_tag = False 
frames = [] 

def callback(in_data, frame_count, time_info, status): 
    print("callback called") 
    callback_flag = pyaudio.paContinue 
    # global record_on 
    if record_on: 
     # global frames 
     frames.append(in_data) 
    if complete_tag: 
     callback_flag = pyaudio.paComplete 

    return in_data, callback_flag 

def on_press(key): 
    global record_on 
    print(record_on) 
    if key == keyboard.Key.space: 
     record_on = True 

def on_release(key): 
    global record_on 
    global complete_tag 
    record_on = False 
    complete_tag = True 
    if key == keyboard.Key.esc: 
     return False 

if __name__ == '__main__': 
    p = pyaudio.PyAudio() 
    stream = p.open(format=FORMAT, 
       channels=CHANNELS, 
       rate=RATE, 
       input=True, 
       frames_per_buffer=CHUNK, 
       stream_callback=callback) 
    with keyboard.Listener(
      on_press=on_press, 
      on_release=on_release) as listener: 
     listener.join() 
    stream.stop_stream() 
    stream.close() 
    p.terminate() 

    wf = wave.open(WAVE_OUTPUT_FILENAME, 'wb') 
    wf.setnchannels(CHANNELS) 
    wf.setsampwidth(p.get_sample_size(FORMAT)) 
    wf.setframerate(RATE) 
    wf.writeframes(b''.join(frames)) 
    wf.close() 

UPDATE:

我只是重寫你的回調,並且它可能工作對你罰款,但不適合我。

def callback(self,in_data, frame_count, time_info, status): 
    print("callback") 
    if self.key_pressed == True: 
     #stream_queue.put(in_data) 
     print("record") 
     frames.append(in_data) 
     return (in_data, pyaudio.paContinue) 

    elif self.key_pressed == False: 
     #stream_queue.put(in_data) 
     frames.append(in_data) 
     return (in_data, pyaudio.paComplete) 

    else: 
     print("not record") 
     return (in_data,pyaudio.paContinue) 

你不明白回調,當你叫p.open with callback,當數據來自hardware.so邏輯應該像我的版本,而不是while 1: time.sleep(0.1)回調寫回調會被調用。

所以,你所有的問題是在回調的第一次調用之後,流接收到PAabort,然後流stop.so回調只被調用一次,所以你的.wav文件只有元數據,沒有持續時間。

,我整個代碼更改爲

from pynput import keyboard 
import pyaudio 
import wave 

CHUNK = 8192 
FORMAT = pyaudio.paInt16 
CHANNELS = 2 
RATE = 44100 
WAVE_OUTPUT_FILENAME = "output.wav" 

class MyListener(keyboard.Listener): 
    def __enter__(self): 
     self.p = pyaudio.PyAudio() 
     self.stream = self.p.open(format=FORMAT, 
          channels=CHANNELS, 
          rate=RATE, 
          input=True, 
          frames_per_buffer=CHUNK, 
          stream_callback = self.callback) 
     self.start() 
     return self 
    def __init__(self): 
     super(MyListener, self).__init__(on_press=self.on_press, on_release=self.on_release) 
     self.key_pressed = False 
     self.complete_tag = False 
     self.frames = [] 

    def on_press(self, key): 
     if key == keyboard.Key.space: 
      self.key_pressed = True 

    def on_release(self, key): 
     if key == keyboard.Key.space: 
      self.key_pressed = False 
      self.complete = True 
     if key == keyboard.Key.esc: 
      return False 

    def callback(self,in_data, frame_count, time_info, status): 
     callback_flag = pyaudio.paContinue 
     if self.key_pressed: 
      self.frames.append(in_data) 
     if self.complete_tag: 
      callback_flag = pyaudio.paComplete 
     return in_data, callback_flag 

    def __exit__(self, exc_type, exc_value, traceback): 
     self.stream.stop_stream() 
     self.stream.close() 
     self.p.terminate() 
     self.stop() 
     wf = wave.open(WAVE_OUTPUT_FILENAME, 'wb') 
     wf.setnchannels(CHANNELS) 
     wf.setsampwidth(self.p.get_sample_size(FORMAT)) 
     wf.setframerate(RATE) 
     wf.writeframes(b''.join(self.frames)) 
     wf.close() 

with MyListener() as listener: 
     listener.join() 
+0

是啊...這個解決方案的工作原理......但是,但是我仍然有點困惑,爲什麼我的版本不起作用......我似乎有本地化的問題是沒有被調用的回調,或者只有在'p.open'被調用時調用一次,但它不會在其他地方被調用... – Smo

+0

是的,工作。 – Smo

2

您還沒有填寫清單,frames。因爲你在這裏使用一個空列表

for i in range(0, int(RATE/CHUNK * RECORD_SECONDS)): 
    data = stream.read(CHUNK) 
    frames.append(data) 

你應該這樣做來填充列表

wf.writeframes(b''.join(frames)) 

我希望這對你的作品。

乾杯!

+0

好..我現在用的回調,所以當'listener.stream.start_stream()'被調用,它應該記錄。 – Smo

+0

@Smo啓動流不會奇蹟般地決定如何使用數據或存儲數據。你試過這個嗎?編輯:你應該重讀你的代碼。你從來沒有真正從流中讀取信息或將信息放入'frames'中,這正是這個答案解釋如何做的。 – eenblam

+0

但您的解決方案正在使用預設的持續時間,這是我正在嘗試使用鍵盤事件進行的操作。 – Smo