Skip to main content

ap_ds:一款轻量级Python音频库

当前版本:v3.1.0 – 性能与批量解析版(2026年7月)
稳定版推荐:v3.0.0 LTS(长期支持版)

🚀 v3.1.0 – 性能与批量解析版

这是ap_ds的功能性大版本更新,专注于批量解析性能和Python 3.15自由线程支持。

✨ 新增功能

📦 批量解析API(全新)

API 说明
batch_get_metadata() 批量解析音频文件,返回完整元数据列表
batch_get_duration() 批量获取音频时长,返回 {path: duration}
batch_get_metadata_by_type() 按格式过滤批量解析(如只解析MP3)

🧩 DAP去重优化

_add_to_dap_recordings() 从 O(n) 线性扫描升级为 O(1) set去重,大播放列表下性能提升显著。

🐍 Python 3.15t 自由线程支持

  • 无GIL真并行:批量解析在多核CPU上线性加速
  • 运行时自检:导入时自动检测GIL状态并给出提示

满血版用户会看到:

🎉 ap_ds: GIL disabled (free-threading mode)

降级版用户会看到:

⚠️ ap_ds: GIL is enabled (multi-core parallelism limited).
   For full performance, upgrade to Python 3.15t

⚙️ 新增环境变量

变量 默认值 说明
AP_DS_SUPPRESS_WARNINGS 不设置 设为 1 抑制降级警告
AP_DS_SHOW_CONGRATS 不设置 设为 0 隐藏恭喜信息

🚀 启动加速

Python 3.15+ 用户自动启用 lazy import,重模块延迟加载,import ap_ds 速度提升显著。

⚡ 性能对比

测试环境说明

项目 v3.0.0 LTS v3.1.0 Mutagen
Python版本 3.13.4(有GIL) 3.15.0b4(无GIL) 3.13.4(有GIL)
并发方式 ThreadPoolExecutor ProcessPoolExecutor 单线程
GIL状态 ✅ 启用 ❌ 禁用 ✅ 启用
批量解析 ❌ 无 ✅ 有 ❌ 无
测试文件 120个MP3 120个MP3 120个MP3

📊 对比一:ap_ds v3.0.0 vs v3.1.0(120文件)

测试项 v3.0.0(有GIL) v3.1.0(无GIL) 结论
串行解析 0.848秒 1.367秒 3.1.0稍慢(无GIL有开销)
2并发 0.789秒(1.08x) 0.795秒(1.72x) ✅ 3.1.0开始加速
4并发 1.863秒(0.46x)❌ 0.471秒(2.90x) 🚀 3.1.0快3.95倍
8并发 1.285秒(0.66x)❌ 0.331秒(4.13x) 🚀 3.1.0快3.88倍
最佳耗时 0.789秒(2线程) 0.331秒(8进程) 🚀 3.1.0快2.38倍

关键发现:

  • v3.0.0(有GIL):多线程完全无效,4线程反而比串行慢一倍(1.86秒),8线程加速比仅0.66x
  • v3.1.0(无GIL):多进程真并行,8进程加速比达4.13x,120个文件从1.37秒降到0.33秒

💡 v3.0.0 的多线程被GIL卡死,线程越多越慢。v3.1.0 使用 ProcessPoolExecutor 实现真并行,彻底释放多核性能!

📊 对比二:ap_ds v3.1.0 vs Mutagen(120文件)

为什么要对比 Mutagen?

Mutagen 是 Python 生态中最流行的音频元数据处理库,被广泛应用于音乐播放器、标签编辑器等场景。然而,它存在以下局限:

  • ❌ 单线程设计:所有解析任务串行执行,无法利用多核CPU
  • ❌ 不支持批量并发:用户需自行实现多线程/多进程包装
  • ❌ 不支持Python 3.15t新特性:Mutagen 未适配自由线程模式,GIL限制依然存在
  • ❌ 无内置批量API:处理大量文件需手写循环,代码繁琐

正是这些痛点,催生了 ap_ds v3.1.0 的批量解析功能。

对比项 Mutagen(3.13.4) ap_ds v3.1.0(3.15t) 优势
解析耗时 0.973秒 0.331秒 🚀 ap_ds 快2.94倍
并发方式 单线程串行 8进程并行 ✅ 真并行
平均每文件 0.0081秒 0.00275秒 🚀 ap_ds 快2.95倍
GIL限制 ❌ 有 ✅ 无 ✅ ap_ds 无限制
批量API ❌ 无 ✅ batch_get_metadata() ✅ 开箱即用
多核利用 ❌ 单核 ✅ 全核心 ✅ 充分利用CPU

📈 综合对比图

                    120个MP3文件解析耗时
                    
Mutagen (单线程)     ████████████████████████████████████ 0.973s
v3.0.0 (8线程)      ████████████████████████████████████ 1.285s  ❌ 反而更慢
v3.1.0 (串行)       ████████████████████████████████████████ 1.367s
v3.1.0 (8进程)      ████████████ 0.331s  🚀 快2.94倍!

🎯 总结

方案 120文件耗时 加速比 推荐场景
Mutagen(单线程) 0.973秒 1.00x 少量文件
v3.0.0(8线程) 1.285秒 0.66x ❌ 不推荐并发
v3.1.0(串行) 1.367秒 1.00x 少量文件
v3.1.0(8进程) 0.331秒 4.13x 大批量文件 🚀

结论:v3.1.0 + Python 3.15t + 8进程批量解析 = 120个MP3文件仅需0.33秒,比Mutagen快3倍,比v3.0.0多线程快4倍!

📦 版本关系

版本 类型 支持周期 适用场景
v3.0.0 LTS 长期支持 至2031年3月 生产环境
v3.1.0 功能版 约6个月 尝鲜/批量解析需求

🌐 apds.top 已正式上线!

ap_ds官方项目主页现已建成并启用TLS加密!

🎉 访问地址:https://apds.top

网站功能

  • 📄 完整文档:API参考、使用指南、常见问题
  • 📦 版本发布:所有版本下载链接及更新日志
  • 🔗 仓库导航:GitCode(主)、Gitee(中国镜像)
  • ✉️ 反馈系统:用户可通过网站直接提交反馈
  • 🔒 全站TLS加密:所有页面均通过HTTPS安全访问

📌 版本升级建议

用户类型 建议
生产环境 继续使用 v3.0.0 LTS,等 v4.0.0 LTS
开发/测试 升级到 v3.1.0 体验新功能
需要批量解析 必须升级到 v3.1.0
Python 3.15t 用户 必须升级到 v3.1.0 发挥无GIL优势
pip install --upgrade ap_ds

✅ 完整功能验证

ap_ds v3.1.0 已通过完整的自动化测试套件验证,确保所有功能可用。

测试覆盖范围

测试模块 覆盖内容
完整API测试 播放、控制、音量、淡入淡出、元数据、DAP、资源管理
淡入淡出专项测试 5秒淡入/淡出、从指定位置淡入、连续切换(淡出→淡入)

测试文件

项目根目录提供以下测试脚本,用户可自行运行验证:

  • ap_ds complete API testing program.py – 覆盖所有 AudioLibrary 方法的完整 API 测试
  • Fade-in and Fade-out Special Test.py – 淡入淡出功能专项测试(建议戴耳机体验音量渐变效果)

测试结果

所有测试均 通过,无错误、无崩溃、无内存泄漏。

💡 用户可自行运行测试脚本进行验证,确保在当前环境下的兼容性和稳定性。如有任何问题,请通过官方渠道提交反馈。

⚠️ 仓库变更说明

GitHub弃用、GitLab放弃、迁移至GitCode,apds.top成为永久家园

本节详细解释了ap_ds官方代码仓库的变更历程和最终归宿。

1. 为何GitHub被弃用

开发者的GitHub账户因丢失双因素认证(2FA)设备而被锁定。在多次尝试联系GitHub支持后,仅收到自动机器回复。由于完全缺乏人工协助,开发者决定彻底放弃该GitHub账户,并且在可预见的未来不会创建新账户。旧的 dvs-web/ap_ds 仓库现已正式弃用,将不再接收任何更新。

2. 为何GitLab(极狐)被放弃

在GitHub问题之后,项目将主仓库迁移到了Gitee和GitLab(极狐)。然而,由于平台政策变更,使基本账户登录成为付费功能,GitLab近期被放弃。由于项目依赖于免费的开源协作,此变更对贡献者和用户造成了不可接受的障碍。开发者曾尝试寻找替代方案,但在平台的免费层级中未找到任何方案。因此,GitLab仓库不再积极维护。

3. 为何Gitee现在成为备份(而非主仓库)

Gitee是一个优秀的平台,尤其对于中国境内的开发者,提供快速稳定的访问。它仍然是一个强烈推荐的选择。然而,其角色已被调整为备份或面向中国的镜像,主要原因有二:

  • 国际可访问性:Gitee的服务器主要位于中国境内。对于中国大陆以外的开发者,访问可能缓慢、不稳定,在某些情况下甚至因国际网络政策而被完全阻断。这给很大一部分用户群带来了糟糕的体验。

  • 用户界面和工作流程:Gitee的用户界面和工作流程虽然功能齐全,但通常被认为过时,且不太符合许多国际开发者习惯的现代Git工作流程。

基于这些原因,虽然Gitee并非“不好”,并将继续作为面向中国用户完全支持的镜像,但它不再适合作为面向全球受众的项目的唯一主仓库。

4. 解决方案:GitCode成为新的主仓库

在评估了免费Git托管平台的情况后,GitCode 成为理想解决方案。GitCode提供现代化的界面、强大的功能集,最重要的是,对国内和国际开发者都具有出色的可访问性。它已成为ap_ds项目新的主要官方仓库。

新的主仓库位于: https://gitcode.com/dvsxt/ap_ds

5. 永久家园:apds.top

apds.top 已正式建成并启用!

这不仅仅是另一个仓库镜像,而是ap_ds的永久官方家园。它解决了所有平台依赖问题:

  • ✅ 完全自主控制:不再受第三方平台政策变化影响
  • ✅ TLS加密:全站HTTPS安全访问
  • ✅ 永久稳定:即使所有第三方平台都出问题,apds.top依然可用
  • ✅ 一站式服务:文档、下载、反馈、仓库导航全部整合

官方项目主页: https://apds.top

6. 最终仓库策略

平台 状态 用途
apds.top ✅ 永久家园 官方来源、文档、下载
GitCode ✅ 主要镜像 全球用户代码托管
Gitee ✅ 中国镜像 中国用户快速访问
GitHub ❌ 已弃用 不再维护
GitLab(极狐) ❌ 已放弃 不再维护

PyPI用户注意:PyPI上的项目描述将随v3.1.0版本发布同步更新。获取最新信息请始终参考 https://apds.top。

概述

ap_ds 是一款轻量级(2.5MB)Python 音频库,用于 MP3、FLAC、OGG 和 WAV 文件的播放及高精度元数据解析。它零外部 Python 依赖,仅使用 Python 标准库,并提供非阻塞播放,适用于 GUI 应用场景。

核心特性:

  • 极致轻量: Windows 仅 2.5MB / macOS 仅 3.36MB 完整解决方案
  • 零 Python 依赖: 仅使用标准库
  • 高精度元数据: WAV/FLAC 100%,OGG 99.99%,MP3 >98%
  • 批量解析: 使用 batch_get_metadata() 并行处理数百个文件
  • 非阻塞播放: 完美适配 GUI 应用
  • 跨平台: Windows、macOS、Linux、嵌入式 ARM64
  • DAP 录制系统: 仅含元数据的自动播放历史
  • Python 3.15t 支持: 无 GIL 真并行,多核性能全开
  • LTS 支持: 首个长期支持版本,5 年维护承诺

联系与支持

📧 许可咨询

me@dvsyun.top 或 dvs6666@163.com · 7 个工作日内回复

🛠️ 技术支持

apds.top Issues · GitCode Issues · Gitee Issues · 邮件(LTS 期间免费)


官方仓库与项目来源

✅ 官方主仓库(第一推荐): https://apds.top – ap_ds 永久官方家园,完全自主控制,TLS 加密,不受第三方平台政策影响。

✅ 主要镜像(全球访问): GitCode – 全球可访问,现代化 UI,作为公共镜像积极维护。

✅ 中国镜像(快速稳定): Gitee – 面向中国开发者的完整镜像,访问快速,UI 经典稳定。

❌ 已弃用与已放弃:

  • GitHub (dvs-web/ap_ds) – 因永久账户锁定而弃用,不再维护。
  • GitLab (极狐) – 因平台政策变更(基本账户登录变为付费功能)而放弃,不再维护。

