<gh_stars>1-10
# -*- coding: UTF-8 -*-
# Interstitial Error Detector
# Version 0.2, 2013-08-28
# Copyright (c) 2013 AudioVisual Preservation Solutions
# All rights reserved.
# Released under the Apache license, v. 2.0
# Created on May 14, 2014
# @author: <NAME> <<EMAIL>>

import numpy as np
from scikits.audiolab import Sndfile
from math import fabs, floor
from re import compile
from os import walk, path, stat
from time import strftime, time, sleep
import datetime

from Core import SharedApp
from Core import DAWDirsCore, ReferenceDirsCore

class DirsHandlerCore(object):
    """
        Application Directories Handler Core  Class
    """

    def __init__(self):
        """
        Constructor
        """
        self.Interstitial = SharedApp.SharedApp.App

        self.number_of_daw_core = 1
        self.number_of_ref_core = 1

        self.daw_dirs_core = {}
        self.reference_dirs_core = {}

        for index_daw in xrange(0, self.number_of_daw_core):
            self.daw_dirs_core[index_daw] = DAWDirsCore.DAWDirsCore()

        for index_ref in xrange(0, self.number_of_ref_core):
            self.reference_dirs_core[index_ref] = ReferenceDirsCore.ReferenceDirsCore()


        pass

    def setNumberOfDawCore(self, number_of_dirs_daw):
        """
        Set Number Of Reference Dirs
        @return daw_dirs_core:String
        """
        self.number_of_daw_core = number_of_dirs_daw


    def setNumberOfRefCore(self, number_of_dirs_ref):
        """
        Set Number Of Daw Dirs
        @return number_of_ref_core:String
        """
        self.number_of_ref_core = number_of_dirs_ref

    def getDawDirsCore(self, index):
        """
        Set Daw Dirs Core
        @return None
        """
        return self.daw_dirs_core[index]

    def setDawDirsCore(self, text, index):
        """
        Set Daw Dirs Core
        @return None
        """
        new_daw = DAWDirsCore.DAWDirsCore()

        new_daw.setCoreDawText(text)
        new_daw.setCoreDawId(index)

        self.daw_dirs_core[index] = new_daw

    def setRefDirsCore(self, text, index):
        """
        Set Ref Dirs Core
        @return None
        """
        new_ref = ReferenceDirsCore.ReferenceDirsCore()

        new_ref.setCoreRefText(text)
        new_ref.setCoreRefId(index)

        self.reference_dirs_core[index] = new_ref

    def getRefDirsCore(self, index):
        """
        Set Ref Dirs Core
        @return None
        """
        return self.reference_dirs_core[index]

    def mono(self, numpy_matrix):
        """
        mono(numpy matrix ar)
        reduces an n-dimensional matrix to a 1-dimensional list if n > 1
        if n = 1, returns it
        @param numpy_matrix: Numpy Matrix
        @return: numpy_matrix
        """

        if numpy_matrix.ndim > 1:
            return numpy_matrix[:,0]
        else:
            return numpy_matrix

    def offs(self, track1, track2):
        """
        offs(audiofile track1, audiofile track2)
        calculates the head offset between two (supposedly) otherwise identitical audio files
        this is achieved via finding the peak-to-peak difference of the waveform heads
        """

        # opens files for reading
        try:
            track_one_file_obj = Sndfile(track1.encode('utf-8'), 'r')
        except:
            print('Corrupted File 1 : '+ track1)
            return
            pass

        try:
            track_two_file_obj = Sndfile(track2, 'r')
        except:
            print('Corrupted File 2 : '+ track2)
            return
            pass

        # calculates the head of each file (first twentieth of the waveform)
        # if this is less than 5 seconds of audio (that is, the waveform is under 100 seconds long)
        # then the head is the first five seconds of the waveform
        track_one_file_obj_head = floor(.05 * track_one_file_obj.nframes)
        if track_one_file_obj_head < (track_one_file_obj.samplerate * 5):
            track_one_file_obj_head = track_one_file_obj.nframes

        track_two_file_obj_head = floor(.05 * track_two_file_obj.nframes)
        if track_two_file_obj_head < (track_two_file_obj.samplerate * 5):
            track_two_file_obj_head = track_two_file_obj.nframes

        # reads the head of each file (as absolute values, accounting for reversed waveforms)
        # into a 1-dimensional numpy matrix (via mono function)
        numpy_matrix_of_track1 = self.mono(np.absolute(track_one_file_obj.read_frames(track_one_file_obj_head)))
        numpy_matrix_of_track2 = self.mono(np.absolute(track_two_file_obj.read_frames(track_two_file_obj_head)))

        # returns the difference between the peak of each list
        return np.argmax(numpy_matrix_of_track1) - np.argmax(numpy_matrix_of_track2)

    def populate(self, dir):
        """
        Populate (File Path Dir)
        walks the file tree under dir recursively and returns all .wav files in it
        """

        populated_list = []

        wav = compile('.[Ww][Aa][Vv]$')
        for root, subFolders, files in walk(dir):
            for singleFile in files:
                if wav.search(singleFile):
                    populated_list.append(path.join(root, singleFile))

        return populated_list

    def specialCharacterHandler(self, string_to_be_handled):
        """
        Method to handle all special characters
        @param string_to_be_handled: String To Be Handled
        @return:  String - Fixed characters String
        """
        try:self.Fixity = SharedApp.SharedApp.App
        except:pass

        try:
            string_to_be_handled = string_to_be_handled.decode('cp1252')
        except:
            pass

        try:
            string_to_be_handled = string_to_be_handled.encode('utf8')
        except:
            pass

        return string_to_be_handled

    def run_executor(self, manifest_path, q_action=None, is_unit_test=False):
        '''
        Run Executor For all Directories
        @param manifest_path: Manifest File Path
        @param q_action: QCoreApplication Object
        @param is_unit_test: Is call generated from Unit test
        @return manifest_file_path/{manifest_info, manifest_file_path}: Sting/List
        '''
        testers = 0
        file_count = 0
        values = ''

        filename = self.Interstitial.Configuration.getManifestFileName()
        columns = self.Interstitial.Configuration.getColumnsOfManifest()

        timer = time()
        initiated = self.Interstitial.Configuration.getCurrentTime()

        current_date = strftime("%Y-%m-%d")
        self.all_ref_files = []
        self.all_daw_files = []

        self.scanned_daw_files = []
        self.scanned_ref_files = []

        for index_daw in xrange(0, self.number_of_daw_core):
            for index_ref in xrange(0, self.number_of_ref_core):

                # Launch The Scanner to Test Audio Files
                report_result = self.execute(index_daw, index_ref, q_action)

                try:
                    testers += len(report_result['manifest_info']['testers'])
                except: pass

                try:
                    file_count += int(report_result['manifest_info']['file_count'])
                except: pass

                try:
                    values += report_result['manifest_info']['values']
                except: pass

                sleep(2)

            if self.unmatched_flag:

                values += path.abspath(self.daw_directories[index_daw]) + ", NONE " + ","
                values += "," + "," + "," + ''
                values += "\n"

                print('')
                print "COULD NOT MATCH FILES: " +self.daw_directories[index_daw]
                print('')

                self.scanned_daw_files.append(self.daw_directories[index_daw])



        for single_daw_file in self.all_daw_files:
            if single_daw_file not in self.scanned_daw_files:
                values += path.abspath(single_daw_file) + ", NONE "
                values += "," + "," + "," + "," + ''
                values += "\n"

                print('')
                print "COULD NOT MATCH FILES: " + single_daw_file
                print('')
                self.scanned_daw_files.append(single_daw_file)

        for single_ref_file in self.all_ref_files:
            if single_ref_file not in self.scanned_ref_files:
                values += "NONE ," + path.abspath(single_ref_file)
                values += "," + "," + "," + "," + ''
                values += "\n"

                print('')
                print "COULD NOT MATCH FILES: " + single_ref_file
                print('')
                self.scanned_ref_files.append(single_ref_file)

        seconds_content = str(floor(time() - timer))
        manifest_info = {'current_date': current_date, 'initiated': initiated, 'seconds_content': seconds_content,
                        'testers': testers, 'file_count': file_count, 'columns': columns, 'values': values}

        # Open template file and get manifest template content to manifest file creation
        template_of_manifest_file = open(self.Interstitial.Configuration.getManifestTemplatePath(), "r")
        template_of_manifest_file_lines = template_of_manifest_file.readlines()
        template_of_manifest_file.close()

        manifest_content = self.generateManifestContent(template_of_manifest_file_lines, manifest_info)

        # Do We Have Metadata? If So, Write A Manifest
        # Write Manifest File
        if len((values + columns)) > 110:
            manifest_file_path = manifest_path + "/" + filename
            self.writeManifestFile(manifest_file_path, manifest_content)

            if is_unit_test:
                return {'manifest_info': manifest_info, 'manifest_file_path':manifest_file_path}
            else:
                return manifest_file_path

    def execute(self, index_daw, index_ref, q_action=None):
        """
        Execute (wavefile first_wave_file, wavefile second_wave_file, directory d, QAction qa)
        The heart of interstitial - performs a null test on two wav files and returns the first difference
        """

        # initialize useful variables

        values = ''
        file_count = 0

        test_done_for_files = []
        targeted_done = []

        # Ensures That We Have Legitimate Directories To Walk Down
        # And Populates The List Of Files To Test

        if not path.isdir(path.abspath(self.getDawDirsCore(index_daw).getCoreDawText())) or not path.isdir(path.abspath(self.getRefDirsCore(index_ref).getCoreRefText())):
            print self.Interstitial.messages['illegalPaths']
            return

        self.daw_directories = []
        self.ref_directories = []

        self.daw_directories = self.populate(self.getDawDirsCore(index_daw).getCoreDawText())
        print str(len(self.daw_directories)) + self.Interstitial.messages['WAV_found'] + path.abspath(self.getDawDirsCore(index_daw).getCoreDawText())

        self.ref_directories = self.populate(self.getRefDirsCore(index_ref).getCoreRefText())
        print str(len(self.ref_directories)) + self.Interstitial.messages['WAV_found'] + path.abspath(self.getRefDirsCore(index_ref).getCoreRefText())

        try:
            q_action.processEvents()
        except:
            pass


        self.unmatched_flag = False
        for index in xrange(len(self.daw_directories)):
            self.all_daw_files.append(self.daw_directories[index])

        for index in xrange(len(self.ref_directories)):
            self.all_ref_files.append(self.ref_directories[index])

        # Process Each File In The Tester Array
        for index in xrange(len(self.daw_directories)):
            found = False
            if self.daw_directories[index] in self.scanned_daw_files:
                continue


            for e in xrange(len(self.ref_directories)):
                if self.ref_directories[e] in self.scanned_ref_files:
                    continue

                try:
                    q_action.processEvents()
                except:
                    pass

                # If We Haven't Already Processed This File, Process It

                if self.ref_directories[e] not in targeted_done:

                    # find the offset and align the waveforms
                    toff = self.offs(self.daw_directories[index], self.ref_directories[e])

                    try:
                        tester_file_obj = Sndfile(self.daw_directories[index], 'r')
                    except:
                        print('Corrupted File : '+ self.daw_directories[index])
                        return
                        pass

                    try:
                        target_file_obj = Sndfile(self.ref_directories[e], 'r')
                    except:
                        print('Corrupted File : ' +self. ref_directories[e])
                        return
                        pass

                    if toff > 0:
                        tester_file_obj.seek(toff)
                    else:
                        target_file_obj.seek(fabs(toff))

                    # Read The First 1000 Samples Of Each File
                    # If Each Sample Is Within 6dB Of The Other, We Have A Match And Can Begin Processing
                    numpy_matrix_of_track1 = self.mono(tester_file_obj.read_frames(1000))
                    numpy_matrix_of_track2 = self.mono(target_file_obj.read_frames(1000))

                    if np.array_equal(numpy_matrix_of_track1, numpy_matrix_of_track2):
                        print('')
                        print "MATCH: " + self.daw_directories[index] + " matches " + self.ref_directories[e]

                        try:
                            q_action.processEvents()
                        except:
                            pass

                        # mark files as done
                        test_done_for_files.append(self.daw_directories[index])
                        targeted_done.append(self.ref_directories[e])

                        # we can't read the entire file into RAM at once
                        # so instead we're breaking it into one-second parts
                        l = min((tester_file_obj.nframes - toff), (target_file_obj.nframes - toff)) / tester_file_obj.samplerate
                        for n in xrange(0, l, 1):
                            errs = 0
                            try:
                                # drop all but the first channel
                                track_one_response = self.mono(tester_file_obj.read_frames(tester_file_obj.samplerate))
                                track_two_response = self.mono(target_file_obj.read_frames(target_file_obj.samplerate))

                                # are these arrays equivalent? if not, there's an error
                                if not np.array_equal(track_one_response, track_two_response):
                                    file_count += 1
                                    # where's the error?
                                    # we find it by comparing sample by sample across this second of audio
                                    for m in xrange(len(track_one_response)):
                                        if not np.array_equal(track_one_response[m], track_two_response[m]):

                                            # We found it! print a message and we're done with these files
                                            errs = (n * tester_file_obj.samplerate) + m + 1000
                                            print self.Interstitial.messages['errorFoundBw'] +self.daw_directories[index] + " and " + self.ref_directories[e] + " at sample " + str(errs)

                                            try:
                                                q_action.processEvents()
                                            except:
                                                pass

                                            break

                                if errs != 0:
                                    break

                            except RuntimeError:
                                break

                        # Append Metadata For Output
                        values += path.abspath(self.daw_directories[index]) + "," + path.abspath(self.ref_directories[e]) + ","
                        values += datetime.datetime.fromtimestamp(stat(self.daw_directories[index]).st_ctime).strftime("%Y-%m-%d %H:%M:%S") + ","
                        values += str(stat(self.daw_directories[index]).st_size) + "," + str(tester_file_obj.channels) + "," + str(tester_file_obj.samplerate) + ","
                        values += str(datetime.timedelta(seconds=int(tester_file_obj.nframes / tester_file_obj.samplerate))) + "," + str(errs) + ","
                        values += str(datetime.timedelta(seconds=int(errs/tester_file_obj.samplerate)))

                        values += "\n"
                        found = True
                        unmatched_flag = False

                        self.scanned_daw_files.append(self.daw_directories[index])
                        self.scanned_ref_files.append(self.ref_directories[e])

                    else:
                        unmatched_flag = True
                        pass

                    if found:
                        break
             # if found:
            #     break




        # Create Header Information For Manifest
        manifest_info = {'testers': self.daw_directories, 'file_count': file_count, 'values': values}
        return {'manifest_info': manifest_info}

    def writeManifestFile(self, file_path, manifest_content):
        """
        Write Manifest File
        @param file_path: Manifest File Path(String)
        @param manifest_content: Manifest Content (Tuple)
        @return:Manifest Content(String)
        """

        try:
            f = open(file_path, 'w')
            f.write(manifest_content)
            print self.Interstitial.messages['wroteManifest'] + path.abspath(f.name)
            f.close()
        except:
            print self.Interstitial.messages['illegalPath'] + file_path

    def generateManifestContent(self, template_of_manifest_file_lines, manifest_info):
        """
        Generate Manifest Content
        @param template_of_manifest_file_lines: Lines Template Of Manifest File
        @return:manifest_content
        """

        manifest_content = ''
        for template_of_manifest_single_line in template_of_manifest_file_lines:
            response = False

            response = self.setValuesForScheduler(template_of_manifest_single_line,
                                                '{{current_date}}',
                                                str(manifest_info['current_date']))

            if response is False:
                response = self.setValuesForScheduler(template_of_manifest_single_line,
                                                '{{initiated}}',
                                                str(manifest_info['initiated']))

            if response is False:
                response = self.setValuesForScheduler(template_of_manifest_single_line,
                                                '{{seconds}}',
                                                str(manifest_info['seconds_content']))

            if response is False:
                response = self.setValuesForScheduler(template_of_manifest_single_line,
                                                '{{testers}}',
                                                str(manifest_info['testers']))

            if response is False:
                response = self.setValuesForScheduler(template_of_manifest_single_line,
                                                '{{bad_files}}',
                                                str(manifest_info['file_count']))

            if response is False:
                response = self.setValuesForScheduler(template_of_manifest_single_line,
                                                '{{columns}}',
                                                str(manifest_info['columns']))

            if response is False:
                response = self.setValuesForScheduler(template_of_manifest_single_line,
                                                '{{values}}',
                                                manifest_info['values'])

            if response is False:
               # If No Value Found To Replace
                manifest_content += template_of_manifest_single_line
            else:
                manifest_content += response

        return manifest_content

    def setValuesForScheduler(self, string, find_string, replace_with_string):
        """
        @param string: Template String
        @param find_string: Find String string to be replaced with
        @param replace_with_string: String to be replaced with

        @return: String
        """

        try:self.Interstitial = SharedApp.SharedApp.App
        except:pass

        string = string
        find_string = find_string
        replace_with_string = replace_with_string

        if find_string in string:
            return string.replace(find_string, replace_with_string)

        return False
