def melodic_arch(score: stream.Stream, phrase_length: int): total_phrases = 0 #total number of phrases sum_pitch_height = [ 0 for i in range(phrase_length) ] #sum of heights for each note position, measured in semitones above middle C phrase = [] #phrase is empty at beginning of piece for n in score.recurse().notesAndRests: if isinstance(n, chord.Chord): n = max(n) if n.tie and (n.tie.type == 'stop' or n.tie.type == 'continue'): #do not count a tied note more than once continue if n.isRest or (len(n.expressions) != 0 and 'fermata' == n.expressions[0].name): if len(phrase) == phrase_length: total_phrases += 1 for i in range(phrase_length): sum_pitch_height[ i] += phrase[i].pitch.ps - 60 #60 is middle C phrase = [] else: phrase.append(n) #if reached end of score, check the last phrase is of desired length if len(phrase) == phrase_length: total_phrases += 1 for i in range(phrase_length): sum_pitch_height[i] += phrase[i].pitch.ps - 60 if total_phrases == 0: return None return [height / total_phrases for height in sum_pitch_height]
def avg_phrase_length(score: stream.Stream): total_phrases = 0 #total number of phrases length = 0 #phrase is empty at beginning of piece phrase_lengths = [] #all the phrase lengths for n in score.recurse().notesAndRests: if isinstance(n, chord.Chord): n = max(n) if n.tie and (n.tie.type == 'stop' or n.tie.type == 'continue'): #do not count a tied note more than once continue if n.isRest or (len(n.expressions) != 0 and 'fermata' == n.expressions[0].name): phrase_lengths.append(length) total_phrases += 1 length = 0 else: length += 1 #reached end if length != 0: phrase_lengths.append(length) total_phrases += 1 if total_phrases == 0: return None return sum(phrase_lengths) / total_phrases
def get_note_lengths(score: stream.Stream): note_lengths = dict() note_count = 0.0 for n in score.recurse().notesAndRests: if isinstance(n, chord.Chord): n = max(n) if n.quarterLength not in note_lengths: note_lengths[n.quarterLength] = 1 else: note_lengths[n.quarterLength] += 1 note_count += 1.0 i = 0 vector = [] while i < 4: i += 0.25 if i in note_lengths: vector.append(note_lengths[i] / note_count) else: vector.append(0) return vector
def nonharmonic_notes(score: stream.Stream): key_sig = score.analyze('key') certainty = key_sig.tonalCertainty() notes_within_key = [p.name for p in key_sig.pitches] for pitch in key_sig.pitches: notes_within_key.extend( [p.name for p in pitch.getAllCommonEnharmonics()]) total_notes = 0 #total number of notes num_nonharmonic = 0 #total number of nonharmonic notes for n in score.recurse().notes: if isinstance(n, chord.Chord): n = max(n) if n.tie and (n.tie.type == 'stop' or n.tie.type == 'continue'): #do not count a tied note more than once continue else: if n.pitch.name not in notes_within_key: num_nonharmonic += 1 total_notes += 1 if total_notes == 0: return None return (certainty, 1 - num_nonharmonic / total_notes)
def get_key(score: stream.Stream): first_key = score.recurse().getElementsByClass(key.KeySignature) if not first_key: return 0 else: return first_key[0].sharps
def get_meter(score: stream.Stream): first_meter = score.recurse().getElementsByClass(meter.TimeSignature) if not first_meter: return (0, 0) else: return (first_meter[0].numerator, first_meter[0].denominator)