-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathflask_ARNN.py
176 lines (143 loc) · 5.62 KB
/
flask_ARNN.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
173
174
175
176
import tempfile
from ARNN.anticipationRNN import AnticipationRNN
from DatasetManager.chorale_dataset import ChoraleDataset
from DatasetManager.dataset_manager import DatasetManager
from DatasetManager.metadata import TickMetadata
from flask import Flask, request, make_response, jsonify
from flask_cors import CORS
from music21 import musicxml, metadata, converter
import click
app = Flask(__name__)
CORS(app)
ALLOWED_EXTENSIONS = {'midi'}
# INITIALIZATION
xml_response_headers = {"Content-Type": "text/xml",
"charset": "utf-8"
}
_current_tensor_chorale = None
_current_tensor_metadata = None
_current_chorale = None
model = None
@click.command()
@click.option('--note_embedding_dim', default=20,
help='size of the note embeddings')
@click.option('--meta_embedding_dim', default=2,
help='size of the metadata embeddings')
@click.option('--num_layers', default=2,
help='number of layers of the LSTMs')
@click.option('--lstm_hidden_size', default=256,
help='hidden size of the LSTMs')
@click.option('--dropout_lstm', default=0.2,
help='amount of dropout between LSTM layers')
@click.option('--input_dropout', default=0.2,
help='amount of dropout between LSTM layers')
@click.option('--linear_hidden_size', default=256,
help='hidden size of the Linear layers')
def init_app(note_embedding_dim,
meta_embedding_dim,
num_layers,
lstm_hidden_size,
dropout_lstm,
input_dropout,
linear_hidden_size,
):
metadatas = [
TickMetadata(subdivision=4),
]
dataset_manager = DatasetManager()
chorale_dataset_kwargs = {
'voice_ids': [0],
'metadatas': metadatas,
'sequences_size': 20,
'subdivision': 4
}
bach_chorales_dataset: ChoraleDataset = dataset_manager.get_dataset(
name='bach_chorales',
**chorale_dataset_kwargs
)
global model
model = AnticipationRNN(chorale_dataset=bach_chorales_dataset,
note_embedding_dim=note_embedding_dim,
metadata_embedding_dim=meta_embedding_dim,
num_layers=num_layers,
num_lstm_constraints_units=lstm_hidden_size,
num_lstm_generation_units=lstm_hidden_size,
linear_hidden_size=linear_hidden_size,
dropout_prob=dropout_lstm,
dropout_input_prob=input_dropout,
unary_constraint=True,
)
model.load()
model.cuda()
# launch the script
# accessible only locally:
app.run()
@app.route('/models', methods=['GET'])
def models():
return jsonify(['ARNN'])
@app.route('/compose', methods=['POST'])
def compose():
global _current_tensor_chorale
global _current_tensor_metadata
global _current_chorale
global model
# global models
# --- Parse request---
with tempfile.NamedTemporaryFile(mode='w', suffix='.xml') as file:
print(file.name)
# file_path = os.path.join(app.config['UPLOAD_FOLDER'], filename)
xml_string = request.form['xml_string']
file.write(xml_string)
# load chorale with music21
_current_chorale = converter.parse(file.name)
NUM_MIDI_TICKS_IN_SIXTEENTH_NOTE = 120
start_tick_selection = int(float(
request.form['start_tick']) / NUM_MIDI_TICKS_IN_SIXTEENTH_NOTE)
end_tick_selection = int(
float(request.form['end_tick']) / NUM_MIDI_TICKS_IN_SIXTEENTH_NOTE)
# use length of the score shown in MuseScore
chorale_length = int(_current_chorale.duration.quarterLength
* model.chorale_dataset.subdivision)
# if no selection REGENERATE and set chorale length
if start_tick_selection == 0 and end_tick_selection == 0:
# randomize
_current_tensor_chorale = model.chorale_dataset.random_chorale(
chorale_length=chorale_length)
_current_tensor_metadata = None
end_tick_selection = chorale_length
else:
_current_tensor_chorale = model.chorale_dataset.chorale_to_tensor(
chorale=_current_chorale,
offsetStart=0,
offsetEnd=chorale_length // model.chorale_dataset.subdivision
)
time_index_range = [start_tick_selection, end_tick_selection]
# --- Generate---
(_current_chorale,
_current_tensor_chorale,
_current_tensor_metadata) = model.generation(
tensor_chorale=_current_tensor_chorale,
tensor_metadata=_current_tensor_metadata,
temperature=1.,
time_index_range=time_index_range
)
# format metadatadata
insert_metadata(_current_chorale)
# convert chorale to xml
response = chorale_to_xml_response(_current_chorale)
return response
def insert_metadata(output_chorale):
for part, name in zip(output_chorale.parts, ['soprano']):
part.id = name
part.partName = name
md = metadata.Metadata()
output_chorale.insert(0, md)
output_chorale.metadata.title = 'Anticipation-RNN'
output_chorale.metadata.composer = 'GH'
def chorale_to_xml_response(chorale):
goe = musicxml.m21ToXml.GeneralObjectExporter(chorale)
xml_chorale_string = goe.parse()
response = make_response((xml_chorale_string, xml_response_headers))
return response
if __name__ == '__main__':
init_app()