def check_motion_of_melody(track): melody = [note[2][0] for note in track.get_notes() if note[2]] if len(melody) <= 1: return 0 # Bool that makes sure all intervals are considered once skip_next_iteration = False # Variable to keep track on if the last two skips are in the same direction (and what direction) last_two_skips_dir = 0 good = 0 for i in range(len(melody) - 1): if skip_next_iteration: # This happens if the interval already is counted skip_next_iteration = False continue note1 = Note(melody[i]) note2 = Note(melody[i + 1]) interval = note1.measure(note2) # Steps are always good if abs(interval) <= 2: good += 1 last_two_skips_dir = 0 # Reset two skip counter continue # Skips are good depending on circumstances: direction = interval / abs( interval) # -1 if downward motion, 1 if upward # Bad, continue: Skip is in the same direction as previous two if direction == last_two_skips_dir: continue else: last_two_skips_dir = 0 # reset counter # Good: Skip is last interval of melody if i + 2 >= len(melody): good += 1 continue # At this point, there is not enough info to determine if the interval is good # without looking at the next one # --------- From here on we consider two intervals at a time ! ---------------- skip_next_iteration = True # So that the new interval is only counted once note3 = Note(melody[i + 2]) next_interval = note2.measure(note3) # Good : Skip - step if abs(next_interval) <= 2: good += 2 continue # Good: Skip - Skip (in opposite directions) if direction != next_interval / abs(next_interval): good += 2 last_two_skips_dir = 0 # Good: Skip - Skip (in same direction, if second skip is smaller than first) elif abs(next_interval) < abs(interval): good += 2 last_two_skips_dir = direction # Save direction as warning else: last_two_skips_dir = direction # Save direction as warning frac_of_good_motion = good / (len(melody) - 1) return frac_of_good_motion
def repeating_passages(track, with_duration=False): note_generetor = copy.deepcopy(track).get_notes() passage_repetitions = { } #directory of occurences of different passages (nmb of repetitions) passage_lengths = { } #directory of passage lenths, Cause you can't store two different values to same key in one directory current_passage = [ ] #List of either just (intervals as ints) or (intervals,relative difference between note durations) previous_note = None previous_note_length = 0 #Only useful when considering note durations nmb_of_notes = 0.0 #Used to calculate percentage for note in note_generetor: nmb_of_notes += 1.0 #If pause go to next note if note[-1] is None: continue #If new bar or first Note, change previous note to be the current note elif (note[0] == 0.0) or (previous_note is None): previous_note = note[-1][0] previous_note_length = note[1] current_passage = [] continue else: #Calculate inteval as an int (works over octaves) diff = Note.measure(previous_note, note[-1][0]) #If we have to take duration into consideration calculate relative duration #ev. TODO not precicely what it does but allows repetitions with all same note duration pass if with_duration: current_passage.append( [diff, (previous_note_length - note[1])]) previous_note_length = note[1] #If we don't consider duration just add interval else: current_passage.append(diff) #Set previous note to be current one previous_note = note[-1][0] #starting with the longes possible passage calculate the possible passages from current_passage for i in range(len(current_passage)): tmp = str(current_passage[i:len(current_passage)]) #key #if passage is already added increace occurance of passage if tmp in passage_repetitions: passage_repetitions[tmp] += 1.0 break #If passage isn't added to dictionary, add it else: passage_repetitions[tmp] = 0.0 passage_lengths[tmp] = len(current_passage) - i + 1.0 average_nm_of_rep = 0.0 #Will get the sum of all occurences average_len_of_repetition = 0.0 #Will get the sum of all passage length of repeated passages nmb_of_repeating_passages = 0.0 #Keeps track of the number of different repeated passages percentage_of_repetition = 0.0 #Will get the sum of all repeated notes for keys, occurences in passage_repetitions.items(): if occurences > 0.0: average_nm_of_rep += occurences length_of_passage = passage_lengths[keys] percentage_of_repetition += (length_of_passage * occurences) average_len_of_repetition += length_of_passage nmb_of_repeating_passages += 1.0 #Calculate final return data if nmb_of_repeating_passages > 0.0: average_nm_of_rep = average_nm_of_rep / nmb_of_repeating_passages average_len_of_repetition = average_len_of_repetition / nmb_of_repeating_passages percentage_of_repetition = percentage_of_repetition / nmb_of_notes #TODO percentage in faulty return (average_nm_of_rep, average_len_of_repetition, percentage_of_repetition)