python一个工程多个py文件_用 Python 在多个输出设备上播放多个声音文件

20190221205338512-0.jpg

有想过用一台主机给不同的设备同时播放不同的音频文件吗?如果你正准备搭建一个DJ应用,需要实现一副耳机和一组扬声器的混音效果;又或者你需要构建一组包含许多个扬声器的音乐系统,而每个扬声器都需要播放不同的音频文件,彼此之间需要实现同步……

下面这个 DEMO 演示了用树莓派驱动8个不同的扬声器,分别播放8种不同的单声道音频文件,不仅有视频,更有必要的说明:

下面是所用的的零部件清单。

参照图片连接树莓派、USB 声卡、功放、USB HUB、扬声器和电源。

20190221205338446-0.jpg

20190221205338912-0.jpg

20190221205338382-0.jpg

20190221205338414-0.jpg

Multi-Audio 范例

首先给树莓派安装 sounddevice,用下面的命令即可。

sudo apt-get install python3-pip python3-numpy libportaudio2 libsndfile1

python3 -m pip install sounddevice soundfile

这里有4个音频文件,和 multi.py 在同一个目录下,目录结构如下。

multi_audio/

├── 1.wav

├── 2.wav

├── 3.wav

├── 4.wav

└── multi.py

这段代码基于 Python 的 sounddevice 库。

"""

multi.py, uses the sounddevice library to play multiple audio files to multiple output devices at the same time

Written by Devon Bray (dev@esologic.com)

"""

import sounddevice

import soundfile

import threading

import os

DATA_TYPE = "float32"

def load_sound_file_into_memory(path):

"""

Get the in-memory version of a given path to a wav file

:param path: wav file to be loaded

:return: audio_data, a 2D numpy array

"""

audio_data, _ = soundfile.read(path, dtype=DATA_TYPE)

return audio_data

def get_device_number_if_usb_soundcard(index_info):

"""

Given a device dict, return True if the device is one of our USB sound cards and False if otherwise

:param index_info: a device info dict from PyAudio.

:return: True if usb sound card, False if otherwise

"""

index, info = index_info

if "USB Audio Device" in info["name"]:

return index

return False

def play_wav_on_index(audio_data, stream_object):

"""

Play an audio file given as the result of `load_sound_file_into_memory`

:param audio_data: A two-dimensional NumPy array

:param stream_object: a sounddevice.OutputStream object that will immediately start playing any data written to it.

:return: None, returns when the data has all been consumed

"""

stream_object.write(audio_data)

def create_running_output_stream(index):

"""

Create an sounddevice.OutputStream that writes to the device specified by index that is ready to be written to.

You can immediately call `write` on this object with data and it will play on the device.

:param index: the device index of the audio device to write to

:return: a started sounddevice.OutputStream object ready to be written to

"""

output = sounddevice.OutputStream(

device=index,

dtype=DATA_TYPE

)

output.start()

return output

if __name__ == "__main__":

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("."))

cwd = os.getcwd()

sound_file_paths = [

os.path.join(cwd, path) for path in sorted(filter(lambda path: good_filepath(path), os.listdir(cwd)))

]

print("Discovered the following .wav files:", sound_file_paths)

files = [load_sound_file_into_memory(path) for path in sound_file_paths]

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())])))

print("Discovered the following usb sound devices", usb_sound_card_indices)

streams = [create_running_output_stream(index) for index in usb_sound_card_indices]

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.")

运行之后将分别在3个设备上播放 1.wav、2.wav 和 3.wav 音频文件。

20190221205338803-0.jpg

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值