跳转到主要内容

无需使用CPython扩展即可播放和录制音频

项目描述

version python status license

contributors downloads

SoundCard是一个库,用于无需使用CPython扩展即可播放和录制音频。相反,它使用神奇的CFFI和Linux、Windows和macOS的本地音频库来实现。

输入和输出数据缩放到0dBFS(全范围)。为了避免削波,将所有数据限制在-1和1之间。

SoundCard是跨平台的,支持Linux/pulseaudio、Mac/coreaudio和Windows/WASAPI。虽然跨平台编程接口相同,但声卡命名方案和默认块大小可能在设备和平台之间有所不同。

SoundCard仍在开发中。所有主要功能在所有平台上都正常工作,但仍有一些已知问题需要修复。如果您发现错误,请打开问题,我将尝试修复它。或者打开一个拉取请求,我将尝试将您的修复包含到SoundCard中。

然而,请注意,这是我免费开发的个人爱好项目,我在业余时间开发。虽然我会尽量配合,但我不能保证及时响应问题。在GitHub上发布开源软件并不意味着有义务 立即修复您的问题。请保持礼貌。

SoundCard根据BSD 3条款许可证许可
(c) 2016 Bastian Bechtold

open-issues closed-issues open-prs closed-prs

教程

以下是您如何访问您的扬声器和麦克风

import soundcard as sc

# get a list of all speakers:
speakers = sc.all_speakers()
# get the current default speaker on your system:
default_speaker = sc.default_speaker()
# get a list of all microphones:
mics = sc.all_microphones()
# get the current default microphone on your system:
default_mic = sc.default_microphone()

# search for a sound card by substring:
>>> sc.get_speaker('Scarlett')
<Speaker Focusrite Scarlett 2i2 (2 channels)>
>>> one_mic = sc.get_microphone('Scarlett')
<Microphone Focusrite Scalett 2i2 (2 channels)>
# fuzzy-search to get the same results:
one_speaker = sc.get_speaker('FS2i2')
one_mic = sc.get_microphone('FS2i2')

所有这些函数都返回SpeakerMicrophone对象,可用于播放和录音。所有传入和传出的数据都是帧 × 通道的Numpy数组。

import numpy

>>> print(default_speaker)
<Speaker Focusrite Scarlett 2i2 (2 channels)>
>>> print(default_mic)
<Microphone Focusrite Scarlett 2i2 (2 channels)>

# record and play back one second of audio:
data = default_mic.record(samplerate=48000, numframes=48000)
# normalized playback
default_speaker.play(data/numpy.max(numpy.abs(data)), samplerate=48000)

# alternatively, get a `Recorder` and `Player` object
# and play or record continuously:
with default_mic.recorder(samplerate=48000) as mic, \
      default_speaker.player(samplerate=48000) as sp:
    for _ in range(100):
        data = mic.record(numframes=1024)
        sp.play(data)

延迟

默认情况下,SoundCard按照操作系统的默认配置进行录制和播放。尤其是在笔记本电脑上,这种配置可能会有极长的延迟,长达几秒钟。

为了请求更低的延迟,可以向playerrecorder传递一个blocksize。这将告诉操作系统您希望达到的延迟,操作系统会尽可能满足您的请求。在Windows/WASAPI上,设置exclusive_mode=True也可能有所帮助(目前是实验性的)。

延迟的另一个来源是record函数,它将输出缓冲到请求的numframes。通常,为了获得最佳延迟,您应该使用一个比上面的blocksize显著低的numframes,可能是两倍或四倍。

为了尽可能快地获取音频数据,您可以使用numframes=None,这将返回现在可用的任何音频数据,而无需任何缓冲。请注意,这可能会接收到不同数量的帧。

使用上述设置,256个样本或10毫秒的块大小通常没问题。不过,播放和录音的总延迟取决于操作系统如何处理这些缓冲区,可能会显著更高。