# -*- coding: UTF-8 -*-
# Interstitial Error Detector
# Version 0.2, 2013-08-28
# Copyright (c) 2013 AudioVisual Preservation Solutions
# All rights reserved.
# Released under the Apache license, v. 2.0
# Created on May 14, 2014
# @author: <NAME> <<EMAIL>>

import numpy as np
from scikits.audiolab import Sndfile
from math import fabs, floor
from re import compile
from os import walk, path, stat
from time import strftime, time, sleep
import datetime

from Core import SharedApp
from Core import DAWDirsCore, ReferenceDirsCore

class DirsHandlerCore(object):
    """
        Application Directories Handler Core  Class
    """

    def __init__(self):
        """
        Constructor
        """
        self.Interstitial = SharedApp.SharedApp.App

        self.number_of_daw_core = 1
        self.number_of_ref_core = 1

        self.daw_dirs_core = {}
        self.reference_dirs_core = {}

        for index_daw in xrange(0, self.number_of_daw_core):
            self.daw_dirs_core[index_daw] = DAWDirsCore.DAWDirsCore()

        for index_ref in xrange(0, self.number_of_ref_core):
            self.reference_dirs_core[index_ref] = ReferenceDirsCore.ReferenceDirsCore()


        pass

    def setNumberOfDawCore(self, number_of_dirs_daw):
        """
        Set Number Of Reference Dirs
        @return daw_dirs_core:String
        """
        self.number_of_daw_core = number_of_dirs_daw


    def setNumberOfRefCore(self, number_of_dirs_ref):
        """
        Set Number Of Daw Dirs
        @return number_of_ref_core:String
        """
        self.number_of_ref_core = number_of_dirs_ref

    def getDawDirsCore(self, index):
        """
        Set Daw Dirs Core
        @return None
        """
        return self.daw_dirs_core[index]

    def setDawDirsCore(self, text, index):
        """
        Set Daw Dirs Core
        @return None
        """
        new_daw = DAWDirsCore.DAWDirsCore()

        new_daw.setCoreDawText(text)
        new_daw.setCoreDawId(index)

        self.daw_dirs_core[index] = new_daw

    def setRefDirsCore(self, text, index):
        """
        Set Ref Dirs Core
        @return None
        """
        new_ref = ReferenceDirsCore.ReferenceDirsCore()

        new_ref.setCoreRefText(text)
        new_ref.setCoreRefId(index)

        self.reference_dirs_core[index] = new_ref

    def getRefDirsCore(self, index):
        """
        Set Ref Dirs Core
        @return None
        """
        return self.reference_dirs_core[index]

    def mono(self, numpy_matrix):
        """
        mono(numpy matrix ar)
        reduces an n-dimensional matrix to a 1-dimensional list if n > 1
        if n = 1, returns it
        @param numpy_matrix: Numpy Matrix
        @return: numpy_matrix
        """

        if numpy_matrix.ndim > 1:
            return numpy_matrix[:,0]
        else:
            return numpy_matrix

    def offs(self, track1, track2):
        """
        offs(audiofile track1, audiofile track2)
        calculates the head offset between two (supposedly) otherwise identitical audio files
        this is achieved via finding the peak-to-peak difference of the waveform heads
        """

        # opens files for reading
        try:
            track_one_file_obj = Sndfile(track1.encode('utf-8'), 'r')
        except:
            print('Corrupted File 1 : '+ track1)
            return
            pass

        try:
            track_two_file_obj = Sndfile(track2, 'r')
        except:
            print('Corrupted File 2 : '+ track2)
            return
            pass

        # calculates the head of each file (first twentieth of the waveform)
        # if this is less than 5 seconds of audio (that is, the waveform is under 100 seconds long)
        # then the head is the first five seconds of the waveform
        track_one_file_obj_head = floor(.05 * track_one_file_obj.nframes)
        if track_one_file_obj_head < (track_one_file_obj.samplerate * 5):
            track_one_file_obj_head = track_one_file_obj.nframes

        track_two_file_obj_head = floor(.05 * track_two_file_obj.nframes)
        if track_two_file_obj_head < (track_two_file_obj.samplerate * 5):
            track_two_file_obj_head = track_two_file_obj.nframes

        # reads the head of each file (as absolute values, accounting for reversed waveforms)
        # into a 1-dimensional numpy matrix (via mono function)
        numpy_matrix_of_track1 = self.mono(np.absolute(track_one_file_obj.read_frames(track_one_file_obj_head)))
        numpy_matrix_of_track2 = self.mono(np.absolute(track_two_file_obj.read_frames(track_two_file_obj_head)))

        # returns the difference between the peak of each list
        return np.argmax(numpy_matrix_of_track1) - np.argmax(numpy_matrix_of_track2)

    def populate(self, dir):
        """
        Populate (File Path Dir)
        walks the file tree under dir recursively and returns all .wav files in it
        """

        populated_list = []

        wav = compile('.[Ww][Aa][Vv]$')
        for root, subFolders, files in walk(dir):
            for singleFile in files:
                if wav.search(singleFile):
                    populated_list.append(path.join(root, singleFile))

        return populated_list

    def specialCharacterHandler(self, string_to_be_handled):
        """
        Method to handle all special characters
        @param string_to_be_handled: String To Be Handled
        @return:  String - Fixed characters String
        """
        try:self.Fixity = SharedApp.SharedApp.App
        except:pass

        try:
            string_to_be_handled = string_to_be_handled.decode('cp1252')
        except:
            pass

        try:
            string_to_be_handled = string_to_be_handled.encode('utf8')
        except:
            pass

        return string_to_be_handled

    def run_executor(self, manifest_path, q_action=None, is_unit_test=False):
        '''
        Run Executor For all Directories
        @param manifest_path: Manifest File Path
        @param q_action: QCoreApplication Object
        @param is_unit_test: Is call generated from Unit test
        @return manifest_file_path/{manifest_info, manifest_file_path}: Sting/List
        '''
        testers = 0
        file_count = 0
        values = ''

        filename = self.Interstitial.Configuration.getManifestFileName()
        columns = self.Interstitial.Configuration.getColumnsOfManifest()

        timer = time()
        initiated = self.Interstitial.Configuration.getCurrentTime()

        current_date = strftime("%Y-%m-%d")
        self.all_ref_files = []
        self.all_daw_files = []

        self.scanned_daw_files = []
        self.scanned_ref_files = []

        for index_daw in xrange(0, self.number_of_daw_core):
            for index_ref in xrange(0, self.number_of_ref_core):

                # Launch The Scanner to Test Audio Files
                report_result = self.execute(index_daw, index_ref, q_action)

                try:
                    testers += len(report_result['manifest_info']['testers'])
                except: pass

                try:
                    file_count += int(report_result['manifest_info']['file_count'])
                except: pass

                try:
                    values += report_result['manifest_info']['values']
                except: pass

                sleep(2)

            if self.unmatched_flag:

                values += path.abspath(self.daw_directories[index_daw]) + ", NONE " + ","
                values += "," + "," + "," + ''
                values += "\n"

                print('')
                print "COULD NOT MATCH FILES: " +self.daw_directories[index_daw]
                print('')

                self.scanned_daw_files.append(self.daw_directories[index_daw])



        for single_daw_file in self.all_daw_files:
            if single_daw_file not in self.scanned_daw_files:
                values += path.abspath(single_daw_file) + ", NONE "
                values += "," + "," + "," + "," + ''
                values += "\n"

                print('')
                print "COULD NOT MATCH FILES: " + single_daw_file
                print('')
                self.scanned_daw_files.append(single_daw_file)

        for single_ref_file in self.all_ref_files:
            if single_ref_file not in self.scanned_ref_files:
                values += "NONE ," + path.abspath(single_ref_file)
                values += "," + "," + "," + "," + ''
                values += "\n"

                print('')
                print "COULD NOT MATCH FILES: " + single_ref_file
                print('')
                self.scanned_ref_files.append(single_ref_file)

        seconds_content = str(floor(time() - timer))
        manifest_info = {'current_date': current_date, 'initiated': initiated, 'seconds_content': seconds_content,
                        'testers': testers, 'file_count': file_count, 'columns': columns, 'values': values}

        # Open template file and get manifest template content to manifest file creation
        template_of_manifest_file = open(self.Interstitial.Configuration.getManifestTemplatePath(), "r")
        template_of_manifest_file_lines = template_of_manifest_file.readlines()
        template_of_manifest_file.close()

        manifest_content = self.generateManifestContent(template_of_manifest_file_lines, manifest_info)

        # Do We Have Metadata? If So, Write A Manifest
        # Write Manifest File
        if len((values + columns)) > 110:
            manifest_file_path = manifest_path + "/" + filename
            self.writeManifestFile(manifest_file_path, manifest_content)

            if is_unit_test:
                return {'manifest_info': manifest_info, 'manifest_file_path':manifest_file_path}
            else:
                return manifest_file_path

    def execute(self, index_daw, index_ref, q_action=None):
        """
        Execute (wavefile first_wave_file, wavefile second_wave_file, directory d, QAction qa)
        The heart of interstitial - performs a null test on two wav files and returns the first difference
        """

        # initialize useful variables

        values = ''
        file_count = 0

        test_done_for_files = []
        targeted_done = []

        # Ensures That We Have Legitimate Directories To Walk Down
        # And Populates The List Of Files To Test

        if not path.isdir(path.abspath(self.getDawDirsCore(index_daw).getCoreDawText())) or not path.isdir(path.abspath(self.getRefDirsCore(index_ref).getCoreRefText())):
            print self.Interstitial.messages['illegalPaths']
            return

        self.daw_directories = []
        self.ref_directories = []

        self.daw_directories = self.populate(self.getDawDirsCore(index_daw).getCoreDawText())
        print str(len(self.daw_directories)) + self.Interstitial.messages['WAV_found'] + path.abspath(self.getDawDirsCore(index_daw).getCoreDawText())

        self.ref_directories = self.populate(self.getRefDirsCore(index_ref).getCoreRefText())
        print str(len(self.ref_directories)) + self.Interstitial.messages['WAV_found'] + path.abspath(self.getRefDirsCore(index_ref).getCoreRefText())

        try:
            q_action.processEvents()
        except:
            pass


        self.unmatched_flag = False
        for index in xrange(len(self.daw_directories)):
            self.all_daw_files.append(self.daw_directories[index])

        for index in xrange(len(self.ref_directories)):
            self.all_ref_files.append(self.ref_directories[index])

        # Process Each File In The Tester Array
        for index in xrange(len(self.daw_directories)):
            found = False
            if self.daw_directories[index] in self.scanned_daw_files:
                continue


            for e in xrange(len(self.ref_directories)):
                if self.ref_directories[e] in self.scanned_ref_files:
                    continue

                try:
                    q_action.processEvents()
                except:
                    pass

                # If We Haven't Already Processed This File, Process It

                if self.ref_directories[e] not in targeted_done:

                    # find the offset and align the waveforms
                    toff = self.offs(self.daw_directories[index], self.ref_directories[e])

                    try:
                        tester_file_obj = Sndfile(self.daw_directories[index], 'r')
                    except:
                        print('Corrupted File : '+ self.daw_directories[index])
                        return
                        pass

                    try:
                        target_file_obj = Sndfile(self.ref_directories[e], 'r')
                    except:
                        print('Corrupted File : ' +self. ref_directories[e])
                        return
                        pass

                    if toff > 0:
                        tester_file_obj.seek(toff)
                    else:
                        target_file_obj.seek(fabs(toff))

                    # Read The First 1000 Samples Of Each File
                    # If Each Sample Is Within 6dB Of The Other, We Have A Match And Can Begin Processing
                    numpy_matrix_of_track1 = self.mono(tester_file_obj.read_frames(1000))
                    numpy_matrix_of_track2 = self.mono(target_file_obj.read_frames(1000))

                    if np.array_equal(numpy_matrix_of_track1, numpy_matrix_of_track2):
                        print('')
                        print "MATCH: " + self.daw_directories[index] + " matches " + self.ref_directories[e]

                        try:
                            q_action.processEvents()
                        except:
                            pass

                        # mark files as done
                        test_done_for_files.append(self.daw_directories[index])
                        targeted_done.append(self.ref_directories[e])

                        # we can't read the entire file into RAM at once
                        # so instead we're breaking it into one-second parts
                        l = min((tester_file_obj.nframes - toff), (target_file_obj.nframes - toff)) / tester_file_obj.samplerate
                        for n in xrange(0, l, 1):
                            errs = 0
                            try:
                                # drop all but the first channel
                                track_one_response = self.mono(tester_file_obj.read_frames(tester_file_obj.samplerate))
                                track_two_response = self.mono(target_file_obj.read_frames(target_file_obj.samplerate))

                                # are these arrays equivalent? if not, there's an error
                                if not np.array_equal(track_one_response, track_two_response):
                                    file_count += 1
                                    # where's the error?
                                    # we find it by comparing sample by sample across this second of audio
                                    for m in xrange(len(track_one_response)):
                                        if not np.array_equal(track_one_response[m], track_two_response[m]):

                                            # We found it! print a message and we're done with these files
                                            errs = (n * tester_file_obj.samplerate) + m + 1000
                                            print self.Interstitial.messages['errorFoundBw'] +self.daw_directories[index] + " and " + self.ref_directories[e] + " at sample " + str(errs)

                                            try:
                                                q_action.processEvents()
                                            except:
                                                pass

                                            break

                                if errs != 0:
                                    break

                            except RuntimeError:
                                break

                        # Append Metadata For Output
                        values += path.abspath(self.daw_directories[index]) + "," + path.abspath(self.ref_directories[e]) + ","
                        values += datetime.datetime.fromtimestamp(stat(self.daw_directories[index]).st_ctime).strftime("%Y-%m-%d %H:%M:%S") + ","
                        values += str(stat(self.daw_directories[index]).st_size) + "," + str(tester_file_obj.channels) + "," + str(tester_file_obj.samplerate) + ","
                        values += str(datetime.timedelta(seconds=int(tester_file_obj.nframes / tester_file_obj.samplerate))) + "," + str(errs) + ","
                        values += str(datetime.timedelta(seconds=int(errs/tester_file_obj.samplerate)))

                        values += "\n"
                        found = True
                        unmatched_flag = False

                        self.scanned_daw_files.append(self.daw_directories[index])
                        self.scanned_ref_files.append(self.ref_directories[e])

                    else:
                        unmatched_flag = True
                        pass

                    if found:
                        break
             # if found:
            #     break




        # Create Header Information For Manifest
        manifest_info = {'testers': self.daw_directories, 'file_count': file_count, 'values': values}
        return {'manifest_info': manifest_info}

    def writeManifestFile(self, file_path, manifest_content):
        """
        Write Manifest File
        @param file_path: Manifest File Path(String)
        @param manifest_content: Manifest Content (Tuple)
        @return:Manifest Content(String)
        """

        try:
            f = open(file_path, 'w')
            f.write(manifest_content)
            print self.Interstitial.messages['wroteManifest'] + path.abspath(f.name)
            f.close()
        except:
            print self.Interstitial.messages['illegalPath'] + file_path

    def generateManifestContent(self, template_of_manifest_file_lines, manifest_info):
        """
        Generate Manifest Content
        @param template_of_manifest_file_lines: Lines Template Of Manifest File
        @return:manifest_content
        """

        manifest_content = ''
        for template_of_manifest_single_line in template_of_manifest_file_lines:
            response = False

            response = self.setValuesForScheduler(template_of_manifest_single_line,
                                                '{{current_date}}',
                                                str(manifest_info['current_date']))

            if response is False:
                response = self.setValuesForScheduler(template_of_manifest_single_line,
                                                '{{initiated}}',
                                                str(manifest_info['initiated']))

            if response is False:
                response = self.setValuesForScheduler(template_of_manifest_single_line,
                                                '{{seconds}}',
                                                str(manifest_info['seconds_content']))

            if response is False:
                response = self.setValuesForScheduler(template_of_manifest_single_line,
                                                '{{testers}}',
                                                str(manifest_info['testers']))

            if response is False:
                response = self.setValuesForScheduler(template_of_manifest_single_line,
                                                '{{bad_files}}',
                                                str(manifest_info['file_count']))

            if response is False:
                response = self.setValuesForScheduler(template_of_manifest_single_line,
                                                '{{columns}}',
                                                str(manifest_info['columns']))

            if response is False:
                response = self.setValuesForScheduler(template_of_manifest_single_line,
                                                '{{values}}',
                                                manifest_info['values'])

            if response is False:
               # If No Value Found To Replace
                manifest_content += template_of_manifest_single_line
            else:
                manifest_content += response

        return manifest_content

    def setValuesForScheduler(self, string, find_string, replace_with_string):
        """
        @param string: Template String
        @param find_string: Find String string to be replaced with
        @param replace_with_string: String to be replaced with

        @return: String
        """

        try:self.Interstitial = SharedApp.SharedApp.App
        except:pass

        string = string
        find_string = find_string
        replace_with_string = replace_with_string

        if find_string in string:
            return string.replace(find_string, replace_with_string)

        return False
