树莓派用 Python 在多个输出设备上播放多个声音文件
准备工作
功放板:https://www.amazon.com/gp/product/B07J4P4FR9
USB 声卡:https://item.taobao.com/item.htm?id=577563502441
DC/DC变压器:https://www.amazon.com/gp/product/B01GJ0SC2C
USB HUB:https://www.amazon.com/gp/product/B076YPRTKF/
DC 接线端子:https://www.amazon.com/gp/product/B06XRT5C2Q
**添加声音设备
声音文件
threading模块(每一个对象代表一个线程 https://blog.csdn.net/goldxwang/article/details/77838072)
argparse模块(argparse是python用于解析命令行参数和选项的标准模块 https://www.2cto.com/kf/201412/363654.html
https://yq.aliyun.com/articles/567308)
pathlib.py模块 (内置pathlib库的常用属性和方法 https://www.cnblogs.com/sigai/p/8074329.html)
argparse 用于将命令行字符串解析为Python对象的对象 添加关注的命令行参数和选项 开始解析
pathlib 检测文件的路径 是否隐藏
确定声音文件路径
文件加载到内存 寻找usb设备
寻找到的usb设备文件的信息
为usb声音设备创建输出索引
检测输出索引是否创建
检测文件是否存在
threading 创建线程 判断线程是否进入
键盘中断模块启动 退出
wait_devices_init.py 设备等待准备
使用对声音设备的外部调用来获取库检测到的设备数量。**
pear.py
""" """ import sounddevice import soundfile import threading import argparse import pathlib import os DATA_TYPE = "float32" def load_sound_file_into_memory(path): """ 获取到wav文件的给定路径的内存版本 :参数路径:要加载的wav文件 :返回:audio_data,一个2D numpy数组 """ audio_data, _ = soundfile.read(path, dtype=DATA_TYPE) return audio_data def dir_path(path): """ 检查给定的路径是否实际上是一个目录 :参数路径:指向目录的路径 :return: path(如果是目录),如果不是,则引发错误 """ p = pathlib.Path(path) if p.is_dir(): return path else: raise NotADirectoryError(path) def get_device_number_if_usb_soundcard(index_info): """ 给定一个设备dict,如果该设备是我们的USB声卡之一,则返回True,否则返回False :param index_info:来自PyAudio的设备信息dict。 :返回:usb声卡为真,否则为假 """ index, info = index_info if "USB Audio Device" in info["name"]: return index return False def play_wav_on_index(audio_data, stream_object): """ 播放一个名为load_sound_file_into_memory的音频文件 :param audio_data:一个二维数字数组 :param stream_object:声音设备。对象,该对象将立即开始播放写入其中的任何数据。 :return: None,当所有数据都被使用时返回 """ stream_object.write(audio_data) def create_running_output_stream(index): """ 创建一个sounddevice。向准备写入的索引指定的设备写入的OutputStream。 你可以立即调用'写'对这个对象与数据,它将发挥在设备上。 :param索引:要写入的音频设备的设备索引 :返回:已启动的声音设备。准备写入的OutputStream对象 """ output = sounddevice.OutputStream( device=index, dtype=DATA_TYPE ) output.start() return output if __name__ == "__main__": parser = argparse.ArgumentParser(description='a simple tool for sound installations') #用于将命令行字符串解析为Python对象的对象 parser.add_argument("dir", type=dir_path)#添加关注的命令行参数和选项 args = parser.parse_args() #开始解析 def good_filepath(path): #检测文件的路径 是否隐藏 """ Macro for returning false if the file is not a non-hidden wav file :param path: path to the file :return: true if a non-hidden wav, false if not a wav or hidden """ return str(path).endswith(".wav") and (not str(path).startswith(".")) sound_file_paths = [os.path.join(args.dir, path) for path in sorted(filter(lambda path: good_filepath(path), os.listdir(args.dir)))] #确定声音文件路径 print("Discovered the following .wav files:", sound_file_paths) #打印声音文件路径 files = [load_sound_file_into_memory(path) for path in sound_file_paths] #文件加载到内存 寻找usb设备 print("Files loaded into memory, Looking for USB devices.") usb_sound_card_indices = list(filter(lambda x: x is not False, map(get_device_number_if_usb_soundcard, [index_info for index_info in enumerate(sounddevice.query_devices())])))#寻找到的usb设备文件的信息 print("Discovered the following usb sound devices", usb_sound_card_indices)#打印寻找到的usb文件设备文件信息 streams = [create_running_output_stream(index) for index in usb_sound_card_indices]#为usb声音设备创建输出索引 running = True if not len(streams) > 0: #检测输出索引是否创建 running = False print("No audio devices found, stopping") if not len(files) > 0: #检测文件是否存在 running = False print("No sound files found, stopping") while running: print("Playing files") threads = [threading.Thread(target=play_wav_on_index, args=[file_path, stream]) for file_path, stream in zip(files, streams)] #创建线程 try: for thread in threads: #在线程中 开始 thread.start() for thread, device_index in zip(threads, usb_sound_card_indices): print("Waiting for device", device_index, "to finish") thread.join()#提示阻塞,等待设备完成 except KeyboardInterrupt:#键盘中断模块启动 停止程序 running = False print("Stopping stream") for stream in streams: stream.abort(ignore_errors=True) stream.close() print("Streams stopped") print("Bye.")
wait_devices_init.py 设备等待准备
""" Blocks until the sounddevice module is able to pick up all of the attached usb sound cards as seen by lsusb 块,直到声音设备模块能够接收到lsusb所看到的所有附加的usb声卡 """ import subprocess def num_sound_devices(): """ 使用对声音设备的外部调用来获取库检测到的设备数量。 这样做很重要,而不仅仅是sounddevice.query_devices(),声音设备询问 返回: """ return str(subprocess.check_output(["python3", "-m", "sounddevice"])).count("USB Audio Device") def wait_for_usb_sound_devices_to_be_initialized(): """ 调用此函数将阻塞,直到lsusb检测到的USB声音声卡设备的数量匹配为止 声音设备后端初始化的数字。 返回: """ while num_sound_devices() != str(subprocess.check_output(["lsusb"])).count("C-Media Electronics"): pass if __name__ == "__main__": wait_for_usb_sound_devices_to_be_initialized() #等待usb声音设备初始化
参考:http://shumeipai.nxez.com/2019/02/21/play-multiple-sound-files-on-multiple-output-devices.html
- python3播放mp3声音文件
- JAVA_怎样处理波形文件( 播放 .au声音文件 url转成波形输出)
- Linux 下如何通过两个或多个输出设备播放声音
- python成长日记2:文件的输入输出
- wpf 指定音频设备播放测试声音
- 播放ogg声音文件
- PyCharm设置python新建文件 模板修改 设置 文件为python 和utf-8 解决控制台输出乱码
- 入手树莓派3+python小试GPIO输出
- WPF中播放声音媒体文件
- python基础入门详解(文件输入/输出 内建类型 字典操作使用方法)
- Android录制声音文件(音频),并播放
- python生成CMPL16类型随机定标测试数据并输出到文件
- 转发自刘鑫专栏:python_简单的声音播放功能
- python3.x输出文件最后几行
- WPF中播放声音媒体文件
- iphone游戏的声音处理-流播放文件
- Python读取UTF-8编码文件并使用命令行执行时输出结果的问题
- Python使用PyMedia播放mp3,wave等文件
- IOS-使用AVAudioPlayer播放音乐文件无声音
- Python:把help的结果输出至文件