ℹ️ ap_ds v3.0.0 LTS – 首个长期支持版本
该版本汇聚了此前所有改进,新增确定性资源清理、哈希校验下载及 5 年支持承诺。旧 GitHub 仓库 (dvs-web/ap_ds) 已弃用,不再更新。GitLab 仓库已放弃。未来更新与贡献请使用官方主仓库 apds.top 或公共镜像 GitCode 与 Gitee。

开发者个人主页与博客: https://dvsx.top – 博客正在维护升级中,敬请期待。
ap_ds 项目专属主页: https://apds.top(官方文档、发布版本与许可证中心)。

🔗 规范 URL: https://apds.top/
📖 博客与作者: dvsx.top – 博客正在维护升级中,敬请期待。


关于作者

开发者: Dvs (DvsXT)
个人主页与博客: https://dvsx.top – 博客正在维护升级中,敬请期待
作者简介: https://dvsyun.top/me/dvs
邮箱: me@dvsyun.top · dvs6666@163.com

ap_ds 官方门户

🎵 ap_ds 官方网站(主站): https://apds.top – 永久官方家园,完整文档、发布版本、许可证中心
📦 PyPI 项目页面: https://pypi.org/project/ap_ds/ – 可通过 pip 安装
🌐 镜像文档站: https://www.dvsyun.top/ap_ds – 备用文档访问

👉 ap_ds 项目专属主页(apds.top)是 第一推荐 的官方来源,托管完整文档、许可证详情、版本变更日志及官方发布版本。作者个人博客(dvsx.top)正在维护升级中,敬请期待。

让我们开始使用吧!

安装

pip install ap_ds

从旧版本升级:

pip install --upgrade ap_ds

💡 为什么推荐 Python 3.15t / 3.14t?

Python 的 自由线程(Free-Threading)版本(文件名带 t)移除了 GIL(全局解释器锁),可实现真正的多核并行。配合 ap_ds v3.1.0 的批量解析功能,120 个 MP3 文件仅需 0.33 秒完成解析。

⚠️ 版本选择说明:Python 3.15t 目前为测试版(b4),可能存在未知问题。如需更稳定的环境,推荐使用 Python 3.14t(稳定版)。两者均支持无 GIL 自由线程模式。

Windows 用户

Python 3.14t(稳定版)下载:

架构 下载链接
Windows 64位 python-3.14.4t-amd64.zip
Windows 32位 python-3.14.4t-win32.zip
ARM64 python-3.14.4t-arm64.zip

Python 3.15t(测试版)下载:

架构 下载链接
Windows 64位 python-3.15.0b4t-amd64.zip
Windows 32位 python-3.15.0b4t-win32.zip
ARM64 python-3.15.0b4t-arm64.zip

📦 ZIP 解压即用:下载后解压到任意目录,将 python.exe 所在路径添加到系统 PATH 环境变量即可使用。无需运行 EXE 安装器,秒级完成部署。

Linux 用户

方式一:使用包管理器

Fedora:

sudo dnf install python3.14-freethreading

安装后解释器位于 /usr/bin/python3.14t。

Ubuntu/Debian(使用 deadsnakes PPA):

sudo add-apt-repository ppa:deadsnakes
sudo apt-get update
sudo apt-get install python3.14-nogil

该 PPA 提供 -nogil 版本,同样是禁用了 GIL 的构建。

方式二:使用 Conda(跨平台)

从 conda-forge 频道安装:

conda create -n nogil -c conda-forge python-freethreading
mamba create -n nogil -c conda-forge python-freethreading

方式三:从源代码编译(通用方法)

# 下载 Python 3.14 源码
wget https://www.python.org/ftp/python/3.14.0/Python-3.14.0.tgz
tar -xzf Python-3.14.0.tgz
cd Python-3.14.0

# 配置:--disable-gil 是关键参数
./configure --disable-gil

# 编译并安装
make -j$(nproc)
sudo make install

macOS 用户

方式一:官方安装器(图形界面)

  1. 从 python.org 下载 macOS 安装包
  2. 运行安装器,在“安装类型”界面点击 “自定” 按钮
  3. 在弹出的组件列表中,勾选“Free-threaded Python” 选项,继续完成安装

方式二:使用 Homebrew

brew install python-freethreading

安装后解释器位于 $(brew --prefix)/bin/python3.14t。

验证安装

运行以下命令验证自由线程版本是否正常工作:

# 检查版本信息(应包含 "free-threading build")
python3.14t --version

# 检查 GIL 状态(输出 False 表示 GIL 已禁用)
python3.14t -c "import sys; print(sys._is_gil_enabled())"

创建虚拟环境

python3.14t -m venv my_env
source my_env/bin/activate  # Linux/macOS
my_env\Scripts\activate     # Windows

💡 提示:使用 python3.14t -m venv 创建的就是无 GIL 的隔离环境。

快速开始

from ap_ds import AudioLibrary

# 初始化库
lib = AudioLibrary()

# 播放音频文件
aid = lib.play_from_file("music/song.mp3")

# 控制播放
lib.pause_audio(aid)      # 暂停
lib.play_audio(aid)       # 恢复
lib.seek_audio(aid, 30.5) # 跳转到30.5秒

# 停止并获取已播放时长
duration = lib.stop_audio(aid)
print(f"已播放 {duration:.2f} 秒")

🚀 批量解析(v3.1.0 新增)

from ap_ds import batch_get_metadata

# 批量解析整个文件夹(120个MP3仅需0.33秒!)
results = batch_get_metadata("/music/playlist/", max_workers=8)

for meta in results:
    print(f"{meta['path']}: {meta['duration']}s, {meta['bitrate']}bps")

批量解析 API 一览:

API 说明
batch_get_metadata() 批量解析,返回完整元数据列表
batch_get_duration() 批量获取时长,返回 {path: duration}
batch_get_metadata_by_type() 按格式过滤批量解析

DAP播放列表系统

音频文件在播放时会自动记录到DAP(Dvs音频播放列表)中:

# 文件自动被记录
aid1 = lib.play_from_file("song1.mp3")
aid2 = lib.play_from_file("song2.ogg")

# 获取所有记录
recordings = lib.get_dap_recordings()
print(f"已记录 {len(recordings)} 个文件")

# 保存为JSON
success = lib.save_dap_to_json("my_playlist.ap_ds-dap")

DAP仅存储元数据(路径、时长、比特率、声道数),不存储音频数据。每条记录内存占用约150字节。

平台支持

Windows

  • 自动下载 SDL2.dll 和 SDL2_mixer.dll 并进行哈希验证
  • 无需手动配置
  • 支持 Windows 7 及更高版本

macOS

  • 自动下载 SDL2.framework 和 SDL2_mixer.framework 并进行哈希验证
  • 无需手动配置
  • 支持 macOS 10.9 及更高版本

Linux

智能多层导入系统:

  1. 系统库检查: 使用系统安装的SDL2库
  2. 用户配置: 检查之前运行保存的路径
  3. 自动安装: 检测包管理器并安装所需包
  4. 交互式引导: 如果上述方法均失败,提供手动选项

包管理器支持:

# Ubuntu/Debian
sudo apt-get install libsdl2-dev libsdl2-mixer-dev

# Fedora
sudo dnf install SDL2-devel SDL2_mixer-devel

# Arch
sudo pacman -S sdl2 sdl2_mixer

嵌入式 ARM64

已在以下设备上测试:

  • Orange Pi 4 Pro(Allwinner A733,2xA76 + 6xA55 @ 2.0GHz)
  • Raspberry Pi 5(BCM2712,4xA76 @ 2.4GHz)

两者均运行 Ubuntu 22.04,通过 3.5mm 输出支持完整音频功能。大量测试后内存增长:约 4MB。

ap_ds 音频库 – 完整API参考

版本:3.1.0
文档日期:2026年7月
项目主页:https://apds.top

目录

  1. AudioLibrary类 – 完整API

    • 初始化
    • 播放方法
    • 控制方法
    • 音量方法
    • 淡入淡出与过渡方法
    • 元数据方法
    • 批量解析方法(v3.1.0 新增)
    • DAP系统方法
    • 资源管理
    • 内部辅助方法
  2. 顶层便捷函数

  3. AudioParser类 – 元数据API

  4. AudioInfo模块 – 格式特定解析器

  5. SDL2集成层

  6. 常量参考

  7. 异常处理

AudioLibrary类 – 完整API

AudioLibrary类是音频播放、控制和元数据提取的主要接口。它管理所有SDL2资源,提供非阻塞播放,并维护DAP(Dvs音频播放列表)记录系统。

初始化

__init__(frequency: int = 44100, format: int = MIX_DEFAULT_FORMAT, channels: int = 2, chunksize: int = 2048) -> None

描述:
初始化SDL2音频子系统和SDL2_mixer库。在任何播放操作之前必须调用此方法。它使用指定的参数设置音频设备,并注册退出时处理程序以进行自动资源清理。

参数:

参数 类型 默认值 描述
frequency int 44100 音频采样率(Hz)。常见值:44100(CD质量)、48000(DVD/视频)、22050(语音)。较高的值提高质量但消耗更多CPU。
format int MIX_DEFAULT_FORMAT 音频采样格式。通常为 AUDIO_S16SYS(16位有符号,系统端序)。参见常量参考了解替代选项。
channels int 2 音频通道数。1 = 单声道,2 = 立体声。如果设备配置为立体声,单声道文件将自动上混为立体声。
chunksize int 2048 缓冲区大小(采样数)。较大的值减少CPU使用但增加延迟。对于实时应用,较小的值(1024)可能更好。

引发异常:

  • RuntimeError:如果SDL2初始化失败(例如,没有可用的音频设备)。
  • RuntimeError:如果混音器初始化失败(例如,不支持的格式)。

示例:

from ap_ds import AudioLibrary

# 默认配置(CD质量、立体声、低延迟)
lib = AudioLibrary()

# 语音播放的自定义配置
lib_voice = AudioLibrary(frequency=22050, channels=1, chunksize=1024)

内部行为:

  1. 调用 SDL_Init(SDL_INIT_AUDIO) 初始化音频子系统。
  2. 调用 Mix_OpenAudio(frequency, format, channels, chunksize) 打开混音器。
  3. 使用 atexit 注册 self.cleanup_function 以确保资源清理。
  4. 初始化内部数据结构:
    • _audio_cache: Dict[str, Mix_Chunk] – 缓存的音效
    • _music_cache: Dict[str, Mix_Music] – 缓存的音乐曲目
    • _channel_info: Dict[int, Dict] – 活动播放会话
    • _aid_to_filepath: Dict[int, str] – AID到文件路径的映射
    • _aid_counter: int – 顺序AID生成器
    • _dap_recordings: List[Dict] – DAP历史列表

播放方法

play_from_file(file_path: str, loops: int = 0, start_pos: float = 0.0) -> int

描述:
直接从磁盘加载并播放音频文件。文件被加载到内存中并立即播放。对于 .ap-ds-dap 文件,此方法记录元数据但不播放音频(DAP文件仅包含元数据)。

参数:

参数 类型 默认值 描述
file_path str 必需 音频文件的完整路径。支持的格式:MP3、WAV、FLAC、OGG
loops int 0 首次播放后的循环次数。0 = 播放一次,-1 = 无限循环。
start_pos float 0.0 起始位置(秒)。对于音效(短WAV文件),可能不支持。

注意: AAC文件支持元数据解析,但由于SDL2的限制,无法播放或对其执行其他操作。

返回:
int – 唯一标识此播放实例的音频ID(AID)。此ID可用于所有控制方法。

引发异常:

  • FileNotFoundError:如果文件不存在。
  • RuntimeError:如果文件格式不受支持或音频无法加载。
  • RuntimeError:如果播放失败(例如,没有可用的通道)。

按文件类型的行为:

文件类型 模式 跳转支持 淡入淡出支持
MP3、OGG、FLAC 音乐(Mix_PlayMusic) 是 是
WAV(时长 ≥ 阈值) 音乐(Mix_PlayMusic) 是 是
WAV(时长 < 阈值) 音效(Mix_PlayChannel) 否 否
其他格式 音效(Mix_PlayChannel) 否 否

示例:

# 从头开始播放一首歌一次
aid = lib.play_from_file("song.mp3")

# 循环播放短音效5次
aid = lib.play_from_file("beep.wav", loops=5)

# 从30秒处开始播放
aid = lib.play_from_file("podcast.mp3", start_pos=30.0)

# 无限循环(背景音乐)
aid = lib.play_from_file("ambient.ogg", loops=-1)

