Please enable Javascript to view the contents

PyAudio录音教程:内录、外录、录音设备选择

 ·  ☕ 4 分钟

Pyaudio 简介

Pyaudio 简介

PyAudio是Python的一个音频处理模块,它可以让我们在Python中使用音频设备,比如录音、播放音频等。PyAudio是基于PortAudio的,所以它可以在多种平台上使用,比如Windows、Linux、Mac等。

安装

1
pip install pyaudio

示例

接下来通过两段代码来演示PyAudio的使用。通过 record.py 可以录音 录制一段 10 秒的音频,然后通过 play.py 可以播放刚刚录制的音频。

录音 recorder.py

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
import pyaudio
import wave

CHUNK = 1024
FORMAT = pyaudio.paInt16
CHANNELS = 2
RATE = 44100
RECORD_SECONDS = 10
WAVE_OUTPUT_FILENAME = "output.wav"

audio = pyaudio.PyAudio()

# start Recording
stream = audio.open(format=FORMAT, channels=CHANNELS,
                    rate=RATE, input=True,
                    frames_per_buffer=CHUNK)
print("recording...")
frames = []

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

# stop Recording
stream.stop_stream()
stream.close()
audio.terminate()

waveFile = wave.open(WAVE_OUTPUT_FILENAME, 'wb')
waveFile.setnchannels(CHANNELS)
waveFile.setsampwidth(audio.get_sample_size(FORMAT))
waveFile.setframerate(RATE)
waveFile.writeframes(b''.join(frames))
waveFile.close()

播放 play.py

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
import pyaudio
import wave

CHUNK = 1024

wf = wave.open('output.wav', 'rb')

p = pyaudio.PyAudio()

# open stream
stream = p.open(format=p.get_format_from_width(wf.getsampwidth()),
                channels=wf.getnchannels(),
                rate=wf.getframerate(),
                output=True)

# read data
data = wf.readframes(CHUNK)

# play stream
while data != '':
    stream.write(data)
    data = wf.readframes(CHUNK)
    
# stop stream
stream.stop_stream()
stream.close()

# close PyAudio
p.terminate()
wf.close()

录音详解

录音参数

1
2
3
4
5
6
CHUNK = 1024
FORMAT = pyaudio.paInt16
CHANNELS = 2
RATE = 44100
RECORD_SECONDS = 10
WAVE_OUTPUT_FILENAME = "output.wav"
  • CHUNK:每次读取的音频块大小,单位是字节,一般取1024的倍数,比如1024、2048、4096等。
  • FORMAT:音频的格式,这里使用的是16位整数,即paInt16。
  • CHANNELS:声道数,这里使用的是双声道,即2。
  • RATE:采样率,这里使用的是44100,即44.1kHz。
  • RECORD_SECONDS:录音的时长,这里是10秒。
  • WAVE_OUTPUT_FILENAME:输出的音频文件名。

录音设备

上面的 record.py 虽然实现了录音的功能,但是我们不知道声音的输入是什么?是内录还是外录?

PC录音一般有以下几种声音来源:

录制声音的几种来源

  • 外录:麦克风
  • 内录:录制电脑上正在播放的声音,即从声卡录制,而不是从麦克风录制

以下是 Windows 系统下录音的几种方式:

Windows 系统下录音的几种方式
Windows 系统下录音的几种方式

录音设备列表

PyAudio 不指定录音设备的情况下,它会自动选择系统默认的录音设备,比如上面的 麦克风陈列,也就是我们常说的外录。而立体声混音即是内录,内录须在声音面板启用立体声混音。

那么如何指定录音设备呢?我们可以通过 PyAudioget_device_info_by_index 方法来获取设备信息,然后通过 get_default_input_device_info 方法来获取系统默认的录音设备。

指定录音设备

PyAudio提供了一个 get_device_count() 方法,可以获取当前系统的录音设备数量,然后通过 get_device_info_by_index() 方法可以获取指定设备的信息。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
import pyaudio

audio = pyaudio.PyAudio()

# get device count
device_count = audio.get_device_count()
print(f"device count: {device_count}")

# get device info
for i in range(device_count):
    device_info = audio.get_device_info_by_index(i)
    print(f"device {i}: {device_info}")

以下是我电脑运行结果:

