【问题标题】:Output audio file not created correctly, or has unknown duration time输出音频文件未正确创建,或持续时间未知
【发布时间】:2017-12-07 00:35:22
【问题描述】:

我目前正在尝试录制一些话语,其中录制会话应在按下并按住某个键时开始,并在释放时停止。我制作了用于记录和存储数据的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 文件的持续时间未知?为什么?

【问题讨论】:

    标签: python keyboard-events pyaudio


    【解决方案1】:

    你还没有填写你的名单,frames

    你应该这样做来填充你的列表:

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

    因为你在这里使用了一个空列表:

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

    我希望这对你有用。

    干杯!

    【讨论】:

    • 好吧..我正在使用回调,所以当listener.stream.start_stream()被调用时,它应该记录。
    • @Smo 启动流并不会神奇地决定如何使用数据或将数据存储在哪里。你试过运行这个了吗?编辑:您应该重新阅读您的代码。你从来没有真正从流中读取或将信息放入frames,这正是这个答案解释如何做的。
    • 但您的解决方案正在使用预先指定的持续时间,我正在尝试对键盘事件执行此操作。
    • 我似乎已经将问题缩小到回调永远不会被调用..
    • @eenblam 我知道这个解决方案会起作用,但不是我想要的......你是对的......我目前没有将数据存储在任何地方......但问题似乎是回调没有被调用..
    【解决方案2】:

    我有你要求的第一版。对不起所有这些global。我不熟悉pynput,所以我只是按照文档,使用pynput的最简单示例。所以这里的代码可以在win7和python3上正常工作。持有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()
    

    更新:

    我只是重写了你的回调,它可能对你有用,但对我来说不行。

    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时,回调将在数据来自硬件时调用。所以逻辑应该像我的版本一样写在回调中而不是while 1: time.sleep(0.1)

    所以,你所有的问题都是在第一次调用回调之后,流接收PAabort,然后流停止。所以回调只被调用一次,所以你的 .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()
    

    【讨论】:

    • 是的......这个解决方案有效......但是是的,但我仍然对为什么我的版本不起作用有点困惑......我似乎已经将问题本地化为回调不被调用,或者只在p.open 时被调用一次,但在其他任何地方都没有被调用...
    猜你喜欢
    • 2015-07-25
    • 1970-01-01
    • 1970-01-01
    • 2021-08-04
    • 1970-01-01
    • 2011-06-15
    • 2022-08-18
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多