19 KiB
用 Python 播放和录制声音
原文:https://realpython.com/playing-and-recording-sound-python/
*立即观看**本教程有真实 Python 团队创建的相关视频课程。配合文字教程一起看,加深理解: 用 Python 演奏录音
如果您想使用 Python 来播放或录制声音,那么您来对地方了!在本教程中,您将学习如何使用一些最流行的音频库在 Python 中播放和录制声音。您将首先了解播放和录制声音的最直接的方法,然后了解一些提供更多功能的库,以换取几行额外的代码。
本教程结束时,你将知道如何:
- 播放 MP3 和 WAV 文件,以及一系列其他音频格式
- 播放包含声音的 NumPy 和 Python 数组
- 使用 Python 录制声音
- 以一系列不同的文件格式保存您的录音或音频文件
要获得与音频相关的 Python 库的完整列表,请查看 Python 中关于音频的维基页面。
免费下载: 从 Python 技巧中获取一个示例章节:这本书用简单的例子向您展示了 Python 的最佳实践,您可以立即应用它来编写更漂亮的+Python 代码。
播放音频文件
下面,您将看到如何使用一系列 Python 库来播放音频文件。其中一些库允许您播放一系列音频格式,包括 MP3 和 NumPy 数组。以下所有库都允许您播放 WAV 文件,有些库比其他库多几行代码:
-
如果你只是想播放一个 WAV 或 MP3 文件,那么
playsound是最简单的软件包。除了简单的回放,它不提供任何功能。 -
simpleaudio让你播放 WAV 文件和 NumPy 数组,并给你检查文件是否还在播放的选项。 -
winsound允许你播放 WAV 文件或者让你的扬声器发出嘟嘟声,但是它只在 Windows 上有效。 -
**
python-sounddevice****pyaudio**为 PortAudio 库提供绑定,用于跨平台播放 WAV 文件。 -
pydub需要pyaudio进行音频播放,但安装了ffmpeg后,只需几行代码就能让你播放大范围的音频格式。
让我们一个一个的来看看这些用于音频播放的库。
playsound
playsound 是一个“纯 Python,跨平台,单一功能模块,对播放声音没有依赖性。”使用这个模块,你可以用一行代码播放一个声音文件:
from playsound import playsound
playsound('myfile.wav')
playsound的文档声明它已经在 WAV 和 MP3 文件上测试过,但它也可能适用于其他文件格式。
这个库最后一次更新是在 2017 年 6 月。在撰写本文时,它似乎工作得很好,但不清楚它是否仍然支持较新的 Python 版本。
simpleaudio
simpleaudio 是一个跨平台的库,用于播放(单声道和立体声)WAV 文件,不依赖。以下代码可用于播放 WAV 文件,并在终止脚本之前等待文件播放完毕:
import simpleaudio as sa
filename = 'myfile.wav'
wave_obj = sa.WaveObject.from_wave_file(filename)
play_obj = wave_obj.play()
play_obj.wait_done() # Wait until sound has finished playing
WAV 文件包含一个代表原始音频数据的位序列,以及 RIFF(资源交换文件格式)格式的带有元数据的头。
对于 CD 录音,行业标准是将每个音频样本(与气压相关的单个音频数据点)存储为一个 16 位值,每秒 44100 个样本。
为了减小文件大小,以较低的采样率(例如每秒 8000 个样本)存储一些记录(例如人类语音)可能就足够了,尽管这确实意味着较高的声音频率可能不会被准确地表示。
本教程中讨论的一些库播放和录制 bytes 对象,而其他的使用 NumPy 数组来存储原始音频数据。
两者都对应于一系列数据点,为了播放声音,可以以指定的采样速率回放这些数据点。对于一个 bytes 对象,每个样本存储为一组两个 8 位值,而在 NumPy 数组中,每个元素可以包含一个对应于单个样本的 16 位值。
这两种数据类型的一个重要区别是, bytes对象是不可变的,而 NumPy 数组是可变的,这使得后者更适合生成声音和更复杂的信号处理。关于如何使用 NumPy 的更多信息,请看我们的 NumPy 教程。
simpleaudio允许你使用simpleaudio.play_buffer()来玩 NumPy 和 Python 数组以及bytes对象。确保您已经安装了 NumPy,以便下面的示例以及simpleaudio能够工作。(安装了pip之后,你可以通过从你的控制台运行pip install numpy来完成这个任务。)
关于如何使用pip安装包的更多信息,请看一下 Pipenv:新 Python 打包工具指南。
在下面,您将看到如何生成一个对应于 440 赫兹音调的 NumPy 数组,并使用simpleaudio.play_buffer()进行回放:
import numpy as np
import simpleaudio as sa
frequency = 440 # Our played note will be 440 Hz
fs = 44100 # 44100 samples per second
seconds = 3 # Note duration of 3 seconds
# Generate array with seconds*sample_rate steps, ranging between 0 and seconds
t = np.linspace(0, seconds, seconds * fs, False)
# Generate a 440 Hz sine wave
note = np.sin(frequency * t * 2 * np.pi)
# Ensure that highest value is in 16-bit range
audio = note * (2**15 - 1) / np.max(np.abs(note))
# Convert to 16-bit data
audio = audio.astype(np.int16)
# Start playback
play_obj = sa.play_buffer(audio, 1, 2, fs)
# Wait for playback to finish before exiting
play_obj.wait_done()
接下来,让我们看看如何使用winsound在 Windows 机器上播放 WAV 文件。
winsound
如果你使用 Windows,你可以使用内置的 winsound 模块来访问其基本的声音播放机制。播放 WAV 文件只需几行代码:
import winsound
filename = 'myfile.wav'
winsound.PlaySound(filename, winsound.SND_FILENAME)
winsound不支持播放除 WAV 文件以外的任何文件。它确实允许你使用winsound.Beep(frequency, duration)让你的扬声器发出嘟嘟声。例如,您可以使用以下代码发出 1000 赫兹的提示音 100 毫秒:
import winsound
winsound.Beep(1000, 100) # Beep at 1000 Hz for 100 ms
接下来,您将学习如何使用python-sounddevice模块进行跨平台音频播放。
python-sounddevice
正如其文档中所述, python-sounddevice “为 PortAudio 库提供绑定和一些方便的函数来播放和录制包含音频信号的 NumPy 数组”。为了播放 WAV 文件,需要安装numpy和soundfile,以 NumPy 数组的形式打开 WAV 文件。
安装了python-sounddevice、numpy和soundfile之后,您现在可以将 WAV 文件作为 NumPy 数组读取并回放:
import sounddevice as sd
import soundfile as sf
filename = 'myfile.wav'
# Extract data and sampling rate from file
data, fs = sf.read(filename, dtype='float32')
sd.play(data, fs)
status = sd.wait() # Wait until file is done playing
包含sf.read()的行提取原始音频数据,以及存储在其 RIFF 头中的文件的采样率,sounddevice.wait()确保脚本仅在声音结束播放后终止。
接下来,我们将学习如何使用pydub来播放声音。安装了正确的依赖项后,它允许你播放各种各样的音频文件,并且比python-soundevice提供了更多的音频处理选项。
pydub
虽然 pydub 可以打开保存 WAV 文件,没有任何依赖关系,但是需要安装音频播放包才能播放音频。强烈推荐simpleaudio,但是pyaudio、ffplay、avplay也是备选方案。
下面的代码可以用来播放带有pydub的 WAV 文件:
from pydub import AudioSegment
from pydub.playback import play
sound = AudioSegment.from_wav('myfile.wav')
play(sound)
为了播放其他音频类型,如 MP3 文件,应安装 ffmpeg 或 libav 。查看pydub的文档获取说明。作为文档中描述的步骤的替代, ffmpeg-python 为ffmpeg提供绑定,可以使用 pip 进行安装:
$ pip install ffmpeg-python
安装了ffmpeg之后,回放一个 MP3 文件只需要对我们之前的代码做一点小小的改动:
from pydub import AudioSegment
from pydub.playback import play
sound = AudioSegment.from_mp3('myfile.mp3')
play(sound)
使用AudioSegment.from_file(filename, filetype)结构,你可以播放任何类型的ffmpeg支持的音频文件。例如,您可以使用以下内容播放 WMA 文件:
sound = AudioSegment.from_file('myfile.wma', 'wma')
除了回放声音文件,pydub还允许您以不同的文件格式保存音频(稍后将详细介绍),分割音频,计算音频文件的长度,淡入或淡出,以及应用交叉淡入淡出。
AudioSegment.reverse()创建倒放的音频片段的副本,文档描述为“对平克·弗洛伊德、鬼混和一些音频处理算法有用。”
pyaudio
pyaudio 为跨平台音频 I/O 库 PortAudio 提供绑定。这意味着您可以使用pyaudio在各种平台上播放和录制音频,包括 Windows、Linux 和 Mac。使用pyaudio,通过写入.Stream来播放音频:
import pyaudio
import wave
filename = 'myfile.wav'
# Set chunk size of 1024 samples per data frame
chunk = 1024
# Open the sound file
wf = wave.open(filename, 'rb')
# Create an interface to PortAudio
p = pyaudio.PyAudio()
# Open a .Stream object to write the WAV file to
# 'output = True' indicates that the sound will be played rather than recorded
stream = p.open(format = p.get_format_from_width(wf.getsampwidth()),
channels = wf.getnchannels(),
rate = wf.getframerate(),
output = True)
# Read data in chunks
data = wf.readframes(chunk)
# Play the sound by writing the audio data to the stream
while data != '':
stream.write(data)
data = wf.readframes(chunk)
# Close and terminate the stream
stream.close()
p.terminate()
您可能已经注意到,用pyaudio播放声音比用您之前看到的库播放声音要复杂一些。这意味着,如果您只想在 Python 应用程序中播放声音效果,它可能不是您的首选。
然而,因为pyaudio给了你更多的底层控制,所以可以获取和设置你的输入和输出设备的参数,并检查你的 CPU 负载和输入或输出延迟。
它还允许您在回调模式下播放和录制音频,在回调模式下,当需要新数据进行回放或可用于录制时,会调用指定的回调函数。如果您的音频需求不仅仅是简单的回放,这些选项使pyaudio成为一个合适的库。
既然您已经看到了如何使用许多不同的库来播放音频,那么是时候看看如何使用 Python 来自己录制音频了。
录制音频
python-sounddevice 和 pyaudio 库提供了用 Python 录制音频的方法。python-sounddevice记录到 NumPy 数组,pyaudio记录到bytes对象。这两个都可以分别使用scipy和wave库存储为 WAV 文件。
python-sounddevice
python-sounddevice 允许你从你的麦克风记录音频,并将其存储为一个 NumPy 数组。这是一种方便的声音处理数据类型,可以使用 scipy.io.wavfile 模块将其转换为 WAV 格式进行存储。确保为以下示例(pip install scipy)安装scipy模块。这将自动安装 NumPy 作为其依赖项之一:
import sounddevice as sd
from scipy.io.wavfile import write
fs = 44100 # Sample rate
seconds = 3 # Duration of recording
myrecording = sd.rec(int(seconds * fs), samplerate=fs, channels=2)
sd.wait() # Wait until recording is finished
write('output.wav', fs, myrecording) # Save as WAV file
pyaudio
在本文前面的中,你通过阅读一首 pyaudio.Stream() 学会了如何弹奏声音。可以通过写入此流来录制音频:
import pyaudio
import wave
chunk = 1024 # Record in chunks of 1024 samples
sample_format = pyaudio.paInt16 # 16 bits per sample
channels = 2
fs = 44100 # Record at 44100 samples per second
seconds = 3
filename = "output.wav"
p = pyaudio.PyAudio() # Create an interface to PortAudio
print('Recording')
stream = p.open(format=sample_format,
channels=channels,
rate=fs,
frames_per_buffer=chunk,
input=True)
frames = [] # Initialize array to store frames
# Store data in chunks for 3 seconds
for i in range(0, int(fs / chunk * seconds)):
data = stream.read(chunk)
frames.append(data)
# Stop and close the stream
stream.stop_stream()
stream.close()
# Terminate the PortAudio interface
p.terminate()
print('Finished recording')
# Save the recorded data as a WAV file
wf = wave.open(filename, 'wb')
wf.setnchannels(channels)
wf.setsampwidth(p.get_sample_size(sample_format))
wf.setframerate(fs)
wf.writeframes(b''.join(frames))
wf.close()
现在您已经了解了如何使用python-sounddevice和pyaudio录制音频,您将学习如何将您的录音(或任何其他音频文件)转换为一系列不同的音频格式。
保存和转换音频
您在前面的中看到,您可以使用scipy.io.wavfile模块将 NumPy 数组存储为 WAV 文件。 wavio模块同样可以让你在 WAV 文件和 NumPy 数组之间转换。如果你想以不同的文件格式存储你的音频, pydub 和 soundfile 就派上了用场,因为它们允许你读写一系列流行的文件格式(如 MP3、FLAC、WMA 和 FLV)。
wavio
这个模块依赖于numpy并允许你读取 WAV 文件作为 NumPy 数组,并保存 NumPy 数组为 WAV 文件。
要将 NumPy 数组保存为 WAV 文件,可以使用wavio.write():
import wavio
wavio.write("myfile.wav", my_np_array, fs, sampwidth=2)
在这个例子中,my_np_array是包含音频的 NumPy 数组,fs是录音的采样率(通常为 44100 或 44800 Hz),sampwidth是音频的采样宽度(每个样本的字节数,通常为 1 或 2 字节)。
soundfile
soundfile 库可以读写libsndfile 支持的所有文件格式。虽然它不能播放音频,但它允许你在 FLAC、AIFF 和一些不太常见的音频格式之间来回转换。要将 WAV 文件转换为 FLAC,可以使用以下代码:
import soundfile as sf
# Extract audio data and sampling rate from file
data, fs = sf.read('myfile.wav')
# Save as FLAC file at correct sampling rate
sf.write('myfile.flac', data, fs)
类似的代码也可以在libsndfile支持的其他文件格式之间转换。
pydub
pydub 可以让你将音频保存为ffmpeg支持的格式,几乎囊括了你日常生活中可能遇到的所有音频类型。例如,您可以使用以下代码将 WAV 文件转换为 MP3:
from pydub import AudioSegment
sound = AudioSegment.from_wav('myfile.wav')
sound.export('myfile.mp3', format='mp3')
使用AudioSegment.from_file()是一种更通用的加载音频文件的方式。例如,如果您想将文件从 MP3 转换回 WAV,您可以执行以下操作:
from pydub import AudioSegment
sound = AudioSegment.from_file('myfile.mp3', format='mp3')
sound.export('myfile.wav', format='wav')
这段代码应该适用于ffmpeg支持的任何音频文件格式。
音频库对比
下表比较了本教程中讨论的库的功能:
| 图书馆 | 平台 | 重放 | 记录 | 皈依者 | 属国 |
|---|---|---|---|---|---|
T2playsound |
跨平台 | WAV,MP3 | - | - | 没有人 |
T2simpleaudio |
跨平台 | WAV,数组,bytes |
- | - | 没有人 |
T2winsound |
Windows 操作系统 | 声音资源文件 | - | - | 没有人 |
T2sounddevice |
跨平台 | 数字阵列 | 数字阵列 | - | numpy,soundfile |
T2pydub |
跨平台 | ffmpeg支持的任何类型 |
- | ffmpeg支持的任何类型 |
simpleaudio,ffmpeg |
T2pyaudio |
跨平台 | bytes |
bytes |
- | wave |
T2wavio |
跨平台 | - | - | WAV,数字阵列 | numpy,wave |
T2soundfile |
跨平台 | - | - | libsndfile支持的任何类型 |
CFFI、libsndfile、numpy |
本教程中包含的库是根据它们的易用性和受欢迎程度而选择的。要获得更全面的 Python 音频库列表,请查看关于 Python 音频的 wiki 页面。
结论:在 Python 中播放和录制声音
在本教程中,您学习了如何使用一些最流行的音频库在 Python 中播放和录制音频。您还了解了如何以各种不同的格式保存音频。
您现在能够:
- 播放多种音频格式,包括 WAV、MP3 和 NumPy 阵列
- 将麦克风中的音频录制到 NumPy 或 Python 数组中
- 储存您录制的各种不同格式的音频,包括 WAV 和 MP3
- 将您的声音文件转换成一系列不同的音频格式
现在,您已经有了所需的信息,可以帮助您决定使用哪些库来开始在 Python 中处理音频。向前迈进,开发一些令人敬畏的音频应用程序!
立即观看本教程有真实 Python 团队创建的相关视频课程。配合文字教程一起看,加深理解: 用 Python 演奏录音***