内部工作流程:

  1. 递增 _aid_counter 以生成新的AID。
  2. 调用 _add_to_dap_recordings() 记录元数据(如果元数据可用)。
  3. 通过 _is_music_file() 确定播放模式。
  4. 对于音乐文件:
    • 调用 Mix_LoadMUS() 加载文件。
    • 调用 Mix_PlayMusic() 开始播放。
    • 将 Mix_Music 对象存储在 _music_cache 中。
    • 设置 channel = -1(音乐使用专用通道)。
  5. 对于音效:
    • 调用 Mix_LoadWAV() 加载文件。
    • 调用 Mix_PlayChannel(-1, audio, loops) 在第一个可用通道上播放。
    • 将 Mix_Chunk 对象存储在 _audio_cache 中。
    • 返回实际的通道号。
  6. 将播放信息存储在 _channel_info[channel] 中。
  7. 如果 start_pos > 0,调用 _seek_audio()。

play_from_memory(file_path: str, loops: int = 0, start_pos: float = 0.0) -> int

描述:
播放已通过 new_aid() 加载到内存中的音频文件。由于文件已被缓存,此方法比 play_from_file() 更快,适用于重复播放同一文件。

参数: 与 play_from_file() 相同。

返回: int – 音频ID(AID)。

引发异常:

  • ValueError:如果文件尚未通过 new_aid() 加载。
  • RuntimeError:如果播放失败。

示例:

# 预加载音效
lib.new_aid("gunshot.wav")
lib.new_aid("explosion.wav")

# 从内存播放(非常快,无磁盘I/O)
aid = lib.play_from_memory("gunshot.wav")

内部工作流程:

  1. 生成新的AID。
  2. 记录到DAP。
  3. 检查文件是否在 _music_cache 或 _audio_cache 中。
  4. 从缓存对象播放。
  5. 在 _channel_info 中记录播放信息。

new_aid(file_path: str) -> int

描述:
将音频文件预加载到内存中但不播放。这对于缓存将多次播放的音效或音乐曲目很有用。文件被加载一次并存储在相应的缓存中。

参数:

参数 类型 描述
file_path str 要缓存的音频文件路径。

返回: int – 缓存文件的音频ID(AID)。

引发异常:

  • FileNotFoundError:如果文件不存在。
  • RuntimeError:如果文件格式不受支持或加载失败。

示例:

# 缓存常用声音
sounds = {
    'hit': lib.new_aid("hit.wav"),
    'jump': lib.new_aid("jump.wav"),
    'coin': lib.new_aid("coin.wav")
}

# 稍后从内存播放
lib.play_from_memory(sounds['hit'])

内部工作流程:

  1. 递增AID计数器。
  2. 记录到DAP。
  3. 通过 _is_music_file() 确定音乐还是音效。
  4. 如果是音乐:
    • 调用 Mix_LoadMUS()。
    • 存储在 _music_cache[file_path] 中。
  5. 如果是音效:
    • 调用 Mix_LoadWAV()。
    • 存储在 _audio_cache[file_path] 中。
  6. 在 _aid_to_filepath 中映射AID到文件路径。

控制方法

play_audio(aid: int) -> None

描述:
恢复暂停的音频实例的播放。如果音频未暂停,此方法无效。

参数:

参数 类型 描述
aid int 由 play_from_file()、play_from_memory() 或 new_aid() 返回的音频ID。

引发异常:

  • ValueError:如果AID无效或音频未暂停。

示例:

aid = lib.play_from_file("song.mp3")
time.sleep(2)
lib.pause_audio(aid)      # 2秒后暂停
time.sleep(1)
lib.play_audio(aid)       # 暂停1秒后恢复

内部行为:

  1. 通过 _find_channel_by_aid() 查找与AID关联的通道。
  2. 从 _channel_info 检索播放信息。
  3. 如果音频已暂停(info['paused'] 为 True):
    • 对于音乐(is_music 为 True):调用 Mix_ResumeMusic()。
    • 对于音效:调用 Mix_Resume(channel)。
    • 将 info['paused'] 重置为 False。
    • 调整 info['start_time'] 以考虑暂停的持续时间。

pause_audio(aid: int) -> None

描述:
暂停由AID指定的音频实例。音频稍后可以通过 play_audio() 恢复。

参数: 与 play_audio() 相同。

引发异常:

  • ValueError:如果AID无效或音频已暂停。

示例:

aid = lib.play_from_file("song.mp3")
time.sleep(5)
lib.pause_audio(aid)

内部行为:

  1. 查找与AID关联的通道。
  2. 检索播放信息。
  3. 如果尚未暂停:
    • 对于音乐:Mix_PauseMusic()。
    • 对于音效:Mix_Pause(channel)。
    • 设置 info['paused'] = True。
    • 记录 paused_position = time.time() - info['start_time']。

stop_audio(aid: int) -> float

描述:
停止指定音频实例的播放并释放相关资源。停止后音频无法恢复。

参数: 与 play_audio() 相同。

返回: float – 停止前播放的总时长(秒)。

引发异常:

  • ValueError:如果AID无效。

示例:

aid = lib.play_from_file("song.mp3")
time.sleep(10)
duration = lib.stop_audio(aid)
print(f"已播放 {duration:.2f} 秒")

内部行为:

  1. 查找与AID关联的通道。
  2. 计算 played_time(当前时间减去开始时间,或暂停位置)。
  3. 如果是音乐:Mix_HaltMusic()。
  4. 如果是音效:Mix_HaltChannel(channel)。
  5. 从 _channel_info 中移除条目。
  6. 返回 played_time。

seek_audio(aid: int, position: float) -> None

描述:
跳转到音频曲目中的特定位置(秒)。此方法仅适用于音乐模式文件(MP3、OGG、FLAC和长WAV文件)。音效(短WAV)不支持跳转。

参数:

参数 类型 描述
aid int 音频ID。
position float 目标位置(秒)。必须在0和总时长之间。

引发异常:

  • ValueError:如果AID无效。
  • RuntimeError:如果音频不可跳转(音效模式)。

示例:

# 跳转到曲目的30秒处
lib.seek_audio(aid, 30.0)

内部行为(音乐):

  1. 使用 Mix_HaltMusic() 停止当前播放。
  2. 使用 Mix_LoadMUS() 重新加载音乐文件。
  3. 使用 Mix_PlayMusic() 从头开始播放。
  4. 如果 Mix_SetMusicPosition 可用,跳转到目标位置。
  5. 使用新的开始时间更新 _channel_info。

内部行为(音效):

  1. 使用 Mix_HaltChannel() 停止当前播放。
  2. 使用 Mix_PlayChannel() 重新播放缓存的块。
  3. 这实际上是从头开始;不支持跳转。

音量方法

set_volume(aid: int, volume: int) -> bool

描述:
设置指定音频实例的音量。音量从0(静音)到128(最大)缩放。该值自动被限制。

参数:

参数 类型 描述
aid int 音频ID。
volume int 音量值(0–128)。超出此范围的值将被限制。

返回: bool – 如果音量设置成功返回 True,否则返回 False。

示例:

# 将音量设置为50%(128中的64)
lib.set_volume(aid, 64)

# 静音
lib.set_volume(aid, 0)

# 最大
lib.set_volume(aid, 128)

内部行为:

  1. 查找与AID关联的通道。
  2. 将音量限制在 [0, 128] 范围内。
  3. 如果是音乐:调用 Mix_VolumeMusic(volume)。
  4. 如果是音效:调用 Mix_Volume(channel, volume)。

get_volume(aid: int) -> int

描述:
返回指定音频实例的当前音量。

参数: 与 set_volume() 相同。

返回: int – 当前音量(0–128)。如果AID无效,返回 0。

示例:

current = lib.get_volume(aid)
print(f"当前音量: {current}")

内部行为:

  1. 查找与AID关联的通道。
  2. 如果是音乐:调用 Mix_VolumeMusic(-1)(-1 表示获取而不设置)。
  3. 如果是音效:调用 Mix_Volume(channel, -1)。

淡入淡出与过渡方法

fadein_music(aid: int, loops: int = -1, ms: int = 0) -> bool

描述:
在指定持续时间内淡入音乐。此方法停止任何当前播放的音乐,并以淡入效果开始指定曲目。仅适用于音乐模式文件。

参数:

参数 类型 默认值 描述
aid int 必需 音乐文件的音频ID。
loops int -1 循环次数。-1 = 无限,0 = 一次,n = n次。
ms int 0 淡入持续时间(毫秒)。0 表示无淡入(立即开始)。

返回: bool – 如果淡入成功开始返回 True,否则返回 False。

示例:

# 在2秒内淡入
lib.fadein_music(aid, loops=-1, ms=2000)

# 无循环淡入(播放一次)
lib.fadein_music(aid, loops=0, ms=500)

内部行为:

  1. 在 _channel_info 中搜索AID并验证它是音乐。
  2. 调用 _add_to_dap_recordings()(记录DAP)。
  3. 如果尚未缓存,加载音乐文件。
  4. 使用 Mix_HaltMusic() 停止任何当前音乐。
  5. 调用 Mix_FadeInMusic(music, loops, ms)。
  6. 如果成功,使用新的开始时间更新 _channel_info。

fadein_music_pos(aid: int, loops: int = -1, ms: int = 0, position: float = 0.0) -> bool

描述:
从特定位置开始淡入音乐。这对于从保存的时间戳恢复播放很有用。

参数:

参数 类型 默认值 描述
aid int 必需 音频ID。
loops int -1 循环次数。
ms int 0 淡入持续时间(毫秒)。
position float 0.0 起始位置(秒)。

返回: bool – 如果成功返回 True,否则返回 False。

示例:

# 从30秒标记处开始,在1秒内淡入
lib.fadein_music_pos(aid, loops=-1, ms=1000, position=30.0)

内部行为:

  1. 检查加载的SDL2_mixer中是否可用 Mix_FadeInMusicPos。
  2. 与 fadein_music() 相同,但使用位置参数调用 Mix_FadeInMusicPos()。

fadeout_music(ms: int = 0) -> bool

描述:
在指定持续时间内淡出当前播放的音乐。

参数:

参数 类型 默认值 描述
ms int 0 淡出持续时间(毫秒)。0 表示立即停止。

返回: bool – 如果淡出开始返回 True,如果没有音乐播放则返回 False。

示例:

# 在3秒内平滑淡出
lib.fadeout_music(ms=3000)

# 立即停止
lib.fadeout_music(ms=0)

内部行为:

  1. 调用 Mix_FadeOutMusic(ms)。
  2. 如果返回值为 1(成功)则返回 True,否则返回 False。

is_music_playing() -> bool

描述:
检查是否有任何音乐当前正在播放。

返回: bool – 如果音乐正在播放返回 True,否则返回 False。

示例:

if lib.is_music_playing():
    print("音乐正在播放")
else:
    print("音乐已停止或暂停")

内部行为: 调用 Mix_PlayingMusic()。

is_music_paused() -> bool

描述:
检查音乐是否暂停。

返回: bool – 如果暂停返回 True,否则返回 False。

内部行为: 调用 Mix_PausedMusic()。

get_music_fading() -> int

描述:
返回音乐的当前淡入淡出状态。

返回: int – 以下之一:

  • 0(MUS_NO_FADING):无淡入淡出进行中。
  • 1(MUS_FADING_OUT):正在淡出。
  • 2(MUS_FADING_IN):正在淡入。

示例:

state = lib.get_music_fading()
if state == 1:
    print("正在淡出...")

内部行为: 调用 Mix_FadingMusic()。

元数据方法

get_audio_duration(source: Union[str, int], is_file: bool = False) -> Union[int, Tuple[int, str]]

描述:
以秒为单位返回音频文件的持续时间。可以接受文件路径(字符串)或AID(整数)。

参数:

参数 类型 默认值 描述
source str 或 int 必需 文件路径或AID。
is_file bool False 如果为 True,将 source 视为文件路径;如果为 False,将其视为AID。

返回:

  • 成功时:int – 持续时间(秒,向下取整)。
  • 失败时:Tuple[int, str] – (0, error_message)。

示例:

# 通过文件路径
duration = lib.get_audio_duration("song.mp3", is_file=True)

# 通过AID
aid = lib.play_from_file("song.mp3")
duration = lib.get_audio_duration(aid, is_file=False)

内部行为:

  1. 如果 is_file 为 True,调用 _get_duration_by_filepath(str(source))。
  2. 如果 is_file 为 False,从 _aid_to_filepath 查找文件路径,然后调用 _get_duration_by_filepath()。

get_audio_metadata(source: Union[str, int], is_file: bool = False) -> Optional[Dict]

描述:
返回音频文件的完整元数据:时长、采样率、声道数、比特率和格式。

