-
Notifications
You must be signed in to change notification settings - Fork 0
/
Quintessential_Viterbi.py
172 lines (136 loc) · 8.08 KB
/
Quintessential_Viterbi.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
166
167
168
169
170
171
172
# -*- coding: utf-8 -*-
"""Quintessential_Viterbi.py
Automatically generated by Colaboratory.
Original file is located at
https://colab.research.google.com/drive/136ri6INH2LxgmOkvSymL8JgNP6RcAGdk
# Quintessential Viterbi (v. 1.2)
***
## Full-featured Viterbi MIDI Music Augmentator
***
#### Project Los Angeles
#### Tegridy Code 2020
# Setup Environment
"""
print('Quintessential Viterbi v. 1.2.')
print('Importing modules...')
#@title Import Modules
import constants
import pretty_midi
import midi_io
import midi_synth
import sequences_lib
import melodies_lib
import melody_inference
import chords_lib
import chord_inference
import copy
print('Starting up the augmentation and generation. Please stand-by...')
"""# Generate Agumented Viterbi Music from your MIDI"""
#@title Please note that Viterbi algorithm may throw errors occasionally so please try generate again if that happens. Also, remove_drums code is a bit buggy so switch this option if you keep getting errors. Same applies for other settings and/or division by zero cases.
full_path_to_MIDI_file = "./Sample_MIDI.mid" #@param {type:"string"}
melody_search_start_step = 0 #@param {type:"slider", min:0, max:200, step:1}
search_melody_with_this_MIDI_instrument_number = 0 #@param {type:"slider", min:0, max:127, step:1}
end_melody_search_after_this_many_empty_bars = 10 #@param {type:"slider", min:1, max:100, step:1}
ignore_polyphonic_notes = True #@param {type:"boolean"}
end_melody_at_the_bar_boundary = False #@param {type:"boolean"}
remove_drums = False #@param {type:"boolean"}
MIDI_instrument_number_for_output_melody_notes = 40 #@param {type:"slider", min:0, max:127, step:1}
MIDI_program_for_output_melody_notes = 40 #@param {type:"slider", min:0, max:127, step:1}
start_output_melody_at_this_second = 0 #@param {type:"slider", min:0, max:200, step:0.1}
transpose_melody_velocity = 10 #@param {type:"slider", min:-30, max:30, step:1}
quarter_notes_per_minute = 120 #@param {type:"slider", min:1, max:480, step:1}
chords_inference_type = "Natural" #@param ["Natural", "Notewise"]
notewise_chords_inference_min_notes_per_chord = 1 #@param {type:"slider", min:1, max:60, step:1}
number_of_chords_per_bar = None #@param ["None", "1", "2", "3", "4", "8", "12", "16", "32"] {type:"raw"}
chord_key_change_probability = 0.9 #@param {type:"slider", min:0.01, max:2, step:0.01}
chord_change_probability = 0.9 #@param {type:"slider", min:0.01, max:2, step:0.01}
chord_pitch_out_of_key_probability = 0.9 #@param {type:"slider", min:0.01, max:2, step:0.01}
melody_notes_per_chord = 1 #@param {type:"slider", min:1, max:20, step:1}
add_key_signature = True #@param {type:"boolean"}
chord_MIDI_instrument_number = 0 #@param {type:"slider", min:0, max:127, step:1}
chord_MIDI_program_number = 0 #@param {type:"slider", min:0, max:127, step:1}
chords_main_octave = 4 #@param {type:"slider", min:1, max:10, step:1}
chords_bass_octave = 3 #@param {type:"slider", min:1, max:10, step:1}
transpose_chords_velocity = 10 #@param {type:"slider", min:-30, max:30, step:1}
augmentation_min_composition_stretch_ratio = -1 #@param {type:"slider", min:-2, max:2, step:0.25}
augmentation_max_composition_stretch_ratio = 1.5 #@param {type:"slider", min:-2, max:2, step:0.25}
augmentation_min_composition_transpose_number = 0 #@param {type:"slider", min:-30, max:30, step:1}
augmentation_max_composition_transpose_number = 20 #@param {type:"slider", min:-30, max:30, step:1}
augmentation_min_allowed_pitch = 20 #@param {type:"slider", min:0, max:127, step:1}
augmentation_max_allowed_pitch = 100 #@param {type:"slider", min:1, max:127, step:1}
augmentation_delete_out_of_range_notes = True #@param {type:"boolean"}
do_not_render_composition_to_audio = True #@param {type:"boolean"}
composition_quantization_steps_per_quarter = 16 #@param {type:"slider", min:1, max:32, step:1}
melody_ns = 0
mel = 0
mel1 = 0
mel0 = 0
mel_q = 0
# Loading a MIDI file
melody_ns = midi_io.midi_file_to_note_sequence(full_path_to_MIDI_file)
# Generating and working with Melody/Notes
melody_ns = sequences_lib.quantize_note_sequence(melody_ns, steps_per_quarter=composition_quantization_steps_per_quarter)
mel0 = melodies_lib.Melody()
mel0.from_quantized_sequence(melody_ns,
search_start_step=melody_search_start_step,
instrument=search_melody_with_this_MIDI_instrument_number,
gap_bars=end_melody_search_after_this_many_empty_bars,
ignore_polyphonic_notes=ignore_polyphonic_notes,
pad_end=end_melody_at_the_bar_boundary,
filter_drums=remove_drums)
mel1 = mel0.to_sequence(velocity=transpose_melody_velocity,
instrument=MIDI_instrument_number_for_output_melody_notes,
program=MIDI_program_for_output_melody_notes,
sequence_start_time=start_output_melody_at_this_second,
qpm=quarter_notes_per_minute
)
mel = sequences_lib.remove_redundant_data(mel1)
# Augmenting the resulting composition
augmented_sequence = sequences_lib.augment_note_sequence(
mel,
min_stretch_factor=augmentation_min_composition_stretch_ratio,
max_stretch_factor=augmentation_max_composition_stretch_ratio,
min_transpose=augmentation_min_composition_transpose_number,
max_transpose=augmentation_max_composition_transpose_number,
min_allowed_pitch=augmentation_min_allowed_pitch,
max_allowed_pitch=augmentation_max_allowed_pitch,
delete_out_of_range_notes=augmentation_delete_out_of_range_notes)
mel = sequences_lib.remove_redundant_data(augmented_sequence)
# Generating and working with Accompaniment/Chords
if chords_inference_type == 'Natural':
mel = sequences_lib.quantize_note_sequence(mel, steps_per_quarter=composition_quantization_steps_per_quarter)
chord_inference.infer_chords_for_sequence(mel,
chords_per_bar=number_of_chords_per_bar,
key_change_prob=chord_key_change_probability,
chord_change_prob=chord_change_probability,
chord_pitch_out_of_key_prob=chord_pitch_out_of_key_probability,
chord_note_concentration=melody_notes_per_chord,
add_key_signatures=add_key_signature
)
else:
#mel = sequences_lib.quantize_note_sequence(mel, steps_per_quarter=composition_quantization_steps_per_quarter)
sequences_lib.infer_dense_chords_for_sequence(mel, min_notes_per_chord=notewise_chords_inference_min_notes_per_chord)
mel = sequences_lib.quantize_note_sequence(mel, steps_per_quarter=composition_quantization_steps_per_quarter)
chords = [(ta.text, ta.time) for ta in mel.text_annotations]
chord = [lis[0] for lis in chords]
chord_times = [lis[1] for lis in chords]
#chords_lib.add_chords_to_sequence(mel, chord, chord_times)
chords_lib.BasicChordRenderer(velocity=transpose_chords_velocity,
instrument=chord_MIDI_instrument_number,
program=chord_MIDI_program_number,
octave=chords_main_octave,
bass_octave=chords_bass_octave).render(mel)
mel = sequences_lib.remove_redundant_data(mel)
print('Done! Creating output, rendering audio, and crunching output stats.')
print('Some stats:')
print('Note Histogram:', melodies_lib.Melody.get_note_histogram(mel0))
print('Major Key Histogram:', melodies_lib.Melody.get_major_key_histogram(mel0))
print('Major Key:', melodies_lib.Melody.get_major_key(mel0))
if not do_not_render_composition_to_audio:
print('Synthesizing the output Viterbi MIDI. Please stand-by... ')
synth=midi_synth.fluidsynth(mel, sample_rate=32000, sf2_path='/usr/share/sounds/sf2/FluidR3_GM.sf2')
notebook_utils.colab_play(synth, sample_rate=32000, autoplay=True)
print('Downloading Viterbi MIDI composition... ')
print('Task complete! Enjoy! :)')
#midi_io.sequence_proto_to_midi_file(melody_ns, 'Original_Melody.mid')
midi_io.sequence_proto_to_midi_file(mel, 'Viterbi_Melody.mid')