CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-pysdl2

Pure Python wrapper around SDL2 libraries for cross-platform multimedia development

Pending

Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

Overview
Eval results
Files

audio.mddocs/

Audio System

Comprehensive audio playback, recording, and mixing capabilities through SDL2 audio and SDL2_mixer integration. PySDL2 provides both low-level audio device control and high-level audio mixing functions.

Capabilities

Core Audio Device Management

Low-level audio device functions for playback and recording.

def SDL_GetNumAudioDevices(iscapture: int) -> int:
    """
    Get number of available audio devices.
    
    Parameters:
    - iscapture: 0 for playback devices, 1 for recording devices
    
    Returns:
    Number of available devices
    """

def SDL_GetAudioDeviceName(index: int, iscapture: int) -> bytes:
    """
    Get name of audio device.
    
    Parameters:
    - index: device index
    - iscapture: 0 for playback, 1 for recording
    
    Returns:
    Device name as bytes
    """

def SDL_OpenAudioDevice(device: bytes, iscapture: int, desired: SDL_AudioSpec, 
                       obtained: SDL_AudioSpec, allowed_changes: int) -> int:
    """
    Open audio device for playback or recording.
    
    Parameters:
    - device: device name (None for default)
    - iscapture: 0 for playback, 1 for recording
    - desired: desired audio specification
    - obtained: actual audio specification (may differ from desired)
    - allowed_changes: allowed changes to audio spec
    
    Returns:
    Audio device ID (>= 2) on success, 0 on failure
    """

def SDL_CloseAudioDevice(dev: int) -> None:
    """Close audio device."""

def SDL_PauseAudioDevice(dev: int, pause_on: int) -> None:
    """Pause or unpause audio device."""

def SDL_GetAudioDeviceStatus(dev: int) -> int:
    """Get audio device status."""

Audio Specification and Format

Audio format constants and specification structure.

# Audio format constants
SDL_AUDIO_MASK_BITSIZE: int = 0xFF
SDL_AUDIO_MASK_DATATYPE: int = (1 << 8)
SDL_AUDIO_MASK_ENDIAN: int = (1 << 12)
SDL_AUDIO_MASK_SIGNED: int = (1 << 15)

# Specific audio formats
AUDIO_U8: int = 0x0008      # Unsigned 8-bit
AUDIO_S8: int = 0x8008      # Signed 8-bit
AUDIO_U16LSB: int = 0x0010  # Unsigned 16-bit little-endian
AUDIO_S16LSB: int = 0x8010  # Signed 16-bit little-endian
AUDIO_U16MSB: int = 0x1010  # Unsigned 16-bit big-endian
AUDIO_S16MSB: int = 0x9010  # Signed 16-bit big-endian
AUDIO_U16: int = AUDIO_U16LSB
AUDIO_S16: int = AUDIO_S16LSB
AUDIO_S32LSB: int = 0x8020  # Signed 32-bit little-endian
AUDIO_S32MSB: int = 0x9020  # Signed 32-bit big-endian
AUDIO_S32: int = AUDIO_S32LSB
AUDIO_F32LSB: int = 0x8120  # 32-bit floating point little-endian
AUDIO_F32MSB: int = 0x9120  # 32-bit floating point big-endian
AUDIO_F32: int = AUDIO_F32LSB

class SDL_AudioSpec:
    """Audio specification structure."""
    freq: int           # Sample rate (samples per second)
    format: int         # Audio format (AUDIO_S16, etc.)
    channels: int       # Number of channels (1=mono, 2=stereo)
    silence: int        # Silence value for audio format
    samples: int        # Audio buffer size in samples (power of 2)
    padding: int        # Padding
    size: int          # Audio buffer size in bytes
    callback: ctypes.CFUNCTYPE  # Audio callback function
    userdata: ctypes.c_void_p   # User data for callback

Audio Conversion

Functions for converting between audio formats.

def SDL_BuildAudioCVT(cvt: SDL_AudioCVT, src_format: int, src_channels: int, src_rate: int,
                     dst_format: int, dst_channels: int, dst_rate: int) -> int:
    """Build audio conversion structure."""

def SDL_ConvertAudio(cvt: SDL_AudioCVT) -> int:
    """Convert audio data using conversion structure."""

