Python 如何同时录制2个音频源?
我想录制一首音轨并将其保存为2个不同的.wav文件。音频曲目应以约6秒的延迟保存,每个.wav应为12秒长 我试着用多处理和pyaudio来实现它,但我无法让它正常工作 请注意,我是python初学者,这是我关于stackoverflow的第一篇文章Python 如何同时录制2个音频源?,python,pyaudio,python-sounddevice,Python,Pyaudio,Python Sounddevice,我想录制一首音轨并将其保存为2个不同的.wav文件。音频曲目应以约6秒的延迟保存,每个.wav应为12秒长 我试着用多处理和pyaudio来实现它,但我无法让它正常工作 请注意,我是python初学者,这是我关于stackoverflow的第一篇文章 def func1(): #Record and save a 12 seconds long .wav def func2(): #Record and save a 12 seconds long .wav if __name__
def func1():
#Record and save a 12 seconds long .wav
def func2():
#Record and save a 12 seconds long .wav
if __name__ == '__main__':
p1 = Process(target=func1)
p1.start()
p2 = Process(target=func2)
p2.start()
p1.join()
p2.join()
#start func2 6 seconds after func1
I would expect a data structure like this:
|---1.wav---|---1.wav---|---1.wav---|
|---2.wav---|---2.wav---|---2.wav---|
6sec 12sec 18sec 24sec 30sec 36sec 42sec
编辑:
我想出了一点代码,似乎工作得很好。它有0.144秒的延迟。我很高兴改进了这个代码。此代码使用线程而不是多处理
导入pyaudio
输入波
从线程导入线程
导入时间
从日期时间导入日期时间
格式=pyaudio.paInt16
通道=2
费率=44100
区块=1024
CHUNK1=1024
记录时间=12秒
WAVE\u OUTPUT\u FILENAME1=name=“outputs/OUTPUT\u 1”+datetime.now().strftime(“%m:%d:%Y-”)
WAVE\u OUTPUT\u FILENAME2=name=“outputs/OUTPUT\u 2”+datetime.now().strftime(“%m:%d:%Y-”)
def func1():
而1==1:
全局格式
全球频道
全球汇率
全局块
全球记录(秒)
全局波形输出文件名1
WAVE_OUTPUT_FILENAME1=name=“outputs/output1”#+datetime.now().strftime(“%m:%d:%Y-”)
audio=pyaudio.pyaudio()
流=音频。打开(格式=格式,频道=频道,
速率=速率,输入=真,
帧(每帧缓冲区=块)
打印(“录制…”)
帧=[]
WAVE_OUTPUT_FILENAME1=WAVE_OUTPUT_FILENAME1+datetime.now().strftime(“%H;%M;%S.%f--”)
对于范围内的i(0,int(速率/块*记录秒)):
data=stream.read(块)
frames.append(数据)
WAVE_OUTPUT_FILENAME1=WAVE_OUTPUT_FILENAME1+datetime.now().strftime(“%H;%M;%S.%f”)+“.wav”
打印(“已完成录制”)
#停止录音
stream.stop_stream()
stream.close()
audio.terminate()
波形文件=wave.open(波形输出文件名1,'wb')
波形文件设置通道(通道)
波形文件.设置采样宽度(音频.获取样本大小(格式))
波形文件设置帧率(速率)
波形文件.写格式(b''。连接(帧))
波形文件关闭()
def func2():
时间。睡眠(6)
而1==1:
全局格式
全球频道
全球汇率
全局块1
全球记录(秒)
全局波形输出文件名2
WAVE_OUTPUT_FILENAME2=name=“outputs/output2”#+datetime.now().strftime(“%m:%d:%Y-”)
audio=pyaudio.pyaudio()
流=音频。打开(格式=格式,频道=频道,
速率=速率,输入=真,
帧每缓冲区=块1)
打印(“录制…”)
帧=[]
WAVE_OUTPUT_FILENAME2=WAVE_OUTPUT_FILENAME2+datetime.now().strftime(“%H;%M;%S.%f--”)
对于范围内的i(0,int(速率/块1*记录秒)):
data=stream.read(CHUNK1)
frames.append(数据)
WAVE_OUTPUT_FILENAME2=WAVE_OUTPUT_FILENAME2+datetime.now().strftime(“%H;%M;%S.%f”)+“.wav”
打印(“已完成录制”)
#停止录音
stream.stop_stream()
stream.close()
audio.terminate()
波形文件=wave.open(波形输出文件名2,'wb')
波形文件设置通道(通道)
波形文件.设置采样宽度(音频.获取样本大小(格式))
波形文件设置帧率(速率)
波形文件.写格式(b''。连接(帧))
波形文件关闭()
如果uuuu name uuuuuu='\uuuuuuu main\uuuuuuu':
线程(目标=func1).start()
线程(目标=func2).start()
为什么您认为需要多处理
?我认为这会使事情复杂化
以6秒(或更小)的块/帧记录,并将正确的帧写入每个文件,怎么样
我有点忘乎所以,为此写了一个很好的类:
import pyaudio
import wave
import time
class OverlappedRecorder:
def __init__(
self, secs_per_file, secs_between_file, *,
num_channels=2, sample_rate=48000,
sample_format=pyaudio.paInt16,
):
# various constants needed later
self.num_channels = num_channels
self.sample_width = pyaudio.get_sample_size(sample_format)
self.sample_rate = sample_rate
self.frames_between_start = int(secs_between_file * sample_rate)
self.frames_per_file = int(secs_per_file * sample_rate)
# mutable state needed to keep everything going
self.files = []
self.frames_till_next_file = 0
self.pa = pyaudio.PyAudio()
self.stream = self.pa.open(
format=sample_format, channels=num_channels,
rate=sample_rate, frames_per_buffer=1024,
input=True, start=False,
stream_callback=self._callback,
)
def sleep_while_active(self):
while self.stream.is_active():
time.sleep(0.2)
def begin_wave_file(self):
"internal function to start a new WAV file"
path = time.strftime(
'recording-%Y-%m-%d-%H.%M.%S.wav',
time.localtime()
)
file = wave.open(path, 'wb')
file.setnchannels(self.num_channels)
file.setsampwidth(self.sample_width)
file.setframerate(self.sample_rate)
self.files.append(file)
# context manager stuff, recording starts when entered using "with"
def __enter__(self):
self.stream.start_stream()
return self
# exiting shuts everything down
def __exit__(self, exc_type, exc_val, exc_tb):
self.stream.stop_stream()
self.stream.close()
self.pa.terminate()
for file in self.files:
file.close()
# called by pyaudio when a new set of frames are ready
def _callback(self, data, frame_count, time_info, status):
self.frames_till_next_file -= frame_count
# see if we need to start a new file
if self.frames_till_next_file < 0:
self.frames_till_next_file += self.frames_between_start
self.begin_wave_file()
# can't remove from lists while iterating
# keep a list of files to close and remove later
done = []
for file in self.files:
remain = self.frames_per_file - file.getnframes()
# add appropriate amount of data to all open files
if frame_count < remain:
file.writeframesraw(data)
else:
remain *= self.sample_width * self.num_channels
file.writeframesraw(data[:remain])
done.append(file)
# close anything that finished
for file in done:
file.close()
self.files.remove(file)
# tell pyaudio to keep going
return (None, pyaudio.paContinue)
将让它运行30秒,或者您可以执行以下操作:
with OverlappedRecorder(12, 6) as rec:
rec.sleep_while_active()
让它一直运行,直到按Ctrl+C终止程序,或者您可以在其中调用input()
,使它在按enter键时停止,或者其他任何您喜欢的操作
关于您发布的代码的一些评论:
- 如果要修改变量,只需声明
变量global
- 为什么你有独立的功能?为什么不只使用一个函数,然后延迟第二个
线程
- 为什么要多次设置
?只需保存WAVE\u OUTPUT\u FILENAME1
和开始时间
,然后一次性格式化字符串结束时间
- 您不必成批地
,如果您知道它将适合内存,只需一次读取所有内容即可read()
- 您不需要一直启动和停止录制,只需在每个线程中打开它一次,如果幸运的话,在将wav文件写入磁盘时,样本将积累在缓冲区中
import pyaudio
import wave
import time
from datetime import datetime
from threading import Thread
FORMAT = pyaudio.paInt16
CHANNELS = 2
RATE = 44100
RECORD_SECONDS = 12
def recorder(prefix):
audio = pyaudio.PyAudio()
stream = audio.open(
format=FORMAT, channels=CHANNELS,
rate=RATE, input=True,
)
try:
while True:
start_time = datetime.now()
print("recording started", start_time)
data = stream.read(RATE * RECORD_SECONDS, False)
end_time = datetime.now()
print("finished", end_time)
name = f'{prefix}{start_time:%Y-%m-%d-%H-%M-%S.%f}-{end_time:%H-%M-%S.%f}.wav'
print("writing", name)
with wave.open(name, 'wb') as waveFile:
waveFile.setnchannels(CHANNELS)
waveFile.setsampwidth(audio.get_sample_size(FORMAT))
waveFile.setframerate(RATE)
waveFile.writeframes(data)
finally:
stream.stop_stream()
stream.close()
audio.terminate()
if __name__ == '__main__':
Thread(target=recorder, args=('outputs/output_1-',)).start()
time.sleep(6)
Thread(target=recorder, args=('outputs/output_2-',)).start()
一些不同之处:
- 使用线程的版本代码要少得多李>
- 我的版本允许任意数量的文件,而无需为每个文件使用多个操作系统线程(有Python线程,
有一个内部线程负责音频缓冲区)pyaudio
- 我的版本保存部分文件
希望所有的帮助都有意义 我不知道这在pyaudio中是否可行。至少对我来说不是。谢谢你所有的工作@Sam Mason。我会试着在接下来的几天再看一遍!我有一个关于代码的一部分及其功能的问题:
done=[]对于self.files中的文件:reserve=self.frames\u per\u file-file.getnframes()#如果frame\u countimport pyaudio
import wave
import time
from datetime import datetime
from threading import Thread
FORMAT = pyaudio.paInt16
CHANNELS = 2
RATE = 44100
RECORD_SECONDS = 12
def recorder(prefix):
audio = pyaudio.PyAudio()
stream = audio.open(
format=FORMAT, channels=CHANNELS,
rate=RATE, input=True,
)
try:
while True:
start_time = datetime.now()
print("recording started", start_time)
data = stream.read(RATE * RECORD_SECONDS, False)
end_time = datetime.now()
print("finished", end_time)
name = f'{prefix}{start_time:%Y-%m-%d-%H-%M-%S.%f}-{end_time:%H-%M-%S.%f}.wav'
print("writing", name)
with wave.open(name, 'wb') as waveFile:
waveFile.setnchannels(CHANNELS)
waveFile.setsampwidth(audio.get_sample_size(FORMAT))
waveFile.setframerate(RATE)
waveFile.writeframes(data)
finally:
stream.stop_stream()
stream.close()
audio.terminate()
if __name__ == '__main__':
Thread(target=recorder, args=('outputs/output_1-',)).start()
time.sleep(6)
Thread(target=recorder, args=('outputs/output_2-',)).start()