# -*- coding: UTF-8 -*- # Interstitial Error Detector # Version 0.2, 2013-08-28 # Copyright (c) 2013 AudioVisual Preservation Solutions # All rights reserved. # Released under the Apache license, v. 2.0 # Created on May 14, 2014 # @author: <NAME> <<EMAIL>> Application Directories Handler Core  Class Constructor Set Number Of Reference Dirs
         @return daw_dirs_core:String Set Number Of Daw Dirs
         @return number_of_ref_core:String Set Daw Dirs Core
         @return None Set Daw Dirs Core
         @return None Set Ref Dirs Core
         @return None Set Ref Dirs Core
         @return None mono(numpy matrix ar)
         reduces an n-dimensional matrix to a 1-dimensional list if n > 1
         if n = 1, returns it
         @param numpy_matrix: Numpy Matrix
         @return: numpy_matrix offs(audiofile track1, audiofile track2)
         calculates the head offset between two (supposedly) otherwise identitical audio files
         this is achieved via finding the peak-to-peak difference of the waveform heads # opens files for reading # calculates the head of each file (first twentieth of the waveform) # if this is less than 5 seconds of audio (that is, the waveform is under 100 seconds long) # then the head is the first five seconds of the waveform # reads the head of each file (as absolute values, accounting for reversed waveforms) # into a 1-dimensional numpy matrix (via mono function) # returns the difference between the peak of each list Populate (File Path Dir)
         walks the file tree under dir recursively and returns all .wav files in it Method to handle all special characters
         @param string_to_be_handled: String To Be Handled
         @return:  String - Fixed characters String Run Executor For all Directories
         @param manifest_path: Manifest File Path
         @param q_action: QCoreApplication Object
         @param is_unit_test: Is call generated from Unit test
         @return manifest_file_path/{manifest_info, manifest_file_path}: Sting/List # Launch The Scanner to Test Audio Files # Open template file and get manifest template content to manifest file creation # Do We Have Metadata? If So, Write A Manifest # Write Manifest File Execute (wavefile first_wave_file, wavefile second_wave_file, directory d, QAction qa)
         The heart of interstitial - performs a null test on two wav files and returns the first difference # initialize useful variables # Ensures That We Have Legitimate Directories To Walk Down # And Populates The List Of Files To Test # Process Each File In The Tester Array # If We Haven't Already Processed This File, Process It # find the offset and align the waveforms # Read The First 1000 Samples Of Each File # If Each Sample Is Within 6dB Of The Other, We Have A Match And Can Begin Processing # mark files as done # we can't read the entire file into RAM at once # so instead we're breaking it into one-second parts # drop all but the first channel # are these arrays equivalent? if not, there's an error # where's the error? # we find it by comparing sample by sample across this second of audio # We found it! print a message and we're done with these files # Append Metadata For Output # if found: #     break # Create Header Information For Manifest Write Manifest File
         @param file_path: Manifest File Path(String)
         @param manifest_content: Manifest Content (Tuple)
         @return:Manifest Content(String) Generate Manifest Content
         @param template_of_manifest_file_lines: Lines Template Of Manifest File
         @return:manifest_content # If No Value Found To Replace @param string: Template String
         @param find_string: Find String string to be replaced with
         @param replace_with_string: String to be replaced with
 
         @return: String