PyAudio 响应式录音
PyAudio Responsive Recording
我在PyAudio网站上看到了录制定长录音的录音教程,但我想知道如何对非定长录音做同样的事情?基本上,我想创建按钮来开始和结束录音,但我还没有找到任何关于此事的信息。有什么想法,我不是在寻找替代库吗?
最好是使用非阻塞的记录方式,即您提供一个回调函数,该函数从您启动流的那一刻起就被调用,并在您停止之前为每个被处理的 block/buffer 不断调用流。
例如,在该回调函数中检查一个布尔值,如果为真,则将传入缓冲区写入数据结构,如果为假,则忽略传入缓冲区。例如,可以通过单击按钮来设置此布尔值。
编辑:查看有线音频示例:http://people.csail.mit.edu/hubert/pyaudio/#wire-callback-example
使用参数
打开流
stream_callback=my_callback
其中 my_callback 是声明为
的常规函数
def my_callback(in_data, frame_count, time_info, status)
每次有新缓冲区可用时都会调用此函数。 in_data
包含您要记录的输入。在此示例中,in_data
仅与 pyaudio.paContinue
一起在元组中返回。这意味着来自输入设备的传入缓冲区 put/copied 返回到发送到输出设备的输出缓冲区(它是同一个设备,所以它实际上将输入路由到输出也就是线路)。有关更多解释,请参阅 api 文档:http://people.csail.mit.edu/hubert/pyaudio/docs/#pyaudio.PyAudio.open
所以在这个函数中你可以做类似的事情(这是我写的一些代码的摘录,它不完整:我使用了一些没有描述的函数。我还在一个频道上播放正弦波并在另一个为 24 位格式。):
record_on = False
playback_on = False
recorded_frames = queue.Queue()
def callback_play_sine(in_data, frame_count, time_info, status):
if record_on:
global recorded_frames
recorded_frames.put(in_data)
if playback_on:
left_channel_data = mysine.next_block(frame_count) * MAX_INT24 * gain
right_channel_data = ((np.random.rand(frame_count) * 2) - 1) * MAX_INT24 * gain
data = interleave_channels(max_nr_of_channels, (left_output_channel, left_channel_data), (right_output_channel, right_channel_data))
data = convert_int32_to_24bit_bytestream(data)
else:
data = np.zeros(frame_count*max_nr_of_channels).tostring()
if stop_callback:
callback_flag = pyaudio.paComplete
else:
callback_flag = pyaudio.paContinue
return data, callback_flag
然后您可以在流为 open/running 时从代码的另一部分将 record_on
和 playback_on
设置为 True
或 False
,从而导致录制和播放以独立开始或停止而不会中断流。
我将 in_data
复制到 (threadsafe) queue
中,另一个线程使用它来写入磁盘,否则一段时间后队列会变大。
顺便说一句:pyaudio 基于 portaudio,它有更多的文档和有用的提示。例如 (http://portaudio.com/docs/v19-doxydocs/writing_a_callback.html):回调函数必须在新缓冲区出现之前完成,否则缓冲区将丢失。所以在回调函数中写入文件通常不是一个好主意。 (尽管写入文件会被缓冲,我不知道它最终写入磁盘时是否会阻塞)
import pyaudio
import wave
import pygame, sys
from pygame.locals import *
pygame.init()
scr = pygame.display.set_mode((640, 480))
recording = True
CHUNK = 1024
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)
print("* recording")
frames = []
while True:
if recording:
data = stream.read(CHUNK)
frames.append(data)
for event in pygame.event.get():
if event.type == KEYDOWN and recording:
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()
recording = False
if event.type == QUIT:
pygame.quit(); sys.exit()
我在PyAudio网站上看到了录制定长录音的录音教程,但我想知道如何对非定长录音做同样的事情?基本上,我想创建按钮来开始和结束录音,但我还没有找到任何关于此事的信息。有什么想法,我不是在寻找替代库吗?
最好是使用非阻塞的记录方式,即您提供一个回调函数,该函数从您启动流的那一刻起就被调用,并在您停止之前为每个被处理的 block/buffer 不断调用流。
例如,在该回调函数中检查一个布尔值,如果为真,则将传入缓冲区写入数据结构,如果为假,则忽略传入缓冲区。例如,可以通过单击按钮来设置此布尔值。
编辑:查看有线音频示例:http://people.csail.mit.edu/hubert/pyaudio/#wire-callback-example 使用参数
打开流stream_callback=my_callback
其中 my_callback 是声明为
的常规函数def my_callback(in_data, frame_count, time_info, status)
每次有新缓冲区可用时都会调用此函数。 in_data
包含您要记录的输入。在此示例中,in_data
仅与 pyaudio.paContinue
一起在元组中返回。这意味着来自输入设备的传入缓冲区 put/copied 返回到发送到输出设备的输出缓冲区(它是同一个设备,所以它实际上将输入路由到输出也就是线路)。有关更多解释,请参阅 api 文档:http://people.csail.mit.edu/hubert/pyaudio/docs/#pyaudio.PyAudio.open
所以在这个函数中你可以做类似的事情(这是我写的一些代码的摘录,它不完整:我使用了一些没有描述的函数。我还在一个频道上播放正弦波并在另一个为 24 位格式。):
record_on = False
playback_on = False
recorded_frames = queue.Queue()
def callback_play_sine(in_data, frame_count, time_info, status):
if record_on:
global recorded_frames
recorded_frames.put(in_data)
if playback_on:
left_channel_data = mysine.next_block(frame_count) * MAX_INT24 * gain
right_channel_data = ((np.random.rand(frame_count) * 2) - 1) * MAX_INT24 * gain
data = interleave_channels(max_nr_of_channels, (left_output_channel, left_channel_data), (right_output_channel, right_channel_data))
data = convert_int32_to_24bit_bytestream(data)
else:
data = np.zeros(frame_count*max_nr_of_channels).tostring()
if stop_callback:
callback_flag = pyaudio.paComplete
else:
callback_flag = pyaudio.paContinue
return data, callback_flag
然后您可以在流为 open/running 时从代码的另一部分将 record_on
和 playback_on
设置为 True
或 False
,从而导致录制和播放以独立开始或停止而不会中断流。
我将 in_data
复制到 (threadsafe) queue
中,另一个线程使用它来写入磁盘,否则一段时间后队列会变大。
顺便说一句:pyaudio 基于 portaudio,它有更多的文档和有用的提示。例如 (http://portaudio.com/docs/v19-doxydocs/writing_a_callback.html):回调函数必须在新缓冲区出现之前完成,否则缓冲区将丢失。所以在回调函数中写入文件通常不是一个好主意。 (尽管写入文件会被缓冲,我不知道它最终写入磁盘时是否会阻塞)
import pyaudio
import wave
import pygame, sys
from pygame.locals import *
pygame.init()
scr = pygame.display.set_mode((640, 480))
recording = True
CHUNK = 1024
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)
print("* recording")
frames = []
while True:
if recording:
data = stream.read(CHUNK)
frames.append(data)
for event in pygame.event.get():
if event.type == KEYDOWN and recording:
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()
recording = False
if event.type == QUIT:
pygame.quit(); sys.exit()