CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-arcade

Arcade Game Development Library

Pending

Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

Overview
Eval results
Files

sound-system.mddocs/

Sound System

Audio playback capabilities with support for multiple formats, volume control, spatial audio, and sound effect management for creating immersive game experiences with music and sound effects.

Capabilities

Core Sound Classes

Base sound classes for loading, playing, and controlling audio in games.

class Sound:
    """
    Audio sound class for loading and playing sound effects and music.
    Supports various audio formats including WAV, OGG, and MP3.
    """
    def __init__(self, file_path: str, streaming: bool = False):
        """
        Create a sound object from an audio file.

        Args:
            file_path: Path to audio file or resource handle (e.g., ":resources:sounds/...")
            streaming: Whether to stream the audio (for large files like music)
        """
    
    # Properties
    file_path: str
    streaming: bool
    
    def play(self, volume: float = 1.0, pan: float = 0.0, loop: bool = False, speed: float = 1.0) -> object:
        """
        Play the sound with specified parameters.

        Args:
            volume: Volume level (0.0 = silent, 1.0 = full volume, >1.0 = amplified)
            pan: Stereo panning (-1.0 = full left, 0.0 = center, 1.0 = full right)
            loop: Whether to loop the sound continuously
            speed: Playback speed (1.0 = normal, 2.0 = double speed, 0.5 = half speed)

        Returns:
            Media player object for controlling playback
        """
    
    def stop(self) -> None:
        """Stop all instances of this sound."""
    
    def get_length(self) -> float:
        """
        Get the duration of the sound in seconds.

        Returns:
            Duration in seconds
        """
    
    def get_volume(self) -> float:
        """
        Get the current volume level.

        Returns:
            Volume level (0.0 to 1.0+)
        """
    
    def set_volume(self, volume: float) -> None:
        """
        Set the volume level for new playback instances.

        Args:
            volume: Volume level (0.0 = silent, 1.0 = full volume)
        """

Sound Loading and Management Functions

Utility functions for loading sounds and managing audio playback.

def load_sound(file_path: str, streaming: bool = False) -> arcade.Sound:
    """
    Load a sound file and return a Sound object.

    Args:
        file_path: Path to audio file or resource handle
        streaming: Whether to stream the audio (recommended for music)

    Returns:
        Sound object ready for playback
    """

def play_sound(sound: arcade.Sound, volume: float = 1.0, pan: float = 0.0, 
               loop: bool = False, speed: float = 1.0) -> object:
    """
    Play a sound with specified parameters.

    Args:
        sound: Sound object to play
        volume: Volume level (0.0 to 1.0+)
        pan: Stereo panning (-1.0 to 1.0)
        loop: Whether to loop the sound
        speed: Playback speed multiplier

    Returns:
        Media player object for controlling playback
    """

def stop_sound(player: object) -> None:
    """
    Stop a specific sound instance.

    Args:
        player: Media player object returned from play_sound()
    """

Audio Control and Effects

Advanced audio control functions for managing playback and applying effects.

def set_background_music(sound: arcade.Sound, volume: float = 0.5) -> None:
    """
    Set and start playing background music.

    Args:
        sound: Sound object to use as background music
        volume: Music volume level
    """

def stop_background_music() -> None:
    """Stop the currently playing background music."""

def pause_background_music() -> None:
    """Pause the background music (can be resumed)."""

def resume_background_music() -> None:
    """Resume paused background music."""

def get_background_music_volume() -> float:
    """
    Get the current background music volume.

    Returns:
        Volume level (0.0 to 1.0+)
    """

def set_background_music_volume(volume: float) -> None:
    """
    Set the background music volume.

    Args:
        volume: New volume level (0.0 to 1.0+)
    """

Spatial Audio

Functions for creating positional and directional audio effects.

def play_sound_3d(sound: arcade.Sound, listener_position: tuple[float, float], 
                  sound_position: tuple[float, float], max_distance: float = 1000.0,
                  volume: float = 1.0) -> object:
    """
    Play a sound with 3D spatial positioning.

    Args:
        sound: Sound object to play
        listener_position: (x, y) position of the listener
        sound_position: (x, y) position of the sound source
        max_distance: Maximum audible distance
        volume: Base volume level

    Returns:
        Media player object for controlling playback
    """

def update_sound_3d(player: object, listener_position: tuple[float, float],
                   sound_position: tuple[float, float], max_distance: float = 1000.0) -> None:
    """
    Update the 3D position of a playing sound.

    Args:
        player: Media player object from play_sound_3d()
        listener_position: New listener position
        sound_position: New sound source position
        max_distance: Maximum audible distance
    """