参数: 与 get_audio_duration() 相同。

返回: Dict 或 None(如果解析失败)。

字典结构:

{
    'path': str,           # 完整文件路径
    'format': str,         # 文件扩展名(mp3、wav等)
    'duration': int,       # 持续时间(秒,向下取整)
    'length': float,       # 精确持续时间(浮点数)
    'sample_rate': int,    # 采样率(Hz)
    'channels': int,       # 1(单声道)或2(立体声)
    'bitrate': int         # 比特率(bps)
}

示例:

metadata = lib.get_audio_metadata("song.flac", is_file=True)
if metadata:
    print(f"采样率: {metadata['sample_rate']} Hz")
    print(f"比特率: {metadata['bitrate'] / 1000:.0f} kbps")

get_audio_metadata_by_path(file_path: str) -> Optional[Dict]

描述:
等效于 get_audio_metadata(file_path, is_file=True) 的便捷方法。

参数:

参数 类型 描述
file_path str 音频文件路径。

返回: Dict 或 None。

get_audio_metadata_by_aid(aid: int) -> Optional[Dict]

描述:
等效于 get_audio_metadata(aid, is_file=False) 的便捷方法。

参数:

参数 类型 描述
aid int 音频ID。

返回: Dict 或 None。

批量解析方法(v3.1.0 新增)

batch_get_metadata(file_paths: Union[List[str], str], max_workers: Optional[int] = None, show_progress: bool = False) -> List[Dict]

描述:
使用多进程并行解析多个音频文件。在 Python 3.15t(无 GIL)环境下,可实现真正的多核并行加速。

参数:

参数 类型 默认值 描述
file_paths List[str] 或 str 必需 文件路径列表,或单个目录路径字符串。如果提供目录,将递归扫描该目录下所有支持的音频文件。
max_workers Optional[int] None 最大工作进程数。默认为 CPU 核心数。
show_progress bool False 如果为 True,向 stdout 打印进度。

返回: List[Dict] – 元数据字典列表。解析失败的文件被省略。

性能参考:

  • 120 个 MP3 文件,8 进程并行:0.33 秒
  • 相比串行解析加速比:4.13 倍
  • 相比 Mutagen(单线程):快 2.94 倍

示例:

from ap_ds import AudioLibrary

lib = AudioLibrary()

# 批量解析整个文件夹
results = lib.batch_get_metadata("/music/playlist/", max_workers=8, show_progress=True)

for meta in results:
    print(f"{meta['path']}: {meta['duration']}s, {meta['bitrate']}bps")

# 解析文件列表
files = ["song1.mp3", "song2.flac", "song3.ogg"]
results = lib.batch_get_metadata(files)

内部行为:

  1. 如果 file_paths 是目录路径,递归扫描收集所有支持的音频文件(.mp3、.wav、.flac、.ogg、.aac)。
  2. 使用 ProcessPoolExecutor 创建进程池,将文件分配给各工作进程。
  3. 每个工作进程调用 _parse_single_file() 解析单个文件。
  4. 收集并返回所有成功解析的元数据。

batch_get_duration(file_paths: Union[List[str], str], max_workers: Optional[int] = None) -> Dict[str, int]

描述:
批量获取多个音频文件的时长。

参数:

参数 类型 默认值 描述
file_paths List[str] 或 str 必需 文件路径列表,或单个目录路径字符串。
max_workers Optional[int] None 最大工作进程数。默认为 CPU 核心数。

返回: Dict[str, int] – {文件路径: 时长(秒)} 的映射。解析失败的文件被省略。

示例:

durations = lib.batch_get_duration("/music/playlist/")
for path, duration in durations.items():
    print(f"{path}: {duration} 秒")

batch_get_metadata_by_type(file_paths: Union[List[str], str], file_type: str, max_workers: Optional[int] = None) -> List[Dict]

描述:
批量解析音频文件,但仅返回指定格式的结果。

参数:

参数 类型 默认值 描述
file_paths List[str] 或 str 必需 文件路径列表,或单个目录路径字符串。
file_type str 必需 文件扩展名过滤(例如 "mp3"、"flac")。
max_workers Optional[int] None 最大工作进程数。默认为 CPU 核心数。

返回: List[Dict] – 匹配指定格式的元数据字典列表。

示例:

# 只解析 MP3 文件
mp3_results = lib.batch_get_metadata_by_type("/music/", "mp3")

DAP系统方法

save_dap_to_json(save_path: str) -> bool

描述:
将内存中当前所有DAP记录保存到JSON文件。文件扩展名必须为 .ap-ds-dap。

参数:

参数 类型 描述
save_path str 输出文件路径(必须以 .ap-ds-dap 结尾)。

返回: bool – 如果成功返回 True,否则返回 False。

引发异常:

  • ValueError:如果文件扩展名不是 .ap-ds-dap。

示例:

if lib.save_dap_to_json("my_playlist.ap-ds-dap"):
    print("播放列表已保存!")
else:
    print("保存失败")

文件格式:

[
  {
    "path": "/music/song1.mp3",
    "duration": 240,
    "bitrate": 320000,
    "channels": 2
  },
  {
    "path": "/music/song2.ogg",
    "duration": 180,
    "bitrate": 128000,
    "channels": 2
  }
]

get_dap_recordings() -> List[Dict]

描述:
返回内存中当前所有DAP记录的副本。

返回: List[Dict] – 记录字典列表。

示例:

records = lib.get_dap_recordings()
for rec in records:
    print(f"{rec['path']}: {rec['duration']}s")

clear_dap_recordings() -> None

描述:
清除内存中的所有DAP记录。此操作不可逆,除非您之前已保存记录。

示例:

lib.clear_dap_recordings()
print(f"剩余记录: {len(lib.get_dap_recordings())}")  # 0

_add_to_dap_recordings(file_path: str) -> None

描述:
内部方法,将文件添加到DAP记录列表。由 play_from_file()、play_from_memory() 和 new_aid() 自动调用。

参数:

参数 类型 描述
file_path str 音频文件路径。

内部行为:

  1. 调用 get_audio_metadata_by_path(file_path) 提取元数据。
  2. 如果元数据可用,创建包含 path、duration、bitrate 和 channels 的记录。
  3. 使用 O(1) set 去重(v3.1.0 优化),避免重复记录。

资源管理

clear_memory_cache() -> None

描述:
释放内存中所有缓存的音频数据(包括音效和音乐)。调用此方法后,任何后续播放都需要从磁盘重新加载文件。

示例:

lib.clear_memory_cache()
print("所有缓存音频已清除")

内部行为:

  1. 遍历 _audio_cache 并对每个调用 Mix_FreeChunk()。
  2. 遍历 _music_cache 并对每个调用 Mix_FreeMusic()。
  3. 清空两个字典。

cleanup_function() -> None

描述:
使用 atexit 注册,在Python解释器退出时清理所有资源。此方法:

  • 清除内存缓存。
  • 使用 Mix_CloseAudio() 关闭音频设备。
  • 使用 SDL_Quit() 关闭SDL。

用户不应直接调用此方法;它在解释器关闭时自动调用。

内部辅助方法

这些方法供内部使用,但为完整性在此记录。

_find_channel_by_aid(aid: int) -> Optional[int]

描述:
在 _channel_info 中搜索与给定AID关联的通道。

返回: int – 通道号,如果未找到则返回 None。

_get_file_path_by_aid(aid: int) -> Optional[str]

描述:
在 _channel_info 中搜索与给定AID关联的文件路径。

返回: str – 文件路径,如果未找到则返回 None。

_is_music_file(file_path: str) -> bool

描述:
确定文件应被视为音乐(支持跳转)还是音效(不支持跳转)。决策基于:

  • 文件扩展名(.mp3、.ogg、.flac → 音乐)。
  • 对于WAV文件:将持续时间与 WAV_THRESHOLD 进行比较。

返回: bool – 如果是音乐模式返回 True,如果是音效模式返回 False。

_seek_audio(channel: int, position: float) -> None

描述:
内部方法,对给定通道执行实际的跳转操作。

_get_duration_by_filepath(file_path: str) -> Union[int, Tuple[int, str]]

描述:
内部方法,使用 audio_parser 提取持续时间。返回整数(成功)或元组 (0, error_message)(失败)。

_get_file_duration(file_path: str) -> float

描述:
内部方法,以浮点数返回持续时间,出错时默认为 0.0。

顶层便捷函数

ap_ds 在包顶层直接导出了以下便捷函数,方便用户快速调用,无需创建 AudioLibrary 实例。

batch_get_metadata(file_paths, max_workers=None, show_progress=False) -> List[Dict]

描述:
批量解析音频文件。等效于 AudioLibrary.batch_get_metadata()。

示例:

from ap_ds import batch_get_metadata

results = batch_get_metadata("/music/", max_workers=8)

batch_get_duration(file_paths, max_workers=None) -> Dict[str, int]

描述:
批量获取音频时长。等效于 AudioLibrary.batch_get_duration()。

示例:

from ap_ds import batch_get_duration

durations = batch_get_duration("/music/")

batch_get_metadata_by_type(file_paths, file_type, max_workers=None) -> List[Dict]

描述:
按格式过滤批量解析。等效于 AudioLibrary.batch_get_metadata_by_type()。

示例:

from ap_ds import batch_get_metadata_by_type

mp3s = batch_get_metadata_by_type("/music/", "mp3")

is_full_performance() -> bool

描述:
检查当前是否运行在满血性能模式(Python 3.15t + profiling 可用)。

返回: bool – 如果满血模式返回 True,否则返回 False。

示例:

from ap_ds import is_full_performance

if is_full_performance():
    print("🚀 满血模式!")

get_runtime_info() -> dict

描述:
获取运行时环境信息。

返回: dict – 包含 Python 版本、GIL 状态、profiling 可用性、CPU 核心数等诊断信息。

示例:

from ap_ds import get_runtime_info

info = get_runtime_info()
print(info["python_version"], info["gil_enabled"])

AudioParser类 – 元数据API

AudioParser类为从音频文件提取元数据提供了统一接口。它由AudioLibrary内部使用,但也可以直接使用。

get_audio_parser() -> AudioParser

描述:
返回AudioParser实例的单例工厂函数。同一实例在多次调用间被重用。

注意: 此函数位于 ap_ds.audio_parser 子模块,需从该子模块导入。

示例:

from ap_ds.audio_parser import get_audio_parser

parser = get_audio_parser()
metadata = parser.get_audio_metadata("song.mp3")

AudioParser.get_audio_metadata(file_path: str) -> Optional[Dict]

描述:
返回给定音频文件的元数据。委托给 audio_info.py 中的格式特定解析器。

参数:

参数 类型 描述
file_path str 音频文件路径。

返回: Dict 或 None(如果解析失败)。

字典结构:

{
    'path': file_path,
    'format': ext,           # 例如 'mp3'、'wav'
    'duration': int(info.length),
    'length': float(info.length),
    'sample_rate': info.sample_rate,
    'channels': info.channels,
    'bitrate': info.bitrate
}

AudioParser.get_audio_duration(file_path: str) -> int

描述:
以秒为单位返回音频文件的持续时间(向下取整)。

返回: int – 持续时间(秒),出错时返回 0。

AudioParser.batch_get_metadata(file_paths, max_workers=None, show_progress=False) -> List[Dict]

描述:
AudioParser 类的批量解析方法。等效于顶层 batch_get_metadata() 函数。

示例:

from ap_ds.audio_parser import get_audio_parser

parser = get_audio_parser()
results = parser.batch_get_metadata("/music/", max_workers=8)

AudioParser.batch_get_duration(file_paths, max_workers=None) -> Dict[str, int]

描述:
AudioParser 类的批量获取时长方法。等效于顶层 batch_get_duration() 函数。

AudioParser.batch_get_metadata_by_type(file_paths, file_type, max_workers=None) -> List[Dict]

描述:
AudioParser 类的按格式过滤批量解析方法。等效于顶层 batch_get_metadata_by_type() 函数。

旧版方法(为向后兼容保留)

这些方法是别名,行为与 get_audio_duration() 相同:

  • get_ogg_duration(file_path)
  • get_flac_duration(file_path)
  • get_mp3_duration(file_path)
  • get_wav_duration(file_path)
  • get_duration_by_extension(file_path)

AudioInfo模块 – 格式特定解析器

audio_info.py 模块包含每种支持格式的低级解析器。每个解析器返回一个 StreamInfo 对象,具有以下属性:

  • length: float – 持续时间(秒,精确)。
  • sample_rate: int – 采样率(Hz)。
  • channels: int – 音频通道数。
  • bitrate: int – 比特率(bps)。

