示例#1
0
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
示例#2
0
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)