Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 3b01662d98 | |||
| 5e926fa7eb | |||
| e272da1177 | |||
| 1bb9e18ea2 |
+33
-15
@@ -53,22 +53,40 @@ def initialize_gui(gameTitle):
|
|||||||
# Enable key repeat for volume controls
|
# Enable key repeat for volume controls
|
||||||
pygame.key.set_repeat(500, 100)
|
pygame.key.set_repeat(500, 100)
|
||||||
|
|
||||||
# Load sound files
|
# Load sound files recursively including subdirectories
|
||||||
try:
|
|
||||||
from os import listdir
|
|
||||||
from os.path import isfile, join
|
|
||||||
soundFiles = [f for f in listdir("sounds/")
|
|
||||||
if isfile(join("sounds/", f))
|
|
||||||
and (f.split('.')[1].lower() in ["ogg", "wav"])]
|
|
||||||
except Exception as e:
|
|
||||||
print("No sounds found.")
|
|
||||||
Speech.get_instance().speak("No sounds found.", False)
|
|
||||||
soundFiles = []
|
|
||||||
|
|
||||||
# Create dictionary of sound objects
|
|
||||||
soundData = {}
|
soundData = {}
|
||||||
for f in soundFiles:
|
try:
|
||||||
soundData[f.split('.')[0]] = pygame.mixer.Sound("sounds/" + f)
|
import os
|
||||||
|
|
||||||
|
soundDir = "sounds/"
|
||||||
|
# Walk through directory tree
|
||||||
|
for dirPath, dirNames, fileNames in os.walk(soundDir):
|
||||||
|
# Get relative path from soundDir
|
||||||
|
relPath = os.path.relpath(dirPath, soundDir)
|
||||||
|
|
||||||
|
# Process each file
|
||||||
|
for fileName in fileNames:
|
||||||
|
# Check if file is a valid sound file
|
||||||
|
if fileName.lower().endswith(('.ogg', '.wav')):
|
||||||
|
# Full path to the sound file
|
||||||
|
fullPath = os.path.join(dirPath, fileName)
|
||||||
|
|
||||||
|
# Create sound key (remove extension)
|
||||||
|
baseName = os.path.splitext(fileName)[0]
|
||||||
|
|
||||||
|
# If in root sounds dir, just use basename
|
||||||
|
if relPath == '.':
|
||||||
|
soundKey = baseName
|
||||||
|
else:
|
||||||
|
# Otherwise use relative path + basename, normalized with forward slashes
|
||||||
|
soundKey = os.path.join(relPath, baseName).replace('\\', '/')
|
||||||
|
|
||||||
|
# Load the sound
|
||||||
|
soundData[soundKey] = pygame.mixer.Sound(fullPath)
|
||||||
|
except Exception as e:
|
||||||
|
print("Error loading sounds:", e)
|
||||||
|
Speech.get_instance().speak("Error loading sounds.", False)
|
||||||
|
soundData = {}
|
||||||
|
|
||||||
# Play intro sound if available
|
# Play intro sound if available
|
||||||
from .sound import cut_scene
|
from .sound import cut_scene
|
||||||
|
|||||||
@@ -256,9 +256,15 @@ def learn_sounds(sounds):
|
|||||||
"""Interactive menu for learning game sounds.
|
"""Interactive menu for learning game sounds.
|
||||||
|
|
||||||
Allows users to:
|
Allows users to:
|
||||||
- Navigate through available sounds
|
- Navigate through available sounds with up/down arrows
|
||||||
- Play selected sounds
|
- Navigate between sound categories (folders) using Page Up/Page Down or Left/Right arrows
|
||||||
- Return to menu with escape key
|
- Play selected sounds with Enter
|
||||||
|
- Return to menu with Escape
|
||||||
|
|
||||||
|
Excluded sounds:
|
||||||
|
- Files in folders named 'ambience' (at any level)
|
||||||
|
- Files in any directory starting with '.'
|
||||||
|
- Files starting with 'game-intro', 'music_menu', or '_'
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
sounds (dict): Dictionary of available sound objects
|
sounds (dict): Dictionary of available sound objects
|
||||||
@@ -269,56 +275,134 @@ def learn_sounds(sounds):
|
|||||||
# Get speech instance
|
# Get speech instance
|
||||||
speech = Speech.get_instance()
|
speech = Speech.get_instance()
|
||||||
|
|
||||||
currentIndex = 0
|
# Define exclusion criteria
|
||||||
|
excludedPrefixes = ["game-intro", "music_menu", "_"]
|
||||||
|
excludedDirs = ["ambience", "."]
|
||||||
|
|
||||||
# Get list of available sounds, excluding special sounds
|
# Organize sounds by directory
|
||||||
soundFiles = [f for f in listdir("sounds/")
|
soundsByDir = {}
|
||||||
if isfile(join("sounds/", f))
|
|
||||||
and (f.split('.')[1].lower() in ["ogg", "wav"])
|
|
||||||
and (f.split('.')[0].lower() not in ["game-intro", "music_menu"])
|
|
||||||
and (not f.lower().startswith("_"))]
|
|
||||||
|
|
||||||
# Sort the sound files alphabetically
|
# Process each sound key in the dictionary
|
||||||
soundFiles.sort()
|
for soundKey in sounds.keys():
|
||||||
|
# Skip if key has any excluded prefix
|
||||||
|
if any(soundKey.lower().startswith(prefix.lower()) for prefix in excludedPrefixes):
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Split key into path parts
|
||||||
|
parts = soundKey.split('/')
|
||||||
|
|
||||||
|
# Skip if any part of the path is an excluded directory
|
||||||
|
if any(part.lower() == dirName.lower() or part.startswith('.') for part in parts for dirName in excludedDirs):
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Determine the directory
|
||||||
|
if '/' in soundKey:
|
||||||
|
directory = soundKey.split('/')[0]
|
||||||
|
else:
|
||||||
|
directory = 'root' # Root directory sounds
|
||||||
|
|
||||||
|
# Add to sounds by directory
|
||||||
|
if directory not in soundsByDir:
|
||||||
|
soundsByDir[directory] = []
|
||||||
|
soundsByDir[directory].append(soundKey)
|
||||||
|
|
||||||
# Total number of sound files
|
# Sort each directory's sounds
|
||||||
totalSounds = len(soundFiles)
|
for directory in soundsByDir:
|
||||||
|
soundsByDir[directory].sort()
|
||||||
|
|
||||||
# Track last spoken index to avoid repetition
|
# If no sounds found, inform the user and return
|
||||||
|
if not soundsByDir:
|
||||||
|
speech.speak("No sounds available to learn.")
|
||||||
|
return "menu"
|
||||||
|
|
||||||
|
# Get list of directories in sorted order
|
||||||
|
directories = sorted(soundsByDir.keys())
|
||||||
|
|
||||||
|
# Start with first directory
|
||||||
|
currentDirIndex = 0
|
||||||
|
currentDir = directories[currentDirIndex]
|
||||||
|
currentSoundKeys = soundsByDir[currentDir]
|
||||||
|
currentSoundIndex = 0
|
||||||
|
|
||||||
|
# Display appropriate message based on number of directories
|
||||||
|
if len(directories) > 1:
|
||||||
|
messagebox(f"Starting with {currentDir if currentDir != 'root' else 'root directory'} sounds. Use left and right arrows or page up and page down to navigate categories.")
|
||||||
|
|
||||||
|
# Track last spoken to avoid repetition
|
||||||
lastSpoken = -1
|
lastSpoken = -1
|
||||||
|
directoryChanged = True # Flag to track if directory just changed
|
||||||
|
|
||||||
# Flag to track when to exit the loop
|
# Flag to track when to exit the loop
|
||||||
returnToMenu = False
|
returnToMenu = False
|
||||||
|
|
||||||
while not returnToMenu:
|
while not returnToMenu:
|
||||||
if currentIndex != lastSpoken:
|
# Announce current sound
|
||||||
# Speak the sound name followed by its position in the list
|
if currentSoundIndex != lastSpoken:
|
||||||
speech.speak(f"{soundFiles[currentIndex][:-4]}, {currentIndex + 1} of {totalSounds}")
|
totalSounds = len(currentSoundKeys)
|
||||||
lastSpoken = currentIndex
|
soundName = currentSoundKeys[currentSoundIndex]
|
||||||
|
|
||||||
|
# Remove directory prefix if present
|
||||||
|
if '/' in soundName:
|
||||||
|
displayName = '/'.join(soundName.split('/')[1:])
|
||||||
|
else:
|
||||||
|
displayName = soundName
|
||||||
|
|
||||||
|
# If directory just changed, include directory name in announcement
|
||||||
|
if directoryChanged:
|
||||||
|
dirDescription = "Root directory" if currentDir == 'root' else currentDir
|
||||||
|
announcement = f"{dirDescription}: {displayName}, {currentSoundIndex + 1} of {totalSounds}"
|
||||||
|
directoryChanged = False # Reset flag after announcement
|
||||||
|
else:
|
||||||
|
announcement = f"{displayName}, {currentSoundIndex + 1} of {totalSounds}"
|
||||||
|
|
||||||
|
speech.speak(announcement)
|
||||||
|
lastSpoken = currentSoundIndex
|
||||||
|
|
||||||
event = pygame.event.wait()
|
event = pygame.event.wait()
|
||||||
if event.type == pygame.KEYDOWN:
|
if event.type == pygame.KEYDOWN:
|
||||||
if event.key == pygame.K_ESCAPE:
|
if event.key == pygame.K_ESCAPE:
|
||||||
returnToMenu = True
|
returnToMenu = True
|
||||||
|
|
||||||
if event.key in [pygame.K_DOWN, pygame.K_s] and currentIndex < len(soundFiles) - 1:
|
# Sound navigation
|
||||||
|
elif event.key in [pygame.K_DOWN, pygame.K_s] and currentSoundIndex < len(currentSoundKeys) - 1:
|
||||||
pygame.mixer.stop()
|
pygame.mixer.stop()
|
||||||
currentIndex += 1
|
currentSoundIndex += 1
|
||||||
|
|
||||||
if event.key in [pygame.K_UP, pygame.K_w] and currentIndex > 0:
|
elif event.key in [pygame.K_UP, pygame.K_w] and currentSoundIndex > 0:
|
||||||
pygame.mixer.stop()
|
pygame.mixer.stop()
|
||||||
currentIndex -= 1
|
currentSoundIndex -= 1
|
||||||
|
|
||||||
if event.key == pygame.K_RETURN:
|
# Directory navigation
|
||||||
|
elif event.key in [pygame.K_PAGEDOWN, pygame.K_RIGHT] and currentDirIndex < len(directories) - 1:
|
||||||
|
pygame.mixer.stop()
|
||||||
|
currentDirIndex += 1
|
||||||
|
currentDir = directories[currentDirIndex]
|
||||||
|
currentSoundKeys = soundsByDir[currentDir]
|
||||||
|
currentSoundIndex = 0
|
||||||
|
directoryChanged = True # Set flag on directory change
|
||||||
|
lastSpoken = -1 # Force announcement
|
||||||
|
|
||||||
|
elif event.key in [pygame.K_PAGEUP, pygame.K_LEFT] and currentDirIndex > 0:
|
||||||
|
pygame.mixer.stop()
|
||||||
|
currentDirIndex -= 1
|
||||||
|
currentDir = directories[currentDirIndex]
|
||||||
|
currentSoundKeys = soundsByDir[currentDir]
|
||||||
|
currentSoundIndex = 0
|
||||||
|
directoryChanged = True # Set flag on directory change
|
||||||
|
lastSpoken = -1 # Force announcement
|
||||||
|
|
||||||
|
# Play sound
|
||||||
|
elif event.key == pygame.K_RETURN:
|
||||||
try:
|
try:
|
||||||
soundName = soundFiles[currentIndex][:-4]
|
soundName = currentSoundKeys[currentSoundIndex]
|
||||||
pygame.mixer.stop()
|
pygame.mixer.stop()
|
||||||
sounds[soundName].play()
|
sounds[soundName].play()
|
||||||
except:
|
except Exception as e:
|
||||||
lastSpoken = -1
|
print(f"Error playing sound: {e}")
|
||||||
speech.speak("Could not play sound.")
|
speech.speak("Could not play sound.")
|
||||||
|
|
||||||
event = pygame.event.clear()
|
event = pygame.event.clear()
|
||||||
|
pygame.event.pump() # Process pygame's internal events
|
||||||
time.sleep(0.001)
|
time.sleep(0.001)
|
||||||
|
|
||||||
return "menu"
|
return "menu"
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ Provides functionality for:
|
|||||||
- Volume controls
|
- Volume controls
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
import os
|
||||||
import pygame
|
import pygame
|
||||||
import random
|
import random
|
||||||
import re
|
import re
|
||||||
@@ -44,46 +45,41 @@ class Sound:
|
|||||||
self.load_sounds()
|
self.load_sounds()
|
||||||
|
|
||||||
def load_sounds(self):
|
def load_sounds(self):
|
||||||
"""Load all sound files from the sound directory."""
|
"""Load all sound files from the sound directory and its subdirectories.
|
||||||
|
|
||||||
|
Searches recursively through subdirectories and loads all sound files with
|
||||||
|
.ogg or .wav extensions. Sound names are stored as relative paths from the
|
||||||
|
sound directory, with directory separators replaced by forward slashes.
|
||||||
|
"""
|
||||||
try:
|
try:
|
||||||
soundFiles = [f for f in listdir(self.soundDir)
|
# Walk through directory tree
|
||||||
if isfile(join(self.soundDir, f))
|
for dirPath, dirNames, fileNames in os.walk(self.soundDir):
|
||||||
and (f.split('.')[1].lower() in ["ogg", "wav"])]
|
# Get relative path from soundDir
|
||||||
|
relPath = os.path.relpath(dirPath, self.soundDir)
|
||||||
# Create dictionary of sound objects
|
|
||||||
for f in soundFiles:
|
# Process each file
|
||||||
self.sounds[f.split('.')[0]] = pygame.mixer.Sound(join(self.soundDir, f))
|
for fileName in fileNames:
|
||||||
|
# Check if file is a valid sound file
|
||||||
|
if fileName.lower().endswith(('.ogg', '.wav')):
|
||||||
|
# Full path to the sound file
|
||||||
|
fullPath = os.path.join(dirPath, fileName)
|
||||||
|
|
||||||
|
# Create sound key (remove extension)
|
||||||
|
baseName = os.path.splitext(fileName)[0]
|
||||||
|
|
||||||
|
# If in root sounds dir, just use basename
|
||||||
|
if relPath == '.':
|
||||||
|
soundKey = baseName
|
||||||
|
else:
|
||||||
|
# Otherwise use relative path + basename, normalized with forward slashes
|
||||||
|
soundKey = os.path.join(relPath, baseName).replace('\\', '/')
|
||||||
|
|
||||||
|
# Load the sound
|
||||||
|
self.sounds[soundKey] = pygame.mixer.Sound(fullPath)
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"Error loading sounds: {e}")
|
print(f"Error loading sounds: {e}")
|
||||||
|
|
||||||
def play_intro(self):
|
|
||||||
"""Play the game intro sound if available."""
|
|
||||||
if 'game-intro' in self.sounds:
|
|
||||||
self.cut_scene('game-intro')
|
|
||||||
|
|
||||||
def get_sounds(self):
|
|
||||||
"""Get the dictionary of loaded sound objects.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
dict: Dictionary of loaded sound objects
|
|
||||||
"""
|
|
||||||
return self.sounds
|
|
||||||
|
|
||||||
def play_bgm(self, musicFile):
|
|
||||||
"""Play background music with proper volume settings.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
musicFile (str): Path to the music file to play
|
|
||||||
"""
|
|
||||||
try:
|
|
||||||
pygame.mixer.music.stop()
|
|
||||||
pygame.mixer.music.load(musicFile)
|
|
||||||
pygame.mixer.music.set_volume(self.volumeService.get_bgm_volume())
|
|
||||||
pygame.mixer.music.play(-1) # Loop indefinitely
|
|
||||||
except Exception as e:
|
|
||||||
pass
|
|
||||||
|
|
||||||
def play_sound(self, soundName, volume=1.0):
|
def play_sound(self, soundName, volume=1.0):
|
||||||
"""Play a sound with current volume settings applied.
|
"""Play a sound with current volume settings applied.
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user