Alex Stabile Period 4 Code Writeup New Code: def chordid(chord

advertisement
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.
Download