Files
snake/sound_manager.py

105 lines
3.4 KiB
Python

"""Sound and music management."""
import time
import pygame
from pathlib import Path
from typing import Optional
from multiprocessing import Queue
class SoundManager:
"""Manages sound effects and music in a separate process."""
def __init__(self):
self.sounds = {}
self.music_file: Optional[str] = None
self.effects_dir = Path(__file__).parent / 'effects'
self.music_dir = Path(__file__).parent / 'music'
def initialize(self) -> None:
"""Initialize pygame mixer."""
pygame.mixer.init()
self._load_effects()
self._load_music()
def _load_effects(self) -> None:
"""Load all sound effects."""
effect_files = {
'eat': 'bing.mp3',
'wall': 'wall.mp3',
'self': 'cut.mp3',
'over': 'over.mp3',
'start': 'start2.mp3',
}
for effect_name, filename in effect_files.items():
effect_path = self.effects_dir / filename
try:
if effect_path.exists():
self.sounds[effect_name] = pygame.mixer.Sound(str(effect_path))
except pygame.error as e:
print(f"Warning: Could not load effect {filename}: {e}")
def _load_music(self) -> None:
"""Load background music."""
# Try different music files in order of preference
music_options = ['bubbles.ogg', 'QonsVivaEveryone.mp3']
for filename in music_options:
music_path = self.music_dir / filename
if music_path.exists():
self.music_file = str(music_path)
break
def play_effect(self, effect_name: str) -> None:
"""Play a sound effect."""
if effect_name in self.sounds:
try:
self.sounds[effect_name].play()
except pygame.error as e:
print(f"Warning: Could not play effect {effect_name}: {e}")
def start_music(self) -> None:
"""Start playing background music."""
if self.music_file:
try:
pygame.mixer.music.load(self.music_file)
pygame.mixer.music.set_volume(0.5)
pygame.mixer.music.play(-1)
except pygame.error as e:
print(f"Warning: Could not play music: {e}")
def stop_music(self) -> None:
"""Stop playing music."""
pygame.mixer.music.stop()
def pause_music(self) -> None:
"""Pause music."""
pygame.mixer.music.pause()
def unpause_music(self) -> None:
"""Resume music."""
pygame.mixer.music.unpause()
def process_queue(self, sound_queue: Queue) -> None:
"""Main loop for processing sound commands from the queue."""
self.initialize()
while True:
if not sound_queue.empty():
command = sound_queue.get()
# Handle various commands
if command in self.sounds:
self.play_effect(command)
elif command == 'music.start':
self.start_music()
elif command == 'music.stop':
self.stop_music()
elif command == 'music.pause':
self.pause_music()
elif command == 'music.unpause':
self.unpause_music()
elif command == 'quit':
break
time.sleep(0.1)