def findTonicNum(songChords,
                 keyTable):  #songChords is a list, keyTable is a list of lists
    # edit songChords to change 7ths to just major
    songChordsNo7 = copy.deepcopy(songChords)
    for i in range(0, len(songChordsNo7)):
        songChordsNo7[i] = songChordsNo7[i].replace("7", "")

    maxKey = 0  #0 thru 11 for C thru B
    maxScore = 0
    #following vars are used as tiebreakers for major/relative minor later
    totalMajors = 0
    totalMinors = 0
    max_I_count = 0
    max_vi_count = 0
    for i in range(
            0, 12
    ):  #go thru each of the 12 major keys--example for key of C: C Dm Em F G G7 Am Bdim
        curScore = 0
        current_I_count = 0
        current_vi_count = 0
        key = keyTable[i]
        for chord in songChordsNo7:
            if (i == 0 and chord.find('m') == -1):
                totalMajors += 1
            elif (i == 0):
                totalMinors += 1
            for j in range(0, len(
                    key)):  #go thru each note in the major scale of the key
                note = key[j]
                if chord == note:
                    if (j == 1 or j == 2 or j == 7):
                        curScore += 0.9  #tiebreaker: the ii, iii, and vii are weighted less
                    else:
                        if (j == 0):
                            current_I_count += 1
                        elif (j == 6):
                            current_vi_count += 1
                        curScore += 1  #if it's a match, add 1 to the "score" of the current key
                    break
        if curScore > maxScore:
            maxScore = curScore
            maxKey = i
            max_I_count = current_I_count
            max_vi_count = current_vi_count
    #now our best-fitting major key is stored in maxKey

    maxKey = "w" + (str)(maxKey)

    # we determine between maxKey and its relative minor
    # naive tiebreaker rules
    # 1. If total Majors or total I's is 0, it's minor
    # likewise, if total minors or total vi's is 0, it's major
    # 2. Otherwise, compare totalMajors+total I's against totalMinors+total vi's
    if (totalMajors == 0 or max_I_count == 0
            or (totalMinors + max_vi_count > totalMajors + max_I_count)):
        maxKey = (caster.shiftNumChord(maxKey, 9)) + "m"

    return maxKey  #return key with most matches for the chords in the song
Example #2
0
                ('B', 11)]

    for origChord in origChords:
        castedFlag = False  #ADDITIONAL CODE FOR CHECKER VERSION
        #example of process: E/C# -> w4/w1 -> w0/w9 (store shift as 4) -> C/A -> Am -> w9m -> w1m -> C#m
        #convert origChord to numeral version
        origChord = caster.makeFlatsSharps(origChord)
        tempChord = caster.letterChordToNumChord(origChord, noteNums)
        #shift numeral chord to C numeral version
        if tempChord[1]=='1' and len(tempChord)>2 and \
            (tempChord[2]=='0' or tempChord[2]=='1'):
            rootNum = int(tempChord[1:3])
        else:
            rootNum = int(tempChord[1])
        shift = rootNum
        tempChord = caster.shiftNumChord(tempChord, -shift)
        #convert C numeral version to C letter version
        tempChord = caster.numChordToLetterChord(tempChord)
        #cast C letter version using table
        for chord in castingTable:
            if tempChord == chord[0]:
                tempChord = chord[1]
                castedFlag = True
                break
        #convert casted letter chord to casted numeral chord
        tempChord = caster.letterChordToNumChord(tempChord, noteNums)
        #shift casted numeral chord back
        tempChord = caster.shiftNumChord(tempChord, shift)
        #convert casted numeral chord to casted letter chord
        tempChord = caster.numChordToLetterChord(tempChord)
        #print('Converted '+origChord+' to '+tempChord)
Example #3
0
                curLine = f.readline()
        # now we've hit a songmarker, so let's move on to processing!

        #--STAGE 2: PROCESSING--
        #only process if there actually are chords in origChords
        if (len(origChords) > 0):
            #find tonic chord
            tonicNum = findTonicNumNo7.findTonicNumNo7(origChords, keyTable)

            #convert all chords in song to number chords
            for origChord in origChords:
                origChord = caster.makeFlatsSharps(origChord)
                # shift numeral chord to relative to C (w0)
                numChords.append(
                    caster.shiftNumChord(
                        caster.letterChordToNumChord(origChord, noteNums),
                        -tonicNum))

            #cast to correct interval based on semitones
            #we convert each chord to its interval notation (e.g. V, vi, I, etc.)
            for i in range(0, len(numChords)):
                for chord in castingTable:
                    if numChords[i] == chord[0]:
                        numChords[i] = chord[1]
                        break  #break out of inner loop

            #iterate through list of chords, tracking and counting each cadence (add it to the list if not there, if it is there, add 1)
            for i in range(
                    0,
                    len(numChords) - 1
            ):  # if we're doing every pair, we want to skip last element for loop
Example #4
0
    ('C#', 1), ('D#', 3), ('F#', 6), ('G#', 8), ('A#', 10), ('C', 0), ('D', 2),
    ('E', 4), ('F', 5), ('G', 7), ('A', 9), ('B', 11)
]  # have to check the sharps first so it doesn't switch 'C#' into 'w0#'

