Openal turned out to be a bust. Attempt to improve sound playback reliability.

This commit is contained in:
Storm Dragon
2025-09-18 19:30:24 -04:00
parent f84a115bc6
commit 1a6ad65139

View File

@@ -48,12 +48,33 @@ def find_available_channel():
channel.stop() channel.stop()
return channel return channel
# If no silent channels, stop the first busy channel as last resort # If no silent channels, stop channel 1 as last resort (avoid channel 0 - reserved for cutscenes)
# This ensures sounds always play rather than being silently dropped # This ensures sounds always play rather than being silently dropped
channel = pygame.mixer.Channel(0) channel = pygame.mixer.Channel(1)
channel.stop() channel.stop()
return channel return channel
def play_sound_with_retry(sound, loop=False, max_retries=3):
"""Play a sound with retry logic, returns (channel, success)."""
for attempt in range(max_retries):
# Try normal playback first
channel = sound.play(-1 if loop else 0)
if channel:
return channel, True
# If failed, force allocation and try again
try:
channel = find_available_channel()
channel.play(sound, -1 if loop else 0)
if channel.get_busy(): # Verify it's actually playing
return channel, True
except Exception as e:
if attempt == max_retries - 1: # Last attempt
print(f"Sound playback failed after {max_retries} attempts: {e}")
return None, False
return None, False
def get_channel_usage(): def get_channel_usage():
"""Return channel usage info for debugging.""" """Return channel usage info for debugging."""
total = pygame.mixer.get_num_channels() total = pygame.mixer.get_num_channels()
@@ -98,7 +119,7 @@ class Sound:
pygame.mixer.pre_init(44100, -16, 2, 4096) pygame.mixer.pre_init(44100, -16, 2, 4096)
pygame.mixer.init() pygame.mixer.init()
pygame.mixer.set_num_channels(48) pygame.mixer.set_num_channels(48)
pygame.mixer.set_reserved(0) pygame.mixer.set_reserved(1) # Reserve channel 0 for cutscenes
self.load_sounds() self.load_sounds()
@@ -175,6 +196,7 @@ class Sound:
# Check if sound exists # Check if sound exists
if soundName not in self.sounds: if soundName not in self.sounds:
print(f"Sound not found: {soundName}")
return None return None
# Handle cut scene mode # Handle cut scene mode
@@ -186,12 +208,11 @@ class Sound:
pygame.event.clear() pygame.event.clear()
pygame.mixer.stop() pygame.mixer.stop()
# Play the sound with guaranteed channel allocation # Play the sound with retry logic
channel = self.sounds[soundName].play(-1 if loop else 0) channel, success = play_sound_with_retry(self.sounds[soundName], loop)
if not channel: if not success:
# If no channel available, force allocation print(f"Failed to play sound: {soundName}")
channel = find_available_channel() return None
channel.play(self.sounds[soundName], -1 if loop else 0)
# Apply appropriate volume settings # Apply appropriate volume settings
sfx_volume = self.volumeService.get_sfx_volume() sfx_volume = self.volumeService.get_sfx_volume()
@@ -308,12 +329,11 @@ class Sound:
if not soundName: if not soundName:
return None return None
# Play the sound with guaranteed channel allocation # Play the sound with retry logic
channel = self.sounds[soundName].play() channel, success = play_sound_with_retry(self.sounds[soundName], False)
if not channel: if not success:
# If no channel available, force allocation print(f"Failed to play falling sound: {soundName}")
channel = find_available_channel() return None
channel.play(self.sounds[soundName])
if channel: if channel:
channel.set_volume( channel.set_volume(
@@ -330,7 +350,7 @@ class Sound:
pygame.mixer.music.set_volume(self.volumeService.get_bgm_volume()) pygame.mixer.music.set_volume(self.volumeService.get_bgm_volume())
pygame.mixer.music.play(-1) pygame.mixer.music.play(-1)
except Exception as e: except Exception as e:
print(f"Error playing background music: {e}") print(f"Failed to load background music {musicFile}: {e}")
def adjust_master_volume(self, change): def adjust_master_volume(self, change):
"""Adjust the master volume for all sounds.""" """Adjust the master volume for all sounds."""
@@ -432,7 +452,8 @@ def play_bgm(musicFile):
pygame.mixer.music.load(musicFile) pygame.mixer.music.load(musicFile)
pygame.mixer.music.set_volume(volumeService.get_bgm_volume()) pygame.mixer.music.set_volume(volumeService.get_bgm_volume())
pygame.mixer.music.play(-1) pygame.mixer.music.play(-1)
except: pass except Exception as e:
print(f"Failed to load background music {musicFile}: {e}")
def adjust_master_volume(change): def adjust_master_volume(change):
"""Adjust the master volume.""" """Adjust the master volume."""
@@ -498,12 +519,11 @@ def play_sound(sound_or_name, volume=1.0, loop=False, playerPos=None, objPos=Non
# Case 4: Sound name with dictionary # Case 4: Sound name with dictionary
elif isinstance(sounds, dict) and isinstance(sound_or_name, str) and sound_or_name in sounds: elif isinstance(sounds, dict) and isinstance(sound_or_name, str) and sound_or_name in sounds:
# Play the sound with guaranteed channel allocation # Play the sound with retry logic
channel = sounds[sound_or_name].play(-1 if loop else 0) channel, success = play_sound_with_retry(sounds[sound_or_name], loop)
if not channel: if not success:
# If no channel available, force allocation print(f"Failed to play sound: {sound_or_name}")
channel = find_available_channel() return None
channel.play(sounds[sound_or_name], -1 if loop else 0)
# Apply volume settings # Apply volume settings
sfx_vol = volumeService.get_sfx_volume() sfx_vol = volumeService.get_sfx_volume()
@@ -597,12 +617,11 @@ def play_random_falling(sounds, soundName, playerX, objectX, startY, currentY=0,
if not matched_sound: if not matched_sound:
return None return None
# Play the sound with guaranteed channel allocation # Play the sound with retry logic
channel = sounds[matched_sound].play() channel, success = play_sound_with_retry(sounds[matched_sound], False)
if not channel: if not success:
# If no channel available, force allocation print(f"Failed to play falling sound: {matched_sound}")
channel = find_available_channel() return None
channel.play(sounds[matched_sound])
if channel: if channel:
channel.set_volume( channel.set_volume(