def next_violin_dyad(previous, harmony, lowest_pitch, highest_pitch): harmony = [p % 12 for p in harmony] prev_lower = min(previous) prev_higher = max(previous) lower_ranked = rank_options(prev_lower, harmony, lowest_pitch, highest_pitch) higher_ranked = rank_options(prev_higher, harmony, lowest_pitch, highest_pitch) ranked = [] for lower_rank, lower in enumerate(lower_ranked): for higher_rank, higher in enumerate(higher_ranked): interval = higher - lower if interval > 0 and interval < 8: rank = lower_rank + higher_rank ranked.append({ 'rank': lower_rank + higher_rank, 'dyad': [lower, higher] }) ranked.sort(key=lambda x: x['rank']) ranked = [r['dyad'] for r in ranked] weights = exp_weights(len(ranked)) return weighted_choice(ranked, weights)
def next_soloist_note(soloist_name, previous, harmony, movement_number, volume_section_number): out_of_tune_rate = OUT_OF_TUNE_RATE[volume_section_number] global FIRST_NOTE if FIRST_NOTE: out_of_tune_rate = 1.0 FIRST_NOTE = False if soloist_name == 'Bb Clarinet': out_of_tune_rate = 0.0 registers = REGISTERS[movement_number] register = registers[soloist_name] lowest = register['lowest'] highest = register['highest'] if previous == None: previous = random.randint(lowest, highest) if random.random() < out_of_tune_rate: options = [p for p in range(previous - 2, previous + 3) if p >= lowest and p <= highest] p = random.choice(options) interval = random.choice([1, 2]) if interval == 2: pitch = [p - 1, p + 1] elif interval == 1: up_or_down = random.choice([1, -1]) pitch = [p, p + up_or_down] pitch.sort() else: options = [p for p in range(previous - 7, previous + 8) if p % 12 in harmony and p >= lowest and p <= highest] ranked_by_distance = rank_by_distance(previous, options) weights = exp_weights(len(ranked_by_distance), exponent=1.5) pitch = weighted_choice(ranked_by_distance, weights) return pitch
def next_bass_note(previous, harmony, lowest_pitch, highest_pitch): harmony = [p % 12 for p in harmony] options = [p for p in range(previous - 7, previous + 8) if p % 12 in harmony and p >= lowest_pitch and p <= highest_pitch] ranked_by_distance = rank_by_distance(previous, options) ranked_by_best_root = rank_by_best_root(harmony, options) ranks = defaultdict(list) len_options = len(options) for p in options: distance_rank = len_options - ranked_by_distance.index(p) root_rank = len_options - ranked_by_best_root.index(p) rank = distance_rank + root_rank ranks[rank].append(p) ranked = [] for k in sorted(ranks.keys(), reverse=True): random.shuffle(ranks[k]) ranked.extend(ranks[k]) weights = exp_weights(len(ranked)) return weighted_choice(ranked, weights)
def next_accompaniment_notes(name_a, name_b, previous_a, previous_b, harmony, unused_harmony, movement_number): registers = REGISTERS[movement_number] a_register = registers[name_a] b_register = registers[name_b] previous_a = get_previous(previous_a) previous_b = get_previous(previous_b) if previous_a == None: previous_a = random.randint(a_register['lowest'], a_register['highest']) if previous_b == None: previous_b = random.randint(b_register['lowest'], b_register['highest']) a_options = build_options(previous_a, harmony, unused_harmony, a_register['lowest'], registers[name_a]['highest']) b_options = build_options(previous_b, harmony, unused_harmony, b_register['lowest'], registers[name_b]['highest']) a_weights = exp_weights(len(a_options)) b_weights = exp_weights(len(b_options)) max_weight = a_weights[0] + b_weights[0] weighted_interval_options = [] for a, a_weight in zip(a_options, a_weights): for b, b_weight in zip(b_options, b_weights): interval_class = get_interval_class(a, b) if interval_class == 1: continue if interval_class in [5, 4, 3]: weight = max_weight elif interval_class in [2, 0]: weight = max_weight / 2 elif interval_class == 6: weight = 0 if a == b: weight = 0 weight = weight + a_weight + b_weight weighted_interval_options.append(((a, b), weight)) choice_a, choice_b = weighted_choice(*zip(*weighted_interval_options)) # Add double stops if name_a == 'Violin' and name_b == 'Cello': new_choice_a = None new_a_options = [] for p in a_options: interval_class = get_interval_class(choice_a, p) in_other = p % 12 == choice_b % 12 if interval_class in [3, 4, 5] or in_other and p != choice_a: new_a_options.append(p) a_options = new_a_options if a_options: violin_second_note = random.choice(a_options) new_choice_a = [choice_a, violin_second_note] new_choice_b = None new_b_options = [] for p in b_options: interval_class = get_interval_class(choice_b, p) in_other = p % 12 == choice_a % 12 if interval_class in [3, 4, 5] or in_other and p != choice_b: new_b_options.append(p) b_options = new_b_options if b_options: cello_second_note = random.choice(b_options) new_choice_b = [choice_b, cello_second_note] if new_choice_a: choice_a = new_choice_a if new_choice_b: choice_b = new_choice_b return choice_a, choice_b
[(4, 1), 1, 1, 1], [4, 1, 1, 1, 1], [4, 2, 2], [1, (3, 4)], [2, (2, 4)], [1, 1, (2, 4)], [1, 1, 1, (1, 4)], [1, 1, 1, 1, 4], [2, 2, 4], ] for k in REPLACE: REPLACE[k]['weights'] = exp_weights(len(REPLACE[k]['options']), exponent=1.8) # Check for k in REPLACE: expected = k if isinstance(k, tuple): expected = sum(k) for option in REPLACE[k]['options']: total = 0 for duration in option: if isinstance(duration, tuple): duration = sum(duration) total += duration
def __init__(self): self.history = [] self.OPTIONS = defaultdict(list) self.WEIGHTS = defaultdict(list) self.OPTIONS[1] = [[8, 8], [12, 4], [16], [8, 4, 4], [4, 12], [4, 4, 8], [4, 8, 4], [4, 4, 4, 4]] self.WEIGHTS[1] = exp_weights(len(self.OPTIONS[1]), exponent=1.5) self.OPTIONS[2] = [ [12, (4, 8), 8], [8, (8, 4), 12], [(16, 8), 8], [8, (8, 12), 4], [(16, 12), 4], [(16, 8), 4, 4], [12, (4, 4), 12], [8, (8, 8), 8], [8, (8, 16)], [(16, 4), 12], [12, (4, 16)], [(16, 16)], [4, (12, 16)], [8, (8, 4), 8, 4], [(16, 4), 8, 4], [8, (8, 4), 4, 8], [(16, 4), 4, 8], [8, (8, 8), 4, 4], [4, (12, 8), 8], [4, 4, (8, 8), 8], [4, (12, 4), 12], [12, (4, 8), 4, 4], [4, 8, (4, 16)], [4, 4, (8, 4), 12], [4, 4, (8, 16)], [(16, 4), 4, 4, 4], [4, (12, 12), 4], [4, (12, 8), 4, 4], [4, 4, (8, 12), 4], [4, 4, 4, (4, 16)], [4, (12, 4), 8, 4], [4, (12, 4), 4, 8], [4, 4, 4, (4, 4), 12], [12, (4, 4), 4, 4, 4], [4, 8, (4, 4), 4, 8], [4, 8, (4, 4), 8, 4], [8, 4, (4, 4), 4, 8], [8, 4, (4, 4), 8, 4], [8, (8, 4), 4, 4, 4], [4, 4, (8, 4), 8, 4], [4, 4, (8, 4), 4, 8], [4, (12, 4), 4, 4, 4], [4, 4, (8, 4), 4, 4, 4], [4, 4, 4, (4, 8), 4, 4], [4, 4, 4, (4, 4), 4, 8], [4, 4, 4, (4, 4), 8, 4], [4, 8, (4, 4), 4, 4, 4], [8, 4, (4, 4), 4, 4, 4], [4, 4, 4, (4, 4), 4, 4, 4], # # 7 # [4, 4, 4, (4, 4), 4, 4, 4], # # 6 # [4, 4, (8, 4), 4, 4, 4], # [4, 4, 4, (4, 8), 4, 4], # [4, 4, 4, (4, 4), 4, 8], # [4, 4, 4, (4, 4), 4, 8], # [4, 4, 4, (4, 4), 8, 4], # [4, 8, (4, 4), 4, 4, 4], # [8, 4, (4, 4), 4, 4, 4], # # 5 # [4, 4, 4, (4, 4), 12], # [12, (4, 4), 4, 4, 4], # [4, 8, (4, 4), 4, 8], # [4, 8, (4, 4), 8, 4], # [8, 4, (4, 4), 4, 8], # [8, 4, (4, 4), 8, 4], # [8, (8, 4), 4, 4, 4], # [4, 4, (8, 4), 8, 4], # [4, 4, (8, 4), 4, 8], # [4, (12, 4), 4, 4, 4], # # 4 # [(16, 4), 4, 4, 4], # [4, (12, 8), 4, 4], # [4, 4, (8, 12), 4], # [4, 4, 4, (4, 16)], # [4, (12, 4), 8, 4], # [4, (12, 4), 4, 8], # [8, (8, 8), 4, 4], # [4, 4, (8, 8), 8], # [8, (8, 4), 8, 4], # [8, (8, 4), 4, 8], # [12, (4, 8), 4, 4], # [4, 4, (8, 4), 12], # # 3 # [(16, 8), 4, 4], # [(16, 4), 8, 4], # [(16, 4), 4, 8], # [12, (4, 4), 8], # [12, (4, 8), 4], # [8, (8, 12), 4], # [8 (8, 8), 8], # [8, (8, 4), 12], # [4, (12, 12), 4], # [4, (12, 8), 8], # [4, (12, 4), 12], # [4, 8, (4, 16)], # [4, 4, (8, 16)], # # 2 # [(16, 12), 4], # [4, (12, 16)], # [(16, 8), 8], # [8, (8, 16)], # [(16, 4), 12], # [12, (4, 16)], # # 1 # [(16, 16)], ] self.WEIGHTS[2] = exp_weights(len(self.OPTIONS[2]), exponent=1.2)