StreamInfo 类

属性:

  • length(float)– 持续时间(秒)。
  • sample_rate(int)– 采样率(Hz)。
  • channels(int)– 通道数(1 = 单声道,2 = 立体声)。
  • bitrate(int)– 比特率(bps)。

字符串表示: "<StreamInfo length=3.141593s rate=44100Hz channels=2 bitrate=320000bps>"

WAVFile 类

解析器: 读取RIFF块,提取 fmt 和 data 块。

准确度: 100%(基于文件结构,无启发式)。

方法:

  1. 读取 RIFF 头和 WAVE 标识符。
  2. 扫描 fmt(格式)和 data 块。
  3. 从 fmt 提取:channels、sample_rate、block_align。
  4. 从 data 提取:data_size。
  5. 计算 total_frames = data_size // block_align。
  6. 计算 length = total_frames / sample_rate。
  7. 计算 bitrate = sample_rate * block_align * 8 // channels。

FLACFile 类

解析器: 读取 STREAMINFO 块(所有FLAC文件中必须存在)。

准确度: 100%(来自元数据)。

方法:

  1. 验证 fLaC 魔术字节。
  2. 遍历元数据块。
  3. 对于块类型 0(STREAMINFO):
    • 从字节10–12提取 sample_rate。
    • 从字节12提取 channels。
    • 从字节13–17提取 total_samples。
    • 计算 length = total_samples / sample_rate。
    • 计算 bitrate = file_size * 8 / length。
  4. 返回 StreamInfo。

MP3File 类

解析器: 逐帧扫描器,计数帧并累积采样数。

准确度: >98%(受可变比特率和不完整最后一帧限制)。

方法:

  1. 逐字节扫描文件,寻找 0xFF(帧同步)。
  2. 读取接下来的3个字节形成帧头。
  3. 提取:
    • 字节1的位4–7的 bitrate。
    • 字节1的位2–3的 sample_rate。
  4. 计算帧长度:144000 * bitrate / sample_rate。
  5. 将文件指针向前移动帧长度。
  6. 递增 total_frames。
  7. 扫描完成后,计算:
    • length = total_frames * 1152 / sample_rate(每个MP3帧1152个采样)。
    • bitrate = file_size * 8 / length。

OGGFile 类

解析器: 读取Ogg页面,从最后一页提取粒度位置(总采样数)。

准确度: 99.99%(粒度位置精确,但如果文件被截断可能略有偏差)。

方法:

  1. 扫描Ogg页面(每个以 OggS 开头)。
  2. 从字节6–13提取粒度位置。
  3. 保留最大粒度位置(最后一页)。
  4. 还读取第一个数据包,从Vorbis标识头提取 sample_rate 和 channels。
  5. 计算 length = last_granule / sample_rate。
  6. 计算 bitrate = file_size * 8 / length。

AACFile 类

解析器: 读取ADTS(音频数据传输流)帧,累积采样数。

准确度: >99%(基于帧计数,类似于MP3)。

方法:

  1. 扫描 0xFFF(ADTS同步字)。
  2. 读取接下来的7个字节作为头。
  3. 提取:
    • 字节2的位2–5的 sample_rate。
    • 字节2的位6–7和字节3的 channels。
    • 字节3–5的 frame_length。
  4. 将 total_samples 增加1024(每个AAC帧的采样数)。
  5. 向前跳转 frame_length - 7。
  6. 计算 length = total_samples / sample_rate。
  7. 计算 bitrate = file_size * 8 / length。

open_audio(filename: str) -> FileType

描述:
根据文件扩展名返回适当解析器实例的工厂函数。

参数:

参数 类型 描述
filename str 音频文件路径。

返回: WAVFile、FLACFile、MP3File、OGGFile 或 AACFile 的实例。

引发异常: 如果格式不受支持,引发 ValueError。

SDL2集成层

player.py 模块包含使用 ctypes 与 SDL2 和 SDL2_mixer 的低级绑定。所有函数都设置了适当的 argtypes 和 restype,以确保跨平台稳定性。

全局SDL2函数

函数 C绑定 描述
SDL_Init(flags) _sdl_lib.SDL_Init 初始化SDL子系统。
SDL_Quit() _sdl_lib.SDL_Quit 关闭SDL。
SDL_GetError() _sdl_lib.SDL_GetError 返回最后一条SDL错误消息。
SDL_Delay(ms) _sdl_lib.SDL_Delay 休眠指定的毫秒数。
SDL_RWFromFile(file, mode) _sdl_lib.SDL_RWFromFile 使用SDL的RWops打开文件进行读取。

全局SDL2_mixer函数

函数 C绑定 描述
Mix_OpenAudio(freq, format, channels, chunksize) _mix_lib.Mix_OpenAudio 打开音频设备。
Mix_CloseAudio() _mix_lib.Mix_CloseAudio 关闭音频设备。
Mix_LoadWAV_RW(rwops, freesrc) _mix_lib.Mix_LoadWAV_RW 将WAV文件加载到 Mix_Chunk 中。
Mix_LoadMUS_RW(rwops, freesrc) _mix_lib.Mix_LoadMUS_RW 将音乐文件加载到 Mix_Music 中。
Mix_FreeChunk(chunk) _mix_lib.Mix_FreeChunk 释放 Mix_Chunk。
Mix_FreeMusic(music) _mix_lib.Mix_FreeMusic 释放 Mix_Music。
Mix_PlayChannel(channel, chunk, loops) _mix_lib.Mix_PlayChannel 在通道上播放块。
Mix_PlayMusic(music, loops) _mix_lib.Mix_PlayMusic 播放音乐。
Mix_Pause(channel) _mix_lib.Mix_Pause 暂停通道。
Mix_PauseMusic() _mix_lib.Mix_PauseMusic 暂停音乐。
Mix_Resume(channel) _mix_lib.Mix_Resume 恢复通道。
Mix_ResumeMusic() _mix_lib.Mix_ResumeMusic 恢复音乐。
Mix_HaltChannel(channel) _mix_lib.Mix_HaltChannel 停止通道。
Mix_HaltMusic() _mix_lib.Mix_HaltMusic 停止音乐。
Mix_Volume(channel, volume) _mix_lib.Mix_Volume 设置/获取通道音量。
Mix_VolumeMusic(volume) _mix_lib.Mix_VolumeMusic 设置/获取音乐音量。
Mix_Playing(channel) _mix_lib.Mix_Playing 检查通道是否正在播放。
Mix_PlayingMusic() _mix_lib.Mix_PlayingMusic 检查音乐是否正在播放。
Mix_Paused(channel) _mix_lib.Mix_Paused 检查通道是否暂停。
Mix_PausedMusic() _mix_lib.Mix_PausedMusic 检查音乐是否暂停。
Mix_FadeInMusic(music, loops, ms) _mix_lib.Mix_FadeInMusic 淡入音乐。
Mix_FadeInMusicPos(music, loops, ms, pos) _mix_lib.Mix_FadeInMusicPos 从位置淡入音乐。
Mix_FadeOutMusic(ms) _mix_lib.Mix_FadeOutMusic 淡出音乐。
Mix_FadingMusic() _mix_lib.Mix_FadingMusic 返回淡入淡出状态。
Mix_SetMusicPosition(pos) _mix_lib.Mix_SetMusicPosition 在音乐中跳转(如果支持)。

常量参考

SDL初始化标志

常量 值 描述
SDL_INIT_TIMER 0x00000001 计时器子系统。
SDL_INIT_AUDIO 0x00000010 音频子系统。
SDL_INIT_VIDEO 0x00000020 视频子系统。
SDL_INIT_JOYSTICK 0x00000200 摇杆子系统。
SDL_INIT_HAPTIC 0x00001000 触觉(力反馈)子系统。
SDL_INIT_GAMECONTROLLER 0x00002000 游戏控制器子系统。
SDL_INIT_EVENTS 0x00004000 事件子系统。
SDL_INIT_EVERYTHING 0x0000F231 所有子系统。

音频格式

常量 值 描述
AUDIO_U8 0x0008 无符号8位采样。
AUDIO_S8 0x8008 有符号8位采样。
AUDIO_U16LSB 0x0010 无符号16位,小端序。
AUDIO_S16LSB 0x8010 有符号16位,小端序。
AUDIO_U16MSB 0x1010 无符号16位,大端序。
AUDIO_S16MSB 0x9010 有符号16位,大端序。
AUDIO_U16 AUDIO_U16LSB 系统端序无符号16位。
AUDIO_S16 AUDIO_S16LSB 系统端序有符号16位。
AUDIO_S32LSB 0x8020 有符号32位,小端序。
AUDIO_S32MSB 0x9020 有符号32位,大端序。
AUDIO_S32 AUDIO_S32LSB 系统端序有符号32位。
AUDIO_F32LSB 0x8120 浮点32位,小端序。
AUDIO_F32MSB 0x9120 浮点32位,大端序。
AUDIO_F32 AUDIO_F32LSB 系统端序浮点32位。
MIX_DEFAULT_FORMAT AUDIO_S16SYS 默认格式(有符号16位,系统端序)。

混音器初始化标志

常量 值 描述
MIX_INIT_FLAC 0x00000001 FLAC支持。
MIX_INIT_MOD 0x00000002 MOD(跟踪器)支持。
MIX_INIT_MP3 0x00000008 MP3支持。
MIX_INIT_OGG 0x00000010 OGG Vorbis支持。
MIX_INIT_MID 0x00000020 MIDI支持。
MIX_INIT_OPUS 0x00000040 Opus支持。

音乐类型常量(由 Mix_GetMusicType 返回)

常量 值 描述
MUS_NONE 0 未加载音乐。
MUS_CMD 1 外部命令(罕见)。
MUS_WAV 2 WAV文件。
MUS_MOD 3 MOD跟踪器文件。
MUS_MID 4 MIDI文件。
MUS_OGG 5 OGG Vorbis。
MUS_MP3 6 MP3。
MUS_FLAC 7 FLAC。
MUS_OPUS 8 Opus。

淡入淡出状态常量

常量 值 描述
MUS_NO_FADING 0 无淡入淡出进行中。
MUS_FADING_OUT 1 正在淡出。
MUS_FADING_IN 2 正在淡入。

异常处理

AudioLibrary中的所有方法在以下情况下引发异常:

异常 引发时机
FileNotFoundError 指定的文件不存在。
RuntimeError SDL2初始化失败、混音器初始化失败、音频文件加载失败、播放失败。
ValueError AID无效、不支持的操作(例如,在音效上跳转)。
ImportError 无法加载SDL2库(Windows/macOS下载失败,Linux系统库缺失)。

示例:

try:
    lib.play_from_file("nonexistent.mp3")
except FileNotFoundError as e:
    print(f"文件未找到: {e}")
except RuntimeError as e:
    print(f"播放错误: {e}")

API参考结束

本文档涵盖了ap_ds库版本3.1.0的所有公共和内部API。有关其他示例和使用模式,请参阅主README.md。

环境变量

1. AP_DS_HIDE_SUPPORT_PROMPT

用途: 控制导入库时是否显示启动横幅。

默认值: 未设置(显示横幅)

行为:

  • 设置为 1 时,完全抑制启动消息。
  • 适用于 GUI 应用程序、守护进程或任何需要最小化控制台输出的环境。

使用方式:

# Linux/macOS
export AP_DS_HIDE_SUPPORT_PROMPT=1

# Windows Command Prompt
set AP_DS_HIDE_SUPPORT_PROMPT=1

# Windows PowerShell
$env:AP_DS_HIDE_SUPPORT_PROMPT=1

代码示例:

import os
os.environ['AP_DS_HIDE_SUPPORT_PROMPT'] = '1'
import ap_ds  # 无横幅输出

2. AP_DS_WAV_THRESHOLD

用途: 决定 WAV 文件是作为音效播放(不支持跳转)还是作为音乐文件播放(支持跳转和淡入淡出)。

默认值: 6 秒

行为:

  • 时长 小于 阈值的文件:视为音效(使用 Mix_PlayChannel)。不支持跳转操作。
  • 时长 大于等于 阈值的文件:视为音乐(使用 Mix_PlayMusic)。支持完整的跳转和淡入淡出操作。
  • 如果阈值设置为 30 或更高,会自动重置为 6 以防止潜在的内存问题。
  • 负值也会重置为 6。
  • 无效(非数字)值回退到默认值。

为什么存在此设置:
SDL2_mixer 有两种不同的播放机制:音效(通道)和音乐。音效轻量级,适合短片段,但不能跳转或淡入淡出。音乐曲目支持这些高级功能,但消耗稍多资源。此阈值允许根据文件时长自动选择适当的机制。