此外,您可以尝试以下建议:[链接](https://askubuntu.com/questions/707171/how-can-i-fix-choppy-audio)并编辑您的/etc/pulse/default.pa文件,将以下行替换为

load-module module-udev-detect

...

load-module module-udev-detect tsched=0

然后不要忘记使用以下命令重启pulseaudio

pulseaudio -k

通道映射

一些专业声卡具有大量通道。如果您只想录制或播放其中的一部分通道,您可以指定一个通道映射。通道映射由一系列通道指定符组成,这些指定符指向正在使用的音频后端中的通道。这些指定符在通道映射列表中的索引表示SoundCard中使用的numpy数据数组中的通道索引。

# record one second of audio from backend channels 0 to 3:
data = default_mic.record(samplerate=48000, channels=[0, 1, 2, 3], numframes=48000)

# play back the recorded audio in reverse channel order:
default_speaker.play(data=data, channels=[3, 2, 1, 0], samplerate=48000)

通道指定符的含义取决于后端。对于WASAPI(Windows)和CoreAudio(macOS),索引指的是所使用的声音设备的物理输出通道。对于PulseAudio后端(Linux),指定符指的是逻辑通道位置,而不是物理硬件通道。

PulseAudio后端中的通道位置标识符基于:[链接](https://freedesktop.org/software/pulseaudio/doxygen/channelmap_8h.html)。由于位置索引到音频通道的映射不是很明显,可以通过调用channel_name_map()来检索包含所有可能位置和通道索引的字典。索引高达10的位置为

'mono': -1,
'left': 0,
'right': 1,
'center': 2,
'rear-center': 3,
'rear-left': 4,
'rear-right': 5,
'lfe': 6,
'front-left-of-center': 7,
'front-right-of-center': 8,
'side-left': 9,
'side-right': 10

标识符mono或索引-1可以用于播放和录音时所有通道的混音。(CoreAudio/macOS将通道-1定义为播放和录音时的静音。)除了索引之外,PulseAudio后端还允许使用名称字符串来定义通道映射

# This example plays one second of noise on each channel defined in the channel map consecutively.
# The channel definition scheme using strings only works with the PulseAudio backend!

# This defines a channel map for a 7.1 audio sink device
channel_map = ['left', 'right', 'center', 'lfe', 'rear-left', 'rear-right', 'side-left', 'side-right']

num_channels = len(channel_map)
samplerate = 48000

# Create the multi channel noise array.
noise_samples = 48000
noise = numpy.random.uniform(-0.1, 0.1, noise_samples)
data = numpy.zeros((num_channels * noise_samples, num_channels), dtype=numpy.float32)
for channel in range(num_channels):
    data[channel * noise_samples:(channel + 1) * noise_samples, channel] = noise

# Playback using the 7.1 channel map.
default_speaker.play(data=data, channels=channel_map, samplerate=samplerate)

可以通过以下方式列出每个PulseAudio源或目的地的可用通道

> pactl list sinks
> pactl list sources

Channel Map属性列出了源/目的地的通道标识符。

> pactl list sinks | grep  "Channel Map" -B 6

Sink #486
    State: SUSPENDED
    Name: alsa_output.usb-C-Media_Electronics_Inc._USB_Advanced_Audio_Device-00.analog-stereo
    Description: USB Advanced Audio Device Analog Stereo
    Driver: PipeWire
    Sample Specification: s24le 2ch 48000Hz
    Channel Map: front-left,front-right
--
Sink #488
        State: RUNNING
        Name: alsa_output.pci-0000_2f_00.4.analog-surround-71
        Description: Starship/Matisse HD Audio Controller Analog Surround 7.1
        Driver: PipeWire
        Sample Specification: s32le 8ch 48000Hz
        Channel Map: front-left,front-right,rear-left,rear-right,front-center,lfe,side-left,side-right

常见问题解答

问:如何在无头树莓派上使其工作?

A: PulseAudio 在 Raspberry Pi OS Lite 发行版(https://www.raspberrypi.org/software/operating-systems/)中默认未安装。为了使用 声卡,您必须首先安装 PulseAudio,然后编辑配置(修复以避免主输出为单声道)。

sudo apt install -y python3-pip python3-numpy pulseaudio
sudo nano /usr/share/pulseaudio/alsa-mixer/profile-sets/default.conf
# comment the block [Mapping analog-mono] with ';'
pulseaudio -D
python3 -m pip install soundcard

已知问题

  • 在 Windows/WASAPI 中,如果您只录制单个通道,则会记录垃圾数据。原因尚不清楚。多通道和通道映射可以正常工作。

  • 在某些情况下,Windows/WASAPI 会静默忽略块大小。显然,它仅支持独占模式下的可变块大小。

  • 即使块大小和 nframes 相匹配,Windows/WASAPI 也可能耗尽其缓冲区。如果发生这种情况,请使用大于 nframes 的块大小。

  • 错误消息通常报告一些内部 CFFI/后端错误。这将在未来得到改进。

  • macOS 记录静音发生在您使用未请求麦克风权限的应用程序运行脚本时,请转到设置并为您正在运行的脚本授予麦克风权限的应用程序。

变更日志

  • 2018-04-25 实现了录制时的固定块大小(感谢,Pariente Manuel!)

  • 2018-05-10 添加了测试套件和针对 Windows 的各种修复

  • 2018-05-11 针对 macOS 的各种修复

  • 2018-06-27 为 Linux/pulseaudio 添加了延迟属性(感谢,Pariente Manuel!)

  • 2018-07-17 为 Windows 添加了回环支持(感谢,Jan Leskovec!)

  • 2018-10-16 为 Windows 上的 IPython 添加了错误修复(感谢,Sebastian Michel!)

  • 2018-11-28 添加了 Sphinx/Readthedocs 文档

  • 2019-03-25 添加了对 Python 3.5 的支持(感谢,Daniel R. Kumor!)

  • 2019-04-29 在 Windows 上添加了对独占模式的实验性支持

  • 2019-05-13 修复了 macOS 上的采样率转换

  • 2019-05-15 修复了 macOS 上的静音录制

  • 2019-06-11 修复了在 Linux 上监视默认设备时的异常(感谢,Inti Pelupessy!)

  • 2019-06-18 修复了在 Linux 上打开多个流时的崩溃

  • 2019-08-23 修复了在 Linux 上访问流状态时的属性错误(感谢,Davíð Sindri Pétursson!)

  • 2019-10-08 修复了在 Linux 上录制时的不一致的 dtypes

  • 2020-01-06 修复了 Windows 上的静音录制

  • 2020-04-28 在 Linux 上获取和设置 pulseaudio 程序名称(感谢,Philipp A.!)

  • 2020-05-14 修复了 Windows 上 Unicode 声卡名称的错误(感谢,BAKEZQ!)

  • 2020-05-18 添加了对 pyinstaller (v4) 的支持(感谢,Bob Thomas!)

  • 2020-05-19 添加了对 Windows 7 的兼容性(感谢,demberto!)

  • 2020-07-22 修复了 Linux 启动期间的冻结错误(感谢,zhujisheng!)

  • 2020-08-01 改进了 Linux 上的错误报告(感谢,Rik van Riel!)

  • 2020-08-13 修复了由于使用后释放导致的 Linux 崩溃(感谢,Rik van Riel!)

  • 2021-01-13 修复了 Windows 上的 Unicode 错误(感谢,paulzzh!)

  • 2021-11-24 添加了对 NixOS 库命名的兼容性(感谢,shithead!)

  • 2021-12-23 修复了 Python 3.10 的弃用(感谢,Nekyo!)

  • 2022-04-29 修复了最近 Numpy 中的弃用

  • 2024-03-16 修复了 macOS 上空的声卡列表(感谢,Patrice Brend’amour!)

项目详情


下载文件

下载适合您平台的应用程序。如果您不确定选择哪一个,请了解更多关于 安装软件包 的信息。

源代码发行版

SoundCard-0.4.3.tar.gz (40.6 kB 查看哈希值)

上传于 源代码

构建版本

SoundCard-0.4.3-py3-none-any.whl (43.7 kB 查看哈希值)

上传于 Python 3

由以下提供支持