class SDL_AudioCVT:
    """Audio conversion structure."""
    needed: int         # Set to 1 if conversion needed
    src_format: int     # Source audio format
    dst_format: int     # Destination audio format
    rate_incr: float    # Rate conversion increment
    buf: ctypes.POINTER(ctypes.c_uint8)  # Audio buffer
    len: int           # Original audio buffer length
    len_cvt: int       # Converted audio buffer length
    len_mult: int      # Buffer length multiplier
    len_ratio: float   # Length ratio

SDL2_mixer Integration

High-level audio mixing functions through SDL2_mixer.

def Mix_OpenAudio(frequency: int, format: int, channels: int, chunksize: int) -> int:
    """
    Initialize audio mixer.
    
    Parameters:
    - frequency: sample rate (22050, 44100, etc.)
    - format: audio format (MIX_DEFAULT_FORMAT recommended)
    - channels: number of output channels (1=mono, 2=stereo)
    - chunksize: audio buffer size in samples
    
    Returns:
    0 on success, -1 on failure
    """

def Mix_CloseAudio() -> None:
    """Close audio mixer."""

def Mix_QuerySpec(frequency: ctypes.POINTER(ctypes.c_int), format: ctypes.POINTER(ctypes.c_uint16),
                 channels: ctypes.POINTER(ctypes.c_int)) -> int:
    """Query mixer audio format."""

def Mix_AllocateChannels(numchans: int) -> int:
    """Set number of mixing channels."""

Sound Loading and Playback

Functions for loading and playing sound effects.

def Mix_LoadWAV(file: bytes) -> Mix_Chunk:
    """
    Load WAV audio file.
    
    Parameters:
    - file: path to WAV file as bytes
    
    Returns:
    Mix_Chunk object or None on failure
    """

def Mix_LoadWAV_RW(src: SDL_RWops, freesrc: int) -> Mix_Chunk:
    """Load WAV from SDL_RWops."""

def Mix_FreeChunk(chunk: Mix_Chunk) -> None:
    """Free audio chunk."""

def Mix_PlayChannel(channel: int, chunk: Mix_Chunk, loops: int) -> int:
    """
    Play audio chunk on channel.
    
    Parameters:
    - channel: channel to play on (-1 for first available)
    - chunk: audio chunk to play
    - loops: number of loops (-1 for infinite)
    
    Returns:
    Channel number playing on, -1 on error
    """

def Mix_PlayChannelTimed(channel: int, chunk: Mix_Chunk, loops: int, ticks: int) -> int:
    """Play audio chunk with time limit."""

def Mix_Volume(channel: int, volume: int) -> int:
    """
    Set channel volume.
    
    Parameters:
    - channel: channel number (-1 for all channels)
    - volume: volume level (0-128)
    
    Returns:
    Previous volume level
    """

def Mix_Pause(channel: int) -> None:
    """Pause channel."""

def Mix_Resume(channel: int) -> None:
    """Resume channel."""

def Mix_HaltChannel(channel: int) -> int:
    """Stop playing on channel."""

def Mix_Playing(channel: int) -> int:
    """Check if channel is playing."""

def Mix_Paused(channel: int) -> int:
    """Check if channel is paused."""

Music Loading and Playback

Functions for loading and playing background music.

def Mix_LoadMUS(file: bytes) -> Mix_Music:
    """
    Load music file.
    
    Parameters:
    - file: path to music file as bytes
    
    Returns:
    Mix_Music object or None on failure
    """

def Mix_LoadMUS_RW(src: SDL_RWops, freesrc: int) -> Mix_Music:
    """Load music from SDL_RWops."""

def Mix_FreeMusic(music: Mix_Music) -> None:
    """Free music."""

def Mix_PlayMusic(music: Mix_Music, loops: int) -> int:
    """
    Play music.
    
    Parameters:
    - music: music to play
    - loops: number of loops (-1 for infinite)
    
    Returns:
    0 on success, -1 on error
    """

def Mix_FadeInMusic(music: Mix_Music, loops: int, ms: int) -> int:
    """Play music with fade-in effect."""

def Mix_VolumeMusic(volume: int) -> int:
    """
    Set music volume.
    
    Parameters:
    - volume: volume level (0-128)
    
    Returns:
    Previous volume level
    """

def Mix_PauseMusic() -> None:
    """Pause music."""

def Mix_ResumeMusic() -> None:
    """Resume music."""

def Mix_HaltMusic() -> int:
    """Stop music."""

