Python 在类中使用进程池 通过sounddevice, 进行不同声卡驱动和通道的音频文件播放

看代码吧…
写代码写到半夜太累, 不想解说了, 直接上代码

# 获取与电脑连接的声卡设备详细信息

import sys
import sounddevice as sd
from python_audio_packages.sounddevice_example.my_exception_class import MyException


def get_pool_object():
    # po 的名字在main函数中定义
    #  __main__ 模块在sys.modules 的键是"__mp_main__"
    return sys.modules["__mp_main__"].po


def get_audio_devices_all_msg_dict():
	# 使用sounddevice 获取电脑连接的声卡以及系统自带的所有音频驱动信息(驱动, 声道名, id)
    audio_drivers_and_channels_msg_dict = {}
    audio_input_channels_msg_dict = {}
    audio_output_channels_msg_dict = {}
    this_tmp_dict = {}
    host_api_tuple = sd.query_hostapis()

    for temp_dict in host_api_tuple:
        this_tmp_dict[temp_dict["name"]] = temp_dict["devices"]

    channels_list = sd.query_devices()
    for driver_name in this_tmp_dict:
        audio_drivers_and_channels_msg_dict[driver_name] = []
        audio_input_channels_msg_dict[driver_name] = []
        audio_output_channels_msg_dict[driver_name] = []

        for id in this_tmp_dict[driver_name]:
            audio_drivers_and_channels_msg_dict[driver_name].append((id, channels_list[id]["name"]))

            if channels_list[id]["max_input_channels"] > 0:
                audio_input_channels_msg_dict[driver_name].append((id, channels_list[id]['name']))

            if channels_list[id]["max_output_channels"] > 0:
                audio_output_channels_msg_dict[driver_name].append((id, channels_list[id]['name']))

    return audio_drivers_and_channels_msg_dict, audio_input_channels_msg_dict, audio_output_channels_msg_dict


def get_device_id(driver_name, channel_name, kind, msg_dict):
    # 获取精准的输入或者输出同道id
    if kind == "input":
        for temp_tuple in msg_dict[driver_name]:
            if temp_tuple[1] == channel_name:
                return temp_tuple[0]

        else:
            raise MyException("找不到此驱动---%s--的输入通道---%s" % (driver_name, channel_name))

    elif kind == "output":
        for temp_tuple in msg_dict[driver_name]:
            if temp_tuple[1] == channel_name:
                return temp_tuple[0]

        else:
            raise MyException("找不到此驱动---%s--的输出通道---%s" % (driver_name, channel_name))

    else:
        raise MyException("kind 不是 input, 也不是output !!!")


if __name__ == "__main__":
    # print(sd.query_devices())

    all_msg_dict, input_msg_dict, output_msg_dict = get_audio_devices_all_msg_dict()
    driver_name = "Windows WDM-KS"
    channel_name = "Speakers 2 (Realtek HD Audio output with SST)"
    kind = "output"

    device_id = get_device_id(driver_name, channel_name, kind, output_msg_dict)
    print(device_id)

    """
    0 Microsoft 声音映射器 - Input, MME (2 in, 0 out)
    >  1 麦克风阵列 (Realtek High Defini, MME (2 in, 0 out)
    2 Microsoft 声音映射器 - Output, MME (0 in, 2 out)
    <  3 喇叭/耳机 (Realtek High Definit, MME (0 in, 2 out)
    4 主声音捕获驱动程序, Windows DirectSound (2 in, 0 out)
    5 麦克风阵列 (Realtek High Definition Audio(SST)), Windows DirectSound (2 in, 0 out)
    6 主声音驱动程序, Windows DirectSound (0 in, 2 out)
    7 喇叭/耳机 (Realtek High Definition Audio(SST)), Windows DirectSound (0 in, 2 out)
    8 喇叭/耳机 (Realtek High Definition Audio(SST)), Windows WASAPI (0 in, 2 out)
    9 麦克风阵列 (Realtek High Definition Audio(SST)), Windows WASAPI (2 in, 0 out)
    10 Speakers 1 (Realtek HD Audio output with SST), Windows WDM-KS (0 in, 2 out)
    11 Speakers 2 (Realtek HD Audio output with SST), Windows WDM-KS (0 in, 6 out)
    12 电脑扬声器 (Realtek HD Audio output with SST), Windows WDM-KS (2 in, 0 out)
    13 麦克风阵列 1 (), Windows WDM-KS (2 in, 0 out)
    14 麦克风阵列 2 (), Windows WDM-KS (1 in, 0 out)
    """

以上模块是用来精确获取 某个声卡驱动下的 channel_name 的 device_id,
这个id是专门用来sounddevice用的

下面的代码是使用 进程池 来实现多个音频来并发播放, 随机使用电脑的不同的输出通道


"""
    本模块用来测试使用python多进程(进程池), sounddevice播放音频文件
"""

import os
import random
import sys
from multiprocessing import Pool, freeze_support
import soundfile
import sounddevice as sd
from python_audio_packages.sounddevice_example.get_audio_channels_msg import get_device_id, \
    get_audio_devices_all_msg_dict