使用方式:

# 设置阈值为10秒
export AP_DS_WAV_THRESHOLD=10

# 使用极低阈值(所有WAV都成为音效)
export AP_DS_WAV_THRESHOLD=0

# 使用高阈值(只有很长的WAV才成为音乐)
export AP_DS_WAV_THRESHOLD=20

验证规则:

# 内部验证逻辑
if WAV_THRESHOLD >= 30:
    WAV_THRESHOLD = 6  # 防止内存问题
elif WAV_THRESHOLD < 0:
    WAV_THRESHOLD = 6

3. AP_DS_SDL2_PATH 和 AP_DS_SDL2_MIXER_PATH(仅限 Linux)

用途: 在 Linux 系统上指定自定义路径指向 SDL2 和 SDL2_mixer 共享库。当系统安装的库未找到或用户编译了自己的版本时使用。

默认值: 未设置;库搜索标准系统路径(/usr/lib、/usr/local/lib 等)和包管理器位置。

行为:

  • 如果两个变量都已设置且文件存在,立即加载,不再进一步搜索。
  • 成功加载后,路径自动保存到 ~/.config/ap_ds/sdl_paths.conf 供将来运行使用。
  • 如果保存的路径变为无效(文件丢失),库回退到正常搜索流程。

使用方式:

export AP_DS_SDL2_PATH=/usr/local/lib/libSDL2.so
export AP_DS_SDL2_MIXER_PATH=/usr/local/lib/libSDL2_mixer.so

配置文件: 首次成功手动配置后,路径保存到:

~/.config/ap_ds/sdl_paths.conf

文件内容:

SDL2_PATH=/path/to/libSDL2.so
SDL2_MIXER_PATH=/path/to/libSDL2_mixer.so

4. AP_DS_SUPPRESS_WARNINGS(v3.1.0 新增)

用途: 抑制运行时降级警告(例如 GIL 启用警告)。

默认值: 未设置(显示警告)

行为:

  • 设置为 1 时,完全抑制所有运行时降级警告。
  • 适用于生产环境或不想看到警告输出的场景。

使用方式:

export AP_DS_SUPPRESS_WARNINGS=1

5. AP_DS_SHOW_CONGRATS(v3.1.0 新增)

用途: 控制是否显示满血性能模式的恭喜信息。

默认值: 未设置(显示恭喜信息)

行为:

  • 设置为 0 时,隐藏满血模式(GIL 禁用)的恭喜信息。
  • 适用于安静模式或无头环境。

使用方式:

export AP_DS_SHOW_CONGRATS=0

6. AP_DS_SKIP_AUTO_CHECK(v3.1.0 新增)

用途: 控制是否跳过导入时的自动运行时自检。

默认值: 0(执行自检)

行为:

  • 设置为 1 时,跳过导入时的运行时自检输出。
  • 适用于测试环境或减少启动噪音。

使用方式:

export AP_DS_SKIP_AUTO_CHECK=1

v3.1.0 – 详细发布概述

什么是 v3.1.0?

v3.1.0 是 ap_ds 的功能性大版本更新(非 LTS),专注于批量解析性能和 Python 3.15t 自由线程支持。它引入了全新的批量解析 API,使用 ProcessPoolExecutor 实现真正的多核并行,并完全适配了 Python 3.15t 的无 GIL 环境。

版本类型: 功能版本(非 LTS)
支持周期: 约 6 个月
推荐用户: 需要批量解析、想体验 Python 3.15t 新特性的开发者和尝鲜用户
生产环境建议: 继续使用 v3.0.0 LTS,等待 v4.0.0 LTS

主要新功能

1. 批量解析 API

API 说明
batch_get_metadata() 批量解析音频文件,返回完整元数据列表
batch_get_duration() 批量获取音频时长,返回 {path: duration}
batch_get_metadata_by_type() 按格式过滤批量解析(如只解析 MP3)

这些 API 使用 ProcessPoolExecutor 实现进程级并行,在 Python 3.15t(无 GIL)环境下实现真正的多核并行加速。

2. 性能提升

120 个 MP3 文件测试结果:

方式 耗时 加速比
串行解析 1.367秒 1.00x
8进程并行 0.331秒 4.13x

与 Mutagen 对比:

库 方式 120文件耗时
Mutagen 单线程 0.973秒
ap_ds v3.1.0 8进程并行 0.331秒(快 2.94 倍)

3. Python 3.15t 自由线程支持

  • 无 GIL 真并行:批量解析在多核 CPU 上线性加速
  • 运行时自检:导入时自动检测 GIL 状态并给出明确提示
  • 满血版用户看到 🎉 ap_ds: GIL disabled (free-threading mode)
  • 降级版用户看到 ⚠️ ap_ds: GIL is enabled (multi-core parallelism limited)

4. DAP 去重优化

_add_to_dap_recordings() 从 O(n) 线性扫描升级为 O(1) set 去重,大播放列表下性能提升显著。同时保留 O(n) 回退机制,确保极端情况下的稳定性。

5. 启动加速:lazy import

Python 3.15+ 用户自动启用 lazy import,重模块(ctypes、urllib.request、struct、json 等)延迟加载,import ap_ds 速度提升显著。

6. 新增环境变量

变量 默认值 说明
AP_DS_SUPPRESS_WARNINGS 不设置 设为 1 抑制降级警告
AP_DS_SHOW_CONGRATS 不设置 设为 0 隐藏满血版恭喜信息
AP_DS_SKIP_AUTO_CHECK 0 设为 1 跳过导入时自检

7. 运行时诊断

新增两个独立工具函数,无需实例化即可使用:

from ap_ds import is_full_performance, get_runtime_info

if is_full_performance():
    print("🚀 满血版!")

info = get_runtime_info()
print(info["python_version"], info["gil_enabled"])

版本关系

版本 类型 支持周期 适用场景
v3.0.0 LTS 长期支持 至2031年3月 生产环境
v3.1.0 功能版 约6个月 尝鲜/批量解析需求
v4.0.0 LTS(计划) 长期支持 待定 基于 Python 3.15 正式版

升级建议

用户类型 建议
生产环境 继续使用 v3.0.0 LTS,等 v4.0.0 LTS
开发/测试 升级到 v3.1.0 体验新功能
需要批量解析 必须升级到 v3.1.0
Python 3.15t 用户 必须升级到 v3.1.0 发挥无 GIL 优势
pip install --upgrade ap_ds

技术架构

核心组件

ap_ds/
├── __init__.py          # 包入口,版本导入,横幅显示
├── player.py            # 主 AudioLibrary 类,SDL2 绑定,播放逻辑
├── audio_parser.py      # 元数据解析器工厂,统一 API
├── audio_info.py        # 格式特定解析器(WAV、FLAC、MP3、OGG、AAC)
└── _version.py          # 自动生成的版本文件(构建时创建)

1. Player 模块(player.py)

用途: 库的核心。管理 SDL2 初始化、音频播放、缓存和 DAP 记录。

关键类与函数:

  • AudioLibrary:用户交互的主类
    • 初始化: __init__(frequency, format, channels, chunksize) – 设置 SDL 音频和混音器
    • 播放: play_from_file()、play_from_memory()、new_aid()
    • 控制: pause_audio()、play_audio()、stop_audio()、seek_audio()
    • 音量: set_volume()、get_volume()
    • 淡入淡出: fadein_music()、fadein_music_pos()、fadeout_music()、is_music_playing()、is_music_paused()、get_music_fading()
    • 元数据: get_audio_duration()、get_audio_metadata()
    • 批量解析(v3.1.0): batch_get_metadata()、batch_get_duration()、batch_get_metadata_by_type()
    • DAP: save_dap_to_json()、get_dap_recordings()、clear_dap_recordings()

内部数据结构:

  • self._audio_cache:dict[str, Mix_Chunk] – 缓存的音效(短文件)
  • self._music_cache:dict[str, Mix_Music] – 缓存的音乐曲目
  • self._channel_info:dict[int, dict] – 活动播放会话,以 SDL 通道 ID 为键
  • self._aid_to_filepath:dict[int, str] – AID(音频 ID)到文件路径的映射
  • self._dap_recordings:list[dict] – DAP 历史记录
  • self._dap_records_set:set[str] – O(1) 去重集合(v3.1.0)

平台抽象:

  • import_sdl2():在 Windows、macOS 和 Linux 上智能加载 SDL2 库
  • download_sdl_libraries():下载平台特定二进制文件并进行哈希验证
  • check_sdl_libraries_exist():验证所需文件是否存在
  • load_sdl2_from_directory():从包目录或系统路径加载库

SDL2 绑定:

  • 所有 SDL2 和 SDL2_mixer 函数通过 ctypes 绑定
  • 函数原型(argtypes、restype)为所有平台设置,以防止段错误
  • 绑定代码无条件执行,确保跨平台稳定性

2. 元数据解析器模块(audio_parser.py)

用途: 提供统一的音频元数据提取接口。处理格式检测并分派到适当的解析器。

关键函数:

  • get_audio_parser():返回 AudioParser 实例的单例工厂
  • AudioParser.get_audio_metadata(file_path):返回包含 path、format、duration、length、sample_rate、channels、bitrate 的字典
  • AudioParser.batch_get_metadata():批量解析(v3.1.0)

回退行为: 如果格式特定解析器失败,返回 None。元数据解析期间不引发异常;错误被记录。

3. 格式特定解析器(audio_info.py)

用途: 每种支持格式的低级解析器。用纯 Python 编写,不依赖外部库。

格式 解析器类 准确度 方法
WAV WAVFile 100% 读取 RIFF 块,提取采样率、通道数、块对齐和数据大小。从总帧数计算精确时长。
FLAC FLACFile 100% 读取 STREAMINFO 块(始终存在)。从元数据提取采样率、通道数和总采样数。
MP3 MP3File >98% 使用 MP3 帧头逐帧扫描文件。累积采样数并基于采样率估算时长。
OGG OGGFile 99.99% 读取 Ogg 页面,从最后一页提取粒度位置(总采样数)。需要扫描整个文件,但准确度极高。
AAC (ADTS) AACFile >99% 逐帧解析 ADTS 头,累积采样数。对于帧大小一致的文件准确。

4. 批量解析架构(v3.1.0 新增)

核心机制: 使用 ProcessPoolExecutor 实现进程级并行。每个子进程独立解析文件,避免文件句柄竞争。

优势:

  • 在 Windows 自由线程构建下完全稳定
  • 真正的多核并行,不受 GIL 限制
  • 进程隔离,消除资源竞争

工作流程:

  1. 用户调用 batch_get_metadata()
  2. 如果是目录,递归扫描收集所有支持的音频文件
  3. 创建 ProcessPoolExecutor 进程池
  4. 每个文件提交给一个工作进程
  5. 每个工作进程调用 _parse_single_file() 解析单个文件
  6. 收集并返回所有成功解析的元数据

5. DAP(Dvs 音频播放列表)系统

用途: 自动记录播放历史,仅存储元数据,使应用程序能够构建收听历史而无需存储音频数据。

工作流程:

  1. 用户调用 play_from_file() 或 play_from_memory()
  2. 方法调用 _add_to_dap_recordings(file_path)
  3. _add_to_dap_recordings() 通过 get_audio_metadata_by_path() 检索元数据
  4. 创建包含 path、duration、bitrate 和 channels 的记录
  5. 使用 O(1) set 去重(v3.1.0)检查重复后添加到 _dap_recordings
  6. 用户可随时调用 save_dap_to_json() 将列表持久化到 .ap_ds-dap JSON 文件

内存特性:

  • 每条记录:约 150 字节(路径字符串 + 三个整数)
  • 10,000 条记录:约 1.5 MB RAM,约 2-3 MB JSON 文件
  • 不存储任何音频数据

6. SDL2 集成与 ctypes 绑定

为什么使用 ctypes?
ctypes 是 Python 标准库的一部分,因此不增加外部依赖。它允许从共享库(DLL、dylib、.so 文件)直接调用 C 函数。这是与 SDL2 接口的最轻量级方式。

函数原型:
为使用的每个 SDL2 和 SDL2_mixer 函数设置 argtypes 和 restype。这对跨平台稳定性至关重要:

  • 没有 argtypes,Python 可能传递错误参数,导致段错误
  • 没有 restype,Python 可能错误解释返回值(尤其对于指针类型)

7. 错误处理理念

ap_ds 遵循 快速失败、清晰失败 的理念:

  • 文件未找到: FileNotFoundError 包含路径
  • 不支持的格式: RuntimeError 包含描述性消息
  • SDL2 初始化失败: RuntimeError 包含 SDL 错误字符串
  • 下载失败: Exception 包含失败详情(哈希不匹配、网络错误等)

