Skip to main content

Audio Player By DVS - Advanced audio processing and playback

Project description

ap_ds: A Lightweight Python Audio Library

Current Stable Version: v3.0.0 LTS (Long‑Term Support) – Released March 22, 2026


📢 Latest Updates

v3.0.0 LTS – The First Long‑Term Support Release

This is the first Long-Term Support (LTS) release in ap_ds history. After years of refinement, extensive real-world testing, and a complete overhaul of internal resource management, we are proud to present a version that is ready for mission-critical applications, enterprise deployment, and personal projects alike. It is strongly recommended for all users.

Why LTS?
We understand that stability and long-term predictability are essential for developers building products, systems, and services. This release marks a commitment to five years of maintenance, including security updates, critical bug fixes, and free technical support. You can confidently build upon ap_ds without worrying about unexpected API changes or deprecations.

What makes v3.0.0 LTS special?

  1. Deterministic Resource Cleanup – The old __del__ finalizer, which could be unreliable in certain interpreter shutdown scenarios, has been replaced with an explicit at-exit handler. All SDL2 resources – audio devices, channels, caches – are now guaranteed to be freed, even when exceptions or signals interrupt normal execution. This eliminates a long-standing source of memory leaks and resource warnings.

  2. Hash-Verified Downloads (Security Hardening) – In previous versions, if SSL certificate verification failed, the library would fall back to an unverified connection without any checks. Starting with v3.0.0 LTS, every downloaded SDL2 library is validated against a hardcoded SHA-256 hash before it is used. If the hash does not match the expected value, the download is rejected and retried. This cryptographic guarantee ensures that the binary you run is exactly the one we released – no tampering, no man-in-the-middle attacks, and no accidental corruption.

  3. Complete Test Coverage – The library has been tested on:

    • Windows 7/10/11 (x86_64)
    • macOS 10.15 – 14 (Intel and Apple Silicon)
    • Linux (Ubuntu 20.04/22.04, Debian 11, Fedora 38, Arch Linux)
    • ARM64 embedded devices (Orange Pi 4 Pro, Raspberry Pi 5) All test suites (playback, seeking, volume, DAP, metadata, resource cleanup) pass with zero memory leaks and no regressions.
  4. 5-Year Support Period – Free technical support is available through Gitee, GitLab, and email until March 22, 2031. You will receive security patches and critical bug fixes without needing to upgrade to a newer major version unless you wish to.

  5. 100% Backward Compatibility – The public API remains unchanged from v2.x. Your existing code will run exactly as before. Upgrading is as simple as pip install --upgrade ap_ds.

Version Maintenance and Support Policy

To further clarify the maintenance boundaries of the Long-Term Support (LTS) release, the ap_ds project is introducing a unified version management and support identification system.

This release, v3.0.0 LTS, along with its subsequent v3.0.x series (i.e., 3.0.0, 3.0.1, 3.0.2, …), is officially designated as the sole version range covered by the APDSLTS001 support plan. All version updates within this series, regardless of the specific patch number, uniformly use APDSLTS001 as their long-term support identifier. This means that as long as you remain on the v3.0.x release line, you are entitled to the full five-year maintenance commitment.

Support Period: Official technical support, security updates, and critical bug fixes for APDSLTS001 will terminate on March 22, 2031 at 23:59:59 UTC. The corresponding Beijing time (UTC+8) is March 23, 2031 at 07:59:59. After this date, the v3.0.x series will no longer receive updates or maintenance of any kind.

Version Branch Description:

  • v3.0.x (APDSLTS001): The Long-Term Support version, which includes only bug fixes, security patches, and stability improvements. No new features are introduced, ensuring complete API and behavioral stability.
  • v3.1.x and above (e.g., v3.1.0, v3.2.0, …): These are regular release versions that do not enjoy long-term technical support. Such versions will include new features, performance optimizations, and possible API extensions. If you need the latest functionality, you may choose to upgrade to these versions; however, for production environments that prioritize long-term stability and wish to avoid frequent changes, it is recommended to remain on the v3.0.x LTS series.

Through this policy, we aim to provide clear choices for users in different scenarios: production projects should stay on the LTS release line, while exploratory projects are free to upgrade to new feature versions. All update patches for the LTS version will continue to be released through Gitee, GitLab, and official channels until the support period ends. We believe that this clear version differentiation and support boundary will help developers better plan their product lifecycles.

All users are encouraged to upgrade immediately. This is the definitive version for production use.

⚠️ Important Version Information

GitHub Repository Deprecation & v2.4.2 Note

