Alex Stabile Period 4 Code Writeup New Code: def chordid(chord): #takes array of note numbers or string of note letters twelvetone=['C','Db','D','Eb','E','F','Gb','G','Ab','A','Bb','B'] interval_types=['P1','m2','M2','m3','M3','P4','TT','P5','m6','M6','m7','M7'] if not str(chord)[0]=='[' and not str(chord)[0]=='(': notes=chord.split() else: notes=chord[:] #not a list or tuple print 'NOTES: ', notes intervals={} for n in notes: intervals[n]='' dict_vals=[] start=notes.index(n)+1 if start==len(notes): start=0 while not notes[start]==n: dist=twelvetone.index(n)-twelvetone.index(notes[start]) if dist>0: dist=12-dist dist=abs(dist) #keep intervals sorted from least to greatest flag=False for x in xrange(0, len(dict_vals)): if flag==True: continue cur=interval_types[dist] if interval_types.index(cur)<interval_types.index(dict_vals[x]): dict_vals.insert(x, cur) flag=True if flag==False: dict_vals.append(interval_types[dist]) if start==len(notes)-1: start=0 else: start+=1 for elem in dict_vals: intervals[n]+=elem+' ' to_cut=intervals[n] intervals[n]=to_cut[:len(to_cut)-1] #cuts off space at end #intervals is a dictionary containing intervals between notes #if each note were the root #creates a list of different possible chords qualities=filter(lambda x:len(x)>0,open('chords.txt').read().split('\n')) thisone='' root='' inversion='root' temp_str='' flag=False for n in notes: #not intervals, because interval keys and notes values should be the same but ordered differently for i in qualities: lookat=i[i.index(':')+1:] if intervals[n]==lookat: root=n #root of chord temp_str=intervals[n] thisone=i[:i.index(':')] #chord quality flag=True if flag==True: break if root=='': return 'CHORD NOT FOUND' i=notes.index(root) bass=notes[0] #find inversion based on distance between the root and bass note of chord: root_to_bass=-1 i=twelvetone.index(root) flag=False while flag==False: root_to_bass+=1 if twelvetone.index(bass)==i: flag=True if i<11: i+=1 else: i=0 root_pos_intervals=temp_str.split() print root_pos_intervals if root_to_bass==0: inversion='Root Position' elif interval_types[root_to_bass]==root_pos_intervals[0]: inversion='First Inversion' elif interval_types[root_to_bass]==root_pos_intervals[1]: inversion='Second Inversion' else: inversion='Third Inversion' return root+' '+thisone+', '+inversion def altnonchord(notes_str, num): if num<1: return 'NO CHORD' notes=notes_str.split() combos=combinations(notes, num) #creates an iterable containing all possible poss_chords=[] #combinations of length given by num for elem in combos: chord=chordid(elem) if not chord=='CHORD NOT FOUND': poss_chords.append(chord) all_chords=filter(lambda x:len(x)>0,open('chords.txt').read().split('\n')) #prioritizes chords based on simplicity: min=999 best='' for elem in poss_chords: print elem justchord=elem[elem.index(' ')+1:elem.index(',')] for i in xrange(0, len(all_chords)): if justchord in all_chords[i] and i<min: min=i best=elem if not best=='': return '\nDECIDED ON: '+best else: return altnonchord(notes_str, num-1) #combinations will get smaller, #eventually removing all the non-chord tones Explanation: The chordid() method can take two kinds of inputs: either a string containing note names separated by spaces, or a list of the note names. A string will simply be split into a list of notes. The method iterates through the list of note names, creating a dictionary. Each key in the dictionary is one of the notes, and the value associated with it is a list of the intervals between that note and all the other notes. The intervals are kept in order from least to greatest as the list is created. The method then reads from a text file I created, creating a list of strings containing which combinations of intervals make up which kinds of chords. For example, one line reads "Major:M3 P5" because the notes in a major chord are a major third and perfect fifth above the root. These strings are then compared to the values in the previously created dictionary in the order that their keys appeared in the chord (from lowest to highest). If the intervals in a dictionary value are found within a string read from the text file, the key corresponding to that value must be the root of that type of chord. This method works very well, but there is a situation that may throw it off. If a group of notes includes non-chord tones, chordid() will attempt to find a chord that includes them, causing it to return "CHORD NOT FOUND." If this happens, the group of notes is passed to the altnonchord() method along with a number (usually 3 to start). This method generates all possible combinations of the notes, of length denoted by the number argument. Each combination is then passed to the chordid() method. Because there are only three notes in each combination, one of them should yield a result from the chordid() method. If it doesn't, the altnonchord() method is called again, but this time will find combinations of length two. This is occasionally necessary when a group of notes contains only two chordal notes. With these methods working together, my code can consistently and accurately identify what kind of chord is represented in each beat of a piece of music.