asigalov61 commited on
Commit
c10c249
·
verified ·
1 Parent(s): 703083e

Upload app.py

Browse files
Files changed (1) hide show
  1. app.py +433 -0
app.py ADDED
@@ -0,0 +1,433 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #================================================================
2
+ # https://huggingface.co/spaces/asigalov61/Advanced-MIDI-Renderer
3
+ #================================================================
4
+ # Packages:
5
+ #
6
+ # sudo apt install fluidsynth
7
+ #
8
+ #================================================================
9
+ # Requirements:
10
+ #
11
+ # pip install gradio
12
+ # pip install numpy
13
+ # pip install scipy
14
+ # pip install matplotlib
15
+ # pip install networkx
16
+ # pip install scikit-learn
17
+ #
18
+ #================================================================
19
+ # Core modules:
20
+ #
21
+ # git clone --depth 1 https://github.com/asigalov61/tegridy-tools
22
+ #
23
+ # import TMIDIX
24
+ # import TPLOTS
25
+ # import midi_to_colab_audio
26
+ #
27
+ #================================================================
28
+
29
+ import os
30
+ import hashlib
31
+
32
+ import time
33
+ import datetime
34
+ from pytz import timezone
35
+
36
+ import copy
37
+ from collections import Counter
38
+ import random
39
+ import statistics
40
+
41
+ import gradio as gr
42
+
43
+ import TMIDIX
44
+ import TPLOTS
45
+
46
+ from midi_to_colab_audio import midi_to_colab_audio
47
+
48
+ #==========================================================================================================
49
+
50
+ def Render_MIDI(input_midi,
51
+ render_type,
52
+ soundfont_bank,
53
+ render_sample_rate,
54
+ custom_render_patch,
55
+ render_align,
56
+ render_transpose_value,
57
+ render_transpose_to_C4,
58
+ render_output_as_solo_piano,
59
+ render_remove_drums
60
+ ):
61
+
62
+ print('*' * 70)
63
+ print('Req start time: {:%Y-%m-%d %H:%M:%S}'.format(datetime.datetime.now(PDT)))
64
+ start_time = time.time()
65
+
66
+ print('=' * 70)
67
+ print('Loading MIDI...')
68
+
69
+ fn = os.path.basename(input_midi)
70
+ fn1 = fn.split('.')[0]
71
+
72
+ fdata = open(input_midi, 'rb').read()
73
+
74
+ input_midi_md5hash = hashlib.md5(fdata).hexdigest()
75
+
76
+ print('=' * 70)
77
+ print('Requested settings:')
78
+ print('=' * 70)
79
+ print('Input MIDI file name:', fn)
80
+ print('Input MIDI md5 hash', input_midi_md5hash)
81
+ print('-' * 70)
82
+ print('Render type:', render_type)
83
+ print('Soudnfont bank', soundfont_bank)
84
+ print('Audio render sample rate', render_sample_rate)
85
+ print('Custom MIDI render patch', custom_render_patch)
86
+ print('Align to bars:', render_align)
87
+ print('Transpose value:', render_transpose_value)
88
+ print('Transpose to C4', render_transpose_to_C4)
89
+ print('Output as Solo Piano', render_output_as_solo_piano)
90
+ print('Remove drums:', render_remove_drums)
91
+ print('=' * 70)
92
+ print('Processing MIDI...Please wait...')
93
+
94
+ #=======================================================
95
+ # START PROCESSING
96
+
97
+ raw_score = TMIDIX.midi2single_track_ms_score(fdata)
98
+
99
+ escore = TMIDIX.advanced_score_processor(raw_score, return_enhanced_score_notes=True)[0]
100
+
101
+ escore = TMIDIX.augment_enhanced_score_notes(escore, timings_divider=1)
102
+
103
+ first_note_index = [e[0] for e in raw_score[1]].index('note')
104
+
105
+ cscore = TMIDIX.chordify_score([1000, escore])
106
+
107
+ meta_data = raw_score[1][:first_note_index] + [escore[0]] + [escore[-1]] + [raw_score[1][-1]]
108
+
109
+ print('Done!')
110
+ print('=' * 70)
111
+ print('Input MIDI metadata:', meta_data[:5])
112
+ print('=' * 70)
113
+ print('Processing...Please wait...')
114
+
115
+ output_score = copy.deepcopy(escore)
116
+
117
+ if render_type == "Extract melody":
118
+ output_score = TMIDIX.add_melody_to_enhanced_score_notes(escore, return_melody=True)
119
+ output_score = TMIDIX.recalculate_score_timings(output_score)
120
+
121
+ elif render_type == "Flip":
122
+ output_score = TMIDIX.flip_enhanced_score_notes(escore)
123
+
124
+ elif render_type == "Reverse":
125
+ output_score = TMIDIX.reverse_enhanced_score_notes(escore)
126
+
127
+ elif render_type == 'Repair Chords':
128
+ fixed_cscore = TMIDIX.advanced_check_and_fix_chords_in_chordified_score(cscore)[0]
129
+ output_score = TMIDIX.flatten(fixed_cscore)
130
+
131
+ elif render_type == "Add Drums Track":
132
+ nd_escore = [e for e in escore if e[3] != 9]
133
+ nd_escore = TMIDIX.augment_enhanced_score_notes(nd_escore)
134
+ output_score = TMIDIX.advanced_add_drums_to_escore_notes(nd_escore)
135
+
136
+ for e in output_score:
137
+ e[1] *= 16
138
+ e[2] *= 16
139
+
140
+ print('Done processing!')
141
+ print('=' * 70)
142
+
143
+ print('Repatching if needed...')
144
+ print('=' * 70)
145
+
146
+ if -1 < custom_render_patch < 128:
147
+ for e in output_score:
148
+ if e[3] != 9:
149
+ e[6] = custom_render_patch
150
+
151
+ print('Done repatching!')
152
+ print('=' * 70)
153
+
154
+ print('Sample output events', output_score[:5])
155
+ print('=' * 70)
156
+ print('Final processing...')
157
+
158
+ new_fn = fn1+'.mid'
159
+
160
+ if render_type != "Render as-is":
161
+
162
+ if render_transpose_value != 0:
163
+ output_score = TMIDIX.transpose_escore_notes(output_score, render_transpose_value)
164
+
165
+ if render_transpose_to_C4:
166
+ output_score = TMIDIX.transpose_escore_notes_to_pitch(output_score)
167
+
168
+ if render_align == "Start Times":
169
+ output_score = TMIDIX.recalculate_score_timings(output_score)
170
+ output_score = TMIDIX.align_escore_notes_to_bars(output_score)
171
+
172
+ elif render_align == "Start Times and Durations":
173
+ output_score = TMIDIX.recalculate_score_timings(output_score)
174
+ output_score = TMIDIX.align_escore_notes_to_bars(output_score, trim_durations=True)
175
+
176
+ elif render_align == "Start Times and Split Durations":
177
+ output_score = TMIDIX.recalculate_score_timings(output_score)
178
+ output_score = TMIDIX.align_escore_notes_to_bars(output_score, split_durations=True)
179
+
180
+ if render_type == "Longest Repeating Phrase":
181
+ zscore = TMIDIX.recalculate_score_timings(output_score)
182
+ lrno_score = TMIDIX.escore_notes_lrno_pattern_fast(zscore)
183
+
184
+ if lrno_score is not None:
185
+ output_score = lrno_score
186
+
187
+ else:
188
+ output_score = TMIDIX.recalculate_score_timings(TMIDIX.escore_notes_middle(output_score, 50))
189
+
190
+ if render_type == "Multi-Instrumental Summary":
191
+ zscore = TMIDIX.recalculate_score_timings(output_score)
192
+ c_escore_notes = TMIDIX.compress_patches_in_escore_notes_chords(zscore)
193
+
194
+ if len(c_escore_notes) > 128:
195
+ cmatrix = TMIDIX.escore_notes_to_image_matrix(c_escore_notes, filter_out_zero_rows=True, filter_out_duplicate_rows=True)
196
+ smatrix = TPLOTS.square_image_matrix(cmatrix, num_pca_components=max(1, min(5, len(c_escore_notes) // 128)))
197
+ output_score = TMIDIX.image_matrix_to_original_escore_notes(smatrix)
198
+
199
+ for o in output_score:
200
+ o[1] *= 250
201
+ o[2] *= 250
202
+
203
+ if render_output_as_solo_piano:
204
+ output_score = TMIDIX.solo_piano_escore_notes(output_score, keep_drums=True)
205
+
206
+ if render_remove_drums:
207
+ output_score = TMIDIX.strip_drums_from_escore_notes(output_score)
208
+
209
+ if render_type == "Solo Piano Summary":
210
+ sp_escore_notes = TMIDIX.solo_piano_escore_notes(output_score, keep_drums=False)
211
+ zscore = TMIDIX.recalculate_score_timings(sp_escore_notes)
212
+
213
+ if len(zscore) > 128:
214
+
215
+ bmatrix = TMIDIX.escore_notes_to_binary_matrix(zscore)
216
+ cmatrix = TMIDIX.compress_binary_matrix(bmatrix, only_compress_zeros=True)
217
+ smatrix = TPLOTS.square_binary_matrix(cmatrix, interpolation_order=max(1, min(5, len(zscore) // 128)))
218
+ output_score = TMIDIX.binary_matrix_to_original_escore_notes(smatrix)
219
+
220
+ for o in output_score:
221
+ o[1] *= 200
222
+ o[2] *= 200
223
+
224
+ SONG, patches, overflow_patches = TMIDIX.patch_enhanced_score_notes(output_score)
225
+
226
+ detailed_stats = TMIDIX.Tegridy_ms_SONG_to_MIDI_Converter(SONG,
227
+ output_signature = 'Advanced MIDI Renderer',
228
+ output_file_name = fn1,
229
+ track_name='Project Los Angeles',
230
+ list_of_MIDI_patches=patches
231
+ )
232
+
233
+ else:
234
+ with open(new_fn, 'wb') as f:
235
+ f.write(fdata)
236
+ f.close()
237
+
238
+ if soundfont_bank in ["Super GM",
239
+ "Orpheus GM",
240
+ "Live HQ GM",
241
+ "Nice Strings + Orchestra",
242
+ "Real Choir",
243
+ "Super Game Boy",
244
+ "Proto Square"
245
+ ]:
246
+
247
+ sf2bank = ["Super GM",
248
+ "Orpheus GM",
249
+ "Live HQ GM",
250
+ "Nice Strings + Orchestra",
251
+ "Real Choir",
252
+ "Super Game Boy",
253
+ "Proto Square"
254
+ ].index(soundfont_bank)
255
+
256
+ else:
257
+ sf2bank = 0
258
+
259
+ if render_sample_rate in ["16000", "32000", "44100"]:
260
+ srate = int(render_sample_rate)
261
+
262
+ else:
263
+ srate = 16000
264
+
265
+ print('-' * 70)
266
+ print('Generating audio with SF2 bank', sf2bank, 'and', srate, 'Hz sample rate')
267
+
268
+ audio = midi_to_colab_audio(new_fn,
269
+ soundfont_path=soundfonts[sf2bank],
270
+ sample_rate=srate,
271
+ volume_scale=10,
272
+ output_for_gradio=True
273
+ )
274
+
275
+ print('-' * 70)
276
+
277
+ new_md5_hash = hashlib.md5(open(new_fn,'rb').read()).hexdigest()
278
+
279
+ print('Done!')
280
+ print('=' * 70)
281
+
282
+ #========================================================
283
+
284
+ output_midi_md5 = str(new_md5_hash)
285
+ output_midi_title = str(fn1)
286
+ output_midi_summary = str(meta_data)
287
+ output_midi = str(new_fn)
288
+ output_audio = (srate, audio)
289
+
290
+ output_plot = TMIDIX.plot_ms_SONG(output_score, plot_title=output_midi, return_plt=True)
291
+
292
+ print('Output MIDI file name:', output_midi)
293
+ print('Output MIDI title:', output_midi_title)
294
+ print('Output MIDI hash:', output_midi_md5)
295
+ print('Output MIDI summary:', output_midi_summary[:5])
296
+ print('=' * 70)
297
+
298
+ #========================================================
299
+
300
+ print('Req end time: {:%Y-%m-%d %H:%M:%S}'.format(datetime.datetime.now(PDT)))
301
+ print('-' * 70)
302
+ print('Req execution time:', (time.time() - start_time), 'sec')
303
+ print('*' * 70)
304
+
305
+ #========================================================
306
+
307
+ return output_midi_md5, output_midi_title, output_midi_summary, output_midi, output_audio, output_plot
308
+
309
+ #==========================================================================================================
310
+
311
+ if __name__ == "__main__":
312
+
313
+ PDT = timezone('US/Pacific')
314
+
315
+ print('=' * 70)
316
+ print('App start time: {:%Y-%m-%d %H:%M:%S}'.format(datetime.datetime.now(PDT)))
317
+ print('=' * 70)
318
+
319
+ soundfonts = ["SGM-v2.01-YamahaGrand-Guit-Bass-v2.7.sf2",
320
+ "Orpheus_18.06.2020.sf2",
321
+ "Live HQ Natural SoundFont GM.sf2",
322
+ "Nice-Strings-PlusOrchestra-v1.6.sf2",
323
+ "KBH-Real-Choir-V2.5.sf2",
324
+ "SuperGameBoy.sf2",
325
+ "ProtoSquare.sf2"
326
+ ]
327
+
328
+ app = gr.Blocks()
329
+
330
+ with app:
331
+
332
+ gr.Markdown("<h1 style='text-align: center; margin-bottom: 1rem'>Advanced MIDI Renderer</h1>")
333
+ gr.Markdown("<h1 style='text-align: center; margin-bottom: 1rem'>Transform and render any MIDI</h1>")
334
+
335
+ gr.Markdown("![Visitors](https://api.visitorbadge.io/api/visitors?path=asigalov61.Advanced-MIDI-Renderer&style=flat)\n\n"
336
+ "This is a demo for tegridy-tools\n\n"
337
+ "Please see [tegridy-tools](https://github.com/asigalov61/tegridy-tools) GitHub repo for more information\n\n"
338
+ )
339
+
340
+ gr.Markdown("## Upload your MIDI")
341
+
342
+ input_midi = gr.File(label="Input MIDI", file_types=[".midi", ".mid", ".kar"], type="filepath")
343
+
344
+ gr.Markdown("## Select desired Sound Font bank and render sample rate")
345
+
346
+ soundfont_bank = gr.Radio(["Super GM",
347
+ "Orpheus GM",
348
+ "Live HQ GM",
349
+ "Nice Strings + Orchestra",
350
+ "Real Choir",
351
+ "Super Game Boy",
352
+ "Proto Square"
353
+ ],
354
+ label="SoundFont bank",
355
+ value="Super GM"
356
+ )
357
+
358
+ render_sample_rate = gr.Radio(["16000",
359
+ "32000",
360
+ "44100"
361
+ ],
362
+ label="MIDI audio render sample rate",
363
+ value="16000"
364
+ )
365
+
366
+ gr.Markdown("## Select desired render type")
367
+
368
+ render_type = gr.Radio(["Render as-is",
369
+ "Custom render",
370
+ "Extract melody",
371
+ "Flip",
372
+ "Reverse",
373
+ "Repair Chords",
374
+ "Longest Repeating Phrase",
375
+ "Multi-Instrumental Summary",
376
+ "Solo Piano Summary",
377
+ "Add Drums Track"
378
+ ],
379
+ label="Render type",
380
+ value="Render as-is"
381
+ )
382
+
383
+ gr.Markdown("## Select custom render options")
384
+
385
+ custom_render_patch = gr.Slider(-1, 127, value=-1, label="Custom render MIDI patch")
386
+
387
+ render_align = gr.Radio(["Do not align",
388
+ "Start Times",
389
+ "Start Times and Durations",
390
+ "Start Times and Split Durations"
391
+ ],
392
+ label="Align output to bars",
393
+ value="Do not align"
394
+ )
395
+
396
+ render_transpose_value = gr.Slider(-12, 12, value=0, step=1, label="Transpose value")
397
+ render_transpose_to_C4 = gr.Checkbox(label="Transpose to C4", value=False)
398
+
399
+
400
+ render_output_as_solo_piano = gr.Checkbox(label="Output as Solo Piano", value=False)
401
+ render_remove_drums = gr.Checkbox(label="Remove drums", value=False)
402
+
403
+ submit = gr.Button("Render MIDI", variant="primary")
404
+
405
+ gr.Markdown("## Render results")
406
+
407
+ output_midi_md5 = gr.Textbox(label="Output MIDI md5 hash")
408
+ output_midi_title = gr.Textbox(label="Output MIDI title")
409
+ output_midi_summary = gr.Textbox(label="Output MIDI summary")
410
+ output_audio = gr.Audio(label="Output MIDI audio", format="wav", elem_id="midi_audio")
411
+ output_plot = gr.Plot(label="Output MIDI score plot")
412
+ output_midi = gr.File(label="Output MIDI file", file_types=[".mid"])
413
+
414
+ run_event = submit.click(Render_MIDI, [input_midi,
415
+ render_type,
416
+ soundfont_bank,
417
+ render_sample_rate,
418
+ custom_render_patch,
419
+ render_align,
420
+ render_transpose_value,
421
+ render_transpose_to_C4,
422
+ render_output_as_solo_piano,
423
+ render_remove_drums
424
+ ],
425
+ [output_midi_md5,
426
+ output_midi_title,
427
+ output_midi_summary,
428
+ output_midi,
429
+ output_audio,
430
+ output_plot
431
+ ])
432
+
433
+ app.queue().launch()