2017-07-04 14 views
2

ボタンを押しながらマイクから録音しようとしていますが、使用しているライブラリが保留イベントを検出できないという問題があります。それだけで私はキーボードイベントと記録のためpyaudioためを使用していますキー押下イベントでon_pressコールバックを複数回呼び出す

import pyaudio 
import wave 
from pynput import keyboard 

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

p = pyaudio.PyAudio() 
stream = p.open(format=FORMAT, 
       channels=CHANNELS, 
       rate=RATE, 
       input=True, 
       frames_per_buffer=CHUNK)   
frames = [] 

def on_press(key): 
    if key == keyboard.Key.cmd_l: 
     print('- Started recording -'.format(key)) 
     try: 
      data = stream.read(CHUNK) 
      frames.append(data) 
     except IOError: 
      print 'warning: dropped frame' # can replace with 'pass' if no message desired 
    else: 
     print('incorrect character {0}, press cmd_l'.format(key)) 


def on_release(key): 
    print('{0} released'.format(
     key)) 
    if key == keyboard.Key.cmd_l: 
     print('{0} stop'.format(key)) 
     keyboard.Listener.stop 
     return False 

print("* recording") 


with keyboard.Listener(on_press=on_press, on_release=on_release) as listener: 
    listener.join() 

print("* done recording") 

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

..マイクが一つだけのサンプルを記録することを意味し、一度起こる押し、上検出します。 cmd_lが押されたときに記録されているように見えます。問題は、生成されたオーディオファイルに何も含まれていないか、または0.19秒という非常に短いです。

ストリームとの関係は複数回呼び出されなければならず、キー入力は1回だけ記録されるため、1つのサンプルだけが記録されます。

しかし、もしそうなら、どうすればstream.readを何度も呼び出させることができます。また、解放されていることを検出しながらも検出できますか? キーボードのon_holdメカニズムをサポートするライブラリがありますか?

スレッドで更新アプローチ:

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 

私は1つのキーボードを監視する2つのスレッド、導入異なるアプローチを試み、他方は記録をソートします。しかし、この解決法はフレームを落とし続けるので、何も実際に記録されていないのですか?..

どうやって来ますか?

答えて

0

これを行う方法の例を以下に示します。別のスレッドで録音を行うことでコードを修正しました。キーボードが押されたり離されたりすると、Eventの状態が設定され、Eventが設定されると、スレッドはループ内にチャンクを記録します。別のEventを使用して、記録が完了した後にスレッドが終了するよう指示します。これは私のために複数の32Kbチャンクを記録します(8192 * 2chans * 16ビット)。

import pyaudio 
import wave 
from pynput import keyboard 
import threading 

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

p = pyaudio.PyAudio() 

stream = p.open(format=FORMAT, 
       channels=CHANNELS, 
       rate=RATE, 
       input=True, 
       frames_per_buffer=CHUNK)   
frames = [] 

recordingEvent = threading.Event() # set to activate recording 
exitEvent = threading.Event()   # set to stop recording thread 


def on_press(key): 
    if key == keyboard.Key.ctrl: 
     print('- Started recording -'.format(key)) 
     recordingEvent.set() 
    else: 
     print('incorrect character {0}, press cmd_l'.format(key)) 


def on_release(key): 
    print('{0} released'.format(key)) 
    if key == keyboard.Key.ctrl: 
     print('{0} stop'.format(key)) 
     recordingEvent.clear() 
     keyboard.Listener.stop 
     return False 


def do_recording(): 
    while (not exitEvent.is_set()): 
     if (recordingEvent.wait(0.1)): 
      try: 
       data = stream.read(CHUNK) 
       # print len(data) 
       frames.append(data) 
      except IOError: 
       print 'warning: dropped frame' # can replace with 'pass' if no message desired 


class myRecorder(threading.Thread): 
    def __init__(self): 
     threading.Thread.__init__(self) 
    def run(self): 
     do_recording() 


# start recorder thread 
recordingThread = myRecorder() 
recordingThread.start() 

# monitor keyboard 
with keyboard.Listener(on_press=on_press, on_release=on_release) as listener: 
    listener.join() 

# stop recorder thread 
exitEvent.set()  
recordingThread.join() 

print("* done recording") 

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

NBそれは私のマシンはより適しように私は、代わりにCmdをキーのCtrlキーを使用していました。これが役に立つと願っています。

+0

私は似たような解決策を試しました(あなたには私より多くのスレッドがあるようです)...しかし、私はあなたや私の記録できません、IOerrorを与え続けます。 – Smo

0

this answerのように、別のスレッドで定期的に関数を実行することができます。最も簡単なソリューションと思われます。

関連する問題