fullKeyTable = [[[]]]  #outer level: major/melodic minor/harmonic minor
#middle level: the twelve "root keys": C, C#, D, D#, etc.
#inner level: all the chords within that root key
fullKeyTable[0][0] = ["C", "Dm", "Em", "F", "G", "G7", "Am", "Bdim"]  #major
fullKeyTable.append(
    [["Cm", "Dm", "D#7", "F", "G", "G7", "Adim",
      "Bdim"]])  #melodic minor... note D#aug converted to D#7 by our casting
fullKeyTable.append([["Cm", "Ddim", "D#7", "Fm", "G", "G7", "G#",
                      "Bdim"]])  #harmonic minor
for k in range(0, len(fullKeyTable)):
    for i in range(1, 12):
        curKey = []
        for j in range(0, len(fullKeyTable[k][0])):
            tempChord = caster.makeFlatsSharps(fullKeyTable[k][0][j])
            curKey.append(
                caster.shiftNumChord(
                    caster.letterChordToNumChord(tempChord, noteNums), i))
        fullKeyTable[k].append(curKey)

with open("key_table_UTF-8.txt", "w") as f:
    for level in fullKeyTable:
        for key in level:
            for note in key:
                note = caster.numChordToLetterChord(note)
                f.write(note + " "),
            f.write("\n")
print("Finished generating key tables")
def convert(input_file, output_file):

    #Example input and output files
    #input_file = "chords_uku_english_only_songmarkers_empty_lines_removed.txt"
    #output_file = "rns_uku_english_only_songmarkers_empty_lines_removed.txt"

    #global scope variables
    noteNums = [
        ('C#', 1), ('D#', 3), ('F#', 6), ('G#', 8), ('A#', 10), ('C', 0),
        ('D', 2), ('E', 4), ('F', 5), ('G', 7), ('A', 9), ('B', 11)
    ]  # have to check the sharps first so it doesn't switch 'C#' into 'w0#'

    # read in cadence casting table
    with open('cadence_casting_UTF-8.txt', 'r') as f:
        inputs = []
        outputs = []
        exploLine = []
        for line in f:
            exploLine = line.split("\t")
            exploLine[0] = exploLine[0].replace('\xef\xbb\xbf',
                                                '')  # clean up special chars
            inputs.append(exploLine[0].replace(
                '\\ufeff', '').strip())  # clean up the special chars
            outputs.append(exploLine[1].replace(
                '\n', '').strip())  # clean up special chars
        castingTable = list(zip(
            inputs, outputs))  # convert casting table to a list of tuples
        print("Opened Cadence Casting Table")
    print(castingTable)  # test to make sure we've read in the table correctly

    # read in key tables for finding tonic num
    keyTable = []
    with open('key_table_UTF-8.txt', 'r') as f:
        curLine = f.readline()
        while (curLine != ""):
            keyTable.append(curLine.split())
            curLine = f.readline()
    print(keyTable)  # test to make sure we've read table correctly

    #read in chords from file, song by song
    #split is by "  | | S O N G M A R K E R | |", and it starts with lyrics and the songmarker is AFTER each song

    with open(input_file, 'r') as f:
        with open(output_file, 'w') as out:
            curLine = f.readline()
            while (curLine != ""):
                #--STAGE 0: RESET--
                origChords = []
                numChords = []
                tonicNum = 0
                songmarker = ""

                #--STAGE 1: READING SONG--
                if (curLine != "\n" and curLine.find("SONG OVER") == -1):
                    while (curLine.find("SONG OVER") == -1
                           ):  #while we're not at the Songmarker
                        lineChords = curLine.split()
                        for chord in lineChords:
                            origChords.append(chord)
                        origChords.append(
                            '\n')  #keep output of original file intact
                        curLine = f.readline()
                    songmarker = curLine  #make sure we print the songmarker line after each song
                # now we've hit a songmarker, so let's move on to processing!
                else:
                    out.write(
                        curLine)  #keep the formatting of original file intact

                #--STAGE 2: PROCESSING--
                #only process if there actually are chords in origChords
                if (len(origChords) > 0):
                    #find tonic chord
                    tonicNum = findTonicNumNo7.findTonicNumNo7(
                        origChords, keyTable)

                    #convert all chords in song to number chords
                    for origChord in origChords:
                        origChord = caster.makeFlatsSharps(origChord)
                        # shift numeral chord to relative to C (w0)
                        numChords.append(
                            caster.shiftNumChord(
                                caster.letterChordToNumChord(
                                    origChord, noteNums), -tonicNum))

                    #cast to correct interval based on semitones
                    #we convert each chord to its interval notation (e.g. V, vi, I, etc.)
                    for i in range(0, len(numChords)):
                        for chord in castingTable:
                            if numChords[i] == chord[0]:
                                numChords[i] = chord[1]
                                break  #break out of inner loop

                    #print
                    for numChord in numChords:
                        out.write(numChord)
                        if numChord != '\n':
                            out.write(" ")
                    out.write(songmarker)
                curLine = f.readline()