1#! /usr/bin/env python 2 3import fnmatch 4import os 5import sys 6import re 7 8 9############### 10## functions ## 11############### 12 13 14# converts a sound path to a name string 15def sound_path_to_name(sound_path): 16 sound_name = os.path.splitext(os.path.basename(sound_path))[0] 17 dir_name = os.path.dirname(sound_path) 18 # sound is inside an object definition: return DEF::NAME 19 if fnmatch.fnmatch(dir_name, '*.ocd'): 20 return get_namespace_ocd(dir_name) + sound_name 21 # sound is inside a .ocg folder: return FOLDER::NAME 22 if fnmatch.fnmatch(dir_name, '*.ocg'): 23 return get_namespace_ocg(dir_name) + sound_name 24 # sound is inside a .ocs or .ocs folder: return NAME 25 if fnmatch.fnmatch(dir_name, '*.ocs') or fnmatch.fnmatch(dir_name, '*.ocf'): 26 return sound_name 27 # return a warning, this should not happen 28 return "Warning: sound found in illegal location (i.e. not in scenario, scenario folder, Sound.ocg folder or subfolerd, object definition." 29 30# gets the sound namespace of object definition 31def get_namespace_ocd(ocd_path): 32 if not os.path.isfile(os.path.join(ocd_path, "DefCore.txt")): 33 return "NOTFOUND::" 34 with open(os.path.join(ocd_path, "DefCore.txt"), "r") as read_defcore: 35 for line in read_defcore: 36 if "id=" in line: 37 return str(line).split('=')[-1].replace('\n', '') + "::" 38 return "NOTFOUND::" 39 40# gets the sound namespace of an ocg folder 41def get_namespace_ocg(ocg_path): 42 dirname = ocg_path 43 namespace = "" 44 while not fnmatch.fnmatch(dirname, '*Sound.ocg') and not fnmatch.fnmatch(dirname, '*Music.ocg'): 45 basename = os.path.basename(dirname) 46 dirname = os.path.dirname(dirname) 47 namespace = os.path.splitext(basename)[0] + "::" + namespace 48 return namespace 49 50# finds all sound calls in a script file 51def find_sound_calls_script(script_file): 52 with open(script_file, "r") as read_script: 53 script = read_script.read() 54 # regular call: Sound("FooBar") 55 calls = re.findall('Sound\(\s*.*\)', script) 56 calls = (str(re.sub('Sound\(\s*"', '', call).split('"')[0]) for call in calls) 57 # regular call: SoundAt("FooBar") 58 callsat = re.findall('SoundAt\(\s*.*\)', script) 59 callsat = (str(re.sub('SoundAt\(\s*"', '', call).split('"')[0]) for call in callsat) 60 # ActMap property: Sound = "FooBar" 61 actprops = re.findall('Sound\s*=\s*.*\n', script) 62 actprops = (str(re.sub('Sound\s*=\s*"', '', prop).split('"')[0]) for prop in actprops) 63 all_calls = [] 64 for call in calls: 65 all_calls.append(call) 66 for call in callsat: 67 all_calls.append(call) 68 for prop in actprops: 69 all_calls.append(prop) 70 return all_calls 71 72# finds all sound calls in a source file 73def find_sound_calls_source(source_file): 74 with open(source_file, "r") as read_source: 75 source = read_source.read() 76 calls = re.findall('GUISound\(.*\)|StartSoundEffectAt\(.*\)|StartSoundEffect\(.*\)', source) 77 calls = (call.replace('GUISound("', '').replace('StartSoundEffectAt("', '').replace('StartSoundEffect("', '').split('"')[0] for call in calls) 78 return calls 79 80 81############# 82## program ## 83############# 84 85 86# program arguments: planet directory and source directory 87planet_dir = "../planet" 88source_dir = "../src" 89if len(sys.argv) >= 2: 90 planet_dir = sys.argv[1] 91if len(sys.argv) >= 3: 92 source_dir = sys.argv[2] 93 94# find all sound and script files in planet 95sound_files = [] 96script_files = [] 97for root, directories, filenames in os.walk(planet_dir): 98 for filename in filenames: 99 full_filename = os.path.join(root, filename) 100 # get the sound files 101 if fnmatch.fnmatch(full_filename, '*.ogg') or fnmatch.fnmatch(full_filename, '*.wav'): 102 sound_files.append(full_filename) 103 # get the script files 104 if fnmatch.fnmatch(full_filename, '*.c'): 105 script_files.append(full_filename) 106 107# remove music files from sound files 108sound_files[:] = (sound_path for sound_path in sound_files if not fnmatch.fnmatch(sound_path, '*Music.ocg*')) 109 110# find all engine files in source 111source_files = [] 112for root, directories, filenames in os.walk(source_dir): 113 for filename in filenames: 114 full_filename = os.path.join(root, filename) 115 # get the source files 116 if fnmatch.fnmatch(full_filename, '*.cpp') or fnmatch.fnmatch(full_filename, '*.h'): 117 source_files.append(full_filename) 118 119 120# get all sound calls from the script and the source files 121sound_calls_script = [] 122for script in script_files: 123 for call in find_sound_calls_script(script): 124 sound_calls_script.append(call) 125sound_calls_source = [] 126for source in source_files: 127 for call in find_sound_calls_source(source): 128 sound_calls_source.append(call) 129 130# check for all found sound files if there is an occurence in the script 131print "Looking for unused sounds in the planet directory: \n\t", planet_dir 132print "WARNING: always double check if the sound really is not played by searching for the sound name in all engine and script files." 133print "\nChecking", len(sound_files), "sound files ..." 134cnt_unused_sounds = 0 135for sound_path in sound_files: 136 sound = sound_path_to_name(sound_path) 137 found = False 138 for call in sound_calls_script + sound_calls_source: 139 if fnmatch.fnmatch(sound, call): 140 found = True 141 break 142 if not found: 143 cnt_unused_sounds += 1 144 print sound_path + " (" + sound + ")" + " has not been found" 145print "Out of the", len(sound_files), "found sound files, the above", cnt_unused_sounds, "may be unused." 146 147 148 149# script for finding non-normal calls to sound only turn on if needed 150if False: 151 for script_file in script_files: 152 with open(script_file, "r") as read_script: 153 script = read_script.read() 154 calls = re.findall('Sound\(\s*.*\)', script) 155 for call in calls: 156 if re.search('Sound\(\s*"', call) is None: 157 print call 158 calls = re.findall('SoundAt\(\s*.*\)', script) 159 for call in calls: 160 if re.search('SoundAt\(\s*"', call) is None: 161 print call 162 calls = re.findall('Sound\s*=\s*.*', script) 163 for call in calls: 164 if re.search('Sound\s*=\s*".*".*', call) is None: 165 print call 166 167