def Mix_FadeOutMusic(ms: int) -> int:
    """Fade out music over time."""

def Mix_PlayingMusic() -> int:
    """Check if music is playing."""

def Mix_PausedMusic() -> int:
    """Check if music is paused."""

def Mix_GetMusicType(music: Mix_Music) -> int:
    """Get music type."""

Mixer Constants and Types

Constants and types for SDL2_mixer.

# Mixer format constants
MIX_DEFAULT_FREQUENCY: int = 22050
MIX_DEFAULT_FORMAT: int = AUDIO_S16LSB
MIX_DEFAULT_CHANNELS: int = 2
MIX_MAX_VOLUME: int = 128

# Mixer initialization flags
MIX_INIT_FLAC: int = 0x00000001
MIX_INIT_MOD: int = 0x00000002
MIX_INIT_MP3: int = 0x00000008
MIX_INIT_OGG: int = 0x00000010
MIX_INIT_MID: int = 0x00000020
MIX_INIT_OPUS: int = 0x00000040

# Music types
MUS_NONE: int = 0
MUS_CMD: int = 1
MUS_WAV: int = 2
MUS_MOD: int = 3
MUS_MID: int = 4
MUS_OGG: int = 5
MUS_MP3: int = 6
MUS_MP3_MAD_UNUSED: int = 7
MUS_FLAC: int = 8
MUS_MODPLUG_UNUSED: int = 9
MUS_OPUS: int = 10

class Mix_Chunk:
    """Audio chunk structure."""
    allocated: int      # 1 if allocated, 0 if not
    abuf: ctypes.POINTER(ctypes.c_uint8)  # Audio buffer
    alen: int          # Audio buffer length
    volume: int        # Volume (0-128)

class Mix_Music:
    """Opaque music structure."""

Audio Callbacks and Effects

Advanced audio processing functions.

def Mix_RegisterEffect(chan: int, f: ctypes.CFUNCTYPE, d: ctypes.CFUNCTYPE, arg: ctypes.c_void_p) -> int:
    """Register audio effect function."""

def Mix_UnregisterEffect(channel: int, f: ctypes.CFUNCTYPE) -> int:
    """Unregister audio effect function."""

def Mix_UnregisterAllEffects(channel: int) -> int:
    """Unregister all effects on channel."""

def Mix_SetPostMix(mix_func: ctypes.CFUNCTYPE, arg: ctypes.c_void_p) -> None:
    """Set post-mix callback function."""

def Mix_HookMusic(mix_func: ctypes.CFUNCTYPE, arg: ctypes.c_void_p) -> None:
    """Set music hook callback function."""

def Mix_HookMusicFinished(music_finished: ctypes.CFUNCTYPE) -> None:
    """Set callback for when music finishes."""

def Mix_ChannelFinished(channel_finished: ctypes.CFUNCTYPE) -> None:
    """Set callback for when channel finishes."""

Usage Examples

Basic Sound Playback

import sdl2
import sdl2.sdlmixer

# Initialize SDL2 with audio
sdl2.SDL_Init(sdl2.SDL_INIT_AUDIO)

# Initialize mixer
if sdl2.sdlmixer.Mix_OpenAudio(22050, sdl2.sdlmixer.MIX_DEFAULT_FORMAT, 2, 1024) == -1:
    print("Failed to initialize mixer")
    exit(1)

# Load sound effect
sound = sdl2.sdlmixer.Mix_LoadWAV(b"sound.wav")
if not sound:
    print("Failed to load sound")
    exit(1)

# Load background music
music = sdl2.sdlmixer.Mix_LoadMUS(b"music.ogg")
if not music:
    print("Failed to load music")
    exit(1)

# Play background music
sdl2.sdlmixer.Mix_PlayMusic(music, -1)  # Loop forever

# Main loop
running = True
event = sdl2.SDL_Event()

while running:
    while sdl2.SDL_PollEvent(event):
        if event.type == sdl2.SDL_QUIT:
            running = False
        elif event.type == sdl2.SDL_KEYDOWN:
            if event.key.keysym.sym == sdl2.SDLK_SPACE:
                # Play sound effect
                sdl2.sdlmixer.Mix_PlayChannel(-1, sound, 0)

