2017-07-03 68 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