Why GitHub is no longer used: The developer’s GitHub account was locked due to a lost 2FA device. After multiple attempts to contact GitHub support, only automated bot replies were received. Frustrated by the complete lack of human assistance, the developer decided to abandon the GitHub account entirely and will not create a new one (at least for the foreseeable future). The official repositories are now on Gitee (https://gitee.com/dssxt/ap_ds) and GitLab (https://jihulab.com/dvs/ap_ds).

About v2.4.2: Version 2.4.2 was accidentally uploaded with a development‑stage player.py file. While it technically works, it may contain minor quirks and is not recommended for any real project. It was meant to be a test release. Because the developer’s PyPI account is also locked due to the same 2FA issue, it cannot be yanked right now. Once the account is restored, it will be marked as deprecated, but the release will remain on PyPI for those curious to see what a “development slip” looks like. Consider it a curiosity – do not use it in production.

Version Release Date Status Recommendation
v3.0.0 LTS March 22, 2026 LTS – Current Stable Recommended for all users
v2.4.2 March 22, 2026 ⚠️ Development mishap Not recommended – for curiosity only
v2.4.1 March 1, 2026 ✅ Stable Safe but superseded by v3.0.0 LTS
v2.4.0 March 1, 2026 ✅ Stable Safe but superseded
v2.3.6 February 27, 2026 ✅ Stable Safe but superseded
v2.3.5 February 26, 2026 ✅ Stable Safe but superseded
v2.3.4 February 10, 2026 ✅ Stable Safe but superseded
v2.3.3 February 9, 2026 ✅ Stable Safe but superseded
v2.3.2 February 9, 2026 ❌ YANKED Do not use
v2.3.1 February 9, 2026 ❌ YANKED Do not use
v2.3.0 January 31, 2026 ❌ YANKED Do not use
v2.2.0 January 19, 2026 ❌ YANKED Do not use

Action Required: Run pip install --upgrade ap_ds immediately to update to the v3.0.0 LTS release.


Overview

ap_ds is a lightweight (2.5MB) Python audio library for playback and accurate metadata parsing of MP3, FLAC, OGG, and WAV files. It has zero external Python dependencies, utilizing only the Python standard library, and provides non‑blocking playback for smooth GUI applications.

Key Features:

  • Extreme Lightweight: Only 2.5MB (Windows) / 3.36MB (macOS) complete solution
  • Zero Python Dependencies: Uses only standard library
  • Accurate Metadata: 100% for WAV/FLAC, 99.99% for OGG, >98% for MP3
  • Non‑blocking Playback: Perfect for GUI applications
  • Cross‑Platform: Windows, macOS, Linux, and embedded ARM64
  • DAP Recording System: Automatic playback history with metadata only
  • LTS Support: First Long‑Term Support release with 5‑year commitment


Contact & support

📧 Licensing inquiries

me@dvsyun.top or dvs6666@163.com · response within 7 business days

🛠️ Technical support

Gitee Issues · GitLab Issues · email (free during LTS period)


Official Repositories & Project Sources

✅ Recommended (Primary): Gitee (China, fast & stable) – actively maintained mirror
✅ Recommended (Backup): GitLab (JihuLab) – secondary official repository
❌ Not recommended (Deprecated): GitHub (dvs-web/ap_ds) – abandoned due to 2FA account lockout; no longer maintained. Use Gitee or JihuLab instead.

ℹ️ ap_ds v3.0.0 LTS – The first Long‑Term Support release
This version is the culmination of all previous improvements and adds deterministic cleanup, hash‑verified downloads, and a 5‑year support commitment. The old GitHub repository (dvs-web/ap_ds) is deprecated and will not receive updates. Please use the new official repositories for future updates and contributions.

For the developer’s personal page & blog: https://dvsx.top – a space where Dvs shares technology insights, life notes, and project philosophy.
For the dedicated ap_ds project homepage, please visit: https://apds.top (official documentation, releases, and license center).

🔗 Canonical URL: https://apds.top/
📖 Blog & about author: dvsx.top – "DVS · Blog: recording tech & life, sharing knowledge and insights"

About the author

Developer: Dvs (DvsXT)
Personal homepage & blog: https://dvsx.topDVS · Blog: recording technology & life, sharing knowledge and insights
Author profile: https://dvsyun.top/me/dvs
Email: me@dvsyun.top · dvs6666@163.com

ap_ds official portals

🎵 ap_ds official website 1 (primary): https://apds.top
🌐 Official website 2 (mirror / docs): https://www.dvsyun.top/ap_ds
📦 PyPI project page: https://pypi.org/project/ap_ds/

👉 The dedicated ap_ds project homepage (apds.top) hosts the full documentation, license details, version changelog, and official releases. The author's personal blog (dvsx.top) contains technical essays, life stories, and project background.



Installation

pip install ap_ds

To upgrade from an older version:

pip install --upgrade ap_ds

Quick Start

from ap_ds import AudioLibrary

# Initialize the library
lib = AudioLibrary()

# Play an audio file
aid = lib.play_from_file("music/song.mp3")

# Control playback
lib.pause_audio(aid)      # Pause
lib.play_audio(aid)       # Resume
lib.seek_audio(aid, 30.5) # Seek to 30.5 seconds

# Stop and get duration played
duration = lib.stop_audio(aid)
print(f"Played for {duration:.2f} seconds")

DAP Playlist System

Audio files are automatically recorded to DAP (Dvs Audio Playlist) upon playback:

# Files are automatically recorded
aid1 = lib.play_from_file("song1.mp3")
aid2 = lib.play_from_file("song2.ogg")

# Get all recordings
recordings = lib.get_dap_recordings()
print(f"Recorded {len(recordings)} files")

# Save to JSON
success = lib.save_dap_to_json("my_playlist.ap_ds-dap")

DAP stores only metadata (path, duration, bitrate, channels), not audio data. Memory usage is approximately 150 bytes per recording.


Platform Support

Windows

  • Automatic download of SDL2.dll and SDL2_mixer.dll with hash verification
  • No manual configuration required
  • Supports Windows 7 and later

macOS

  • Automatic download of SDL2.framework and SDL2_mixer.framework with hash verification
  • No manual configuration required
  • Supports macOS 10.9 and later

Linux

Intelligent Multi-Layer Import System:

  1. System Library Check: Uses system-installed SDL2 libraries
  2. User Configuration: Checks saved paths from previous runs
  3. Automatic Installation: Detects package manager and installs required packages
  4. Interactive Guidance: Manual options if all else fails

Package Manager Support:

# 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

Embedded ARM64

Tested on:

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

Both run Ubuntu 22.04 with full audio support via 3.5mm output. Memory growth after extensive testing: ~4MB.


ap_ds Audio Library – Complete API Reference

Version: 3.0.0 LTS
Document Date: March 22, 2026
Project Homepage: https://apds.top


Table of Contents

  1. AudioLibrary Class – Complete API

  2. AudioParser Class – Metadata API

  3. AudioInfo Module – Format-Specific Parsers

  4. SDL2 Integration Layer

  5. Constants Reference

  6. Exception Handling


AudioLibrary Class – Complete API

The AudioLibrary class is the primary interface for audio playback, control, and metadata extraction. It manages all SDL2 resources, provides non‑blocking playback, and maintains a DAP (Dvs Audio Playlist) recording system.

Initialization

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

Description:
Initializes the SDL2 audio subsystem and the SDL2_mixer library. This method must be called before any playback operations. It sets up the audio device with the specified parameters and registers an at‑exit handler for automatic resource cleanup.

Parameters:

Parameter Type Default Description
frequency int 44100 Audio sample rate in Hz. Common values: 44100 (CD quality), 48000 (DVD/video), 22050 (speech). Higher values increase quality but consume more CPU.
format int MIX_DEFAULT_FORMAT Audio sample format. Usually AUDIO_S16SYS (16‑bit signed, system endian). See Constants Reference for alternatives.
channels int 2 Number of audio channels. 1 = mono, 2 = stereo. Mono files will be automatically upmixed to stereo if the device is configured for stereo.
chunksize int 2048 Buffer size in samples. Larger values reduce CPU usage but increase latency. For real‑time applications, smaller values (1024) may be better.

Raises:

  • RuntimeError: If SDL2 initialization fails (e.g., no audio device available).
  • RuntimeError: If mixer initialization fails (e.g., unsupported format).

Example:

from ap_ds import AudioLibrary

# Default configuration (CD quality, stereo, low latency)
lib = AudioLibrary()

# Custom configuration for voice playback
lib_voice = AudioLibrary(frequency=22050, channels=1, chunksize=1024)

Internal Behavior:

  1. Calls SDL_Init(SDL_INIT_AUDIO) to initialize the audio subsystem.
  2. Calls Mix_OpenAudio(frequency, format, channels, chunksize) to open the mixer.
  3. Registers self.cleanup_function with atexit to guarantee resource cleanup.
  4. Initializes internal data structures:
    • _audio_cache: Dict[str, Mix_Chunk] – cached sound effects
    • _music_cache: Dict[str, Mix_Music] – cached music tracks
    • _channel_info: Dict[int, Dict] – active playback sessions
    • _aid_to_filepath: Dict[int, str] – AID to file path mapping
    • _aid_counter: int – sequential AID generator
    • _dap_recordings: List[Dict] – DAP history list

Playback Methods

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

Description:
Loads and plays an audio file directly from disk. The file is loaded into memory and played immediately. For .ap-ds-dap files, this method records metadata but does not play audio (DAP files are metadata‑only).

Parameters:

Parameter Type Default Description
file_path str required Full path to the audio file. Supported formats: MP3, WAV, FLAC, OGG
loops int 0 Number of times to loop after the first play. 0 = play once, -1 = loop infinitely.
start_pos float 0.0 Starting position in seconds. For sound effects (short WAV files), this may not be supported.

Note: AAC files support metadata parsing, but due to SDL2 limitations, we are unable to play or perform other operations on them.

Returns:
int – Audio ID (AID) that uniquely identifies this playback instance. This ID can be used with all control methods.

Raises:

  • FileNotFoundError: If the file does not exist.
  • RuntimeError: If the file format is unsupported or the audio cannot be loaded.
  • RuntimeError: If playback fails (e.g., no available channels).

Behavior by File Type:

File Type Mode Seek Support Fade Support
MP3, OGG, FLAC Music (Mix_PlayMusic) Yes Yes
WAV (duration ≥ threshold) Music (Mix_PlayMusic) Yes Yes
WAV (duration < threshold) Sound effect (Mix_PlayChannel) No No (use fadein_channel)
Other formats Sound effect (Mix_PlayChannel) No No

Example:

# Play a song once from the beginning
aid = lib.play_from_file("song.mp3")

# Loop a short sound effect 5 times
aid = lib.play_from_file("beep.wav", loops=5)

# Start playback from 30 seconds into the track
aid = lib.play_from_file("podcast.mp3", start_pos=30.0)

# Infinite loop (background music)
aid = lib.play_from_file("ambient.ogg", loops=-1)

Internal Workflow:

  1. Increments _aid_counter to generate a new AID.
  2. Calls _add_to_dap_recordings() to record metadata (if metadata is available).
  3. Determines playback mode via _is_music_file().
  4. For music files:
    • Calls Mix_LoadMUS() to load the file.
    • Calls Mix_PlayMusic() to start playback.
    • Stores the Mix_Music object in _music_cache.
    • Sets channel = -1 (music uses a dedicated channel).
  5. For sound effects:
    • Calls Mix_LoadWAV() to load the file.
    • Calls Mix_PlayChannel(-1, audio, loops) to play on the first available channel.
    • Stores the Mix_Chunk object in _audio_cache.
    • Returns the actual channel number.
  6. Stores playback info in _channel_info[channel].
  7. If start_pos > 0, calls _seek_audio().

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

Description:
Plays an audio file that has already been loaded into memory via new_aid(). This method is faster than play_from_file() for repeated playback of the same file because the file is already cached.

Parameters: Same as play_from_file().

Returns: int – Audio ID (AID).

Raises:

  • ValueError: If the file has not been loaded with new_aid().
  • RuntimeError: If playback fails.

Example:

# Pre-load sound effects
lib.new_aid("gunshot.wav")
lib.new_aid("explosion.wav")

# Play from memory (very fast, no disk I/O)
aid = lib.play_from_memory("gunshot.wav")

Internal Workflow:

  1. Generates a new AID.
  2. Records to DAP.
  3. Checks if the file is in _music_cache or _audio_cache.
  4. Plays from the cached object.
  5. Records playback info in _channel_info.

new_aid(file_path: str) -> int

Description:
Pre‑loads an audio file into memory without playing it. This is useful for caching sound effects or music tracks that will be played multiple times. The file is loaded once and stored in the appropriate cache.

Parameters:

Parameter Type Description
file_path str Path to the audio file to cache.

Returns: int – Audio ID (AID) for the cached file.

Raises:

  • FileNotFoundError: If the file does not exist.
  • RuntimeError: If the file format is unsupported or loading fails.

Example:

# Cache frequently used sounds
sounds = {
    'hit': lib.new_aid("hit.wav"),
    'jump': lib.new_aid("jump.wav"),
    'coin': lib.new_aid("coin.wav")
}

# Later, play from memory
lib.play_from_memory(sounds['hit'])

Internal Workflow:

  1. Increments AID counter.
  2. Records to DAP.
  3. Determines music vs. sound effect via _is_music_file().
  4. If music:
    • Calls Mix_LoadMUS().
    • Stores in _music_cache[file_path].
  5. If sound effect:
    • Calls Mix_LoadWAV().
    • Stores in _audio_cache[file_path].
  6. Maps AID to file path in _aid_to_filepath.

Control Methods

play_audio(aid: int) -> None

Description:
Resumes playback of a paused audio instance. If the audio was not paused, this method has no effect.

Parameters:

Parameter Type Description
aid int Audio ID returned by play_from_file(), play_from_memory(), or new_aid().

Raises:

  • ValueError: If the AID is invalid or the audio is not paused.

Example:

aid = lib.play_from_file("song.mp3")
time.sleep(2)
lib.pause_audio(aid)      # Pause after 2 seconds
time.sleep(1)
lib.play_audio(aid)       # Resume after 1 second pause

Internal Behavior:

  1. Finds the channel associated with the AID via _find_channel_by_aid().
  2. Retrieves playback info from _channel_info.
  3. If the audio is paused (info['paused'] is True):
    • For music (is_music True): calls Mix_ResumeMusic().
    • For sound effects: calls Mix_Resume(channel).
    • Resets info['paused'] to False.
    • Adjusts info['start_time'] to account for the paused duration.

pause_audio(aid: int) -> None

Description:
Pauses the audio instance specified by the AID. The audio can later be resumed with play_audio().

Parameters: Same as play_audio().

Raises:

  • ValueError: If the AID is invalid or the audio is already paused.

Example:

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

Internal Behavior:

  1. Finds the channel for the AID.
  2. Retrieves playback info.
  3. If not already paused:
    • For music: Mix_PauseMusic().
    • For sound effects: Mix_Pause(channel).
    • Sets info['paused'] = True.
    • Records paused_position = time.time() - info['start_time'].

stop_audio(aid: int) -> float

Description:
Stops playback of the specified audio instance and releases associated resources. The audio cannot be resumed after stopping.

Parameters: Same as play_audio().

Returns: float – The total duration played (in seconds) before stopping.

Raises:

  • ValueError: If the AID is invalid (returns 0.0 silently? Actually raises ValueError per code).

Example:

aid = lib.play_from_file("song.mp3")
time.sleep(10)
duration = lib.stop_audio(aid)
print(f"Played for {duration:.2f} seconds")

Internal Behavior:

  1. Finds the channel for the AID.
  2. Calculates played_time (current time minus start time, or paused position).
  3. If music: Mix_HaltMusic().
  4. If sound effect: Mix_HaltChannel(channel).
  5. Removes the entry from _channel_info.
  6. Returns played_time.

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

Description:
Seek to a specific position in the audio track (in seconds). This method works only for music‑mode files (MP3, OGG, FLAC, and long WAV files). Sound effects (short WAVs) do not support seeking.

Parameters:

Parameter Type Description
aid int Audio ID.
position float Target position in seconds. Must be between 0 and the total duration.

Raises:

  • ValueError: If the AID is invalid.
  • RuntimeError: If the audio is not seekable (sound effect mode).

Example:

# Seek to 30 seconds into the track
lib.seek_audio(aid, 30.0)

Internal Behavior (Music):

  1. Stops current playback with Mix_HaltMusic().
  2. Reloads the music file with Mix_LoadMUS().
  3. Plays from the beginning with Mix_PlayMusic().
  4. If Mix_SetMusicPosition is available, seeks to the target position.
  5. Updates _channel_info with new start time.

Internal Behavior (Sound Effect):

  1. Stops current playback with Mix_HaltChannel().
  2. Re‑plays the cached chunk with Mix_PlayChannel().
  3. This effectively starts from the beginning; seeking is not supported.

Volume Methods

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

Description:
Sets the volume for the specified audio instance. Volume is scaled from 0 (silent) to 128 (maximum). The value is clamped automatically.

Parameters:

Parameter Type Description
aid int Audio ID.
volume int Volume value (0–128). Values outside this range are clamped.

Returns: boolTrue if the volume was set successfully, False otherwise.

Example:

# Set volume to 50% (64 out of 128)
lib.set_volume(aid, 64)

# Mute
lib.set_volume(aid, 0)

# Maximum
lib.set_volume(aid, 128)

Internal Behavior:

  1. Finds the channel for the AID.
  2. Clamps volume to [0, 128].
  3. If music: calls Mix_VolumeMusic(volume).
  4. If sound effect: calls Mix_Volume(channel, volume).

get_volume(aid: int) -> int

Description:
Returns the current volume of the specified audio instance.

Parameters: Same as set_volume().

Returns: int – Current volume (0–128). Returns 0 if the AID is invalid.

Example:

current = lib.get_volume(aid)
print(f"Current volume: {current}")

Internal Behavior:

  1. Finds the channel for the AID.
  2. If music: calls Mix_VolumeMusic(-1) (‑1 means get without setting).
  3. If sound effect: calls Mix_Volume(channel, -1).

Fade & Transition Methods

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

Description:
Fades in music over the specified duration. This method stops any currently playing music and starts the specified track with a fade‑in effect. Works only for music‑mode files.

Parameters:

Parameter Type Default Description
aid int required Audio ID of the music file.
loops int -1 Number of loops. -1 = infinite, 0 = once, n = n times.
ms int 0 Fade duration in milliseconds. 0 means no fade (instant start).

Returns: boolTrue if fade‑in started successfully, False otherwise.

Raises:

  • Prints error message if AID not found or not a music file.

Example:

# Fade in over 2 seconds
lib.fadein_music(aid, loops=-1, ms=2000)

# Fade in with no loop (play once)
lib.fadein_music(aid, loops=0, ms=500)

Internal Behavior:

  1. Searches _channel_info for the AID and verifies it is music.
  2. Calls _add_to_dap_recordings() (records DAP).
  3. Loads the music file if not already cached.
  4. Stops any current music with Mix_HaltMusic().
  5. Calls Mix_FadeInMusic(music, loops, ms).
  6. If successful, updates _channel_info with new start time.

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

Description:
Fades in music starting from a specific position. This is useful for resuming playback from a saved timestamp.

Parameters:

Parameter Type Default Description
aid int required Audio ID.
loops int -1 Number of loops.
ms int 0 Fade duration in milliseconds.
position float 0.0 Starting position in seconds.

Returns: boolTrue if successful, False otherwise.

Example:

# Fade in from the 30-second mark over 1 second
lib.fadein_music_pos(aid, loops=-1, ms=1000, position=30.0)

Internal Behavior:

  1. Checks if Mix_FadeInMusicPos is available in the loaded SDL2_mixer.
  2. Same as fadein_music(), but calls Mix_FadeInMusicPos() with the position parameter.

fadeout_music(ms: int = 0) -> bool

Description:
Fades out the currently playing music over the specified duration.

Parameters:

Parameter Type Default Description
ms int 0 Fade duration in milliseconds. 0 means stop immediately.

Returns: boolTrue if fade‑out started, False if no music was playing.

Example:

# Smooth fade out over 3 seconds
lib.fadeout_music(ms=3000)

# Stop immediately
lib.fadeout_music(ms=0)

Internal Behavior:

  1. Calls Mix_FadeOutMusic(ms).
  2. Returns True if the return value is 1 (success), False otherwise.

is_music_playing() -> bool

Description:
Checks whether any music is currently playing.

Returns: boolTrue if music is playing, False otherwise.

Example:

if lib.is_music_playing():
    print("Music is playing")
else:
    print("Music is stopped or paused")

Internal Behavior: Calls Mix_PlayingMusic().


is_music_paused() -> bool

Description:
Checks whether the music is paused.

Returns: boolTrue if paused, False otherwise.

Internal Behavior: Calls Mix_PausedMusic().


get_music_fading() -> int

Description:
Returns the current fade state of the music.

Returns: int – One of:

  • 0 (MUS_NO_FADING): No fade in progress.
  • 1 (MUS_FADING_OUT): Fading out.
  • 2 (MUS_FADING_IN): Fading in.

Example:

state = lib.get_music_fading()
if state == 1:
    print("Fading out...")

Internal Behavior: Calls Mix_FadingMusic().


Metadata Methods

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

Description:
Returns the duration of an audio file in seconds. Can accept either a file path (string) or an AID (integer).

Parameters:

Parameter Type Default Description
source str or int required File path or AID.
is_file bool False If True, treats source as a file path; if False, treats it as an AID.

Returns:

  • On success: int – duration in seconds (rounded down).
  • On failure: Tuple[int, str](0, error_message).

Example:

# By file path
duration = lib.get_audio_duration("song.mp3", is_file=True)

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

Internal Behavior:

  1. If is_file is True, calls _get_duration_by_filepath(str(source)).
  2. If is_file is False, looks up the file path from _aid_to_filepath and then calls _get_duration_by_filepath().

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

Description:
Returns complete metadata for the audio file: duration, sample rate, channels, bitrate, and format.

Parameters: Same as get_audio_duration().

Returns: Dict or None (if parsing fails).

Dictionary Structure:

{
    'path': str,           # Full file path
    'format': str,         # File extension (mp3, wav, etc.)
    'duration': int,       # Duration in seconds (rounded)
    'length': float,       # Exact duration as float
    'sample_rate': int,    # Sample rate in Hz
    'channels': int,       # 1 (mono) or 2 (stereo)
    'bitrate': int         # Bitrate in bps
}

Example:

metadata = lib.get_audio_metadata("song.flac", is_file=True)
if metadata:
    print(f"Sample rate: {metadata['sample_rate']} Hz")
    print(f"Bitrate: {metadata['bitrate'] / 1000:.0f} kbps")

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

Description:
Convenience method equivalent to get_audio_metadata(file_path, is_file=True).

Parameters:

Parameter Type Description
file_path str Path to the audio file.

Returns: Dict or None.


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

Description:
Convenience method equivalent to get_audio_metadata(aid, is_file=False).

Parameters:

Parameter Type Description
aid int Audio ID.

Returns: Dict or None.

Raises:

  • ValueError: If the AID is invalid (returns None).

DAP System Methods

save_dap_to_json(save_path: str) -> bool

Description:
Saves all DAP records currently in memory to a JSON file. The file extension must be .ap-ds-dap.

Parameters:

Parameter Type Description
save_path str Output file path (must end with .ap-ds-dap).

Returns: boolTrue if successful, False otherwise.

Raises:

  • ValueError: If the file extension is not .ap-ds-dap.

Example:

if lib.save_dap_to_json("my_playlist.ap-ds-dap"):
    print("Playlist saved!")
else:
    print("Failed to save")

File Format:

[
  {
    "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]

Description:
Returns a copy of all DAP records currently in memory.

Returns: List[Dict] – List of record dictionaries.

Example:

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

clear_dap_recordings() -> None

Description:
Clears all DAP records from memory. This operation is irreversible unless you have previously saved the records.

Example:

lib.clear_dap_recordings()
print(f"Remaining records: {len(lib.get_dap_recordings())}")  # 0

_add_to_dap_recordings(file_path: str) -> None

Description:
Internal method that adds a file to the DAP recordings list. Called automatically by play_from_file(), play_from_memory(), and new_aid().

Parameters:

Parameter Type Description
file_path str Path to the audio file.

Internal Behavior:

  1. Calls get_audio_metadata_by_path(file_path) to extract metadata.
  2. If metadata is available, creates a record with path, duration, bitrate, and channels.
  3. Checks for duplicates (by path) before appending.

Resource Management

clear_memory_cache() -> None

Description:
Frees all cached audio data (both sound effects and music) from memory. After calling this, any subsequent playback will require reloading files from disk.

Example:

lib.clear_memory_cache()
print("All cached audio cleared")

Internal Behavior:

  1. Iterates through _audio_cache and calls Mix_FreeChunk() on each.
  2. Iterates through _music_cache and calls Mix_FreeMusic() on each.
  3. Clears both dictionaries.

cleanup_function() -> None

Description:
Registered with atexit to clean up all resources when the Python interpreter exits. This method:

  • Clears memory cache.
  • Closes the audio device with Mix_CloseAudio().
  • Shuts down SDL with SDL_Quit().

Users should not call this method directly; it is automatically invoked on interpreter shutdown.


Internal Helper Methods

These methods are intended for internal use but are documented here for completeness.

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

Description:
Searches _channel_info for the channel associated with the given AID.

Returns: int – Channel number, or None if not found.


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

Description:
Searches _channel_info for the file path associated with the given AID.

Returns: str – File path, or None if not found.


_is_music_file(file_path: str) -> bool

Description:
Determines whether a file should be treated as music (supports seek) or as a sound effect (no seek). The decision is based on:

  • File extension (.mp3, .ogg, .flac → music).
  • For WAV files: compares duration against WAV_THRESHOLD.

Returns: boolTrue if music mode, False if sound effect mode.


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

Description:
Internal method that performs the actual seek operation for a given channel.


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

Description:
Internal method that extracts duration using audio_parser. Returns either an integer (success) or a tuple (0, error_message) (failure).


_get_file_duration(file_path: str) -> float

Description:
Internal method that returns duration as a float, defaulting to 0.0 on error.


AudioParser Class – Metadata API

The AudioParser class provides a unified interface for extracting metadata from audio files. It is used internally by AudioLibrary but can also be used directly.

get_audio_parser() -> AudioParser

Description:
Singleton factory function that returns an instance of AudioParser. The same instance is reused across calls.

Example:

from ap_ds import get_audio_parser

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

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

Description:
Returns metadata for the given audio file. Delegates to the format‑specific parser in audio_info.py.

Parameters:

Parameter Type Description
file_path str Path to the audio file.

Returns: Dict or None (if parsing fails).

Dictionary Structure:

{
    'path': file_path,
    'format': ext,           # e.g., '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

Description:
Returns the duration of the audio file in seconds (rounded down).

Returns: int – Duration in seconds, or 0 on error.


Legacy Methods (for backward compatibility)

These methods are aliases and behave identically to 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 Module – Format-Specific Parsers

The audio_info.py module contains the low‑level parsers for each supported format. Each parser returns a StreamInfo object with the following attributes:

  • length: float – Duration in seconds (exact).
  • sample_rate: int – Sample rate in Hz.
  • channels: int – Number of audio channels.
  • bitrate: int – Bitrate in bps.

StreamInfo Class

Attributes:

  • length (float) – Duration in seconds.
  • sample_rate (int) – Sample rate in Hz.
  • channels (int) – Number of channels (1 = mono, 2 = stereo).
  • bitrate (int) – Bitrate in bps.

String Representation: "<StreamInfo length=3.141593s rate=44100Hz channels=2 bitrate=320000bps>"


WAVFile Class

Parser: Reads RIFF chunks, extracts fmt and data chunks.

Accuracy: 100% (based on file structure, no heuristics).

Method:

  1. Reads RIFF header and WAVE identifier.
  2. Scans chunks for fmt (format) and data.
  3. From fmt : extracts channels, sample_rate, block_align.
  4. From data: extracts data_size.
  5. Computes total_frames = data_size // block_align.
  6. Computes length = total_frames / sample_rate.
  7. Computes bitrate = sample_rate * block_align * 8 // channels.

FLACFile Class

Parser: Reads the STREAMINFO block (must be present in all FLAC files).

Accuracy: 100% (from metadata).

Method:

  1. Verifies fLaC magic bytes.
  2. Iterates through metadata blocks.
  3. For block type 0 (STREAMINFO):
    • Extracts sample_rate from bytes 10–12.
    • Extracts channels from byte 12.
    • Extracts total_samples from bytes 13–17.
    • Computes length = total_samples / sample_rate.
    • Computes bitrate = file_size * 8 / length.
  4. Returns StreamInfo.

MP3File Class

Parser: Frame‑by‑frame scanner that counts frames and accumulates samples.

Accuracy: >98% (limited by variable bitrate and incomplete final frames).

Method:

  1. Scans the file byte‑by‑byte looking for 0xFF (frame sync).
  2. Reads the next 3 bytes to form the frame header.
  3. Extracts:
    • bitrate from bits 4–7 of byte 1.
    • sample_rate from bits 2–3 of byte 1.
  4. Calculates frame length: 144000 * bitrate / sample_rate.
  5. Moves the file pointer forward by the frame length.
  6. Increments total_frames.
  7. After scanning, computes:
    • length = total_frames * 1152 / sample_rate (1152 samples per MP3 frame).
    • bitrate = file_size * 8 / length.

OGGFile Class

Parser: Reads Ogg pages, extracts granule position (total samples) from the last page.

Accuracy: 99.99% (granule position is exact, but may be slightly off if the file is truncated).

Method:

  1. Scans Ogg pages (each starts with OggS).
  2. Extracts granule position from bytes 6–13.
  3. Keeps the maximum granule position (last page).
  4. Also reads the first packet to extract sample_rate and channels from the Vorbis identification header.
  5. Computes length = last_granule / sample_rate.
  6. Computes bitrate = file_size * 8 / length.

AACFile Class

Parser: Reads ADTS (Audio Data Transport Stream) frames, accumulates samples.

Accuracy: >99% (based on frame counting, similar to MP3).

Method:

  1. Scans for 0xFFF (ADTS sync word).
  2. Reads the next 7 bytes as header.
  3. Extracts:
    • sample_rate from bits 2–5 of byte 2.
    • channels from bits 6–7 of byte 2 and byte 3.
    • frame_length from bytes 3–5.
  4. Increments total_samples by 1024 (samples per AAC frame).
  5. Seeks forward by frame_length - 7.
  6. Computes length = total_samples / sample_rate.
  7. Computes bitrate = file_size * 8 / length.

open_audio(filename: str) -> FileType

Description:
Factory function that returns the appropriate parser instance based on file extension.

Parameters:

Parameter Type Description
filename str Path to the audio file.

Returns: Instance of WAVFile, FLACFile, MP3File, OGGFile, or AACFile.

Raises: ValueError if the format is unsupported.


SDL2 Integration Layer

The player.py module contains the low‑level bindings to SDL2 and SDL2_mixer using ctypes. All functions are bound with proper argtypes and restype to ensure cross‑platform stability.

Global SDL2 Functions

Function C Binding Description
SDL_Init(flags) _sdl_lib.SDL_Init Initializes SDL subsystems.
SDL_Quit() _sdl_lib.SDL_Quit Shuts down SDL.
SDL_GetError() _sdl_lib.SDL_GetError Returns last SDL error message.
SDL_Delay(ms) _sdl_lib.SDL_Delay Sleeps for the specified milliseconds.
SDL_RWFromFile(file, mode) _sdl_lib.SDL_RWFromFile Opens a file for reading with SDL's RWops.

Global SDL2_mixer Functions

Function C Binding Description
Mix_OpenAudio(freq, format, channels, chunksize) _mix_lib.Mix_OpenAudio Opens the audio device.
Mix_CloseAudio() _mix_lib.Mix_CloseAudio Closes the audio device.
Mix_LoadWAV_RW(rwops, freesrc) _mix_lib.Mix_LoadWAV_RW Loads a WAV file into a Mix_Chunk.
Mix_LoadMUS_RW(rwops, freesrc) _mix_lib.Mix_LoadMUS_RW Loads a music file into a Mix_Music.
Mix_FreeChunk(chunk) _mix_lib.Mix_FreeChunk Frees a Mix_Chunk.
Mix_FreeMusic(music) _mix_lib.Mix_FreeMusic Frees a Mix_Music.
Mix_PlayChannel(channel, chunk, loops) _mix_lib.Mix_PlayChannel Plays a chunk on a channel.
Mix_PlayMusic(music, loops) _mix_lib.Mix_PlayMusic Plays music.
Mix_Pause(channel) _mix_lib.Mix_Pause Pauses a channel.
Mix_PauseMusic() _mix_lib.Mix_PauseMusic Pauses music.
Mix_Resume(channel) _mix_lib.Mix_Resume Resumes a channel.
Mix_ResumeMusic() _mix_lib.Mix_ResumeMusic Resumes music.
Mix_HaltChannel(channel) _mix_lib.Mix_HaltChannel Stops a channel.
Mix_HaltMusic() _mix_lib.Mix_HaltMusic Stops music.
Mix_Volume(channel, volume) _mix_lib.Mix_Volume Sets/get channel volume.
Mix_VolumeMusic(volume) _mix_lib.Mix_VolumeMusic Sets/get music volume.
Mix_Playing(channel) _mix_lib.Mix_Playing Checks if a channel is playing.
Mix_PlayingMusic() _mix_lib.Mix_PlayingMusic Checks if music is playing.
Mix_Paused(channel) _mix_lib.Mix_Paused Checks if a channel is paused.
Mix_PausedMusic() _mix_lib.Mix_PausedMusic Checks if music is paused.
Mix_FadeInMusic(music, loops, ms) _mix_lib.Mix_FadeInMusic Fades in music.
Mix_FadeInMusicPos(music, loops, ms, pos) _mix_lib.Mix_FadeInMusicPos Fades in music from a position.
Mix_FadeOutMusic(ms) _mix_lib.Mix_FadeOutMusic Fades out music.
Mix_FadingMusic() _mix_lib.Mix_FadingMusic Returns fade state.
Mix_SetMusicPosition(pos) _mix_lib.Mix_SetMusicPosition Seeks in music (if supported).

Constants Reference

SDL Initialization Flags

Constant Value Description
SDL_INIT_TIMER 0x00000001 Timer subsystem.
SDL_INIT_AUDIO 0x00000010 Audio subsystem.
SDL_INIT_VIDEO 0x00000020 Video subsystem.
SDL_INIT_JOYSTICK 0x00000200 Joystick subsystem.
SDL_INIT_HAPTIC 0x00001000 Haptic (force feedback) subsystem.
SDL_INIT_GAMECONTROLLER 0x00002000 Game controller subsystem.
SDL_INIT_EVENTS 0x00004000 Events subsystem.
SDL_INIT_EVERYTHING 0x0000F231 All subsystems.

Audio Formats

Constant Value Description
AUDIO_U8 0x0008 Unsigned 8‑bit samples.
AUDIO_S8 0x8008 Signed 8‑bit samples.
AUDIO_U16LSB 0x0010 Unsigned 16‑bit, little‑endian.
AUDIO_S16LSB 0x8010 Signed 16‑bit, little‑endian.
AUDIO_U16MSB 0x1010 Unsigned 16‑bit, big‑endian.
AUDIO_S16MSB 0x9010 Signed 16‑bit, big‑endian.
AUDIO_U16 AUDIO_U16LSB System‑endian unsigned 16‑bit.
AUDIO_S16 AUDIO_S16LSB System‑endian signed 16‑bit.
AUDIO_S32LSB 0x8020 Signed 32‑bit, little‑endian.
AUDIO_S32MSB 0x9020 Signed 32‑bit, big‑endian.
AUDIO_S32 AUDIO_S32LSB System‑endian signed 32‑bit.
AUDIO_F32LSB 0x8120 Float 32‑bit, little‑endian.
AUDIO_F32MSB 0x9120 Float 32‑bit, big‑endian.
AUDIO_F32 AUDIO_F32LSB System‑endian float 32‑bit.
MIX_DEFAULT_FORMAT AUDIO_S16SYS Default format (signed 16‑bit, system endian).

Mixer Initialization Flags

Constant Value Description
MIX_INIT_FLAC 0x00000001 FLAC support.
MIX_INIT_MOD 0x00000002 MOD (tracker) support.
MIX_INIT_MP3 0x00000008 MP3 support.
MIX_INIT_OGG 0x00000010 OGG Vorbis support.
MIX_INIT_MID 0x00000020 MIDI support.
MIX_INIT_OPUS 0x00000040 Opus support.

Music Type Constants (Returned by Mix_GetMusicType)

Constant Value Description
MUS_NONE 0 No music loaded.
MUS_CMD 1 External command (rare).
MUS_WAV 2 WAV file.
MUS_MOD 3 MOD tracker file.
MUS_MID 4 MIDI file.
MUS_OGG 5 OGG Vorbis.
MUS_MP3 6 MP3.
MUS_FLAC 7 FLAC.
MUS_OPUS 8 Opus.

Fade State Constants

Constant Value Description
MUS_NO_FADING 0 No fade in progress.
MUS_FADING_OUT 1 Fading out.
MUS_FADING_IN 2 Fading in.

Exception Handling

All methods in AudioLibrary raise exceptions in the following circumstances:

Exception When Raised
FileNotFoundError The specified file does not exist.
RuntimeError SDL2 initialization fails, mixer initialization fails, audio file loading fails, playback fails.
ValueError Invalid AID, unsupported operation (e.g., seeking a sound effect).
ImportError SDL2 libraries cannot be loaded (Windows/macOS download failure, Linux system library missing).

Example:

try:
    lib.play_from_file("nonexistent.mp3")
except FileNotFoundError as e:
    print(f"File not found: {e}")
except RuntimeError as e:
    print(f"Playback error: {e}")

End of API Reference

This document covers all public and internal APIs of the ap_ds library version 3.0.0 LTS. For additional examples and usage patterns, refer to the main README.md.


Environment Variables

1. AP_DS_HIDE_SUPPORT_PROMPT

Purpose: Controls the display of the startup banner when the library is imported.

Default: Not set (banner is shown)

Behavior:

  • When set to 1 (any non‑empty string that evaluates to 1), the startup message is completely suppressed.
  • This is useful for GUI applications, daemons, or any environment where console output should be minimal.

Usage:

# 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

Code Example:

import os
os.environ['AP_DS_HIDE_SUPPORT_PROMPT'] = '1'
import ap_ds  # No banner output

2. AP_DS_WAV_THRESHOLD

Purpose: Determines whether a WAV file is played as a sound effect (no seek capability) or as a music file (full seek and fade support).

Default: 6 seconds

Behavior:

  • Files with duration less than the threshold: treated as sound effects (using Mix_PlayChannel). Seek operations are not supported.
  • Files with duration greater than or equal to the threshold: treated as music (using Mix_PlayMusic). Full seek and fade operations are available.
  • If the threshold is set to 30 or higher, it is automatically reset to 6 to prevent potential memory issues.
  • Negative values are also reset to 6.
  • Invalid (non‑numeric) values fall back to the default.

Why this exists:
SDL2_mixer has two distinct playback mechanisms: sound effects (channels) and music. Sound effects are lightweight and ideal for short clips, but they cannot be seeked or faded. Music tracks support these advanced features but consume slightly more resources. This threshold allows you to automatically choose the appropriate mechanism based on file duration.

Usage:

# Set threshold to 10 seconds
export AP_DS_WAV_THRESHOLD=10

# Use a very low threshold (all WAVs become sound effects)
export AP_DS_WAV_THRESHOLD=0

# Use a high threshold (only very long WAVs become music)
export AP_DS_WAV_THRESHOLD=20

Validation Rules:

# Internal validation logic
if WAV_THRESHOLD >= 30:
    WAV_THRESHOLD = 6  # Prevent memory issues
elif WAV_THRESHOLD < 0:
    WAV_THRESHOLD = 6

3. AP_DS_SDL2_PATH and AP_DS_SDL2_MIXER_PATH (Linux only)

Purpose: Specify custom paths to SDL2 and SDL2_mixer shared libraries on Linux systems. These variables are used when the system‑installed libraries are not found or when you have compiled your own versions.

Default: Not set; the library searches standard system paths (/usr/lib, /usr/local/lib, etc.) and package‑manager locations.

Behavior:

  • If both variables are set and the files exist, they are loaded immediately without any further search.
  • After successful loading, the paths are automatically saved to ~/.config/ap_ds/sdl_paths.conf for future runs.
  • If the saved paths become invalid (file missing), the library falls back to the normal search process.

Usage:

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

Why this exists:
Linux distributions have diverse package managers and library locations. Some users may compile SDL2 from source for performance or compatibility reasons. These environment variables provide a direct way to point the library to exactly the files you want to use.

Configuration File:
After first successful manual configuration, the paths are saved to:

~/.config/ap_ds/sdl_paths.conf

The file contains:

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

Security Note: The configuration file is stored in the user's home directory and is only readable by the user. It does not contain any sensitive information beyond library paths.


v3.0.0 LTS – Detailed Release Overview

What is an LTS Release?

Long‑Term Support (LTS) releases are a common practice in the software industry, particularly for libraries and frameworks that are used as foundations for other products. An LTS release is a version that will receive security updates, critical bug fixes, and maintenance patches for a defined period, without introducing new features or breaking changes.

For ap_ds, the LTS designation means:

  • Stability guarantee: The API will not change. Your code written for v3.0.0 LTS will continue to work for the entire support period.
  • Security updates: Any discovered vulnerabilities will be patched and backported to v3.0.0 LTS.
  • Critical bug fixes: Major bugs (crashes, memory leaks, severe functionality issues) will be fixed.
  • No new features: Feature development will continue in newer versions, but those features will not be added to the LTS branch. This ensures that upgrading is a conscious decision, not a forced migration.

Why v3.0.0 LTS Exists

The decision to create an LTS release was driven by user demand. Over the years, we have seen ap_ds used in:

  • Commercial software: Integrated into paid applications where stability is paramount.
  • Embedded systems: Deployed on devices that may not be updated frequently.
  • Educational environments: Used in curriculum where consistency is important.
  • Personal projects: Developers who want a reliable baseline.

For these users, the ability to pin a version and receive only critical updates is essential. v3.0.0 LTS fulfills that need.

Detailed Technical Changes in v3.0.0 LTS

1. Deterministic Resource Cleanup

Problem in earlier versions:
The AudioLibrary class relied on Python's __del__ finalizer to release SDL2 resources when the object was garbage‑collected. However, __del__ is not guaranteed to run in all circumstances, especially during interpreter shutdown or when exceptions occur. This could lead to:

  • Audio device handles remaining open.
  • SDL2 mixer channels not being freed.
  • Warning messages about unclosed resources.

Solution:
v3.0.0 LTS uses atexit.register() to install a cleanup function that is guaranteed to run when the Python interpreter exits normally. Additionally, the cleanup logic is now explicit and deterministic:

  • All cached Mix_Chunk and Mix_Music objects are freed.
  • Mix_CloseAudio() is called to shut down the audio device.
  • SDL_Quit() is called to clean up SDL2 subsystems.

This ensures that even if your program terminates unexpectedly (e.g., via sys.exit() or unhandled exception), the at‑exit handler will still run and release all resources.

Implementation snippet:

def cleanup_function():
    self.clear_memory_cache()
    Mix_CloseAudio()
    SDL_Quit()

atexit.register(self.cleanup_function)

Impact: No more resource leaks, no more warnings, and cleaner integration with long‑running processes.

2. Hash‑Verified Downloads (Security Hardening)

Problem in earlier versions:
When SSL certificate verification failed (common on older Windows systems or behind corporate proxies), the library would fall back to an unverified connection. This was necessary for usability but introduced a theoretical risk: if a man‑in‑the‑middle attack occurred during that fallback, the downloaded DLL could be replaced with a malicious version.

Solution:
v3.0.0 LTS adds a cryptographic hash check to every downloaded file. The expected SHA‑256 hashes are hardcoded into the source:

FILE_HASHES = {
    "SDL2.dll": "520d0459b91efa32fbccf9027a9ca1fc5aae657e679ce8e90f179f9cf5afd279",
    "SDL2_mixer.dll": "2a0fc5e9f72c2eaec3240cb82b7594a58ccda609485981f256b94d0a4dd8d6f8",
    "SDL2.dmg": "2bf2cb8f6b44d584b14e8d4ca7437080d1d968fe3962303be27217b336b82249",
    "SDL2_mixer.dmg": "d74052391ee4d91836bf1072a060f1d821710f3498a54996c66b9a17c79a72d1",
}

When a file is downloaded (whether with SSL verification or without), the library:

  1. Calculates the SHA‑256 hash of the downloaded content.
  2. Compares it to the expected hash.
  3. If they match, the file is saved and used.
  4. If they do not match, the download is rejected and retried (up to 3 times).

Security implications:
Even if a malicious actor manages to intercept the download and replace the file, they cannot produce a file with the same SHA‑256 hash without breaking the cryptographic algorithm (computationally infeasible). The hash is stored in the source code, which is itself distributed via PyPI and verified by pip's own integrity mechanisms.

Performance impact:
Hash calculation adds a trivial overhead (a few milliseconds for files up to 3MB). This is negligible compared to network latency.

3. Complete Test Coverage

Tested environments:

Platform Architecture Python Versions SDL2 Source
Windows 7 x86_64 3.7, 3.8, 3.9, 3.10, 3.11, 3.12, 3.13 Auto‑downloaded
Windows 10 x86_64 3.7 – 3.13 Auto‑downloaded
Windows 11 x86_64 3.7 – 3.13 Auto‑downloaded
macOS 10.15 Intel 3.7 – 3.13 Auto‑downloaded
macOS 11 Apple Silicon (Rosetta) 3.7 – 3.13 Auto‑downloaded
macOS 14 Apple Silicon (native) 3.7 – 3.13 Auto‑downloaded
Ubuntu 20.04 x86_64 3.7 – 3.13 System libraries
Ubuntu 22.04 ARM64 3.7 – 3.13 System libraries
Debian 11 x86_64 3.7 – 3.13 System libraries
Fedora 38 x86_64 3.7 – 3.13 System libraries
Arch Linux x86_64 3.7 – 3.13 System libraries
Orange Pi 4 Pro ARM64 3.10 System libraries
Raspberry Pi 5 ARM64 3.11 System libraries

Test categories:

  • Library loading: Successful import on all platforms, fallback behavior on network failure.
  • Playback: MP3, FLAC, OGG, WAV formats; variable bitrate; concurrent playback.
  • Seeking: Accuracy within ±0.1 seconds; boundary conditions; seek during pause/stop.
  • Volume control: Range 0‑128; persistence across playbacks.
  • DAP system: Recording deduplication; JSON save/load; memory cleanup.
  • Resource cleanup: No memory leaks after 10,000 play/stop cycles; at‑exit handler verification.
  • Error handling: Invalid file paths, corrupted files, missing SDL2 libraries.

Results: All tests pass with zero failures. Memory growth after 10,000 cycles is under 4MB.

LTS Support Commitment and Additional License Terms

Support Period

  • Start Date: March 22, 2026
  • End Date: March 22, 2031

During this period, the following services are provided free of charge:

  • Security updates: Any vulnerability discovered in the LTS branch will be patched and released as a minor version update (e.g., v3.0.1, v3.0.2, etc.). Users can upgrade to the latest LTS patch without changing any code.
  • Critical bug fixes: Bugs that cause crashes, memory leaks, or severe functionality loss will be fixed and backported.
  • Technical support: Questions and issues can be submitted via Gitee Issues, GitLab Issues, or email. Response time is within 7 business days for all inquiries, and within 48 hours for critical issues.

What is NOT Covered

  • New features: Feature development will continue in the main branch, but those features will not be added to the LTS branch.
  • Non‑critical bugs: Minor bugs that do not affect functionality may not be fixed in the LTS branch.
  • Platform‑specific issues: If a new operating system version introduces incompatibilities, support will be evaluated on a case‑by‑case basis.

LTS Additional License Terms

The DVS Audio Library Open Source License Version 2.0 applies to v3.0.0 LTS, with the following clarifications:

  1. Commercial Use: The LTS version may be used in commercial products, cloud services, and SaaS platforms without any additional licensing fees. Attribution requirements remain as specified in Section 3.1 of the license.

  2. Redistribution: You may redistribute v3.0.0 LTS as part of your own applications. You must include the original copyright notices and provide attribution.

  3. Modified Versions: If you modify the source code and distribute your modified version, you must use an independent brand name and clearly indicate that it is not the official LTS version. You are responsible for supporting your modified version.

  4. Support for Modified Versions: The official LTS support (security updates, bug fixes) applies only to the unmodified source code as distributed by the author. If you modify the code, you assume all responsibility for maintaining it.

  5. LTS Mark: The “LTS” designation is a trademark of the project. You may not call your modified version “LTS” or imply that it has the same support commitment as the official LTS release.


Technical Architecture

Core Components

ap_ds/
├── __init__.py          # Package entry point, version import, banner display
├── player.py            # Main AudioLibrary class, SDL2 bindings, playback logic
├── audio_parser.py      # Metadata parser factory, unified API
├── audio_info.py        # Format‑specific parsers (WAV, FLAC, MP3, OGG, AAC)
└── _version.py          # Auto‑generated version file (created during build)

1. Player Module (player.py)

Purpose: The heart of the library. Manages SDL2 initialization, audio playback, caching, and DAP recording.

Key Classes and Functions:

  • AudioLibrary: Main class that users interact with.

    • Initialization: __init__(frequency, format, channels, chunksize) – sets up SDL audio and mixer.
    • Playback: play_from_file(), play_from_memory(), new_aid()
    • Control: pause_audio(), play_audio(), stop_audio(), seek_audio()
    • Volume: set_volume(), get_volume()
    • Fade Effects: fadein_music(), fadein_music_pos(), fadeout_music(), is_music_playing(), is_music_paused(), get_music_fading()
    • Metadata: get_audio_duration(), get_audio_metadata()
    • DAP: save_dap_to_json(), get_dap_recordings(), clear_dap_recordings()
  • Internal Data Structures:

    • self._audio_cache: dict[str, Mix_Chunk] – cached sound effects (short files).
    • self._music_cache: dict[str, Mix_Music] – cached music tracks.
    • self._channel_info: dict[int, dict] – active playback sessions, keyed by SDL channel ID.
    • self._aid_to_filepath: dict[int, str] – AID (Audio ID) to file path mapping.
    • self._dap_recordings: list[dict] – DAP history records.
  • Platform Abstraction:

    • import_sdl2(): Intelligently loads SDL2 libraries on Windows, macOS, and Linux.
    • download_sdl_libraries(): Downloads platform‑specific binaries with hash verification.
    • check_sdl_libraries_exist(): Verifies presence of required files.
    • load_sdl2_from_directory(): Loads libraries from the package directory or system paths.
  • SDL2 Binding:

    • All SDL2 and SDL2_mixer functions are bound via ctypes.
    • Function prototypes (argtypes, restype) are set for all platforms to prevent segmentation faults.
    • The binding code is unconditional – it runs on every platform, ensuring stability.

2. Metadata Parser Module (audio_parser.py)

Purpose: Provides a unified interface for extracting audio metadata. Handles format detection and dispatches to the appropriate parser.

Key Functions:

  • get_audio_parser(): Singleton factory that returns an instance of AudioParser.
  • AudioParser.get_audio_metadata(file_path): Returns a dictionary with path, format, duration, length, sample_rate, channels, bitrate.

Fallback Behavior: If a format‑specific parser fails, the library returns None. No exceptions are raised during metadata parsing; errors are logged.

3. Format‑Specific Parsers (audio_info.py)

Purpose: Low‑level parsers for each supported format. These modules are written in pure Python and do not depend on external libraries.

Supported Formats and Parsing Methods:

Format Parser Class Accuracy Method
WAV WAVFile 100% Reads RIFF chunks, extracts sample rate, channels, block align, and data size. Computes exact duration from total frames.
FLAC FLACFile 100% Reads STREAMINFO block (always present). Extracts sample rate, channels, and total samples from the metadata.
MP3 MP3File >98% Scans the file frame‑by‑frame using MP3 frame headers. Accumulates samples and estimates duration based on sample rate.
OGG OGGFile 99.99% Reads Ogg pages, extracts granule position (total samples) from the last page. Requires scanning the entire file, but is highly accurate.
AAC (ADTS) AACFile >99% Parses ADTS headers frame‑by‑frame, accumulates samples. Accurate for files with consistent frame sizes.

Why not 100% for MP3?
MP3 frames can have variable bitrates, and the Xing/LAME header (which contains accurate frame counts) is optional and not always present. The frame‑by‑frame scanner is the most reliable method, but due to the way MP3 frames are packed, the last frame may be incomplete, causing a small error (<1%). For most use cases, this is acceptable.

4. DAP (Dvs Audio Playlist) System

Purpose: Automatically records playback history with metadata only, enabling applications to build listening histories without storing audio data.

Workflow:

  1. User calls play_from_file() or play_from_memory().
  2. The method calls _add_to_dap_recordings(file_path).
  3. _add_to_dap_recordings() retrieves metadata via get_audio_metadata_by_path().
  4. A record is created with path, duration, bitrate, and channels.
  5. The record is added to self._dap_recordings if not already present (deduplication).
  6. User can call save_dap_to_json() at any time to persist the list to a .ap_ds-dap JSON file.

Memory Characteristics:

  • Each record: approximately 150 bytes (path string + three integers).
  • 10,000 records: ~1.5 MB RAM, ~2‑3 MB JSON file.
  • No audio data is stored.

File Format:

[
  {
    "path": "/Music/song.mp3",
    "duration": 240,
    "bitrate": 320000,
    "channels": 2
  }
]

5. SDL2 Integration and ctypes Binding

Why ctypes?
ctypes is part of the Python standard library, so it adds no external dependencies. It allows direct calling of C functions from shared libraries (DLLs, dylibs, .so files). This is the most lightweight way to interface with SDL2.

Function Prototypes:
For every SDL2 and SDL2_mixer function used, we set argtypes and restype. This is critical for cross‑platform stability:

  • Without argtypes, Python may pass arguments incorrectly, leading to segmentation faults.
  • Without restype, Python may misinterpret the return value (especially for pointer types).

In early versions (v2.2.x and earlier), these prototypes were only set on Windows, causing crashes on macOS and Linux. v2.3.3 fixed this by making the prototype definitions unconditional.

Memory Management:
SDL2 allocates memory for Mix_Chunk and Mix_Music objects. The library stores them in caches and frees them with Mix_FreeChunk() and Mix_FreeMusic() when no longer needed. The at‑exit handler ensures they are freed even if the user forgets to call clear_memory_cache().

6. Cross‑Platform Download and Extraction

Windows:

  • Downloads SDL2.dll and SDL2_mixer.dll from https://dvsyun.top/ap_ds/download/SDL2 and .../SDL2_M.
  • After download, calculates SHA‑256 hash and compares to expected values.
  • Saves DLLs to the package directory (site-packages/ap_ds/).

macOS:

  • Downloads SDL2.dmg and SDL2_mixer.dmg.
  • Mounts the DMG using hdiutil.
  • Searches for SDL2.framework and SDL2_mixer.framework in the mounted volume.
  • Copies the frameworks to the package directory.
  • Unmounts the DMG and deletes the temporary file.

Linux:

  • Does not download libraries automatically. Instead, relies on system package manager or user‑provided paths.
  • Four‑layer fallback: system libraries → user config → automatic package manager installation → interactive guidance.

Hash Verification:
For all downloaded files, SHA‑256 is calculated and compared to a hardcoded dictionary. If the hash does not match, the download is rejected and retried. After three failures, an exception is raised.

7. Error Handling Philosophy

ap_ds follows a fail‑fast, fail‑clearly philosophy:

  • File not found: FileNotFoundError with the path.
  • Unsupported format: RuntimeError with a descriptive message.
  • SDL2 initialization failure: RuntimeError with the SDL error string.
  • Download failure: Exception with details about the failure (hash mismatch, network error, etc.).

Why not structured error codes?
Structured error codes (like -1 for failure, 0 for success) are common in C APIs but less Pythonic. Python exceptions are preferred because they force the caller to handle errors explicitly and provide rich context.

Why not complex error messages with suggestions?
Developers are expected to read error messages and use common sense. Adding suggestions (e.g., “try reinstalling SDL2”) adds maintenance burden and may be incorrect in edge cases. The library focuses on being correct, not prescriptive.


Frequently Asked Questions

1. Which version should I use for production?

v3.0.0 LTS is the recommended version for all production deployments. It receives security updates and critical bug fixes for five years. No breaking changes will be introduced during the LTS period.

2. Can I use v3.0.0 LTS in commercial products?

Yes, absolutely. The license explicitly permits commercial use, including integration into commercial products, cloud services, and SaaS platforms, completely free of charge. You must comply with the attribution requirements (see Section 3.1 of the license).

3. Why is the library so small?

ap_ds focuses precisely on playback and parsing for the four most common formats, avoiding the bloat of editing/transcoding features. It is built on the efficient SDL2 C library and uses only the Python standard library. The total size on Windows is 2.5MB, and on macOS it is 3.36MB.

4. How accurate is MP3 duration parsing?

MP3 duration parsing is >98% accurate. This is due to the format's variable header complexities. For WAV and FLAC we guarantee 100% accuracy, and for OGG 99.99%.

5. Does it work on embedded devices?

Yes! v3.0.0 LTS has been tested on Orange Pi 4 Pro and Raspberry Pi 5 (ARM64) running Ubuntu 22.04. Memory growth is minimal (~4MB after extensive testing). Audio output via 3.5mm works without modification.

6. What are the system requirements?

  • Windows: Windows 7+, Python 3.7+
  • macOS: macOS 10.9+, Python 3.7+
  • Linux: Modern distributions, Python 3.7+, SDL2 libraries (automatically installed via package manager if possible)
  • Embedded: ARM64 devices with Ubuntu 22.04 or similar

7. How do I suppress the startup banner?

Set the environment variable AP_DS_HIDE_SUPPORT_PROMPT=1 before importing the library:

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

8. How do I configure the WAV threshold?

Set AP_DS_WAV_THRESHOLD to the desired number of seconds. Files shorter than this threshold will be treated as sound effects (no seek), files equal to or longer will be treated as music (full seek and fade support).

export AP_DS_WAV_THRESHOLD=10  # Linux/macOS
set AP_DS_WAV_THRESHOLD=10     # Windows Command Prompt
$env:AP_DS_WAV_THRESHOLD=10    # Windows PowerShell

9. How do I provide custom SDL2 paths on Linux?

Set AP_DS_SDL2_PATH and AP_DS_SDL2_MIXER_PATH to the full paths of the shared libraries. These paths are automatically saved for future runs.

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

10. What if SSL verification fails on Windows?

The library will fall back to downloading without certificate verification, but then validates the SHA‑256 hash of the downloaded file. If the hash matches, the file is safe. If the hash does not match, the download is rejected. This is more secure than the previous behavior (which simply accepted any file).

11. Is the hash‑verified download safe?

Yes. The hash is hardcoded in the source code. Even if the download is intercepted, the attacker would need to produce a file with the same SHA‑256 hash, which is computationally infeasible. The hash itself is distributed via PyPI, which uses its own integrity checks (package signing).

12. Can I use ap_ds in a multithreaded application?

Yes, but you must ensure that calls to the AudioLibrary instance are serialized. SDL2 and SDL2_mixer are not thread‑safe in all respects. For best results, create one AudioLibrary instance and call its methods from a single thread, or use a lock to serialize access. The library itself does not create additional threads except during download operations (which are isolated).

13. How do I get support for the LTS version?

Free support is available via:

Response time: within 7 business days for standard inquiries, within 48 hours for critical issues.

14. What happens after the LTS support period ends (March 22, 2031)?

After the LTS period, the v3.0.0 branch will enter end‑of‑life. No further updates will be provided. Users are encouraged to migrate to a newer LTS release (if available) or the latest stable version at that time. The source code will remain available, but security issues will not be patched.

15. Can I modify the source code and still call it “ap_ds”?

No. Modified versions must use an independent brand name (see Section 3.2 of the license). You can still use the code, but you cannot use the original project name, logo, or imply that your version is the official release.

16. How do I save DAP records to a file?

Call save_dap_to_json() with a filename ending in .ap_ds-dap:

success = lib.save_dap_to_json("my_history.ap_ds-dap")
if success:
    print("Saved!")

The file is in JSON format and can be loaded with any JSON parser.

17. What is the maximum number of concurrent audio streams?

This depends on the SDL2_mixer configuration. The default is 8 channels (mixer channels) for sound effects, plus one music channel. You can increase the number of channels with Mix_AllocateChannels() (exposed as lib._mix_lib.Mix_AllocateChannels()), but note that each channel consumes additional resources. For most applications, the default is sufficient.

18. Can I play audio from memory (bytes) instead of a file?

Yes, but it requires pre‑loading the file with new_aid() and then using play_from_memory(). There is no direct API for playing from a bytes object because SDL2_mixer expects a file path. However, you can write the bytes to a temporary file and then play it.

19. Why does the library print “AP_DS © - Audio Library By DVS v3.0.0 | https://apds.top” on import?

This is the welcome banner. It can be suppressed by setting AP_DS_HIDE_SUPPORT_PROMPT=1 before importing the library. The banner serves to:

  • Inform users of the version they are using.
  • Provide a direct link to the official website for documentation and support.
  • Acknowledge the project’s authorship.

20. How do I report a security vulnerability?

Please email the author directly at me@dvsyun.top. Do not create a public issue for security vulnerabilities. The author will respond within 7 business days with an acknowledgment and a timeline for a fix.


Version History

v3.0.0 LTS (March 22, 2026) – First Long‑Term Support Release

This is the first LTS release. It introduces:

  • Deterministic resource cleanup (replaced __del__ with at‑exit handlers).
  • Hash‑verified downloads – every downloaded SDL2 library is validated against a hardcoded SHA‑256 hash.
  • Complete test coverage on all platforms with zero memory leaks.
  • 5‑year support period with free technical support.

No breaking changes – fully backward‑compatible with v2.x.


v2.4.2 (March 22, 2026) – Development Mishap

This version was accidentally uploaded with a development‑stage player.py. While it works for basic playback, it may contain minor quirks and is not recommended for production. It remains on PyPI because the developer’s PyPI account is temporarily locked due to a 2FA issue; it will be deprecated once the account is restored. Do not use this version in real projects.


v2.4.1 (March 1, 2026) - Documentation Update

This version updates the PyPI documentation to fully reflect the new features introduced in v2.4.0, including detailed API descriptions, usage examples, and environment variable documentation.

Changes:

  • Updated PyPI project description with complete 2.4.0 feature documentation
  • Added detailed examples for all new fade functions
  • Documented AP_DS_HIDE_SUPPORT_PROMPT environment variable
  • Improved quick start guide with common usage patterns

Note: This release contains no code changes from v2.4.0—only documentation improvements.


v2.4.0 (March 1, 2026) - Audio Effects & Engineering Improvements

✅ This version introduces professional audio transitions and significant internal engineering upgrades.


🎵 New Audio Control Features

Fade In/Out Functions:

Function Description
fadein_music(aid, loops=-1, ms=0) Fade in music over specified milliseconds
fadein_music_pos(aid, loops=-1, ms=0, position=0.0) Fade in from specific position
fadeout_music(ms=0) Fade out currently playing music
is_music_playing() Check if music is currently playing
is_music_paused() Check if music is paused
get_music_fading() Get current fade state (fading in/out/none)

Implementation Details:

# Fade in over 2 seconds
aid = lib.play_from_file("song.mp3")
lib.fadein_music(aid, loops=-1, ms=2000)

# Fade in from 30-second mark
lib.fadein_music_pos(aid, loops=-1, ms=1500, position=30.0)

# Fade out over 3 seconds
lib.fadeout_music(ms=3000)

# Check states
if lib.is_music_playing():
    print("Music is playing")
    
fade_state = lib.get_music_fading()  # Returns MIX_NO_FADING, MIX_FADING_OUT, MIX_FADING_IN

Underlying SDL2 Functions:

  • Mix_FadeInMusic() - Basic fade in
  • Mix_FadeInMusicPos() - Positioned fade in
  • Mix_FadeOutMusic() - Fade out
  • Mix_PlayingMusic() - Play state check
  • Mix_PausedMusic() - Pause state check
  • Mix_FadingMusic() - Fade state query

🧠 Engineering Improvements

1. Smart Welcome Message

The startup banner is now cleaner and user-controllable:

# Default behavior (shows once)
import ap_ds  # Prints: AP_DS © - Audio Library By DVS v2.4.0 | https://dvsx.top

# Silence it with environment variable
import os
os.environ['AP_DS_HIDE_SUPPORT_PROMPT'] = '1'
import ap_ds  # No output

2. Centralized Version Management

Version is now defined once in setup.py and automatically generates _version.py:

# setup.py
VERSION = "2.4.0"

def write_version_file():
    version_file_path = os.path.join("ap_ds", "_version.py")
    with open(version_file_path, "w", encoding="utf-8") as f:
        f.write(f'__version__ = "{VERSION}"\n')

3. Robust Import System

Two-layer fallback ensures compatibility across all Python environments:

try:
    from ._version import __version__
except ImportError:
    try:
        from _version import __version__
    except ImportError:
        __version__ = "unknown"

# Same pattern for core modules
try:
    from .player import *
except ImportError:
    from player import *

4. Unified Project URL

All project references now point to the central hub: https://dvsx.top


📋 Full API Changes

Function Parameters Return Description
fadein_music aid: int, loops: int = -1, ms: int = 0 None Fade in audio instance
fadein_music_pos aid: int, loops: int = -1, ms: int = 0, position: float = 0.0 None Fade in from position
fadeout_music ms: int = 0 None Fade out current music
is_music_playing () bool Check playing state
is_music_paused () bool Check paused state
get_music_fading () int Get fade state (0=no fade, 1=fade out, 2=fade in)

🔧 Environment Variables

Variable Default Description
AP_DS_WAV_THRESHOLD 6 WAV threshold in seconds (from v2.3.5)
AP_DS_HIDE_SUPPORT_PROMPT not set Set to 1 to hide startup message

⚡ Performance & Compatibility

  • Zero API breakage – All existing code continues to work
  • No size increase – Still under 4MB across all platforms
  • Full backward compatibility – v2.3.x applications run unchanged
  • Python 3.7+ support – Maintained

📦 Migration Guide

No migration needed. Simply upgrade and enjoy the new features:

pip install --upgrade ap_ds

To use the new fade functions in existing code:

# Before (v2.3.x)
aid = lib.play_from_file("song.mp3")
time.sleep(5)
lib.stop_audio(aid)

# After (v2.4.0) - Professional transitions!
aid = lib.play_from_file("song.mp3")
lib.fadeout_music(ms=3000)  # Smooth exit

🎯 Summary

v2.4.0 transforms ap_ds from a "playback library" into a professional audio tool with:

  • Smooth audio transitions (fade in/out)
  • Complete state querying
  • Cleaner, more professional startup
  • Industrial-strength version management
  • Bulletproof import system

All while maintaining the core promise: lightweight, zero external Python dependencies, and cross-platform compatibility.


Next: Planning v2.5.0 was superseded by v3.0.0 LTS.

v2.3.6 (February 27, 2026)

This version updates the PyPi documentation, adding detailed license information and version history, and adding more examples.

v2.3.5 (February 26, 2026) - Stability Optimization & Embedded Validation

Stability & Testing

Six-Dimension Test Coverage:

  1. Library Loading & Initialization

    • Cross-platform SDL2 loading validation
    • Network failure, file corruption, permission error recovery
    • AudioLibrary parameter verification
    • Default settings validation across devices
  2. Playback Testing

    • MP3, FLAC, OGG, WAV format validation
    • Variable bitrate and non-standard file handling
    • Non-blocking playback verification
    • Concurrent audio playback testing
  3. Seek Testing

    • Precision validation across formats
    • Boundary condition testing (start, end, beyond duration)
    • Seek during paused/stopped states
  4. Memory Pressure & Leak Detection

    • Long-duration playback monitoring
    • Repeated load/unload cycles
    • Cache behavior validation
    • Result: ~4MB growth after extensive testing
  5. Metadata Parsing Accuracy

    • Sample collection from diverse sources
    • Edge case analysis
    • Format-specific parser validation
  6. DAP System Validation

    • Automatic recording verification
    • Save/load reliability
    • Memory cleanup on clear

Embedded Platform Support

Tested Environments:

Platform SoC Cores RAM OS Audio Output
Orange Pi 4 Pro Allwinner A733 2xA76 + 6xA55 @ 2.0GHz 8GB LPDDR5 Ubuntu 22.04 ARM64 3.5mm → TPA3116D2 @ 2×8Ω 5W
Raspberry Pi 5 BCM2712 4xA76 @ 2.4GHz 8GB LPDDR4X Ubuntu 22.04 ARM64 3.5mm → TPA3116D2 @ 2×8Ω 5W

Results:

  • Intelligent package management: Working normally
  • Audio output: Normal via 3.5mm
  • AID management system: Working normally
  • Memory growth: ~4MB after comprehensive testing

Important Note: ap_ds is a wrapper library. Low-level concerns (power optimization, I2S/HDMI/ALSA output, fine-grained memory management) are handled by SDL2 and the operating system. Python's language nature limits fine resource control. We have tested and confirmed functionality; no embedded-specific optimizations are planned as they fall outside our scope.

Bug Fixes

WAV Playback Mode Selection

Fixed an issue where WAV files were incorrectly treated as sound effects, preventing seek operations.

New Logic:

  • Files < threshold (default 6s) → Sound effect mode (no seek)
  • Files >= threshold → Music mode (full seek support)
  • Configurable via AP_DS_WAV_THRESHOLD environment variable

Validation:

WAV_THRESHOLD = int(os.environ.get('AP_DS_WAV_THRESHOLD', '6'))
if WAV_THRESHOLD >= 30:  # Reset to default to prevent memory issues
    WAV_THRESHOLD = 6
elif WAV_THRESHOLD < 0:
    WAV_THRESHOLD = 6

Error Message Decision

Design Decision: Keep Existing Simple Error Format

Proposed Change Rejected: Structured error messages with causes and suggestions were considered but rejected.

Reasons:

  1. Limited Help for Complex Errors

    • Simple errors are easy to debug
    • Complex errors cannot be accurately diagnosed by the library
    • LLM integration for error analysis was considered but rejected due to cost and security concerns
  2. Target Users Are Developers

    • Developers can read error messages
    • Beginners can ask ChatGPT or search engines
    • Pre-written suggestions add little value
  3. Maintenance Burden

    • Modifying all error paths is time-consuming
    • High risk of introducing new bugs
    • Existing format works: raise RuntimeError(f"Failed to load: {file_path}")

Final Decision: Maintain existing simple exception format with clear error messages.

SSL Certificate Issue: R12 Certificate Compatibility

Problem: On some Windows systems, R12 certificates cause verification failures during SDL2 download.

Solution Implemented:

def download_with_ssl(url):
    try:
        # First attempt: Standard SSL verification
        return urllib.request.urlopen(url)
    except (URLError, SSLError) as e:
        # Fallback: Unverified context
        ssl_context = ssl.create_default_context()
        ssl_context.check_hostname = False
        ssl_context.verify_mode = ssl.CERT_NONE
        opener = urllib.request.build_opener(
            urllib.request.HTTPSHandler(context=ssl_context)
        )
        urllib.request.install_opener(opener)
        return urllib.request.urlopen(url)

Note: In v3.0.0 LTS, the fallback is still present, but hash verification makes it safe: even if the download is intercepted, the file will be rejected unless its hash matches the official one.


v1.0.0 (July 8, 2025) - Initial Release Milestone: Project birth, foundational functionality

Core Features

Basic audio playback: MP3, WAV, FLAC, OGG formats Playback control: Play, Pause, Stop, Seek basic APIs Lightweight design: Initial version ~2MB Technical Characteristics

SDL2-based audio processing Pure Python encapsulation, no complex dependencies Clean API design v2.0.0 (November 5, 2025) - Architecture Refactoring Milestone: Introduction of modern audio management system

Major Improvements

AID System: Audio ID for unified audio instance management Architecture Refactoring: Modular design for improved maintainability Smart Memory Management: Automatic cleanup of unused audio resources State Management: Unified playback state tracking Technical Upgrades

Introduction of AudioLibrary class as core manager Audio instance lifecycle management Error handling and recovery mechanisms v2.1.0 (December 26, 2025) - Feature Enhancement Milestone: Professional functionality expansion

New Features

Volume Control: Real-time volume adjustment (0-100%) Metadata Enhancement: More precise audio information parsing Playback Accuracy Improvement: Better time control and seeking Optimization Improvements

Enhanced audio format compatibility Optimized memory usage efficiency More user-friendly API interface v2.1.4 (January 18, 2026) - Stable Version Milestone: Production environment stable release

Version Highlights

Core Stability: Thoroughly tested with no known critical bugs Extreme Lightweight: Complete solution at only 2.5MB Pain Point Resolution: Fills Python audio development gap Complete Documentation: Detailed technical manual and examples Market Positioning "2.5MB Windows Python Audio Solution"

Technical Specifications Size Analysis:

├── SDL2.dll: 2.1MB ├── SDL2_mixer.dll: 400KB └── Python Code: 42KB Comparison Advantages:

├── FFmpeg Solution: At least 160MB (64x larger!) ├── Pygame Solution: Bloated with incomplete features └── ap_ds: 2.5MB perfect solution ✓ v2.2.0 (January 19, 2026) - Cross-Platform Revolution Milestone: From single-platform to cross-platform

Major New Features

  1. Complete macOS Support

Automatic download and installation of SDL2.framework, SDL2_mixer.framework Smart .dmg file extraction and framework loading Maintains extreme lightweight: Only 3.36MB (vs 2.5MB Windows version) Cross-platform unified API, code requires no modification 2. Enhanced Automatic Dependency Management

Cross-platform intelligent download strategy: Windows: Automatic .dll download macOS: Automatic .framework download and extraction Complete error handling and retry mechanisms Dependency file local caching to avoid repeated downloads 3. Strengthened Platform Position Statement

Explicit Linux non-support with detailed technical reasoning Professional rejection strategy and alternative solution suggestions Focus on serving real user needs (Windows/macOS developers) Performance & Optimization Size Control Breakthrough:

Windows Version: 2.5MB

├── SDL2.dll: 2.1MB ├── SDL2_mixer.dll: 400KB └── Python Code: 42KB macOS Version: 3.36MB

├── SDL2.framework: 1.82MB ├── SDL2_mixer.framework: 1.54MB └── Python Code: 42KB Comparison with Traditional Solutions:

├── FFmpeg Solution: At least 160MB (47x larger than ap_ds!) ├── Pygame + Parser Libraries: Bloated with incomplete features └── ap_ds: 3.36MB complete solution ✓ Loading Performance Optimization

First load: Automatic dependency download Subsequent loads: Use local cache Cross-platform loading logic unified and efficient Technical Architecture Improvements Cross-Platform Loading System:

def import_sdl2(): """Intelligent SDL2 library loading (Windows/macOS)""" if platform == "win32": # Load .dll elif platform == "darwin": # Load .framework else: # Explicitly reject unsupported platforms Enhanced Error Handling

More user-friendly error messages Detailed troubleshooting suggestions Intelligent environment detection and problem diagnosis Documentation & Examples Update

Windows Installation: pip install ap_ds (fully automatic) macOS Installation: pip install ap_ds (fully automatic, requires network download) Linux: Clear explanation of non-support reasons and alternatives Design Philosophy Reiteration

Audio playback only, no editing/transcoding Serves real needs: Python desktop application developers Willingness to say no: No Linux support, no AAC support Market Positioning Upgrade From: "2.5MB Windows Python Audio Solution"

To: "3.36MB Cross-Platform Python Audio Solution"

v2.3.0 (January 31, 2026) - DAP Recording System Milestone: From playback to memory, introducing audio playback history recording system

DAP (Dvs Audio Playlist) is a major functional extension of the ap_ds library, providing developers with a complete solution for audio playback history recording. This is not a traditional playlist manager, but a lightweight system focused on recording and memory.

Core Characteristics

  1. Intelligent Automatic Recording

Seamless integration: Automatically triggered in play_from_file(), play_from_memory() Precise timing: Records only during actual playback, avoiding misoperations Complete metadata: Records path, duration, bitrate, channel count, and other key information 2. Lightweight Design Philosophy

Metadata only: No audio data storage, maintaining extremely low memory usage Intelligent deduplication: Automatically avoids duplicate records of the same file On-demand persistence: Runtime memory storage, explicit call required for file saving 3. Standardized File Format

Dedicated extension: .ap_ds-dap ensures format recognition Standard JSON: Easy parsing, editing, and exchange Format validation: Enforced extension, ensuring data integrity New API Details

DAP Recording Function List

  1. _add_to_dap_recordings(file_path: str) -> None Function: Add audio file metadata to memory record list

Characteristics:

Internal use only (automatically triggered via playback methods) Automatic audio metadata extraction (duration, bitrate, channel count) Intelligent deduplication mechanism Standardized recording format Usage Example:

Automatically triggered via playback

lib.play_from_file("song.mp3") # Automatically recorded to DAP

Log output: Recorded DAP file: song.mp3

  1. save_dap_to_json(save_path: str) -> bool Function: Save DAP records from memory to JSON file

Mandatory Requirements:

File extension must be .ap_ds-dap UTF-8 encoding for multilingual compatibility Pretty JSON format (2-space indentation) Return Value:

True: Save successful False: Save failed (error logged) Error Handling:

try: success = lib.save_dap_to_json("history.ap_ds-dap") except ValueError as e: print(f"Format error: {e}") # Extension doesn't meet requirements 3. get_dap_recordings() -> List[Dict] Function: Get deep copy of all current DAP records

Data Format:

[ { "path": "/music/song1.mp3", "duration": 240, "bitrate": 320000, "channels": 2 } ] Usage Scenarios:

Display playback history statistics Export to other formats Custom interface display 4. clear_dap_recordings() -> None Function: Clear all DAP records from memory

Characteristics:

Irreversible operation (unless already saved) Clear operation logging Immediate memory release Technical Architecture Design

Workflow:

User plays audio Calls play_from_file() Automatically calls _add_to_dap_recordings() Extracts metadata via get_audio_metadata_by_path() Creates standardized record Adds to _dap_recordings list Intelligent deduplication check Stores in memory User optionally calls save_dap_to_json() Extension validation JSON serialization File saving Memory Management Design:

class AudioLibrary: def init(self): # DAP memory storage self._dap_recordings = [] # List[Dict]

    # Approximate memory usage per record:
    # path: ~100 bytes
    # metadata: ~50 bytes
    # total: ~150 bytes/record

Performance Characteristics:

Record operation: O(1) complexity (adding new records) Deduplication check: O(n) complexity (linear check) Memory usage: ~1.5MB per 10,000 records File size: ~2-3MB per 10,000 records (JSON format) v2.3.1(February 9, 2026) - Documentation Update Milestone: Improved documentation and minor fixes

Changes:

Updated README.md with better examples and explanations Minor bug fixes in documentation examples Improved error messages for common usage scenarios Enhanced installation instructions for different platforms v2.3.2 (February 9, 2026) - Linux Support Enhancement Milestone: Extended Linux support with interactive setup

Major New Features:

  1. Interactive Linux Support

Three options for Linux users:

Use system-installed libraries (via package manager) Specify paths to compiled .so files Get detailed compilation instructions Smart platform detection and guidance

Unified API across all platforms

  1. Enhanced Cross-Platform Compatibility

Windows: Full auto-download support for SDL2 libraries macOS: Full auto-download support for SDL2 frameworks Linux: Interactive setup with user guidance 3. Improved User Experience

Clear platform-specific installation guidance Better error handling for library loading failures Enhanced troubleshooting documentation Technical Implementation:

def import_sdl2(): """Main function: Import SDL2 libraries with cross-platform support""" platform = sys.platform

if platform == "win32":
    # Windows - auto-download and load .dll
elif platform == "darwin":
    # macOS - auto-download and load .framework
elif platform.startswith("linux"):
    # Linux - interactive setup with options:
    print("Linux SDL2 Library Loading")
    print("Options:")
    print("1. Use system-installed libraries (if available)")
    print("2. Specify path to your compiled .so files")
    print("3. Get compilation instructions")
    # User interaction and library loading

Market Positioning Upgrade From: "3.36MB Cross-Platform Python Audio Solution"

To: "Complete Cross-Platform Python Audio Solution (Windows, macOS, Linux)"

Performance & Optimization:

Maintains lightweight design across all platforms Intelligent dependency management for each platform Consistent API experience regardless of platform Backward Compatibility:

All existing code continues to work unchanged New Linux support doesn't affect Windows/macOS users DAP system fully functional on all platforms v2.3.3 (February 9, 2026) - Critical Bug Fix & Platform Stabilization 🚨 This is a critical update that fixes a major bug. Previous versions (2.2.0, 2.3.0, 2.3.1, 2.3.2) have been yanked from PyPI due to this issue. Please upgrade immediately.

Critical Fix Resolved Cross-Platform Crash: Fixed a critical segmentation fault bug that prevented the library from functioning on macOS and Linux. The issue was caused by missing C function prototypes (ctypes argtypes/restype) on non-Windows platforms. Root Cause: In earlier versions, the platform-specific code only defined essential C function bindings (prototypes) for Windows (win32), causing memory access violations on other operating systems. Solution: The library now unconditionally defines all necessary C function bindings immediately after loading the SDL2 libraries, regardless of the operating system. This ensures stable and safe calls across Windows, macOS, and Linux. Enhanced Stability & Integrity Guaranteed Functionality: The core promise—pip install ap_ds followed by functional playback and parsing—is now reliably fulfilled on all three major platforms. Validated Workflow: The existing, user-friendly platform-handling logic (auto-download for Windows/macOS, interactive guidance for Linux) has been fully stabilized and verified end-to-end. What This Means for You For All Users: If you are using any version prior to 2.3.4, you are affected. Please run pip install --upgrade ap_ds now. For Linux/macOS Users: The library will now work correctly. The interactive Linux setup (choosing system libraries, specifying paths, or getting compilation help) functions as intended. For Windows Users: While you may not have experienced crashes, upgrading is essential to stay on the supported, stable release. Technical Summary This patch (2.3.2 → 2.3.4) is a PATCH-level version change under Semantic Versioning, signifying a backward-compatible bug fix that resolves incorrect behavior. The core API, features, and user experience remain unchanged and now operate reliably everywhere.

Maintainer's Note: We sincerely apologize for the disruption. Upholding stability and a professional standard for all users is our top priority. Version 2.3.4 represents that commitment.

v2.3.4 (February 10, 2026) - Linux Intelligent Import System 🚀 This update revolutionizes Linux support with an intelligent, multi-layer import system that dramatically improves user experience.

Intelligent Linux Import System Four-Layer Fallback Strategy: Implements a sophisticated, progressive library discovery system:

System Library Check: First attempts to use system-installed SDL2 libraries via standard library paths User Configuration: Checks for user-saved library paths from previous successful configurations Automatic Installation: Intelligently detects package manager and attempts non-interactive installation Interactive Guidance: Only presents manual options when all automatic methods fail Package Manager Detection & Auto-Install:

Ubuntu/Debian: Auto-detects apt-get and installs libsdl2-dev libsdl2-mixer-dev Fedora: Auto-detects dnf and installs SDL2-devel SDL2_mixer-devel Arch: Auto-detects pacman and installs sdl2 sdl2_mixer All installations use non-interactive mode (-y/--noconfirm) for seamless setup Configuration Persistence & Smart Memory Automatic Path Saving: User-specified library paths are automatically saved to both:

Environment variables (AP_DS_SDL2_PATH, AP_DS_SDL2_MIXER_PATH) Persistent config file (~/.config/ap_ds/sdl_paths.conf) One-Time Setup: Linux users only need to configure paths once; subsequent runs use saved configurations automatically

Configuration Validation: Saved paths are validated before use to ensure libraries are still accessible

Enhanced User Experience Reduced User Interaction: Most users will experience automatic setup without any manual input Clear Progress Feedback: Real-time status updates during each layer of the discovery process Intelligent Fallback: System gracefully degrades through each layer, always providing the next-best option Technical Implementation Highlights def import_sdl2(): """Intelligent multi-layer SDL2 import system""" if platform.startswith("linux"): # Layer 1: System library check if find_system_libraries(): return load_from_system()

    # Layer 2: User-configured paths
    if check_user_config():
        return load_from_user_config()
    
    # Layer 3: Automatic package manager installation
    if try_auto_install():
        return load_from_newly_installed()
    
    # Layer 4: Interactive guidance (only if all else fails)
    return interactive_setup_and_save()

Platform-Specific Improvements Windows/macOS: Unchanged - continue with seamless auto-download functionality Linux: Transformed from manual setup to intelligent automatic configuration All Platforms: Consistent API experience with zero changes to user code Performance & Stability Faster First-Time Setup: Linux users experience dramatically reduced setup time Reduced Error Rates: Intelligent validation prevents common configuration mistakes Enhanced Reliability: Multi-layer approach ensures maximum compatibility across diverse Linux distributions What This Means for You For New Linux Users: Installation is now as simple as Windows/macOS - pip install ap_ds followed by automatic setup in most cases For Existing Linux Users: Your saved configurations continue to work; new users benefit from the intelligent system For All Users: The library maintains its lightweight design (still under 4MB) while gaining sophisticated platform intelligence


License

This project is licensed under the DVS Audio Library (ap_ds) Open Source License Version 2.0. The full license text is provided below. By using, copying, modifying, or distributing the Software, you accept all terms and conditions of this license.


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 GitHub 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.


Final Notes

ap_ds is built on a simple philosophy: focus on playback and parsing, stay lightweight, and let developers build great applications.

We welcome feedback, bug reports, and contributions. For questions or issues, please reach out through the official channels.

Thank you for using ap_ds!

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

ap_ds-3.0.0.tar.gz (147.6 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

ap_ds-3.0.0-py3-none-any.whl (74.0 kB view details)

Uploaded Python 3

File details

Details for the file ap_ds-3.0.0.tar.gz.

File metadata

  • Download URL: ap_ds-3.0.0.tar.gz
  • Upload date:
  • Size: 147.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.10.12

File hashes

Hashes for ap_ds-3.0.0.tar.gz
Algorithm Hash digest
SHA256 d48a1930cd10b230bedfb945c72f6da1b9bde2a674fe428f941d5b35536ebbf4
MD5 b1ec9311ef77aaffe0ba4ecf867795c5
BLAKE2b-256 3ac557910283cdf3af8a92898091186f859cb74fa138d35bc0113123210e395e

See more details on using hashes here.

File details

Details for the file ap_ds-3.0.0-py3-none-any.whl.

File metadata

  • Download URL: ap_ds-3.0.0-py3-none-any.whl
  • Upload date:
  • Size: 74.0 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.10.12

File hashes

Hashes for ap_ds-3.0.0-py3-none-any.whl
Algorithm Hash digest
SHA256 f34bce914d894111db4f6144f7b3b1008c090fbb5e898526d763ee03707151c6
MD5 8eb8e02223a18aacf236078ae9da3890
BLAKE2b-256 66c8ee6f4d615db39e9ae972820916ab112fc55494168917efb6809bbc9ba0c2

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page