为什么不用结构化错误码?
结构化错误码(如 -1 表示失败,0 表示成功)在 C API 中常见,但在 Python 中不够 Pythonic。Python 异常是首选,因为它们强制调用方显式处理错误并提供丰富的上下文。

常见问题解答

1. 我应该使用哪个版本用于生产环境?

v3.0.0 LTS 是所有生产部署的推荐版本。它接收五年的安全更新和关键错误修复。在 LTS 期间不会引入破坏性变更。

v3.1.0 是功能版本(非 LTS),适合需要批量解析和 Python 3.15t 支持的用户。

2. 我可以在商业产品中使用 ap_ds 吗?

可以,绝对可以。许可证明确允许商业使用,包括集成到商业产品、云服务和 SaaS 平台中,完全免费。您必须遵守归属要求。

3. 为什么库这么小?

ap_ds 专注于播放和解析四种最常见的格式,避免了编辑/转码功能的臃肿。它构建在高效的 SDL2 C 库之上,仅使用 Python 标准库。Windows 总大小 2.5MB,macOS 3.36MB。

4. MP3 时长解析有多准确?

MP3 时长解析准确度 >98%。这是由于格式的可变头复杂性。WAV 和 FLAC 保证 100% 准确度,OGG 为 99.99%。

5. 它能在嵌入式设备上工作吗?

可以!v3.0.0 LTS 已在 Orange Pi 4 Pro 和 Raspberry Pi 5(ARM64)上测试,运行 Ubuntu 22.04。内存增长极小(大量测试后约 4MB)。通过 3.5mm 的音频输出无需修改即可工作。

6. 系统要求是什么?

  • Windows: Windows 7+,Python 3.7+
  • macOS: macOS 10.9+,Python 3.7+
  • Linux: 现代发行版,Python 3.7+,SDL2 库(如可能通过包管理器自动安装)
  • 嵌入式: 运行 Ubuntu 22.04 或类似的 ARM64 设备

7. 如何抑制启动横幅?

在导入库之前设置环境变量 AP_DS_HIDE_SUPPORT_PROMPT=1:

import os
os.environ['AP_DS_HIDE_SUPPORT_PROMPT'] = '1'
import ap_ds

8. 如何配置 WAV 阈值?

设置 AP_DS_WAV_THRESHOLD 为所需的秒数。短于此阈值的文件将作为音效处理(不支持跳转),等于或长于此阈值的文件将作为音乐处理(完全支持跳转和淡入淡出)。

9. 为什么 v3.1.0 使用多进程而不是多线程?

在 Python 3.15t(无 GIL)环境下,多线程文件 I/O 在 Windows 上存在文件句柄竞争问题,导致 BrokenProcessPool 错误。多进程(ProcessPoolExecutor)通过进程隔离完全避免此问题,实现真正的并行且 100% 稳定。

10. 批量解析应该用多少进程?

建议 max_workers 设置为 CPU 核心数或稍低。对于大多数系统,4-8 个进程 是最佳选择。文件数较少时,进程启动开销可能超过并行收益;文件数 > 100 时,并行优势明显。

11. 什么是自由线程(Free-Threading)Python?

自由线程 Python(文件名带 t)是移除了 GIL(全局解释器锁)的 Python 构建版本。这意味着多个线程可以同时执行 Python 字节码,实现真正的多核并行。Python 3.14t 和 3.15t 都支持此功能。

12. 如何验证我使用的是自由线程版本?

运行以下命令:

python3.14t -c "import sys; print(sys._is_gil_enabled())"

输出 False 表示 GIL 已禁用(自由线程版本)。

13. v3.1.0 与 Mutagen 相比如何?

对比项 Mutagen ap_ds v3.1.0
批量解析 ❌ 无 ✅ 有
多核并行 ❌ 单线程 ✅ 8进程并行
120文件耗时 0.973秒 0.331秒
Python 3.15t 支持 ❌ 无 ✅ 完全支持

ap_ds v3.1.0 比 Mutagen 快 2.94 倍。

14. v3.0.0 LTS 会收到 v3.1.0 的新功能吗?

不会。LTS 版本只接收安全更新和关键错误修复,不引入新功能。这是为了确保 LTS 用户的 API 稳定性和可预测性。新功能将仅在新功能版本(如 v3.1.0、v3.2.0 等)中提供。

15. 下一个 LTS 版本是什么时候?

计划在 Python 3.15 正式版发布后 推出 v4.0.0 LTS(预计 2026 年 10 月)。届时 Python 3.15 将稳定,所有自由线程相关的坑都将被填平,ap_ds 将基于此发布新的 LTS 版本。

16. 如何获取技术支持?

免费支持可通过以下渠道获得:

响应时间:标准咨询 7 个工作日内,关键问题 48 小时内。

版本历史

v3.1.0(2026年7月) – 性能与批量解析版

这是ap_ds的功能性大版本更新(非LTS),专注于批量解析性能和Python 3.15t自由线程支持。

🚀 新增功能

1. 批量解析API(全新)

API 说明
batch_get_metadata() 批量解析音频文件,返回完整元数据列表
batch_get_duration() 批量获取音频时长,返回 {path: duration}
batch_get_metadata_by_type() 按格式过滤批量解析(如只解析MP3)

2. Python 3.15t 自由线程支持

  • 完全适配 Python 3.15t(无 GIL)环境
  • 运行时自检:导入时自动检测 GIL 状态并给出提示
  • 满血版用户看到 🎉 ap_ds: GIL disabled (free-threading mode)
  • 降级版用户看到 ⚠️ ap_ds: GIL is enabled (multi-core parallelism limited)

3. DAP 去重优化

_add_to_dap_recordings() 从 O(n) 线性扫描升级为 O(1) set 去重,大播放列表下性能提升显著。同时保留 O(n) 回退机制,确保极端情况下的稳定性。

4. 启动加速:lazy import

Python 3.15+ 用户自动启用 lazy import,重模块(ctypes、urllib.request、struct、json 等)延迟加载,import ap_ds 速度提升显著。

5. 运行时诊断函数

新增两个独立工具函数,无需实例化即可使用:

  • is_full_performance() – 检查是否满血版(3.15t + profiling)
  • get_runtime_info() – 返回 Python 版本、GIL 状态、profiling 状态等诊断信息

6. 运行时自检

导入时自动执行运行时自检,打印环境信息(Python 版本、GIL 状态、profiling 可用性、性能模式、CPU 核心数等),可通过 AP_DS_SKIP_AUTO_CHECK=1 跳过。

7. 新环境变量

变量 默认值 说明
AP_DS_SUPPRESS_WARNINGS 不设置 设为 1 抑制降级警告
AP_DS_SHOW_CONGRATS 不设置 设为 0 隐藏满血版恭喜信息
AP_DS_SKIP_AUTO_CHECK 0 设为 1 跳过导入时自检

⚡ 性能提升

120 个 MP3 文件测试结果:

方式 耗时 加速比
串行解析 1.367秒 1.00x
8进程并行 0.331秒 4.13x

与 Mutagen 对比:

库 方式 120文件耗时
Mutagen 单线程 0.973秒
ap_ds v3.1.0 8进程并行 0.331秒(快 2.94 倍)

与 v3.0.0 对比:

测试项 v3.0.0(有GIL) v3.1.0(无GIL) 结论
8并发120文件 1.285秒(0.66x)❌ 0.331秒(4.13x) 🚀 v3.1.0快3.88倍
最佳耗时 0.789秒(2线程) 0.331秒(8进程) 🚀 3.1.0快2.38倍

🔧 修改内容

底层改进:

  • 批量解析使用 ProcessPoolExecutor 替代 ThreadPoolExecutor
  • 在 Python 3.15t(无 GIL)环境下实现真正的多核并行
  • 完全移除 profiling 相关代码(避免性能开销)

API 新增:

  • AudioLibrary.batch_get_metadata()
  • AudioLibrary.batch_get_duration()
  • AudioLibrary.batch_get_metadata_by_type()
  • AudioLibrary.is_full_performance() → 改为顶层函数
  • AudioLibrary.get_runtime_info() → 改为顶层函数

API 变更:

  • 无破坏性变更,完全向后兼容 v3.0.0

文档更新:

  • 新增批量解析 API 完整文档
  • 新增环境变量说明
  • 新增性能对比数据(vs Mutagen、vs v3.0.0)
  • 更新 apds.top 为官方主仓库

依赖变更:

  • 无新增外部依赖
  • 保持零 Python 外部依赖

🐛 修复问题

  • 修复 Windows + Python 3.15t 下 ThreadPoolExecutor 文件句柄竞争导致崩溃的问题
  • 修复 ProcessPoolExecutor 子进程重新执行模块级代码导致崩溃的问题(使用 if __name__ == "__main__" 保护)

📦 版本关系

版本 类型 支持周期
v3.0.0 LTS 长期支持 至2031年3月
v3.1.0 功能版 约6个月

🔗 仓库变更

  • 官方主仓库: https://apds.top(永久官方家园)
  • 主要镜像: GitCode
  • 中国镜像: Gitee
  • 已弃用: GitHub(dvs-web/ap_ds)、GitLab(极狐)

⬆️ 升级命令

pip install --upgrade ap_ds

⚠️ 注意: v3.1.0 是功能版本(非LTS),生产环境请继续使用 v3.0.0 LTS。


v3.0.0 LTS(2026年3月22日) – 首个长期支持版本

这是ap_ds的首个LTS版本。 经过多年的完善、广泛的现实世界测试以及内部资源管理的彻底重构,此版本为关键任务应用、企业部署及个人项目做好了准备。

新增特性:

  • 确定性资源清理 – 用显式的退出时处理程序取代了不可靠的 __del__ 终结器
  • 哈希验证下载 – 每个下载的SDL2库在使用前根据硬编码的SHA-256哈希进行验证
  • 完整测试覆盖 – 在所有平台上测试通过,零内存泄漏
  • 5年支持期 – 至2031年3月22日,免费技术支持

无破坏性变更 – 完全向后兼容 v2.x。

pip install --upgrade ap_ds

v2.4.2(2026年3月22日) – 开发失误

此版本意外上传了包含开发阶段 player.py 文件的版本。 虽然它在技术上可以工作,但可能包含细微问题,不建议在任何实际项目中使用。

⚠️ 此版本为开发失误,仅作好奇心查看,请勿在生产环境中使用。

v2.4.1(2026年3月1日) – 文档更新

更新 PyPI 文档,完整反映 v2.4.0 的新功能,包括详细的 API 描述、使用示例和环境变量文档。

变更:

  • 更新 PyPI 项目描述
  • 为所有新的淡入淡出函数添加详细示例
  • 文档化 AP_DS_HIDE_SUPPORT_PROMPT 环境变量
  • 改进快速入门指南

注意: 此版本不包含代码变更,仅文档改进。

v2.4.0(2026年3月1日) – 音频效果与工程改进

引入专业的音频过渡和重要的内部工程升级。

🎵 新音频控制功能:

函数 描述
fadein_music(aid, loops=-1, ms=0) 在指定毫秒内淡入音乐
fadein_music_pos(aid, loops=-1, ms=0, position=0.0) 从指定位置淡入音乐
fadeout_music(ms=0) 淡出当前播放的音乐
is_music_playing() 检查音乐是否正在播放
is_music_paused() 检查音乐是否暂停
get_music_fading() 获取当前淡入淡出状态

🧠 工程改进:

  • 更干净的启动横幅,可通过 AP_DS_HIDE_SUPPORT_PROMPT 控制
  • 集中化版本管理
  • 健壮的导入系统(双层回退)
  • 统一的项目 URL

无破坏性变更 – 所有现有代码继续工作。

v2.3.6(2026年2月27日) – 文档更新

更新 PyPI 文档,添加详细的许可证信息和版本历史,增加更多示例。

v2.3.5(2026年2月26日) – 稳定性优化与嵌入式验证

六维测试覆盖:

  1. 库加载与初始化
  2. 播放测试(MP3、FLAC、OGG、WAV)
  3. 跳转测试
  4. 内存压力与泄漏检测(约4MB增长)
  5. 元数据解析准确度
  6. DAP 系统验证

嵌入式平台支持:

  • Orange Pi 4 Pro(Allwinner A733)
  • Raspberry Pi 5(BCM2712)

Bug 修复:

  • 修复 WAV 文件被错误视为音效的问题,使用 AP_DS_WAV_THRESHOLD 配置

v2.3.4(2026年2月10日) – Linux 智能导入系统

