Openal turned out to be a bust. Attempt to improve sound playback reliability.
This commit is contained in:
77
sound.py
77
sound.py
@@ -48,12 +48,33 @@ def find_available_channel():
|
||||
channel.stop()
|
||||
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
|
||||
channel = pygame.mixer.Channel(0)
|
||||
channel = pygame.mixer.Channel(1)
|
||||
channel.stop()
|
||||
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():
|
||||
"""Return channel usage info for debugging."""
|
||||
total = pygame.mixer.get_num_channels()
|
||||
@@ -98,7 +119,7 @@ class Sound:
|
||||
pygame.mixer.pre_init(44100, -16, 2, 4096)
|
||||
pygame.mixer.init()
|
||||
pygame.mixer.set_num_channels(48)
|
||||
pygame.mixer.set_reserved(0)
|
||||
pygame.mixer.set_reserved(1) # Reserve channel 0 for cutscenes
|
||||
|
||||
self.load_sounds()
|
||||
|
||||
@@ -175,6 +196,7 @@ class Sound:
|
||||
|
||||
# Check if sound exists
|
||||
if soundName not in self.sounds:
|
||||
print(f"Sound not found: {soundName}")
|
||||
return None
|
||||
|
||||
# Handle cut scene mode
|
||||
@@ -186,12 +208,11 @@ class Sound:
|
||||
pygame.event.clear()
|
||||
pygame.mixer.stop()
|
||||
|
||||
# Play the sound with guaranteed channel allocation
|
||||
channel = self.sounds[soundName].play(-1 if loop else 0)
|
||||
if not channel:
|
||||
# If no channel available, force allocation
|
||||
channel = find_available_channel()
|
||||
channel.play(self.sounds[soundName], -1 if loop else 0)
|
||||
# Play the sound with retry logic
|
||||
channel, success = play_sound_with_retry(self.sounds[soundName], loop)
|
||||
if not success:
|
||||
print(f"Failed to play sound: {soundName}")
|
||||
return None
|
||||
|
||||
# Apply appropriate volume settings
|
||||
sfx_volume = self.volumeService.get_sfx_volume()
|
||||
@@ -308,12 +329,11 @@ class Sound:
|
||||
if not soundName:
|
||||
return None
|
||||
|
||||
# Play the sound with guaranteed channel allocation
|
||||
channel = self.sounds[soundName].play()
|
||||
if not channel:
|
||||
# If no channel available, force allocation
|
||||
channel = find_available_channel()
|
||||
channel.play(self.sounds[soundName])
|
||||
# Play the sound with retry logic
|
||||
channel, success = play_sound_with_retry(self.sounds[soundName], False)
|
||||
if not success:
|
||||
print(f"Failed to play falling sound: {soundName}")
|
||||
return None
|
||||
|
||||
if channel:
|
||||
channel.set_volume(
|
||||
@@ -330,7 +350,7 @@ class Sound:
|
||||
pygame.mixer.music.set_volume(self.volumeService.get_bgm_volume())
|
||||
pygame.mixer.music.play(-1)
|
||||
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):
|
||||
"""Adjust the master volume for all sounds."""
|
||||
@@ -432,7 +452,8 @@ def play_bgm(musicFile):
|
||||
pygame.mixer.music.load(musicFile)
|
||||
pygame.mixer.music.set_volume(volumeService.get_bgm_volume())
|
||||
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):
|
||||
"""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
|
||||
elif isinstance(sounds, dict) and isinstance(sound_or_name, str) and sound_or_name in sounds:
|
||||
# Play the sound with guaranteed channel allocation
|
||||
channel = sounds[sound_or_name].play(-1 if loop else 0)
|
||||
if not channel:
|
||||
# If no channel available, force allocation
|
||||
channel = find_available_channel()
|
||||
channel.play(sounds[sound_or_name], -1 if loop else 0)
|
||||
# Play the sound with retry logic
|
||||
channel, success = play_sound_with_retry(sounds[sound_or_name], loop)
|
||||
if not success:
|
||||
print(f"Failed to play sound: {sound_or_name}")
|
||||
return None
|
||||
|
||||
# Apply volume settings
|
||||
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:
|
||||
return None
|
||||
|
||||
# Play the sound with guaranteed channel allocation
|
||||
channel = sounds[matched_sound].play()
|
||||
if not channel:
|
||||
# If no channel available, force allocation
|
||||
channel = find_available_channel()
|
||||
channel.play(sounds[matched_sound])
|
||||
# Play the sound with retry logic
|
||||
channel, success = play_sound_with_retry(sounds[matched_sound], False)
|
||||
if not success:
|
||||
print(f"Failed to play falling sound: {matched_sound}")
|
||||
return None
|
||||
|
||||
if channel:
|
||||
channel.set_volume(
|
||||
|
Reference in New Issue
Block a user