用python库播放音频存在听不到声音的问题,使用如下方法找到正确的发声设备id
#!/usr/bin/env python3
"""Load an audio file into memory and play its contents.
NumPy and the soundfile module (https://python-soundfile.readthedocs.io/)
must be installed for this to work.
This example program loads the whole file into memory before starting
playback.
To play very long files, you should use play_long_file.py instead.
This example could simply be implemented like this::
import sounddevice as sd
import soundfile as sf
data, fs = sf.read('my-file.wav')
sd.play(data, fs)
sd.wait()
... but in this example we show a more low-level implementation
using a callback stream.
"""
import argparse
import threading
import sounddevice as sd
import soundfile as sf
def int_or_str(text):
"""Helper function for argument parsing."""
try:
return int(text)
except ValueError:
return text
parser = argparse.ArgumentParser(add_help=False)
parser.add_argument(
'-l', '--list-devices', action='store_true',
help='show list of audio devices and exit')
args, remaining = parser.parse_known_args()
if args.list_devices:
print(sd.query_devices())
parser.exit(0)
parser = argparse.ArgumentParser(
description=__doc__,
formatter_class=argparse.RawDescriptionHelpFormatter,
parents=[parser])
parser.add_argument(
'filename', metavar='FILENAME',
help='audio file to be played back')
parser.add_argument(
'-d', '--device', type=int_or_str,
help='output device (numeric ID or substring)')
args = parser.parse_args(remaining)
event = threading.Event()
print(sd.default.device)
try:
data, fs = sf.read(args.filename, always_2d=True)
current_frame = 0
def callback(outdata, frames, time, status):
global current_frame
if status:
print(status)
chunksize = min(len(data) - current_frame, frames)
outdata[:chunksize] = data[current_frame:current_frame + chunksize]
if chunksize < frames:
outdata[chunksize:] = 0
raise sd.CallbackStop()
current_frame += chunksize
print(data.shape[1])
stream = sd.OutputStream(
samplerate=fs, device=args.device, channels=data.shape[1],
callback=callback, finished_callback=event.set)
with stream:
event.wait() # Wait until playback is finished
except KeyboardInterrupt:
parser.exit('\nInterrupted by user')
except Exception as e:
parser.exit(type(e).__name__ + ': ' + str(e))
python test.py A2_0.wav -l,获取声卡设备列表,以输出的第一个设备信息0 HDA Intel PCH: ALC887-VD Analog (hw:0,0), ALSA (2 in, 2 out)为例,有两个输入通道和两个输出通道,假如A2_0.wav是单通道文件,而输出设备的输出通道数是0,则会出现报错:PortAudioError: Error opening OutputStream: Invalid number of channels [PaErrorCode -9998]。sounddevice.default.device表示sounddevice默认选择的输出设备编号。接下来python test.py A2_0.wav -d $id脚本批量化执行该命令,找出能正常播放音频的设备id。结果是23和31(-l参数返回的结果的id)。以上代码来自Example Programs§
pyaudio库
"""PyAudio Example: Play a wave file."""
import pyaudio
import wave
import sys
CHUNK = 1024
# if len(sys.argv) < 2:
# print("Plays a wave file.\n\nUsage: %s filename.wav" % sys.argv[0])
# sys.exit(-1)
wf = wave.open(sys.argv[1], 'rb')
# instantiate PyAudio (1)
p = pyaudio.PyAudio()
# open stream (2)
stream = p.open(format=p.get_format_from_width(wf.getsampwidth()),
channels=wf.getnchannels(),
rate=wf.getframerate(),
output_device_index=int(sys.argv[2]),
output=True)
# read data
data = wf.readframes(CHUNK)
# play stream (3)
while len(data):
stream.write(data)
data = wf.readframes(CHUNK)
# stop stream (4)
stream.stop_stream()
stream.close()
# close PyAudio (5)
p.terminate(),python test.py A2_0.wav $id,批量查找能发出声音的设备id,设备id的获取方式[2]:
import pyaudio
p=pyaudio.PyAudio()
for i in range(p.get_device_count()):
device_info=p.get_device_info_by_index(i)
print(device_info),结果是10,而且播放这个音频之前不能用设备10听b站音乐,听了会报OSError: [Errno -9998] Invalid number of channels的错误,需要用其他设备听一下(也不会有声音,但没报错),之后就能播放这个音频,我这台主机硬件设备有点儿特殊,造成pyaudio的这种bug.
参考链接:Python常用音频库
[2].pyaduio使用指定设备录制或播放音频