1
2
3
4
5
6
7
8
C:\projects\python\pyaudio> python .\devs.py
device count: 24
device 0: {'index': 0, 'structVersion': 2, 'name': 'Microsoft 声音映射器 - Input', 'hostApi': 0, 'maxInputChannels': 2, 'maxOutputChannels': 0, 'defaultLowInputLatency': 0.09, 'defaultLowOutputLatency': 0.09, 'defaultHighInputLatency': 0.18, 'defaultHighOutputLatency': 0.18, 'defaultSampleRate': 44100.0}
device 1: {'index': 1, 'structVersion': 2, 'name': '麦克风阵列 (适用于数字麦克风的英特尔® 智音技 术)', 'hostApi': 0, 'maxInputChannels': 4, 'maxOutputChannels': 0, 'defaultLowInputLatency': 0.09, 'defaultLowOutputLatency': 0.09, 'defaultHighInputLatency': 0.18, 'defaultHighOutputLatency': 0.18, 'defaultSampleRate': 44100.0}
device 2: {'index': 2, 'structVersion': 2, 'name': '立体声混音 (Realtek(R) Audio)', 'hostApi': 0, 'maxInputChannels': 2, 'maxOutputChannels': 0, 'defaultLowInputLatency': 0.09, 'defaultLowOutputLatency': 0.09, 'defaultHighInputLatency': 0.18, 'defaultHighOutputLatency': 0.18, 'defaultSampleRate': 44100.0}
device 3: {'index': 3, 'structVersion': 2, 'name': 'Microsoft 声音映射器 - Output', 'hostApi': 0, 'maxInputChannels': 0, 'maxOutputChannels': 2, 'defaultLowInputLatency': 0.09, 'defaultLowOutputLatency': 0.09, 'defaultHighInputLatency': 0.18, 'defaultHighOutputLatency': 0.18, 'defaultSampleRate': 44100.0}
device 4: {'index': 4, 'structVersion': 2, 'name': 'Realtek HD Audio 2nd output (Re', 'hostApi': 0, 'maxInputChannels': 0, 'maxOutputChannels': 2, 'defaultLowInputLatency': 0.09, 'defaultLowOutputLatency': 0.09, 'defaultHighInputLatency': 0.18, 'defaultHighOutputLatency': 0.18, 'defaultSampleRate': 44100.0}
... ...

其中 立体声混音 (Realtek(R) Audio) 是 device 2。即使此时系统默认的录音设备是外录,我们也可以通过指定 `input_device_index = 2 进行内录。

1
2
3
4
5
# start Recording
stream = audio.open(format=FORMAT, channels=CHANNELS,
                    rate=RATE, input=True,
                    input_device_index = 2,
                    frames_per_buffer=CHUNK)

如何同时内录和外录

我们可以使用 2 个单独的线程将 2 个不同的录音设备(声音输入源)记录到单独的 Wav 文件中。然后使用 pydub 库混合这两个文件。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
import pyaudio
import wave
from tqdm import tqdm
from pydub import AudioSegment

CHUNK = 1024
FORMAT = pyaudio.paInt16
CHANNELS = 2
RATE = 44100
RECORD_SECONDS = 10

audio = pyaudio.PyAudio()

system_sound = audio.open(format=FORMAT, channels=CHANNELS,
                          rate=RATE, input=True,
                          input_device_index=2,
                          frames_per_buffer=CHUNK)
speaker_sound = audio.open(format=FORMAT, channels=CHANNELS,
                           rate=RATE, input=True,
                           input_device_index=1,
                           frames_per_buffer=CHUNK)

print("recording...")
system_sound.start_stream()
speaker_sound.start_stream()

frames1 = []
frames2 = []

for i in tqdm(range(0, int(RATE / CHUNK * RECORD_SECONDS))):
    data1 = system_sound.read(CHUNK)
    frames1.append(data1)

    data2 = speaker_sound.read(CHUNK)
    frames2.append(data2)

print("finished recording")

# stop Recording
system_sound.stop_stream()
system_sound.close()
speaker_sound.stop_stream()
speaker_sound.close()
audio.terminate()

# save the audio frames as .wav file
wf1 = wave.open("system.wav", 'wb')
wf1.setnchannels(CHANNELS)
wf1.setsampwidth(audio.get_sample_size(FORMAT))
wf1.setframerate(RATE)
wf1.writeframes(b''.join(frames1))
wf1.close()

wf2 = wave.open("speaker.wav", 'wb')
wf2.setnchannels(CHANNELS)
wf2.setsampwidth(audio.get_sample_size(FORMAT))
wf2.setframerate(RATE)
wf2.writeframes(b''.join(frames2))
wf2.close()

# merge two wav files
speakersound = AudioSegment.from_file("speaker.wav")
micsound = AudioSegment.from_file("system.wav")

mixsound = speakersound.overlay(micsound)

mixsound.export("mixsound.wav", format='wav')

参考资料

分享

码中人
作者
码中人
Web Developer