from python_audio_packages.sounddevice_example.my_exception_class import MyException


def play_in_sounddevice(wav_data, sample_rate, *args):
    print("index---%d---本音频---%s---文件的采样率为---%s\n\n" % (args[1], args[0].split("\\")[-1], sample_rate))
    try:
        sd.default.device[1] = args[2]
        sd.play(wav_data, samplerate=sample_rate)
    except Exception as e:
        raise e
    else:
        sd.wait()


class TestSounddeviceMultiprocess(object):
    def __init__(self, wav_file_dir):
        self.wav_file_dir = wav_file_dir
        self.wav_file_path_list = []
        self.process_num = self.get_wav_file_path_list()
        self.channel_list = [("MME", "Microsoft 声音映射器 - Output"),
                             ("MME", "喇叭/耳机 (Realtek High Definit"),
                             ("Windows DirectSound", "主声音驱动程序"),
                             ("Windows DirectSound", "喇叭/耳机 (Realtek High Definition Audio(SST))"),
                             ("Windows WASAPI", "喇叭/耳机 (Realtek High Definition Audio(SST))"),
                             ("Windows WDM-KS", "Speakers 1 (Realtek HD Audio output with SST)"),
                             ("Windows WDM-KS", "Speakers 2 (Realtek HD Audio output with SST)")]

        self.all_msg_dict, self.input_msg_dict, self.output_msg_dict = get_audio_devices_all_msg_dict()

    def get_wav_file_path_list(self):
        if os.path.exists(self.wav_file_dir):
            wav_file_list = os.listdir(self.wav_file_dir)
            for file_name in wav_file_list:
                if file_name.endswith(".wav"):
                    self.wav_file_path_list.append(os.path.join(self.wav_file_dir, file_name))

            return len(self.wav_file_path_list)
        else:
            raise MyException("Please make sure your input is a dir path !!!")

    def read_file_soundfile(self, wave_file_path):
        try:
            data, sample_rate = soundfile.read(wave_file_path)
        except Exception as e:
            print(str(e))
            return 0, 0
        else:
            return data, sample_rate

    def __get_device_id(self, index=None, wav_file=None):
        rand_int = random.randint(0, len(self.channel_list) - 1)
        device_id = get_device_id(self.channel_list[rand_int][0], self.channel_list[rand_int][1],
                                  "output", self.output_msg_dict)

        print("index--{}--{}--声卡--{}--{}--device_id--{}".format(index,
                                                                wav_file.split("\\")[-1],
                                                                self.channel_list[rand_int][0],
                                                                self.channel_list[rand_int][1],
                                                                device_id))
        return device_id

    def run_play_multiprocess(self):
        for index, wav_file_path in enumerate(self.wav_file_path_list):
            data, sample_rate = self.read_file_soundfile(wav_file_path)
            if sample_rate:
                device_id = self.__get_device_id(index, wav_file_path)

                # 进程池加进的函数, 不能是类中的, 必须是类外的, 否则会报错
                po.apply_async(func=play_in_sounddevice, args=(data, sample_rate, wav_file_path,
                                                               index, device_id, device_id))

        po.close()
        po.join()


if __name__ == "__main__":
    t = TestSounddeviceMultiprocess(r"F:\sounddevice_test_wav")
    process_num = t.process_num

    po = Pool(process_num)  # 注意, 进程池创建, 只能在 if __name__ == "__main__": 之下
    # 而且, 进程池的创建不能在类里面

    freeze_support()
    t.run_play_multiprocess()

  • 1
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 6
    评论
使用 Pythonsounddevice 库可以很方便地实现音频播放和录制。要实现实时切换通道,你需要在创建流对象时指定输出设备和输入设备的 ID,然后在运行时可以通过修改这些 ID 来切换通道。 下面是一个简单的示例代码,演示了如何使用 sounddevice 播放声音并实时切换通道: ```python import sounddevice as sd import numpy as np # 定义输出设备和输入设备的 ID,可以通过 sd.query_devices() 获取 output_device_id = 0 input_device_id = 1 # 定义采样率和缓冲区大小 sample_rate = 44100 block_size = 1024 # 创建流对象 stream = sd.Stream(device=(output_device_id, input_device_id), samplerate=sample_rate, blocksize=block_size) # 定义一个简单的正弦波 freq = 440 t = np.linspace(0, 1, sample_rate * block_size) waveform = np.sin(2 * np.pi * freq * t) # 开始流 with stream: while True: # 从输入设备读取数据 input_data, _ = stream.read(block_size) # 将读取的数据写入输出设备 stream.write(waveform) # 实时切换通道,你可以在代码加入一些逻辑实现自动或手动切换 if some_condition: stream.stop() stream.close() output_device_id, input_device_id = input_device_id, output_device_id stream = sd.Stream(device=(output_device_id, input_device_id), samplerate=sample_rate, blocksize=block_size) stream.start() ``` 上面的代码,我们首先定义了输出设备和输入设备的 ID,并创建了一个流对象。在 while 循环,我们从输入设备读取数据,将正弦波写入输出设备,并通过一些逻辑实现了实时切换通道的功能。你可以根据自己的需要修改代码。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值