Audio Streaming

Classes and functions for handling streaming audio, particularly useful for music and large audio files.

class StreamingSound(arcade.Sound):
    """
    Specialized sound class for streaming large audio files from disk.
    More memory efficient for long audio tracks like background music.
    """
    def __init__(self, file_path: str, buffer_size: int = 65536):
        """
        Create a streaming sound.

        Args:
            file_path: Path to audio file
            buffer_size: Size of streaming buffer in bytes
        """
    
    buffer_size: int
    
    def preload_streaming(self, seconds: float = 2.0) -> None:
        """
        Preload a portion of the streaming audio to reduce latency.

        Args:
            seconds: Amount of audio to preload in seconds
        """

def create_sound_stream(file_path: str, buffer_size: int = 65536) -> arcade.StreamingSound:
    """
    Create a streaming sound object for large audio files.

    Args:
        file_path: Path to audio file
        buffer_size: Streaming buffer size

    Returns:
        StreamingSound object
    """

Audio Format Support

Information about supported audio formats and codec capabilities.

# Supported audio formats
SUPPORTED_FORMATS: list[str] = [
    ".wav",    # Waveform Audio File Format (uncompressed)
    ".ogg",    # Ogg Vorbis (compressed, open source)
    ".mp3",    # MPEG Audio Layer 3 (compressed)
    ".flac",   # Free Lossless Audio Codec
    ".aiff",   # Audio Interchange File Format
    ".au",     # Sun/Unix audio format
]

def is_audio_format_supported(file_path: str) -> bool:
    """
    Check if an audio file format is supported.

    Args:
        file_path: Path to audio file

    Returns:
        True if format is supported, False otherwise
    """

def get_audio_info(file_path: str) -> dict:
    """
    Get information about an audio file.

    Args:
        file_path: Path to audio file

    Returns:
        Dictionary with audio properties (duration, sample_rate, channels, etc.)
    """

Usage Examples

Basic Sound Effects

import arcade

class SoundEffectsGame(arcade.Window):
    def __init__(self):
        super().__init__(800, 600, "Sound Effects Example")
        
        self.sound_list = {}
        self.background_music = None
        
    def setup(self):
        # Load sound effects
        self.sound_list["jump"] = arcade.load_sound(":resources:sounds/jump1.wav")
        self.sound_list["coin"] = arcade.load_sound(":resources:sounds/coin1.wav") 
        self.sound_list["hit"] = arcade.load_sound(":resources:sounds/hit1.wav")
        self.sound_list["explosion"] = arcade.load_sound(":resources:sounds/explosion1.wav")
        
        # Load and start background music
        self.background_music = arcade.load_sound(":resources:music/1918.mp3", streaming=True)
        arcade.play_sound(self.background_music, volume=0.3, loop=True)
        
        # Create some sprites for interaction
        self.player_list = arcade.SpriteList()
        self.coin_list = arcade.SpriteList()
        
        # Player sprite
        self.player = arcade.Sprite(":resources:images/animated_characters/female_adventurer/femaleAdventurer_idle.png", 0.5)
        self.player.center_x = 400
        self.player.center_y = 300
        self.player_list.append(self.player)
        
        # Create coins
        for i in range(5):
            coin = arcade.Sprite(":resources:images/items/coinGold.png", 0.3)
            coin.center_x = 150 + i * 100
            coin.center_y = 200
            self.coin_list.append(coin)
    
    def on_draw(self):
        self.clear()
        self.player_list.draw()
        self.coin_list.draw()
        
        # Draw instructions
        arcade.draw_text("SPACE = Jump sound", 10, 550, arcade.color.WHITE, 16)
        arcade.draw_text("Move player to collect coins", 10, 525, arcade.color.WHITE, 16)
        arcade.draw_text("X = Explosion sound", 10, 500, arcade.color.WHITE, 16)
        arcade.draw_text("M = Toggle music", 10, 475, arcade.color.WHITE, 16)
    
    def on_update(self, delta_time):
        self.player_list.update()
        
        # Check for coin collisions
        coins_hit = arcade.check_for_collision_with_list(self.player, self.coin_list)
        for coin in coins_hit:
            # Play coin sound with slight volume variation
            arcade.play_sound(self.sound_list["coin"], volume=0.8 + (0.4 * random.random()))
            coin.remove_from_sprite_lists()
    
    def on_key_press(self, key, modifiers):
        if key == arcade.key.SPACE:
            # Play jump sound
            arcade.play_sound(self.sound_list["jump"], volume=0.5)
            
        elif key == arcade.key.X:
            # Play explosion with random pan
            pan = (random.random() - 0.5) * 2  # Random pan from -1.0 to 1.0
            arcade.play_sound(self.sound_list["explosion"], volume=0.7, pan=pan)
            
        elif key == arcade.key.M:
            # Toggle background music
            if self.background_music_playing:
                arcade.stop_sound(self.background_music)
                self.background_music_playing = False
            else:
                arcade.play_sound(self.background_music, volume=0.3, loop=True)
                self.background_music_playing = True
        
        # Movement controls
        elif key == arcade.key.LEFT:
            self.player.change_x = -5
        elif key == arcade.key.RIGHT:
            self.player.change_x = 5
        elif key == arcade.key.UP:
            self.player.change_y = 5
        elif key == arcade.key.DOWN:
            self.player.change_y = -5
    
    def on_key_release(self, key, modifiers):
        if key in (arcade.key.LEFT, arcade.key.RIGHT):
            self.player.change_x = 0
        elif key in (arcade.key.UP, arcade.key.DOWN):
            self.player.change_y = 0

