geekdoc-python-zh/docs/realpython/playing-and-recording-sound...

19 KiB
Raw Permalink Blame History

用 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后,只需几行代码就能让你播放大范围的音频格式。

让我们一个一个的来看看这些用于音频播放的库。

Remove ads

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模块进行跨平台音频播放。

Remove ads

python-sounddevice

正如其文档中所述, python-sounddevice “为 PortAudio 库提供绑定和一些方便的函数来播放和录制包含音频信号的 NumPy 数组”。为了播放 WAV 文件,需要安装numpysoundfile,以 NumPy 数组的形式打开 WAV 文件。

安装了python-sounddevicenumpysoundfile之后,您现在可以将 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,但是pyaudioffplayavplay也是备选方案。

下面的代码可以用来播放带有pydub的 WAV 文件:

from pydub import AudioSegment
from pydub.playback import play

sound = AudioSegment.from_wav('myfile.wav')
play(sound)

为了播放其他音频类型,如 MP3 文件,应安装 ffmpeglibav 。查看pydub文档获取说明。作为文档中描述的步骤的替代, ffmpeg-pythonffmpeg提供绑定,可以使用 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 来自己录制音频了。

Remove ads

录制音频

python-sounddevicepyaudio 库提供了用 Python 录制音频的方法。python-sounddevice记录到 NumPy 数组,pyaudio记录到bytes对象。这两个都可以分别使用scipywave库存储为 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-sounddevicepyaudio录制音频,您将学习如何将您的录音(或任何其他音频文件)转换为一系列不同的音频格式。

保存和转换音频

在前面的中看到,您可以使用scipy.io.wavfile模块将 NumPy 数组存储为 WAV 文件。 wavio模块同样可以让你在 WAV 文件和 NumPy 数组之间转换。如果你想以不同的文件格式存储你的音频, pydubsoundfile 就派上了用场,因为它们允许你读写一系列流行的文件格式(如 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支持的其他文件格式之间转换。

Remove ads

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 跨平台 WAVMP3 - - 没有人
T2simpleaudio 跨平台 WAV数组bytes - - 没有人
T2winsound Windows 操作系统 声音资源文件 - - 没有人
T2sounddevice 跨平台 数字阵列 数字阵列 - numpysoundfile
T2pydub 跨平台 ffmpeg支持的任何类型 - ffmpeg支持的任何类型 simpleaudioffmpeg
T2pyaudio 跨平台 bytes bytes - wave
T2wavio 跨平台 - - WAV数字阵列 numpywave
T2soundfile 跨平台 - - libsndfile支持的任何类型 CFFIlibsndfilenumpy

本教程中包含的库是根据它们的易用性和受欢迎程度而选择的。要获得更全面的 Python 音频库列表,请查看关于 Python 音频的 wiki 页面。

结论:在 Python 中播放和录制声音

在本教程中,您学习了如何使用一些最流行的音频库在 Python 中播放和录制音频。您还了解了如何以各种不同的格式保存音频。

您现在能够:

  • 播放多种音频格式,包括 WAV、MP3 和 NumPy 阵列
  • 将麦克风中的音频录制到 NumPy 或 Python 数组中
  • 储存您录制的各种不同格式的音频,包括 WAV 和 MP3
  • 将您的声音文件转换成一系列不同的音频格式

现在,您已经有了所需的信息,可以帮助您决定使用哪些库来开始在 Python 中处理音频。向前迈进,开发一些令人敬畏的音频应用程序!

立即观看本教程有真实 Python 团队创建的相关视频课程。配合文字教程一起看,加深理解: 用 Python 演奏录音***