库名为: sounddevice
可用pip install sounddevice
安装
假如你要播放example.wav
import sounddevice as sd
import wave
import numpy as np
wav = wave.open("example.wav", "r") # 打开文件
frames = wav.readframes(wav.getnframes()) # 读取所有帧
data = np.frombuffer(frames, dtype=np.int16) # 转换为数组
sd.play(data, blocking=True) # 堵塞播放
如果播放的声音听起来很糊,可以更改dtype从np.int16转到np.int32
或者自动匹配
dtype_map = {
1: np.int8,
2: np.int16,
4: np.int32
}
dtype = dtype_map[wav.getsampwidth()]
假设要录制3秒并播放
import sounddevice as sd
print("开始录音3秒")
data = sd.rec(frames=44100*3, samplerate=44100, channels=1, blocking=True)
print("开始播放")
sd.play(data, samplerate=44100, blocking=True)
返回类型为numpy的二维数组,由channels决定每行的元素数量
如果channels为1,data的数据就长下面这样
[[ 0.0000000e+00]
[ 0.0000000e+00]
[-3.0517578e-05]
...
[ 2.3773193e-02]
[ 1.1810303e-02]
[-3.5705566e-03]]
如果channels为2,data的数据就长下面这样
[[ 0.0000000e+00 0.0000000e+00]
[-3.0517578e-05 0.0000000e+00]
[ 0.0000000e+00 0.0000000e+00]
...
[ 1.6479492e-03 1.6479492e-03]
[ 1.3122559e-03 1.3427734e-03]
[ 1.1596680e-03 1.1901855e-03]]
第一列为左声道,第二列为右声道
假设录的音要保存
import wave
import numpy as np
import sounddevice as sd
print("开始录音3秒")
data = sd.rec(frames=44100*3, samplerate=44100, channels=1, blocking=True, dtype=np.int16)
with wave.open("example.wav", 'w') as wav:
wav.setnchannels(1)
wav.setsampwidth(2) # 通过dtype_map查看int16对应2
wav.setframerate(44100)
# 转换数据类型并保存
audio_data = data.tobytes()
wav.writeframes(audio_data)
假设要实时获取麦克风声音并播放,可以用sd.playrec
,但这次使用流
import sounddevice as sd
# with会调用Stream的start和stop,close方法
with (sd.InputStream(samplerate=44100, channels=1) as inp,
sd.OutputStream(samplerate=44100, channels=1) as out):
while True:
# inp.read返回(data,overflowed),overflowed为True表示缓冲区溢出了
# 在长时间不读取时就会溢出,所以要及时处理
data, _ = inp.read(int(44100*0.1)) # 读取0.1秒数据
out.write(data)
如果不想手动开个线程,也可以使用回调函数
import sounddevice as sd
def callback(indata, frames, time, status):
"""
签名要求(在InputStream的文档中有):
callback(indata: numpy.ndarray, frames: int,
time: CData, status: CallbackFlags) -> None
"""
out.write(indata.copy()) # indata需要复制,因为它会被InputStream复写
inp = sd.InputStream(samplerate=44100, channels=1, callback=callback)
out = sd.OutputStream(samplerate=44100, channels=1)
inp.start()
out.start()
input("stop:")
# 执行stop和close
InputStream还有个blocksize参数,决定缓冲区大小,如果设置为samplerate的值,那么callback就会被每秒调用一次