def main():
    game = SoundEffectsGame()
    game.setup()
    arcade.run()

if __name__ == "__main__":
    main()

3D Spatial Audio Example

import arcade
import math

class SpatialAudioGame(arcade.Window):
    def __init__(self):
        super().__init__(800, 600, "3D Spatial Audio")
        
        self.player_list = arcade.SpriteList()
        self.sound_source_list = arcade.SpriteList()
        self.ambient_sound = None
        self.sound_players = []
        
    def setup(self):
        # Create player (listener)
        self.player = arcade.Sprite(":resources:images/animated_characters/female_adventurer/femaleAdventurer_idle.png", 0.4)
        self.player.center_x = 400
        self.player.center_y = 300
        self.player_list.append(self.player)
        
        # Create sound sources around the map
        self.sound_sources = []
        
        # Campfire sound source
        campfire = arcade.Sprite(":resources:images/tiles/torch1.png", 0.5)
        campfire.center_x = 200
        campfire.center_y = 200
        campfire.sound = arcade.load_sound(":resources:sounds/fire.wav")
        self.sound_source_list.append(campfire)
        self.sound_sources.append(campfire)
        
        # Water sound source  
        water = arcade.Sprite(":resources:images/tiles/water.png", 0.5)
        water.center_x = 600
        water.center_y = 400
        water.sound = arcade.load_sound(":resources:sounds/water.wav")
        self.sound_source_list.append(water)
        self.sound_sources.append(water)
        
        # Start playing spatial sounds
        self.start_spatial_sounds()
        
    def start_spatial_sounds(self):
        """Start playing all spatial sound sources."""
        for source in self.sound_sources:
            player = arcade.play_sound_3d(
                source.sound,
                listener_position=(self.player.center_x, self.player.center_y),
                sound_position=(source.center_x, source.center_y),
                max_distance=300.0,
                volume=0.5
            )
            source.player = player
            self.sound_players.append(player)
    
    def update_spatial_audio(self):
        """Update 3D audio based on player position."""
        listener_pos = (self.player.center_x, self.player.center_y)
        
        for source in self.sound_sources:
            source_pos = (source.center_x, source.center_y)
            
            # Update 3D position
            arcade.update_sound_3d(
                source.player,
                listener_position=listener_pos,
                sound_position=source_pos,
                max_distance=300.0
            )
    
    def on_draw(self):
        self.clear()
        
        # Draw sound source ranges
        for source in self.sound_sources:
            # Draw audible range circle
            arcade.draw_circle_outline(source.center_x, source.center_y, 300, arcade.color.YELLOW, 2)
            
        self.sound_source_list.draw()
        self.player_list.draw()
        
        # Draw instructions and info
        arcade.draw_text("Move with arrow keys", 10, 570, arcade.color.WHITE, 16)
        arcade.draw_text("Listen to spatial audio effects", 10, 545, arcade.color.WHITE, 16)
        
        # Draw distance to nearest sound source
        if self.sound_sources:
            nearest = min(self.sound_sources, 
                         key=lambda s: arcade.get_distance_between_sprites(self.player, s))
            distance = arcade.get_distance_between_sprites(self.player, nearest)
            arcade.draw_text(f"Distance to nearest source: {distance:.1f}", 10, 520, arcade.color.WHITE, 16)
    
    def on_update(self, delta_time):
        self.player_list.update()
        self.update_spatial_audio()
        
    def on_key_press(self, key, modifiers):
        if key == arcade.key.LEFT:
            self.player.change_x = -5
        elif key == arcade.key.RIGHT:
            self.player.change_x = 5
        elif key == arcade.key.UP:
            self.player.change_y = 5
        elif key == arcade.key.DOWN:
            self.player.change_y = -5
    
    def on_key_release(self, key, modifiers):
        if key in (arcade.key.LEFT, arcade.key.RIGHT):
            self.player.change_x = 0
        elif key in (arcade.key.UP, arcade.key.DOWN):
            self.player.change_y = 0

