Experimental sound improvements. I'm about to say to hell with it and try using openal.

This commit is contained in:
Storm Dragon
2025-09-18 16:02:30 -04:00
parent 7555429433
commit f84a115bc6

View File

@@ -19,6 +19,72 @@ from .services import VolumeService
# Global instance for backward compatibility
volumeService = VolumeService.get_instance()
def find_silent_channels():
"""Find channels that are playing but with zero volume (effectively silent)."""
silent_channels = []
for n in range(pygame.mixer.get_num_channels()):
channel = pygame.mixer.Channel(n)
if channel.get_busy():
# Get current volume setting (single value for both channels)
volume = channel.get_volume()
# Consider silent if volume is effectively zero
if volume <= 0.001:
silent_channels.append(channel)
return silent_channels
def find_available_channel():
"""Find an available channel, prioritizing silent channels over stopping active ones."""
# Try to find an idle channel first
for n in range(pygame.mixer.get_num_channels()):
channel = pygame.mixer.Channel(n)
if not channel.get_busy():
return channel
# If no idle channels, look for silent ones to reclaim
silent_channels = find_silent_channels()
if silent_channels:
# Stop the first silent channel and return it
channel = silent_channels[0]
channel.stop()
return channel
# If no silent channels, stop the first busy channel as last resort
# This ensures sounds always play rather than being silently dropped
channel = pygame.mixer.Channel(0)
channel.stop()
return channel
def get_channel_usage():
"""Return channel usage info for debugging."""
total = pygame.mixer.get_num_channels()
busy = sum(1 for n in range(total) if pygame.mixer.Channel(n).get_busy())
silent = len(find_silent_channels())
return f"Channels: {busy}/{total} busy ({silent} silent)"
def print_channel_debug():
"""Print detailed channel usage for debugging."""
total = pygame.mixer.get_num_channels()
print(f"Channel usage: {get_channel_usage()}")
busy_channels = []
silent_channels = []
for n in range(total):
channel = pygame.mixer.Channel(n)
if channel.get_busy():
volume = channel.get_volume()
if volume <= 0.001:
silent_channels.append(n)
else:
busy_channels.append(n)
if busy_channels:
print(f"Active channels: {busy_channels}")
if silent_channels:
print(f"Silent channels: {silent_channels}")
if not busy_channels and not silent_channels:
print("No busy channels")
class Sound:
"""Handles sound loading and playback."""
@@ -120,10 +186,12 @@ class Sound:
pygame.event.clear()
pygame.mixer.stop()
# Play the sound
# Play the sound with guaranteed channel allocation
channel = self.sounds[soundName].play(-1 if loop else 0)
if not channel:
return None
# If no channel available, force allocation
channel = find_available_channel()
channel.play(self.sounds[soundName], -1 if loop else 0)
# Apply appropriate volume settings
sfx_volume = self.volumeService.get_sfx_volume()
@@ -240,8 +308,13 @@ class Sound:
if not soundName:
return None
# Play the sound
# 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])
if channel:
channel.set_volume(
finalLeft * self.volumeService.sfxVolume,
@@ -425,10 +498,12 @@ 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
# Play the sound with guaranteed channel allocation
channel = sounds[sound_or_name].play(-1 if loop else 0)
if not channel:
return None
# If no channel available, force allocation
channel = find_available_channel()
channel.play(sounds[sound_or_name], -1 if loop else 0)
# Apply volume settings
sfx_vol = volumeService.get_sfx_volume()
@@ -522,8 +597,13 @@ def play_random_falling(sounds, soundName, playerX, objectX, startY, currentY=0,
if not matched_sound:
return None
# Play the sound
# 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])
if channel:
channel.set_volume(
finalLeft * volumeService.sfxVolume,