革命性的 Linux 支持改进,四层回退策略:

  1. 系统库检查
  2. 用户配置检查
  3. 自动包管理器安装(apt-get、dnf、pacman)
  4. 交互式引导

自动保存配置:

  • 环境变量(AP_DS_SDL2_PATH、AP_DS_SDL2_MIXER_PATH)
  • 持久化配置文件(~/.config/ap_ds/sdl_paths.conf)

v2.3.3(2026年2月9日) – 关键 Bug 修复与平台稳定化

🚨 关键更新: 修复了导致库在 macOS 和 Linux 上无法运行的严重段错误。

根因: 早期版本仅在 Windows 上定义 C 函数原型(ctypes argtypes/restype),导致其他操作系统上内存访问违规。

解决方案: 加载 SDL2 库后,无条件定义所有必要的 C 函数绑定。

v2.3.2(2026年2月9日) – Linux 支持增强

扩展 Linux 支持,提供交互式设置。

交互式 Linux 支持:

  1. 使用系统安装的库
  2. 指定编译的 .so 文件路径
  3. 获取详细编译说明

v2.3.1(2026年2月9日) – 文档更新

改进 README.md,提供更好的示例和解释。修复文档示例中的小错误。

v2.3.0(2026年1月31日) – DAP 录制系统

引入 DAP(Dvs 音频播放列表)系统。

核心特性:

  • 智能自动录制: 在 play_from_file()、play_from_memory() 中自动触发
  • 轻量级设计: 仅存储元数据,无音频数据
  • 标准化文件格式: .ap_ds-dap 扩展名,JSON 格式
  • 智能去重: 自动避免相同文件的重复记录

新增 API:

  • _add_to_dap_recordings(file_path) – 内部使用
  • save_dap_to_json(save_path) – 保存为 JSON
  • get_dap_recordings() – 获取所有记录
  • clear_dap_recordings() – 清除记录

v2.2.0(2026年1月19日) – 跨平台革命

从单平台到跨平台。

主要新功能:

1. 完整 macOS 支持

  • 自动下载和安装 SDL2.framework、SDL2_mixer.framework
  • 智能 .dmg 文件提取和框架加载
  • 保持极致轻量:仅 3.36MB(vs Windows 2.5MB)

2. 增强的自动依赖管理

  • 跨平台智能下载策略
  • 完整错误处理和重试机制
  • 依赖文件本地缓存

v2.1.4(2026年1月18日) – 稳定版本

生产环境稳定版本。

  • 核心稳定性:经过彻底测试,无已知关键 Bug
  • 极致轻量:完整解决方案仅 2.5MB
  • 完整文档:详细技术手册和示例

v2.1.0(2025年12月26日) – 功能增强

专业功能扩展。

新增功能:

  • 元数据增强:更精确的音频信息解析
  • 播放准确度改进:更好的时间控制和跳转

v2.0.0(2025年11月5日) – 架构重构

引入现代音频管理系统。

主要改进:

  • AID 系统: 统一的音频实例管理
  • 架构重构: 模块化设计,提高可维护性
  • 智能内存管理: 自动清理未使用的音频资源
  • 状态管理: 统一的播放状态跟踪

v1.0.0(2025年7月8日) – 初始发布

项目诞生,基础功能。

核心功能:

  • 基础音频播放:MP3、WAV、FLAC、OGG 格式
  • 播放控制:播放、暂停、停止、跳转基础 API
  • 音量控制:实时音量调整(0-100%)
  • 轻量级设计:初始版本约 2MB

许可证

本项目采用DVS音频库(ap_ds)开源许可证版本2.0。完整许可证文本如下。通过使用、复制、修改或分发本软件,您接受本许可证的所有条款和条件。



DVS Audio Library (ap_ds) Open Source License Version 2.0

Version: 2.0 Effective Date: March 22, 2026 Applies to: ap_ds version 2.4.1 and above (except for subsequent license updates) Project Homepage: https://www.dvsyun.top/ap_ds | https://apds.top


1. Definitions

1.1. “Software” means the DVS Audio Library (ap_ds) project and all its components, source code, object code, and related documentation. The official name of this project is “ap_ds”, and the following names are also granted as officially recognized brand identifiers:

  • AP_DS
  • Audio Library By DVS
  • DVS Audio Player (All of the above names are case-insensitive and are considered officially recognized brand names.)

1.2. “Source Code” means the human-readable form of the Software, which is the basis for modification, study, and distribution.

1.3. “Modified Version” means any derivative work created by modifying, supplementing, translating, or otherwise altering the Software, in whole or in part.

1.4. “Distribute” means making the Software or a Modified Version available to any third party by any means or medium.

1.5. “You” means any individual or legal entity exercising the rights granted under this License.

1.6. “Independent Brand” means a completely new project name, logo, and brand identity that has no confusing association with the official names of the Software (including but not limited to “ap_ds”, “AP_DS”, “Audio Library By DVS”, “DVS Audio Player”, and any variants thereof).


2. Grant of License

Subject to the terms and conditions of this License, the Author hereby grants You a perpetual, worldwide, royalty-free, non-exclusive, irrevocable right to:

2.1. Use and Run: Run the Software on any computer system for any lawful purpose.

2.2. Copy and Distribute: Make any number of copies of the Software and Distribute them.

2.3. Study and Modify: Study the Software's Source Code and make any modifications to meet Your needs.

2.4. Integrate and Commercially Use: Integrate the Software into Your products or projects, and use it in any commercial context, including but not limited to commercial product integration, cloud service deployment, selling solutions incorporating the Software, and internal corporate use.


3. Obligations and Restrictions

3.1. Attribution and Source Identification

Any time the Software or a Modified Version is used, Distributed, or integrated, You must:

a) Retain Original Copyright Notices: Keep intact all original copyright, patent, and trademark notices in all copies of the Software.

b) Provide Prominent Source Attribution: Clearly and conspicuously state the following information in the software documentation, official website, user interface, or related materials: Based on DVS Audio Library (ap_ds) v[version number] Original Author: Dvs (DvsXT) Project Homepage: https://www.dvsyun.top/ap_ds | https://apds.top

c) Add Notice for Modified Versions: If You Distribute a Modified Version, in addition to the attribution above, You must add the following notice: This is a modified version maintained by [Your Name/Organization]. Support: [Your Contact Information]. This version is not the official version and is not affiliated with the original author.

3.2. Brand Protection

To prevent brand confusion and project fragmentation, Modified Versions must comply with the following strict rules:

a) Prohibition on Using Original Brand Names: You must not name a Modified Version “ap_ds”, “AP_DS”, “Audio Library By DVS”, “DVS Audio Player”, or any variant, combination, or derivative that could cause confusion.

b) Requirement for Independent Brand: Modified Versions must use a completely independent project name and establish their own independent project identity, documentation, and community.

c) Maintainer Responsibility Statement: The distributor of a Modified Version must state prominently on their project homepage or in a conspicuous location: This project is based on DVS Audio Library (ap_ds) but has evolved independently and is fully maintained by [Your Name]. For the original version, please visit: https://www.dvsyun.top/ap_ds or https://apds.top. The maintainer is solely responsible for any issues related to this project.

3.3. Quality Commitment for Modified Versions

If You Distribute a Modified Version, You must:

a) Clearly State the Nature of Modifications: Clearly indicate that this is a modified version and list the key modifications and compatibility notes compared to the original version.

b) Provide Technical Support: Provide a valid means of technical support contact for the Modified Version You distribute, and define the scope of support.

c) Not Mislead Users: You must not imply in any way that Your Modified Version is officially endorsed, supported, or is a continuation of the original project.

3.4. Prohibited Uses

You must not use the Software for any illegal activities, malicious purposes, or actions that violate local laws or regulations, including but not limited to: a) Disrupting computer systems or network security. b) Distributing malware or viruses. c) Infringing on the intellectual property or privacy rights of others.


4. Patent Grant

4.1. Patent License: The Author hereby grants You a worldwide, royalty-free, non-exclusive, non-transferable patent license to make, use, sell, offer for sale, import, or otherwise transfer the Software.

4.2. Patent Defense Termination: If You or Your affiliates file a patent infringement lawsuit against the Author regarding the Software, all rights granted to You under this License will automatically and immediately terminate.


5. Technical Transparency and Security

5.1. Right to Security Review: Any user has the right to conduct a security audit of the Software's Source Code. Commercial users may engage third-party professionals for this purpose.

5.2. Security Reporting: Reporting discovered security issues to the original Author (me@dvsyun.top) is encouraged, and public disclosure after resolution is supported.

5.3. No Backdoors Commitment: The officially released version commits to containing no malicious code, backdoors, or user-data collection features without explicit user consent.


6. Disclaimer of Warranty and Limitation of Liability

6.1. Disclaimer of Warranty: THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND ABSENCE OF ERRORS.

6.2. Limitation of Liability: TO THE FULLEST EXTENT PERMITTED BY APPLICABLE LAW, IN NO EVENT SHALL THE AUTHOR OR COPYRIGHT HOLDER BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, CONSEQUENTIAL, OR PUNITIVE DAMAGES (INCLUDING BUT NOT LIMITED TO LOSS OF PROFITS, DATA LOSS, OR BUSINESS INTERRUPTION) ARISING OUT OF THE USE OF OR INABILITY TO USE THE SOFTWARE.


7. License Management and Termination

7.1. Version Control: This License is version 2.0. Subsequent versions will be published on the project homepage. You may choose to follow the terms of this version or any later version.

7.2. Compatibility: This License is compatible with the MIT, BSD 3-Clause, and Apache 2.0 licenses.

7.3. Automatic Termination: Your rights under this License will terminate automatically if You fail to comply with its terms. However, if You cease all non-compliance and cure all violations within 30 days of receiving notice from the copyright holder, and the copyright holder has not terminated Your rights within that period, Your rights will be reinstated.


8. Governing Law and Dispute Resolution

8.1. Governing Law: This License shall be governed by the laws of the People's Republic of China, without regard to its conflict of law provisions.

8.2. Dispute Resolution: Any dispute arising out of or in connection with this License shall first be resolved through friendly negotiation. If negotiation fails, either party may submit the dispute to the competent people's court located in the project author's domicile.


9. Contact Information

9.1. Licensing and Inquiries:

9.2. Technical Support:

  • Priority should be given to submitting issues via GitCode Issues.
  • Urgent matters can be directed to the emails above.

BY USING, COPYING, MODIFYING, OR DISTRIBUTING THE SOFTWARE, YOU ACCEPT ALL TERMS AND CONDITIONS OF THIS LICENSE.



最终说明

ap_ds建立在简单的理念之上:专注于播放和解析,保持轻量级,让开发者构建出色的应用程序。

我们欢迎反馈、错误报告和贡献。如有问题或疑问,请通过官方渠道联系我们。

感谢您使用ap_ds!

Release files for ap-ds 3.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for ap-ds 3.1.0
File Size Uploaded
ap_ds-3.1.0.tar.gz 143.8 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for ap-ds 3.1.0
File Interpreter ABI Platform
ap_ds-3.1.0-py3-none-any.whl Python 3 none any Details

Total release size: 222.8 kB

Release files / ap_ds-3.1.0.tar.gz

Download URL ap_ds-3.1.0.tar.gz
Size 143.8 kB
Tags Source
SHA-256 checksum
How to use checksums
854360c2450062b1e39b80813dc6d5c1a9b3ef72b31dfc3e6737ba6ac895575c
BLAKE2b-256 checksum
How to use checksums
c923bccc6c4f5d5fede7fddbc43bee315793a751229b4a7b5cce693764df1c7c
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.13.4

Release files / ap_ds-3.1.0-py3-none-any.whl

Download URL ap_ds-3.1.0-py3-none-any.whl
Size 79.0 kB
Tags Python 3
SHA-256 checksum
How to use checksums
f637fc54974918f620e57858a48283589b6fc8272708dc16f24dbc82b8f3425a
BLAKE2b-256 checksum
How to use checksums
435091f3c807df7a037b9bfa8c96b4f205ae56c67935f9df0b7637d8bd28570a
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.13.4

Release history Release notifications | RSS feed

4.0.1

2 release files

4.0.0

2 release files

3.1.2

2 release files

3.1.1

2 release files

This release

3.1.0 This release

2 release files

3.0.0

2 release files

2.4.2

2 release files

2.4.1

2 release files

2.4.0

2 release files

2.3.6

2 release files

2.3.5

2 release files

2.3.4

2 release files

2.3.3

2 release files

2.3.2

2 release files

2.3.1

2 release files

2.3.0

2 release files

2.2.0

2 release files

1.4.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page