def main():
    game = SpatialAudioGame()
    game.setup()
    arcade.run()

if __name__ == "__main__":
    main()

Music Player with Controls

import arcade

class MusicPlayerExample(arcade.Window):
    def __init__(self):
        super().__init__(800, 600, "Music Player")
        
        self.music_list = []
        self.current_track = 0
        self.current_player = None
        self.is_playing = False
        self.volume = 0.7
        
    def setup(self):
        # Load music tracks
        self.music_list = [
            arcade.load_sound(":resources:music/1918.mp3", streaming=True),
            arcade.load_sound(":resources:music/funkyrobot.mp3", streaming=True),
        ]
        
        # Start with first track
        self.play_current_track()
        
    def play_current_track(self):
        """Start playing the current track."""
        if self.current_player:
            arcade.stop_sound(self.current_player)
        
        if self.music_list:
            music = self.music_list[self.current_track]
            self.current_player = arcade.play_sound(music, volume=self.volume, loop=True)
            self.is_playing = True
    
    def next_track(self):
        """Switch to the next track."""
        if self.music_list:
            self.current_track = (self.current_track + 1) % len(self.music_list)
            self.play_current_track()
    
    def previous_track(self):
        """Switch to the previous track."""
        if self.music_list:
            self.current_track = (self.current_track - 1) % len(self.music_list)
            self.play_current_track()
    
    def toggle_playback(self):
        """Toggle play/pause."""
        if self.is_playing:
            arcade.pause_background_music()
            self.is_playing = False
        else:
            arcade.resume_background_music()
            self.is_playing = True
    
    def adjust_volume(self, change: float):
        """Adjust the volume up or down."""
        self.volume = max(0.0, min(1.0, self.volume + change))
        if self.current_player:
            arcade.set_background_music_volume(self.volume)
    
    def on_draw(self):
        self.clear()
        
        # Draw music player interface
        arcade.draw_text("Music Player", 400, 500, arcade.color.WHITE, 36, anchor_x="center")
        
        if self.music_list:
            track_name = f"Track {self.current_track + 1}/{len(self.music_list)}"
            arcade.draw_text(track_name, 400, 450, arcade.color.WHITE, 24, anchor_x="center")
        
        status = "Playing" if self.is_playing else "Paused"
        arcade.draw_text(f"Status: {status}", 400, 400, arcade.color.WHITE, 20, anchor_x="center")
        
        arcade.draw_text(f"Volume: {self.volume:.1f}", 400, 350, arcade.color.WHITE, 20, anchor_x="center")
        
        # Draw controls
        controls = [
            "SPACE = Play/Pause",
            "N = Next Track", 
            "P = Previous Track",
            "+ = Volume Up",
            "- = Volume Down"
        ]
        
        for i, control in enumerate(controls):
            arcade.draw_text(control, 400, 280 - i * 30, arcade.color.LIGHT_GRAY, 16, anchor_x="center")
    
    def on_key_press(self, key, modifiers):
        if key == arcade.key.SPACE:
            self.toggle_playback()
        elif key == arcade.key.N:
            self.next_track()
        elif key == arcade.key.P:
            self.previous_track()
        elif key == arcade.key.PLUS or key == arcade.key.EQUAL:
            self.adjust_volume(0.1)
        elif key == arcade.key.MINUS:
            self.adjust_volume(-0.1)

def main():
    game = MusicPlayerExample()
    game.setup()
    arcade.run()

if __name__ == "__main__":
    main()

Install with Tessl CLI

npx tessl i tessl/pypi-arcade

docs

camera-system.md

core-graphics.md

gui-framework.md

index.md

math-utilities.md

physics-engines.md

sound-system.md

specialized-features.md

sprite-system.md

texture-management.md

window-management.md

tile.json