588 lines
24 KiB
Python
588 lines
24 KiB
Python
#!/usr/bin/env python
|
|
# coding: utf-8
|
|
|
|
# In[1]:
|
|
|
|
|
|
from itertools import chain, combinations, permutations, product, pairwise
|
|
from math import prod, log
|
|
from copy import deepcopy
|
|
import networkx as nx
|
|
from fractions import Fraction
|
|
import json
|
|
from operator import add
|
|
|
|
def hs_array_to_fr(hs_array):
|
|
return prod([pow(dims[d], hs_array[d]) for d in range(len(dims))])
|
|
|
|
def hs_array_to_cents(hs_array):
|
|
return (1200 * log(hs_array_to_fr(hs_array), 2))
|
|
|
|
def expand_pitch(hs_array):
|
|
expanded_pitch = list(hs_array)
|
|
frequency_ratio = hs_array_to_fr(hs_array)
|
|
if frequency_ratio < 1:
|
|
while frequency_ratio < 1:
|
|
frequency_ratio *= 2
|
|
expanded_pitch[0] += 1
|
|
elif frequency_ratio >= 2:
|
|
while frequency_ratio >= 2:
|
|
frequency_ratio *= 1/2
|
|
expanded_pitch[0] += -1
|
|
return tuple(expanded_pitch)
|
|
|
|
def expand_chord(chord):
|
|
return tuple(expand_pitch(p) for p in chord)
|
|
|
|
def collapse_pitch(hs_array):
|
|
collapsed_pitch = list(hs_array)
|
|
collapsed_pitch[0] = 0
|
|
return tuple(collapsed_pitch)
|
|
|
|
def collapse_chord(chord):
|
|
return tuple(collapse_pitch(p) for p in chord)
|
|
|
|
def transpose_pitch(pitch, trans):
|
|
return tuple(map(add, pitch, trans))
|
|
|
|
def transpose_chord(chord, trans):
|
|
return tuple(transpose_pitch(p, trans) for p in chord)
|
|
|
|
def cent_difference(hs_array1, hs_array2):
|
|
return hs_array_to_cents(hs_array2) - hs_array_to_cents(hs_array1)
|
|
|
|
def pitch_difference(hs_array1, hs_array2):
|
|
return transpose_pitch(hs_array1, [p * -1 for p in hs_array2])
|
|
|
|
def edges(chords, min_symdiff, max_symdiff, max_chord_size):
|
|
|
|
def reverse_movements(movements):
|
|
return {value['destination']:{'destination':key, 'cent_difference':value['cent_difference'] * -1} for key, value in movements.items()}
|
|
|
|
def is_directly_tunable(intersection, diff):
|
|
# this only works for now when intersection if one element - need to fix that
|
|
return max([sum(abs(p) for p in collapse_pitch(pitch_difference(d, list(intersection)[0]))) for d in diff]) == 1
|
|
|
|
for combination in combinations(chords, 2):
|
|
[expanded_base, expanded_comp] = [expand_chord(chord) for chord in combination]
|
|
edges = []
|
|
transpositions = set(pitch_difference(pair[0], pair[1]) for pair in set(product(expanded_base, expanded_comp)))
|
|
for trans in transpositions:
|
|
expanded_comp_transposed = transpose_chord(expanded_comp, trans)
|
|
intersection = set(expanded_base) & set(expanded_comp_transposed)
|
|
symdiff_len = sum([len(chord) - len(intersection) for chord in [expanded_base, expanded_comp_transposed]])
|
|
if (min_symdiff <= symdiff_len <= max_symdiff):
|
|
rev_trans = tuple(t * -1 for t in trans)
|
|
[diff1, diff2] = [list(set(chord) - intersection) for chord in [expanded_base, expanded_comp_transposed]]
|
|
base_map = {val: {'destination':transpose_pitch(val, rev_trans), 'cent_difference': 0} for val in intersection}
|
|
base_map_rev = reverse_movements(base_map)
|
|
maps = []
|
|
diff1 += [None] * (max_chord_size - len(diff1) - len(intersection))
|
|
perms = [list(perm) + [None] * (max_chord_size - len(perm) - len(intersection)) for perm in set(permutations(diff2))]
|
|
for p in perms:
|
|
appended_map = {
|
|
diff1[index]:
|
|
{
|
|
'destination': transpose_pitch(val, rev_trans) if val != None else None,
|
|
'cent_difference': cent_difference(diff1[index], val) if None not in [diff1[index], val] else None
|
|
} for index, val in enumerate(p)}
|
|
yield (tuple(expanded_base), tuple(expanded_comp), {
|
|
'transposition': trans,
|
|
'symmetric_difference': symdiff_len,
|
|
'is_directly_tunable': is_directly_tunable(intersection, diff2),
|
|
'movements': base_map | appended_map
|
|
},)
|
|
yield (tuple(expanded_comp), tuple(expanded_base), {
|
|
'transposition': rev_trans,
|
|
'symmetric_difference': symdiff_len,
|
|
'is_directly_tunable': is_directly_tunable(intersection, diff1),
|
|
'movements': base_map_rev | reverse_movements(appended_map)
|
|
},)
|
|
|
|
def graph_from_edges(edges):
|
|
g = nx.MultiDiGraph()
|
|
g.add_edges_from(edges)
|
|
return g
|
|
|
|
def generate_graph(chord_set, min_symdiff, max_symdiff, max_chord_size):
|
|
#chord_set = chords(pitch_set, min_chord_size, max_chord_size)
|
|
edge_set = edges(chord_set, min_symdiff, max_symdiff, max_chord_size)
|
|
res_graph = graph_from_edges(edge_set)
|
|
return res_graph
|
|
|
|
def compact_sets(root, m1, m2):
|
|
|
|
def branch(r):
|
|
b = set()
|
|
for d in range(1, len(root)):
|
|
for a in [-1, 1]:
|
|
b.add((*r[:d], r[d] + a, *r[(d + 1):]))
|
|
return b
|
|
|
|
def grow(c, p, e):
|
|
l = len(c)
|
|
if l >= m1 and l <= m2:
|
|
#yield tuple(sorted(c, key=hs_array_to_fr))
|
|
yield c
|
|
if l < m2:
|
|
e = set(e)
|
|
for b in p:
|
|
if b not in e:
|
|
e.add(b)
|
|
yield from grow((*c, b), p | branch(b), e)
|
|
yield from grow((root,), branch(root), set((root,)))
|
|
|
|
def display_graph(graph):
|
|
show_graph = nx.Graph(graph)
|
|
pos = nx.draw_spring(show_graph, node_size=5, width=0.1)
|
|
plt.figure(1, figsize=(12,12))
|
|
nx.draw(show_graph, pos, node_size=5, width=0.1)
|
|
plt.show()
|
|
#plt.savefig('compact_sets.png', dpi=150)
|
|
|
|
def path_to_chords(path, start_root):
|
|
current_root = start_root
|
|
start_chord = tuple(sorted(path[0][0], key=hs_array_to_fr))
|
|
chords = ((start_chord, start_chord,),)
|
|
for edge in path:
|
|
trans = edge[2]['transposition']
|
|
movements = edge[2]['movements']
|
|
current_root = transpose_pitch(current_root, trans)
|
|
current_ref_chord = chords[-1][0]
|
|
next_ref_chord = tuple(movements[pitch]['destination'] for pitch in current_ref_chord)
|
|
next_transposed_chord = tuple(transpose_pitch(pitch, current_root) for pitch in next_ref_chord)
|
|
chords += ((next_ref_chord, next_transposed_chord,),)
|
|
return tuple(chord[1] for chord in chords)
|
|
|
|
def write_chord_sequence(seq, path):
|
|
file = open(path, "w+")
|
|
content = json.dumps(seq)
|
|
content = content.replace("[[[", "[\n\t[[")
|
|
content = content.replace(", [[", ",\n\t[[")
|
|
content = content.replace("]]]", "]]\n]")
|
|
file.write(content)
|
|
file.close()
|
|
|
|
|
|
# In[3]:
|
|
|
|
|
|
from random import choice, choices, seed
|
|
|
|
# This is for the static version
|
|
def stochastic_hamiltonian(graph, start_root):
|
|
|
|
def movement_size_weights(edges):
|
|
|
|
def max_cent_diff(edge):
|
|
res = max([abs(v) for val in edge[2]['movements'].values() if (v:=val['cent_difference']) is not None])
|
|
return res
|
|
|
|
def min_cent_diff(edge):
|
|
res = [abs(v) for val in edge[2]['movements'].values() if (v:=val['cent_difference']) is not None]
|
|
res.remove(0)
|
|
return min(res)
|
|
|
|
for e in edges:
|
|
yield 1000 if ((max_cent_diff(e) < 200) and (min_cent_diff(e)) > 1) else 0
|
|
|
|
def hamiltonian_weights(edges):
|
|
for e in edges:
|
|
yield 10 if e[1] not in [path_edge[0] for path_edge in path] else 1 / graph.nodes[e[1]]['count']
|
|
|
|
def contrary_motion_weights(edges):
|
|
|
|
def is_contrary(edge):
|
|
cent_diffs = [v for val in edge[2]['movements'].values() if (v:=val['cent_difference']) is not None]
|
|
cent_diffs.sort()
|
|
return (cent_diffs[0] < 0) and (cent_diffs[1] == 0) and (cent_diffs[2] > 0)
|
|
|
|
for e in edges:
|
|
yield 10 if is_contrary(e) else 1
|
|
|
|
def is_directly_tunable_weights(edges):
|
|
for e in edges:
|
|
yield 10 if e[2]['is_directly_tunable'] else 0
|
|
|
|
|
|
def is_connected_to(edges, chordrefs):
|
|
|
|
def is_connected(edge, chordrefs):
|
|
trans = edge[2]['transposition']
|
|
movements = edge[2]['movements']
|
|
tmp_root = transpose_pitch(current_root, trans)
|
|
current_ref_chord = chords[-1][0]
|
|
next_ref_chord = tuple(movements[pitch]['destination'] for pitch in current_ref_chord)
|
|
next_transposed_chord = tuple(transpose_pitch(pitch, tmp_root) for pitch in next_ref_chord)
|
|
#return min([min([sum(abs(d) for d in collapse_pitch(pitch_difference(c, p))) for p in next_transposed_chord]) for c in chordrefs]) == 0
|
|
return min([min([sum(abs(d) for d in pitch_difference(c, p)) for p in next_transposed_chord]) for c in chordrefs]) == 0
|
|
|
|
|
|
for e in edges:
|
|
yield 10 if is_connected(e, chordrefs) else 0
|
|
|
|
def voice_crossing_weights(edges):
|
|
|
|
def has_voice_crossing(edge):
|
|
source = list(edge[0])
|
|
ordered_source = sorted(source, key=hs_array_to_fr)
|
|
source_order = [ordered_source.index(p) for p in source]
|
|
destination = [transpose_pitch(edge[2]['movements'][p]['destination'], edge[2]['transposition']) for p in source]
|
|
ordered_destination = sorted(destination, key=hs_array_to_fr)
|
|
destination_order = [ordered_destination.index(p) for p in destination]
|
|
return source_order != destination_order
|
|
|
|
for e in edges:
|
|
yield 10 if not has_voice_crossing(e) else 0
|
|
|
|
def is_bass_rooted(chord):
|
|
return max([sum(abs(p) for p in collapse_pitch(pitch_difference(chord[0], p))) for p in chord[1:]]) == 1
|
|
|
|
current_root = start_root
|
|
check_graph = graph.copy()
|
|
next_node = choice([node for node in graph.nodes() if is_bass_rooted(node)])
|
|
check_graph.remove_node(next_node)
|
|
start_chord = tuple(sorted(next_node, key=hs_array_to_fr))
|
|
chords = ((start_chord, start_chord,),)
|
|
for node in graph.nodes(data=True):
|
|
node[1]['count'] = 1
|
|
path = []
|
|
index = 0
|
|
pathRefChords = ((0, 0, 0, 0, 0, 0, 0, 0), (-1, 1, 0, 0, 0, 0, 0, 0), (-2, 0, 1, 0, 0, 0, 0, 0), (-2, 0, 0, 1, 0, 0, 0, 0), (-3, 0, 0, 0, 1, 0, 0, 0), (-3, 0, 0, 0, 0, 1, 0, 0))
|
|
while (nx.number_of_nodes(check_graph) > 0) and (len(path) < 50):
|
|
out_edges = list(graph.out_edges(next_node, data=True))
|
|
factors = [
|
|
movement_size_weights(out_edges),
|
|
hamiltonian_weights(out_edges),
|
|
contrary_motion_weights(out_edges),
|
|
is_directly_tunable_weights(out_edges),
|
|
voice_crossing_weights(out_edges),
|
|
#is_sustained_voice_alt(out_edges, 1, current_root)
|
|
is_connected_to(out_edges, (pathRefChords[(len(path) + index) % 6], pathRefChords[(len(path) + index + 1) % 6], pathRefChords[(len(path) + index + 2) % 6]))
|
|
#is_connected_to(out_edges, pathRefChords)
|
|
]
|
|
index += 1
|
|
weights = [prod(a) for a in zip(*factors)]
|
|
edge = choices(out_edges, weights=weights)[0]
|
|
#edge = random.choice(out_edges)
|
|
|
|
trans = edge[2]['transposition']
|
|
movements = edge[2]['movements']
|
|
current_root = transpose_pitch(current_root, trans)
|
|
current_ref_chord = chords[-1][0]
|
|
next_ref_chord = tuple(movements[pitch]['destination'] for pitch in current_ref_chord)
|
|
next_transposed_chord = tuple(transpose_pitch(pitch, current_root) for pitch in next_ref_chord)
|
|
chords += ((next_ref_chord, next_transposed_chord,),)
|
|
|
|
next_node = edge[1]
|
|
node[1]['count'] += 1
|
|
path.append(edge)
|
|
if next_node in check_graph.nodes:
|
|
check_graph.remove_node(next_node)
|
|
return tuple(chord[1] for chord in chords)
|
|
|
|
|
|
# In[4]:
|
|
|
|
|
|
dims = (2, 3, 5, 7, 11, 13, 17, 19)
|
|
root = (0, 0, 0, 0, 0, 0, 0, 0)
|
|
chord = (root,)
|
|
chord_set = compact_sets(root, 3, 3)
|
|
#print(len(list(chord_set)))
|
|
graph = generate_graph(chord_set, 4, 4, 3)
|
|
#len(list(chord_set))
|
|
|
|
|
|
# In[5]:
|
|
|
|
|
|
seed(8729743)
|
|
path = stochastic_hamiltonian(graph, root)
|
|
#for edge in path:
|
|
# print(edge)
|
|
write_chord_sequence(path, "sirens.txt")
|
|
|
|
|
|
# In[58]:
|
|
|
|
|
|
len(list(chord_set))
|
|
|
|
|
|
# In[10]:
|
|
|
|
|
|
from random import choice, choices, seed
|
|
|
|
def stochastic_hamiltonian(chord_set, start_root, min_symdiff, max_symdiff, max_chord_size):
|
|
|
|
def movement_size_weights(edges):
|
|
|
|
def max_cent_diff(edge):
|
|
res = max([abs(v) for val in edge[2]['movements'].values() if (v:=val['cent_difference']) is not None])
|
|
return res
|
|
|
|
def min_cent_diff(edge):
|
|
res = [abs(v) for val in edge[2]['movements'].values() if (v:=val['cent_difference']) is not None]
|
|
res.remove(0)
|
|
return min(res)
|
|
|
|
for e in edges:
|
|
if ((max_cent_diff(e) < 100) and (min_cent_diff(e)) >= 0):
|
|
yield 1000
|
|
elif ((max_cent_diff(e) < 200) and (min_cent_diff(e)) >= 0):
|
|
yield 10
|
|
else:
|
|
yield 0
|
|
|
|
def hamiltonian_weights(edges):
|
|
for e in edges:
|
|
yield 10 if e[1] not in [path_edge[0] for path_edge in path] else 1 #/ graph.nodes[e[1]]['count']
|
|
|
|
def contrary_motion_weights(edges):
|
|
|
|
def is_contrary(edge):
|
|
cent_diffs = [v for val in edge[2]['movements'].values() if (v:=val['cent_difference']) is not None]
|
|
cent_diffs.sort()
|
|
return (cent_diffs[0] < 0) and (cent_diffs[1] == 0) and (cent_diffs[2] > 0)
|
|
#return (cent_diffs[0] < 0) and (cent_diffs[1] == 0) and (cent_diffs[2] == 0) and (cent_diffs[3] > 0)
|
|
|
|
for e in edges:
|
|
yield 100 if is_contrary(e) else 0
|
|
|
|
def is_directly_tunable_weights(edges):
|
|
for e in edges:
|
|
yield 10 if e[2]['is_directly_tunable'] else 0
|
|
|
|
def transposition_weight(edges):
|
|
for e in edges:
|
|
yield 1000 if 0 <= hs_array_to_cents(e[2]['transposition']) < 100 else 0
|
|
|
|
def is_sustained_voice(edges, voice):
|
|
|
|
def is_sustained(edge):
|
|
source = list(edge[0])
|
|
ordered_source = sorted(source, key=hs_array_to_fr)
|
|
destination = [transpose_pitch(edge[2]['movements'][p]['destination'], edge[2]['transposition']) for p in source]
|
|
ordered_destination = sorted(destination, key=hs_array_to_fr)
|
|
return ordered_source[voice] == ordered_destination[voice]
|
|
|
|
for e in edges:
|
|
yield 10 if is_sustained(e) else 0
|
|
|
|
def is_sustained_voice_alt(edges, voice, current_root):
|
|
|
|
def is_sustained(edge):
|
|
|
|
trans = edge[2]['transposition']
|
|
movements = edge[2]['movements']
|
|
tmp_root = transpose_pitch(current_root, trans)
|
|
current_ref_chord = chords[-1][0]
|
|
next_ref_chord = tuple(movements[pitch]['destination'] for pitch in current_ref_chord)
|
|
next_transposed_chord = tuple(transpose_pitch(pitch, tmp_root) for pitch in next_ref_chord)
|
|
return chords[-1][1][voice] == next_transposed_chord[voice]
|
|
|
|
for e in edges:
|
|
yield 10 if is_sustained(e) else 1
|
|
|
|
def is_connected_to(edges, chordrefs):
|
|
|
|
def is_connected(edge, chordrefs):
|
|
trans = edge[2]['transposition']
|
|
movements = edge[2]['movements']
|
|
tmp_root = transpose_pitch(current_root, trans)
|
|
current_ref_chord = chords[-1][0]
|
|
next_ref_chord = tuple(movements[pitch]['destination'] for pitch in current_ref_chord)
|
|
next_transposed_chord = tuple(transpose_pitch(pitch, tmp_root) for pitch in next_ref_chord)
|
|
#return min([min([sum(abs(d) for d in collapse_pitch(pitch_difference(c, p))) for p in next_transposed_chord]) for c in chordrefs]) == 0
|
|
return min([min([sum(abs(d) for d in pitch_difference(c, p)) for p in next_transposed_chord]) for c in chordrefs]) == 0
|
|
|
|
|
|
for e in edges:
|
|
yield 10 if is_connected(e, chordrefs) else 0
|
|
|
|
def voice_crossing_weights(edges):
|
|
|
|
def has_voice_crossing(edge):
|
|
source = list(edge[0])
|
|
ordered_source = sorted(source, key=hs_array_to_fr)
|
|
source_order = [ordered_source.index(p) for p in source]
|
|
destination = [transpose_pitch(edge[2]['movements'][p]['destination'], edge[2]['transposition']) for p in source]
|
|
ordered_destination = sorted(destination, key=hs_array_to_fr)
|
|
destination_order = [ordered_destination.index(p) for p in destination]
|
|
return source_order != destination_order
|
|
|
|
for e in edges:
|
|
yield 10 if not has_voice_crossing(e) else 0
|
|
|
|
def dca_weight(edges, last_chords):
|
|
for edge in edges:
|
|
source = list(edge[0])
|
|
ordered_source = sorted(source, key=hs_array_to_fr)
|
|
source_order = [ordered_source.index(p) for p in source]
|
|
destination = [transpose_pitch(edge[2]['movements'][p]['destination'], edge[2]['transposition']) for p in source]
|
|
ordered_destination = tuple(sorted(destination, key=hs_array_to_fr))
|
|
test_sequence = tuple(zip(*(last_chords + (ordered_destination, ))))
|
|
#print('here')
|
|
#print(test_sequence)
|
|
if len(test_sequence[0]) < 4:
|
|
yield 10
|
|
else:
|
|
if len(set(test_sequence[0][-2:])) == 1 or len(set(test_sequence[1][-2:])) == 1 or len(set(test_sequence[2][-2:])) == 1:
|
|
yield 0
|
|
else:
|
|
yield 10
|
|
|
|
def is_bass_rooted(chord):
|
|
return max([sum(abs(p) for p in collapse_pitch(pitch_difference(chord[0], p))) for p in chord[1:]]) == 1
|
|
|
|
def is_directly_tunable(intersection, diff):
|
|
# this only works for now when intersection if one element - need to fix that
|
|
return max([sum(abs(p) for p in collapse_pitch(pitch_difference(d, list(intersection)[0]))) for d in diff]) == 1
|
|
|
|
def gen_edges(source, candidates, min_symdiff, max_symdiff, max_chord_size, ostinato_ref):
|
|
for target in candidates:
|
|
[expanded_source, expanded_target] = [expand_chord(chord) for chord in [source, target]]
|
|
edges = []
|
|
expanded_source_with_ostinato_ref = expanded_source + ostinato_ref
|
|
#print(expanded_source + ostinato_ref)
|
|
transpositions = set(pitch_difference(pair[0], pair[1]) for pair in set(product(expanded_source, expanded_target)))
|
|
#print(transpositions)
|
|
for trans in transpositions:
|
|
expanded_target_transposed = transpose_chord(expanded_target, trans)
|
|
intersection = set(expanded_source) & set(expanded_target_transposed)
|
|
symdiff_len = sum([len(chord) - len(intersection) for chord in [expanded_source, expanded_target_transposed]])
|
|
if (min_symdiff <= symdiff_len <= max_symdiff):
|
|
rev_trans = tuple(t * -1 for t in trans)
|
|
[diff1, diff2] = [list(set(chord) - intersection) for chord in [expanded_source, expanded_target_transposed]]
|
|
base_map = {val: {'destination':transpose_pitch(val, rev_trans), 'cent_difference': 0} for val in intersection}
|
|
#base_map_rev = reverse_movements(base_map)
|
|
maps = []
|
|
diff1 += [None] * (max_chord_size - len(diff1) - len(intersection))
|
|
perms = [list(perm) + [None] * (max_chord_size - len(perm) - len(intersection)) for perm in set(permutations(diff2))]
|
|
for p in perms:
|
|
appended_map = {
|
|
diff1[index]:
|
|
{
|
|
'destination': transpose_pitch(val, rev_trans) if val != None else None,
|
|
'cent_difference': cent_difference(diff1[index], val) if None not in [diff1[index], val] else None
|
|
} for index, val in enumerate(p)}
|
|
yield (tuple(expanded_source), tuple(expanded_target), {
|
|
'transposition': trans,
|
|
'symmetric_difference': symdiff_len,
|
|
'is_directly_tunable': is_directly_tunable(intersection, diff2),
|
|
'movements': base_map | appended_map
|
|
},)
|
|
|
|
current_root = start_root
|
|
#weighted_chord_set = {
|
|
# chord:
|
|
# {
|
|
# 'weight': 10
|
|
# } for index, chord in enumerate(chord_set)}
|
|
next_chord = tuple(sorted(expand_chord(choice(chord_set)), key=hs_array_to_fr))
|
|
#tuple(sorted(next_node, key=hs_array_to_fr))
|
|
print(next_chord)
|
|
#weighted_chord_set[next_chord]['weight'] = 1;
|
|
chords = ((next_chord, next_chord,),)
|
|
last_chords = (next_chord,)
|
|
path = []
|
|
index = 0
|
|
pathRefChords = ((0, 0, 0, 0, 0, 0, 0), (-2, 0, 1, 0, 0, 0, 0), (-3, 0, 0, 0, 1, 0, 0), (-1, 1, 0, 0, 0, 0, 0), (-3, 0, 0, 0, 0, 1, 0), (-2, 0, 0, 1, 0, 0, 0))
|
|
#pathRefChords = ((0, 0, 0, 0, 0, 0), (-1, 1, 0, 0, 0, 0), (-2, 0, 1, 0, 0, 0), (-2, 0, 0, 1, 0, 0), (-3, 0, 0, 0, 1, 0), (-3, 0, 0, 0, 0, 1))
|
|
while (len(path) < 100):
|
|
ostinato_ref = (pathRefChords[len(path)%6],)
|
|
edges = list(gen_edges(next_chord, chord_set, min_symdiff, max_symdiff, max_chord_size, ostinato_ref))
|
|
#print(edges)
|
|
factors = [
|
|
movement_size_weights(edges),
|
|
hamiltonian_weights(edges),
|
|
#contrary_motion_weights(edges),
|
|
is_directly_tunable_weights(edges),
|
|
voice_crossing_weights(edges),
|
|
#dca_weight(edges, last_chords),
|
|
is_sustained_voice_alt(edges, choice([0, 1, 2]), current_root),
|
|
#is_connected_to(edges, (pathRefChords[len(path)%6],))
|
|
#is_connected_to(edges, (pathRefChords[(len(path) + index) % 6], pathRefChords[(len(path) + index + 1) % 6], pathRefChords[(len(path) + index + 2) % 6]))
|
|
#is_connected_to(edges, pathRefChords)
|
|
]
|
|
index += 1
|
|
weights = [prod(a) for a in zip(*factors)]
|
|
edge = choices(edges, weights=weights)[0]
|
|
#edge = random.choice(out_edges)
|
|
#print(edge)
|
|
|
|
trans = edge[2]['transposition']
|
|
movements = edge[2]['movements']
|
|
current_root = transpose_pitch(current_root, trans)
|
|
current_ref_chord = chords[-1][0]
|
|
next_ref_chord = tuple(movements[pitch]['destination'] for pitch in current_ref_chord)
|
|
next_transposed_chord = tuple(transpose_pitch(pitch, current_root) for pitch in next_ref_chord)
|
|
chords += ((next_ref_chord, next_transposed_chord,),)
|
|
|
|
next_chord = edge[1]
|
|
#node[1]['count'] += 1
|
|
|
|
last_chords = last_chords + (next_chord,)
|
|
if len(last_chords) > 2:
|
|
last_chords = last_chords[-2:]
|
|
#print(last_chords)
|
|
|
|
path.append(edge)
|
|
#if next_node in check_graph.nodes:
|
|
# check_graph.remove_node(next_node)
|
|
return tuple(chord[1] for chord in chords)
|
|
|
|
|
|
# In[7]:
|
|
|
|
|
|
seed(872984353450043)
|
|
dims = (2, 3, 5, 7, 11, 13, 17)
|
|
root = (0, 0, 0, 0, 0, 0, 0)
|
|
chord = (root,)
|
|
chord_set = compact_sets(root, 3, 3)
|
|
path = stochastic_hamiltonian(list(chord_set), root, 4, 4, 3)
|
|
#for edge in path:
|
|
# print(edge)
|
|
write_chord_sequence(path, "sirens.txt")
|
|
|
|
|
|
# In[18]:
|
|
|
|
|
|
seed(872984353450043)
|
|
dims = (2, 3, 5, 7)
|
|
root = (0, 0, 0, 0)
|
|
chord = (root,)
|
|
chord_set = compact_sets(root, 5, 5)
|
|
path = stochastic_hamiltonian(list(chord_set), root, 4, 4, 5)
|
|
#for edge in path:
|
|
# print(edge)
|
|
write_chord_sequence(path, "sirens.txt")
|
|
|
|
|
|
# dims = (2, 3, 5, 7, 11, 13, 17)
|
|
# root = (0, 0, 0, 0, 0, 0, 0)
|
|
# chord = (root,)
|
|
# chord_set = compact_sets(root, 3, 3)
|
|
# #print(len(list(chord_set)))
|
|
# reduced_chord_set = tuple()
|
|
# for chord in chord_set:
|
|
# c_flag = False
|
|
# for p1, p2 in combinations(collapse_chord(chord), 2):
|
|
# diff = pitch_difference(p1, p2)
|
|
# print(diff)
|
|
# if diff in ((0, 1, 0, 0, 0, 0, 0), (0, 0, 1, 0, 0, 0, 0), (0, 0, 0, 1, 0, 0, 0), (0, -1, 0, 0, 0, 0, 0), (0, 0, -1, 0, 0, 0, 0), (0, 0, 0, -1, 0, 0, 0)) and not c_flag:
|
|
# #if (abs(p1[1] - p2[1]) == 1 or abs(p1[2] - p2[2]) == 1 or abs(p1[3] - p2[3]) == 1) and not c_flag:
|
|
# c_flag = True
|
|
# #break
|
|
# if c_flag:
|
|
# reduced_chord_set += (chord,)
|
|
#
|
|
#
|
|
# len(reduced_chord_set)
|
|
#
|
|
# pitch_difference(
|