-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathmutators.py
165 lines (113 loc) · 4.99 KB
/
mutators.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
from note_util import isMeasureSilent, GANote, getNonRestNotes
from random import random, choice, shuffle, sample
# all functions here have same args, and will return an array of notes, without editing anything
# return false if operation fails for some reason
def pickRandomChordTone(currentPiece, chordProgression, measureIndex, noteIndex):
original_midi_note = currentPiece[measureIndex][noteIndex].midi_note
new_midi_note = choice(chordProgression[measureIndex])
delta = original_midi_note - new_midi_note
while abs(delta) > 6:
# try to bring them closer together
if delta < 0:
new_midi_note -= 12
else:
new_midi_note += 12
delta = original_midi_note - new_midi_note
currentPiece[measureIndex][noteIndex].midi_note = new_midi_note
return True
def copyNoteInMeasure(currentPiece, chordProgression, measureIndex, noteIndex):
currentPiece[measureIndex][noteIndex].midi_note = choice(currentPiece[measureIndex]).midi_note
return True
def transposeWholeNote(currentPiece, chordProgression, measureIndex, noteIndex):
note = currentPiece[measureIndex][noteIndex]
transpose = 2
if random() > 0.5:
transpose *= -1
currentPiece[measureIndex][noteIndex].midi_note = note.midi_note + transpose
return True
def becomeLeadingNote(currentPiece, chordProgression, measureIndex, noteIndex):
measure = currentPiece[measureIndex]
is_last_note = (noteIndex == len(measure) - 1)
# if it's literally the last note
if (measureIndex == len(currentPiece) - 1 and is_last_note) or (not is_last_note and measure[noteIndex + 1].midi_note is None) or (currentPiece[measureIndex + 1][0].midi_note is None):
return False
next_note = None
if is_last_note:
next_note = currentPiece[measureIndex + 1][0].midi_note
else:
next_note = measure[noteIndex + 1].midi_note
delta = 1
if random() < 0.5:
delta = -1
currentPiece[measureIndex][noteIndex].midi_note = (next_note + delta)
return True
def subdivide(currentPiece, chordProgression, measureIndex, noteIndex):
p = random()
note = currentPiece[measureIndex][noteIndex]
note_array = []
if p < 0.5:
# even subdivision
note_array = [note.clone(new_duration=note.duration / 2.0), note.clone(new_duration=note.duration / 2.0)]
elif p < 0.75:
# triplet
note_array = [note.clone(new_duration=note.duration / 3.0), note.clone(new_duration=note.duration / 3.0), note.clone(new_duration=note.duration / 3.0)]
else:
# dotted
long_note = note.clone(new_duration=note.duration * 0.75)
short_note = note.clone(new_duration=note.duration * 0.25)
if random() < 0.5:
note_array = [long_note, short_note]
else:
note_array = [short_note, long_note]
measure = currentPiece[measureIndex]
currentPiece[measureIndex] = measure[:noteIndex] + note_array + measure[noteIndex+1:]
return True
def copyNoteFromSimilarChord(currentPiece, chordProgression, measureIndex, noteIndex):
target_chord = chordProgression[measureIndex]
measure_indices_with_same_chord = []
for i in range(len(chordProgression)):
if i == measureIndex:
continue
chord = chordProgression[i]
if chord == target_chord:
measure = currentPiece[measureIndex]
if not isMeasureSilent(measure):
measure_indices_with_same_chord.append(i)
if len(measure_indices_with_same_chord) == 0:
return False
similar_index = choice(measure_indices_with_same_chord)
note_possibilities = getNonRestNotes(currentPiece[similar_index])
if len(note_possibilities) == 0:
return False
currentPiece[measureIndex][noteIndex].midi_note = currentPiece[similar_index][choice(note_possibilities)].midi_note
return True
def shiftNotes(currentPiece, chordProgression, measureIndex, noteIndex):
measure = currentPiece[measureIndex]
notes = [note.midi_note for note in measure]
# TODO, consider deltas > 1
delta = 1
if random() < 0.5:
delta = -1
for i in range(len(notes)):
shifted_index = (i + delta + len(notes)) % len(notes)
currentPiece[measureIndex][i].midi_note = notes[shifted_index]
return True
def shuffleNotes(currentPiece, chordProgression, measureIndex, noteIndex):
shuffle(currentPiece[measureIndex])
return True
def dropNote(currentPiece, chordProgression, measureIndex, noteIndex):
measure = currentPiece[measureIndex]
random_index = int(random() * len(measure))
currentPiece[measureIndex][random_index].midi_note = None
return True
def swapNotes(currentPiece, chordProgression, measureIndex, noteIndex):
measure = currentPiece[measureIndex]
# not enough notes to swap
if len(measure) <= 1:
return False
a, b = sample(range(0, len(measure)), 2)
temp = measure[a]
measure[a] = measure[b]
measure[b] = temp
currentPiece[measureIndex] = measure
return True