I've got a Python script that traverses two file trees, checking all .wav files for duplication.I'm still an undergrad, and have never worked with audio before.  I'm not entirely sure this is going to be a valid comparison.I lost the SO answer I was using as a guideline, but the general idea is to split the audio into chunks, FFT those chunks, then compare the results.I also would appreciate any structure/style advice.Note: All Olympus Recordings are valid, but I need to load them to have the ffts to compare.import osimport os.pathimport waveimport numpyimport structfrom shutil import copyfrom subprocess import call, Popen, PIPEoly_path = /home/will/Desktop/soundfiles/Olympus Recordingstitan_path = /home/will/Desktop/soundfiles/TITAN Recordingswav_roots = [oly_path, titan_path]destination_path = /home/will/Desktop/soundfiles/outputtemp_wav_path = /home/will/Desktop/soundfiles/temp.wavsimilarity_threshold = 95validated_wavs = {}bunk_wavs = {}def get_fft_similarity(fft1, fft2):        hits = 0        len1 = len(fft1)        len2 = len(fft2)        limit = (len1 if len1<len2 else len2)        if limit == 0:                return 0        for i in xrange(limit):                if (fft1[i] == fft2[i]).all():                        hits += 1        ratio = float(hits)/limit        return int(ratio*100)def sort_wav(to_sort):        key = to_sort.filename        if Olympus in to_sort.source:                while key in validated_wavs:                        to_sort.generate_new_name()                        key = to_sort.filename                validated_wavs[key] = to_sort                return 1        if key in validated_wavs:                if get_fft_similarity(to_sort.fft, validated_wavs[key].fft) >= similarity_threshold:                        bunk_wavs[key] = to_sort                        return 0                while key in validated_wavs:                        to_sort.generate_new_name()                        key = to_sort.filename        for w in validated_wavs.values():                if get_fft_similarity(to_sort.fft, w.fft) >= similarity_threshold:                        bunk_wavs[key] = to_sort                        return 0        validated_wavs[key] = to_sort        return 1def get_fft(fft_path):        return_list = []        frames_list = []        chunk_size = 36        start = 0        wav = wave.open(fft_path, 'r')        frames = wav.readframes(wav.getnframes())        wav.close()        while start+chunk_size < len(frames):                data = struct.unpack(>fdddd, frames[start:start+chunk_size])                frames_list.append(data)                start += chunk_size                if len(frames_list) >= 1000:                        return_list.append(numpy.fft.fft(frames_list))                        frames_list = []        return return_listdef ensure_encoding(encoding_path):        command = [soxi, -e, encoding_path]        command_proc = Popen(command, stdin=PIPE, stdout=PIPE, stderr=PIPE)        encoding = command_proc.communicate()[0].rstrip()        if encoding != Signed Integer PCM:                call([sox, encoding_path, -e, signed, temp_wav_path])        else:                copy(encoding_path, temp_wav_path)def validate(validate_path):        ensure_encoding(validate_path)        ivr_wav = IVR_Wav(validate_path)        return sort_wav(ivr_wav)class IVR_Wav:        def __init__(self, source):                self.source = source                self.destination = destination_path + source.split(/)[-1]                self.size = os.path.getsize(source)                self.fft = get_fft(temp_wav_path)                self.filename = os.path.split(source)[-1]        def generate_new_name(self):                name = os.path.split(self.source)[-1].replace(.wav, )                directory = os.path.split(self.source)[-2].split(/ if / in self.source else \\)[-1]                self.filename = .join([name, _, directory, .wav])                self.destination = os.path.join(destination_path, self.filename)def main():        valid = 0        total = 0        for wav_root in wav_roots:                for root, dirs, files in os.walk(wav_root):                        for f in files:                                if f.endswith(wav) and os.path.getsize(os.path.join(root, f)) > 16:                                        total += 1                                        temp_path = os.path.join(root, f)                                        valid += validate(temp_path)                                print \r, valid, /, total,  valid::::::, len(validated_wavs),main()
Comparing FFTs to deduplicate IVR recordings
python;beginner;numpy;audio;signal processing
UPPERCASE for constantsAs a convention, in Python constants are uppercase:OLY_PATH = /home/will/Desktop/soundfiles/Olympus RecordingsTITAN_PATH = /home/will/Desktop/soundfiles/TITAN RecordingsWAV_ROOTS = [oly_path, titan_path]DESTINATION_PATH = /home/will/Desktop/soundfiles/outputTEEMP_WAV_PATH = /home/will/Desktop/soundfiles/temp.wavNo need for temporary variables    len1 = len(fft1)    len2 = len(fft2)Are useless because you use them only once, thus leading to no efficiency gain and code clutter.def get_fft_similarity(fft1, fft2):        hits = 0        limit = (len1 if len(fft1)<len(fft2) else len2)        if limit == 0:                return 0        for i in xrange(limit):                if (fft1[i] == fft2[i]).all():                        hits += 1        ratio = float(hits)/limit        return int(ratio*100)Also about this function:float(hits)/limit you can remove float if you from __future__ import divisionDown below: for i in xrange(limit):            if (fft1[i] == fft2[i]).all():                    hits += 1You are using explicit indexing and a counter variable. Maybe zip is and sum will simplify your code.Use more constantsYou already use some, and that is nice, but things like:Olympus.wavSigned Integer PCMsoxi...Should be in their own named constant.Are you sure of your class?Usually if a class has init and only one other function, maybe you can use just a function for simplicity: I am looking at class IVR_WavPeculiar double effect sort_wavI noticed that sort_wav both modifies a global variable and returns 1 or 0. It is then called by validate. Maybe you could write a validator_helper to make the check and another function to update the dictionary.