# Cleanup
sdl2.sdlmixer.Mix_FreeChunk(sound)
sdl2.sdlmixer.Mix_FreeMusic(music)
sdl2.sdlmixer.Mix_CloseAudio()
sdl2.SDL_Quit()

Low-Level Audio Device Control

import sdl2
import ctypes

def audio_callback(userdata, stream, length):
    """Audio callback function."""
    # Fill stream with audio data
    # This example just fills with silence
    ctypes.memset(stream, 0, length)

# Initialize SDL2
sdl2.SDL_Init(sdl2.SDL_INIT_AUDIO)

# Set up audio specification
audio_spec = sdl2.SDL_AudioSpec()
audio_spec.freq = 44100
audio_spec.format = sdl2.AUDIO_S16LSB
audio_spec.channels = 2
audio_spec.samples = 1024
audio_spec.callback = audio_callback
audio_spec.userdata = None

# Open audio device
obtained = sdl2.SDL_AudioSpec()
device_id = sdl2.SDL_OpenAudioDevice(None, 0, audio_spec, obtained, 0)

if device_id == 0:
    print("Failed to open audio device")
    exit(1)

print(f"Opened audio device {device_id}")
print(f"Format: {obtained.format}, Freq: {obtained.freq}, Channels: {obtained.channels}")

# Start audio playback
sdl2.SDL_PauseAudioDevice(device_id, 0)

# Run for a while
sdl2.SDL_Delay(5000)

# Stop and close
sdl2.SDL_PauseAudioDevice(device_id, 1)
sdl2.SDL_CloseAudioDevice(device_id)
sdl2.SDL_Quit()

Audio Format Conversion

import sdl2
import ctypes

# Initialize SDL2
sdl2.SDL_Init(sdl2.SDL_INIT_AUDIO)

# Set up conversion from 16-bit stereo to 8-bit mono
cvt = sdl2.SDL_AudioCVT()
result = sdl2.SDL_BuildAudioCVT(
    cvt,
    sdl2.AUDIO_S16LSB, 2, 44100,  # Source: 16-bit stereo 44.1kHz
    sdl2.AUDIO_U8, 1, 22050       # Dest: 8-bit mono 22.05kHz
)

if result == -1:
    print("Audio conversion not possible")
    exit(1)
elif result == 0:
    print("No conversion needed")
    exit(0)

# Allocate buffer for conversion (example with 1024 samples)
original_len = 1024 * 2 * 2  # 1024 samples * 2 channels * 2 bytes per sample
cvt.len = original_len
cvt.buf = (ctypes.c_uint8 * (original_len * cvt.len_mult))()

# Fill buffer with sample data (normally you'd load from file)
# ... fill cvt.buf with audio data ...

# Perform conversion
if sdl2.SDL_ConvertAudio(cvt) == 0:
    print(f"Conversion successful. New length: {cvt.len_cvt}")
else:
    print("Conversion failed")

sdl2.SDL_Quit()

Volume and Effects Control

import sdl2
import sdl2.sdlmixer

# Initialize SDL2 and mixer
sdl2.SDL_Init(sdl2.SDL_INIT_AUDIO)
sdl2.sdlmixer.Mix_OpenAudio(44100, sdl2.sdlmixer.MIX_DEFAULT_FORMAT, 2, 1024)

# Load sound
sound = sdl2.sdlmixer.Mix_LoadWAV(b"sound.wav")

# Set channel volume to 50%
sdl2.sdlmixer.Mix_Volume(0, sdl2.sdlmixer.MIX_MAX_VOLUME // 2)

# Play sound on channel 0
channel = sdl2.sdlmixer.Mix_PlayChannel(0, sound, 0)

# Wait for sound to finish
while sdl2.sdlmixer.Mix_Playing(channel):
    sdl2.SDL_Delay(100)

# Play with fade-in effect
sdl2.sdlmixer.Mix_FadeInChannelTimed(0, sound, 0, 1000, 5000)  # 1s fade-in, 5s total

# Cleanup
sdl2.sdlmixer.Mix_FreeChunk(sound)
sdl2.sdlmixer.Mix_CloseAudio()
sdl2.SDL_Quit()

Install with Tessl CLI

npx tessl i tessl/pypi-pysdl2

docs

audio.md

events-input.md

file-io.md

fonts-text.md

graphics-rendering.md

image-processing.md

index.md

joystick-input.md

sprites-animation.md

system-utils.md

timer.md

window-display.md

tile.json