无需使用CPython扩展即可播放和录制音频
项目描述
SoundCard是一个库,用于无需使用CPython扩展即可播放和录制音频。相反,它使用神奇的CFFI和Linux、Windows和macOS的本地音频库来实现。
输入和输出数据缩放到0dBFS(全范围)。为了避免削波,将所有数据限制在-1和1之间。
SoundCard是跨平台的,支持Linux/pulseaudio、Mac/coreaudio和Windows/WASAPI。虽然跨平台编程接口相同,但声卡命名方案和默认块大小可能在设备和平台之间有所不同。
SoundCard仍在开发中。所有主要功能在所有平台上都正常工作,但仍有一些已知问题需要修复。如果您发现错误,请打开问题,我将尝试修复它。或者打开一个拉取请求,我将尝试将您的修复包含到SoundCard中。
然而,请注意,这是我免费开发的个人爱好项目,我在业余时间开发。虽然我会尽量配合,但我不能保证及时响应问题。在GitHub上发布开源软件并不意味着有义务 立即修复您的问题。请保持礼貌。
教程
以下是您如何访问您的扬声器和麦克风
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')
所有这些函数都返回Speaker和Microphone对象,可用于播放和录音。所有传入和传出的数据都是帧 × 通道的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按照操作系统的默认配置进行录制和播放。尤其是在笔记本电脑上,这种配置可能会有极长的延迟,长达几秒钟。
为了请求更低的延迟,可以向player或recorder传递一个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 哈希值
算法 | 哈希摘要 | |
---|---|---|
SHA256 | 410835514ba10809803cb9887d4270f392b59eaf365915bb94516af3f8b1d037 |
|
MD5 | 53d057d8a305d5db2998a65d9b23aeaa |
|
BLAKE2b-256 | fe618fa850aacd49ad4c838cb51cd8893c1696ac32693efc22640f39f8190d50 |
SoundCard-0.4.3-py3-none-any.whl 哈希值
算法 | 哈希摘要 | |
---|---|---|
SHA256 | 2af6f6b49c24dc8a997d8189206206f1bf1d48d7e8f313777293996809cfdfe3 |
|
MD5 | 1338c701d1672b1565308e058ff344b7 |
|
BLAKE2b-256 | e91d13d4c96e3785f00e7b0ae2fd04fd1c7a6016345114594a1050c8471a907a |