输出音频文件未正确创建,或持续时间未知
Posted
技术标签:
【中文标题】输出音频文件未正确创建,或持续时间未知【英文标题】: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 文件的持续时间未知?为什么?
【问题讨论】:
【参考方案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
时被调用一次,但在其他任何地方都没有被调用...以上是关于输出音频文件未正确创建,或持续时间未知的主要内容,如果未能解决你的问题,请参考以下文章
win7 进入传奇提示音频设备无法初始化(插上耳机就可以玩,不想插入耳机如何解决)
iOS 将 2 个或多个音频文件合并(混合)为 wav 格式