Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
@@ -129,7 +129,48 @@ def kmp_search(main_list, sublist):
|
|
129 |
|
130 |
#==================================================================================
|
131 |
|
132 |
-
def
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
133 |
comp_loops_mult,
|
134 |
chords_chunks_len,
|
135 |
loops_chords_set_len
|
@@ -142,8 +183,13 @@ def Remix_MIDI(max_num_loops,
|
|
142 |
start_time = reqtime.time()
|
143 |
print('=' * 70)
|
144 |
|
|
|
|
|
|
|
|
|
145 |
print('Requested settings:')
|
146 |
print('=' * 70)
|
|
|
147 |
print('Max number of loops:', max_num_loops)
|
148 |
print('Num of loops reps:', comp_loops_mult)
|
149 |
print('Matches chords chunks len:', chords_chunks_len)
|
@@ -153,24 +199,20 @@ def Remix_MIDI(max_num_loops,
|
|
153 |
|
154 |
#===============================================================================
|
155 |
|
156 |
-
|
157 |
-
|
158 |
-
chunk_len = chords_chunks_len
|
159 |
-
chunk_chords_set = loops_chords_set_len
|
160 |
|
161 |
-
|
162 |
|
163 |
-
|
|
|
|
|
164 |
|
165 |
-
|
166 |
-
|
167 |
-
fn = loop[0]
|
168 |
-
chords = loop[1]
|
169 |
-
score = loop[2]
|
170 |
-
|
171 |
-
all_chords_chunks.append(chords[:chunk_len])
|
172 |
|
173 |
-
|
|
|
|
|
|
|
174 |
|
175 |
print('Done!')
|
176 |
print('=' * 70)
|
@@ -179,106 +221,65 @@ def Remix_MIDI(max_num_loops,
|
|
179 |
|
180 |
#==================================================================
|
181 |
|
182 |
-
print('
|
183 |
print('=' * 70)
|
184 |
|
185 |
-
|
186 |
-
|
187 |
-
|
188 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
189 |
|
190 |
-
|
|
|
191 |
|
192 |
-
|
193 |
|
194 |
-
|
195 |
-
|
196 |
-
|
197 |
-
stries += 1
|
198 |
|
199 |
-
|
200 |
-
|
201 |
-
|
202 |
-
while not midxs:
|
203 |
-
|
204 |
-
song_names = []
|
205 |
-
song_chords = []
|
206 |
-
song_scores = []
|
207 |
-
song_idxs = []
|
208 |
-
sidx = -1
|
209 |
-
|
210 |
-
while sidx in sidxs:
|
211 |
-
sidx = random.randint(0, len(midi_loops)-1)
|
212 |
-
|
213 |
-
song_idxs.append(sidx)
|
214 |
-
sidxs.append(sidx)
|
215 |
-
|
216 |
-
song_names.append(midi_loops[sidx][0])
|
217 |
-
song_chords.append(midi_loops[sidx][1][-chunk_len:]) #tv
|
218 |
-
song_scores.append(midi_loops[sidx][2])
|
219 |
-
|
220 |
-
song_midxs = [(song_idxs[-1]*loops_mult)+3]
|
221 |
-
|
222 |
-
midxs = [song_midxs[-1]]
|
223 |
-
|
224 |
-
midxs = find_matches(np.array(song_chords[-1]), all_chords_chunks)
|
225 |
-
midxs = [midx for midx in midxs if midx != song_midxs[-1]]
|
226 |
-
|
227 |
-
song_loops_counter = 1
|
228 |
-
rtries = 0
|
229 |
-
end = False
|
230 |
-
|
231 |
-
while song_loops_counter < max_num_loops and not end:
|
232 |
-
|
233 |
-
midxs = [song_midxs[-1]]
|
234 |
-
midxs = []
|
235 |
-
rmidxs = [-1]
|
236 |
-
|
237 |
-
midxs = find_matches(np.array(song_chords[-1]), all_chords_chunks)
|
238 |
-
midxs = [midx for midx in midxs if midx != song_midxs[-1]]
|
239 |
-
|
240 |
-
if midxs:
|
241 |
-
midx = find_best_midx(midi_loops, midxs, song_midxs[-1])
|
242 |
-
|
243 |
-
else:
|
244 |
-
midx = rmidxs[-1]
|
245 |
-
|
246 |
-
if midx not in rmidxs and midx not in song_midxs:
|
247 |
-
|
248 |
-
song_midxs.append(midx)
|
249 |
|
250 |
-
|
251 |
-
|
252 |
-
|
253 |
-
|
254 |
-
|
255 |
-
|
256 |
-
|
257 |
-
song_scores.append(song[2])
|
258 |
-
|
259 |
-
song_loops_counter += 1
|
260 |
|
261 |
-
|
262 |
-
|
263 |
-
|
264 |
-
song_midxs.pop()
|
265 |
-
song_names.pop()
|
266 |
-
song_chords.pop()
|
267 |
-
song_scores.pop()
|
268 |
-
song_loops_counter -= 1
|
269 |
-
rtries += 1
|
270 |
-
rmidxs.append(midx)
|
271 |
|
272 |
-
|
273 |
-
|
274 |
-
break
|
275 |
|
276 |
-
|
277 |
-
|
278 |
-
|
279 |
-
|
280 |
-
|
281 |
-
|
|
|
|
|
|
|
|
|
282 |
print('=' * 70)
|
283 |
print('Done!')
|
284 |
print('=' * 70)
|
@@ -287,105 +288,41 @@ def Remix_MIDI(max_num_loops,
|
|
287 |
|
288 |
print('Creating final MIDI score...')
|
289 |
|
290 |
-
|
291 |
|
292 |
-
|
293 |
-
|
294 |
-
last_max_dur = 0
|
295 |
-
last_dtime = 0
|
296 |
-
mode_dtime = 0
|
297 |
-
mode_dur = 0
|
298 |
|
299 |
-
|
300 |
-
|
301 |
-
|
302 |
-
|
303 |
-
score = copy.deepcopy(src_score)
|
304 |
-
|
305 |
-
for j in range(loops_mult):
|
306 |
-
|
307 |
-
if j == loops_mult-1 and not (i == len(song_scores)-1 and j == loops_mult-1):
|
308 |
|
309 |
-
|
310 |
-
|
311 |
-
|
312 |
-
last_max_dur = max([e[1] for e in last_chord])
|
313 |
-
|
314 |
-
dtimes = [e[0] for e in score if e[0] != 0]
|
315 |
-
durs = [e[1] for e in score]
|
316 |
-
|
317 |
-
mode_dtime= statistics.mode(dtimes)
|
318 |
-
mode_dur = statistics.mode(durs)
|
319 |
-
|
320 |
-
score[0][0] = max(mode_dtime, mode_dur)
|
321 |
-
|
322 |
-
rscore = list(reversed(score))
|
323 |
-
|
324 |
-
ccount = 0
|
325 |
-
|
326 |
-
for r in range(len(rscore)):
|
327 |
-
if rscore[r][0] > 0:
|
328 |
-
ccount += 1
|
329 |
-
|
330 |
-
if ccount == chunk_len:
|
331 |
-
break
|
332 |
-
|
333 |
-
trimmed_score = score[:-(r+1)]
|
334 |
|
335 |
-
|
336 |
|
337 |
-
|
338 |
-
|
|
|
339 |
|
340 |
-
|
341 |
-
if i > 0:
|
342 |
-
last_chord = score[[e for e in range(len(score)) if score[e][0] > 0][-1]:]
|
343 |
-
last_dtime = last_chord[0][0]
|
344 |
-
last_max_dur = max([e[1] for e in last_chord])
|
345 |
-
|
346 |
-
dtimes = [e[0] for e in score if e[0] != 0]
|
347 |
-
durs = [e[1] for e in score]
|
348 |
-
|
349 |
-
mode_dtime= statistics.mode(dtimes)
|
350 |
-
mode_dur = statistics.mode(durs)
|
351 |
-
|
352 |
-
score[0][0] = max(mode_dtime, mode_dur)
|
353 |
|
354 |
-
|
355 |
-
|
356 |
-
final_song.extend(extended_score)
|
357 |
-
|
358 |
-
final_song_abs = TMIDIX.delta_score_to_abs_score(final_song)
|
359 |
|
360 |
print('Done!')
|
361 |
print('=' * 70)
|
362 |
|
363 |
-
#===============================================================================
|
364 |
-
|
365 |
-
print('Creating MIDI summary...')
|
366 |
-
|
367 |
-
midi_summary = 'Number of source MIDI loops: ' + str(len(song_names) * loops_mult) + '\n'
|
368 |
-
midi_summary += '-' * 40
|
369 |
-
midi_summary += '\n'
|
370 |
-
|
371 |
-
for i, song_name in enumerate(song_names):
|
372 |
-
|
373 |
-
son_art = song_name.split('___')[:2]
|
374 |
-
|
375 |
-
son = son_art[0]
|
376 |
-
art = son_art[1]
|
377 |
-
|
378 |
-
midi_summary += 'Loops # ' + str((i*loops_mult)+1) + '-' + str((i*loops_mult)+loops_mult) + ': "' + son + '" by ' + art + '\n'
|
379 |
-
|
380 |
-
#===============================================================================
|
381 |
|
382 |
print('Rendering results...')
|
383 |
|
384 |
print('=' * 70)
|
385 |
-
print('Sample MIDI events:',
|
386 |
print('=' * 70)
|
387 |
|
388 |
-
output_score, patches, overflow_patches = TMIDIX.patch_enhanced_score_notes(
|
389 |
|
390 |
fn1 = "MIDI-Remixer-Composition"
|
391 |
|
@@ -412,7 +349,6 @@ def Remix_MIDI(max_num_loops,
|
|
412 |
|
413 |
#========================================================
|
414 |
|
415 |
-
output_midi_summary = str(midi_summary)
|
416 |
output_midi = str(new_fn)
|
417 |
output_audio = (16000, audio)
|
418 |
|
@@ -424,10 +360,6 @@ def Remix_MIDI(max_num_loops,
|
|
424 |
|
425 |
print('Output MIDI file name:', output_midi)
|
426 |
print('=' * 70)
|
427 |
-
print('Output MIDI summary:')
|
428 |
-
print('-' * 70)
|
429 |
-
print(output_midi_summary)
|
430 |
-
print('=' * 70)
|
431 |
|
432 |
#========================================================
|
433 |
|
@@ -436,7 +368,7 @@ def Remix_MIDI(max_num_loops,
|
|
436 |
print('-' * 70)
|
437 |
print('Req execution time:', (reqtime.time() - start_time), 'sec')
|
438 |
|
439 |
-
return
|
440 |
|
441 |
#==================================================================================
|
442 |
|
@@ -475,25 +407,22 @@ with gr.Blocks() as demo:
|
|
475 |
chords_chunks_len = gr.Slider(6, 10, value=6, step=1, label="Number of loops chords to match")
|
476 |
loops_chords_set_len = gr.Slider(16, 24, value=16, step=1, label="Minimum number of unique chords in each loop")
|
477 |
|
478 |
-
mix_btn = gr.Button("
|
479 |
|
480 |
gr.Markdown("## Mixing results")
|
481 |
|
482 |
-
output_midi_summary = gr.Textbox(label="MIDI summary")
|
483 |
output_audio = gr.Audio(label="MIDI audio", format="wav", elem_id="midi_audio")
|
484 |
output_plot = gr.Plot(label="MIDI score plot")
|
485 |
output_midi = gr.File(label="MIDI file", file_types=[".mid"])
|
486 |
|
487 |
mix_btn.click(Remix_MIDI,
|
488 |
-
[
|
489 |
max_num_loops,
|
490 |
comp_loops_mult,
|
491 |
chords_chunks_len,
|
492 |
loops_chords_set_len
|
493 |
],
|
494 |
-
[
|
495 |
-
output_midi_summary,
|
496 |
-
output_audio,
|
497 |
output_plot,
|
498 |
output_midi
|
499 |
]
|
|
|
129 |
|
130 |
#==================================================================================
|
131 |
|
132 |
+
def load_midi(midi_file):
|
133 |
+
|
134 |
+
print('Loading MIDI...')
|
135 |
+
|
136 |
+
raw_score = TMIDIX.midi2single_track_ms_score(midi_file)
|
137 |
+
escore_notes = TMIDIX.advanced_score_processor(raw_score, return_enhanced_score_notes=True)[0]
|
138 |
+
escore_notes = TMIDIX.augment_enhanced_score_notes(escore_notes, sort_drums_last=True)
|
139 |
+
|
140 |
+
zscore = TMIDIX.recalculate_score_timings(escore_notes)
|
141 |
+
|
142 |
+
cscore = TMIDIX.chordify_score([1000, zscore])
|
143 |
+
|
144 |
+
tones_chords = []
|
145 |
+
tones_chords_idxs = []
|
146 |
+
|
147 |
+
for i, c in enumerate(cscore):
|
148 |
+
pitches = [e[4] for e in c if e[3] != 9]
|
149 |
+
|
150 |
+
if pitches:
|
151 |
+
tones_chord = sorted(set([p % 12 for p in pitches]))
|
152 |
+
|
153 |
+
if tones_chord in TMIDIX.ALL_CHORDS_SORTED:
|
154 |
+
chord_token = TMIDIX.ALL_CHORDS_SORTED.index(tones_chord)
|
155 |
+
|
156 |
+
else:
|
157 |
+
tones_chord = TMIDIX.check_and_fix_tones_chord(tones_chord)
|
158 |
+
chord_token = TMIDIX.ALL_CHORDS_SORTED.index(tones_chord)
|
159 |
+
|
160 |
+
tones_chords.append(chord_token)
|
161 |
+
tones_chords_idxs.append(i)
|
162 |
+
|
163 |
+
print('Done!')
|
164 |
+
print('=' * 70)
|
165 |
+
print('MIDI has', len(tones_chords), 'chords')
|
166 |
+
print('=' * 70)
|
167 |
+
|
168 |
+
return tones_chords, tones_chords_idxs
|
169 |
+
|
170 |
+
#==================================================================================
|
171 |
+
|
172 |
+
def Remix_MIDI(input_midi,
|
173 |
+
max_num_loops,
|
174 |
comp_loops_mult,
|
175 |
chords_chunks_len,
|
176 |
loops_chords_set_len
|
|
|
183 |
start_time = reqtime.time()
|
184 |
print('=' * 70)
|
185 |
|
186 |
+
fn = os.path.basename(input_midi)
|
187 |
+
fn1 = fn.split('.')[0]
|
188 |
+
|
189 |
+
print('=' * 70)
|
190 |
print('Requested settings:')
|
191 |
print('=' * 70)
|
192 |
+
print('Input MIDI file name:', fn)
|
193 |
print('Max number of loops:', max_num_loops)
|
194 |
print('Num of loops reps:', comp_loops_mult)
|
195 |
print('Matches chords chunks len:', chords_chunks_len)
|
|
|
199 |
|
200 |
#===============================================================================
|
201 |
|
202 |
+
tones_chords, tones_chords_idxs = load_midi(input_midi.name)
|
|
|
|
|
|
|
203 |
|
204 |
+
#===============================================================================
|
205 |
|
206 |
+
print('Prepping chords chunks...')
|
207 |
+
|
208 |
+
chunk_len = 4
|
209 |
|
210 |
+
all_chords_chunks = Counter()
|
|
|
|
|
|
|
|
|
|
|
|
|
211 |
|
212 |
+
for i in range(0, len(tones_chords)):
|
213 |
+
chunk = tones_chords[i:i+chunk_len]
|
214 |
+
if len(chunk) == chunk_len:
|
215 |
+
all_chords_chunks[tuple(chunk)] += 1
|
216 |
|
217 |
print('Done!')
|
218 |
print('=' * 70)
|
|
|
221 |
|
222 |
#==================================================================
|
223 |
|
224 |
+
print('Remixing MIDI...')
|
225 |
print('=' * 70)
|
226 |
|
227 |
+
other_chunks = [list(k) for k, v in all_chords_chunks.most_common(10)]
|
228 |
+
|
229 |
+
all_match_chunks = {}
|
230 |
+
|
231 |
+
for mc_chunk in other_chunks:
|
232 |
+
chunk_lens = fuzzy_find([len(l) for l in split_by_sublist(tones_chords, mc_chunk) if len(l) > chunk_len])
|
233 |
+
match_chunks = [l for l in split_by_sublist(tones_chords, mc_chunk) if len(l) in chunk_lens]
|
234 |
+
all_match_chunks[tuple(mc_chunk)] = match_chunks
|
235 |
+
|
236 |
+
chunks_map = random.choices(other_chunks, k=10)
|
237 |
+
|
238 |
+
#==================================================================
|
239 |
+
|
240 |
+
matched_chunks = []
|
241 |
+
start_chunk = []
|
242 |
+
res = -1
|
243 |
+
tries = 0
|
244 |
+
while res == -1 and len(start_chunk[:res]) < chunk_len and tries < 100:
|
245 |
|
246 |
+
start_chunk = random.choice(all_match_chunks[tuple(chunks_map[0])])
|
247 |
+
res = kmp_search(start_chunk, chunks_map[1])[0]
|
248 |
|
249 |
+
tries += 1
|
250 |
|
251 |
+
#print(res)
|
252 |
+
if tries < 100:
|
253 |
+
matched_chunks.append(start_chunk[:res])
|
|
|
254 |
|
255 |
+
else:
|
256 |
+
print('FAIL!')
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
257 |
|
258 |
+
#==================================================================
|
259 |
+
|
260 |
+
mchunks = [-1]
|
261 |
+
tries = 0
|
262 |
+
while -1 in mchunks and tries < 100:
|
263 |
+
|
264 |
+
mchunks = []
|
|
|
|
|
|
|
265 |
|
266 |
+
for i, chunk in enumerate(chunks_map[1:-1]):
|
267 |
+
start_chunk = random.choice(all_match_chunks[tuple(chunk)])
|
268 |
+
res = kmp_search(start_chunk, chunks_map[i+2])[0]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
269 |
|
270 |
+
#print(res)
|
271 |
+
mchunks.append(start_chunk[:res])
|
|
|
272 |
|
273 |
+
tries += 1
|
274 |
+
|
275 |
+
if tries < 100:
|
276 |
+
matched_chunks.extend(mchunks)
|
277 |
+
|
278 |
+
else:
|
279 |
+
print('FAIL!')
|
280 |
+
|
281 |
+
#==================================================================
|
282 |
+
|
283 |
print('=' * 70)
|
284 |
print('Done!')
|
285 |
print('=' * 70)
|
|
|
288 |
|
289 |
print('Creating final MIDI score...')
|
290 |
|
291 |
+
all_matches_dscores = []
|
292 |
|
293 |
+
for match in matched_chunks:
|
|
|
|
|
|
|
|
|
|
|
294 |
|
295 |
+
start, end = kmp_search(tones_chords, match)
|
296 |
+
|
297 |
+
sidx = tones_chords_idxs[start]
|
298 |
+
eidx = tones_chords_idxs[end]
|
|
|
|
|
|
|
|
|
|
|
299 |
|
300 |
+
all_matches_dscores.append(TMIDIX.delta_score_notes(TMIDIX.flatten(cscore[sidx:eidx+1])))
|
301 |
+
|
302 |
+
#===============================================================================
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
303 |
|
304 |
+
new_dscore = all_matches_dscores[0]
|
305 |
|
306 |
+
for score in all_matches_dscores[1:]:
|
307 |
+
score[0][1] = statistics.mode([e[1] for e in new_dscore[-75:] if e[1] != 0 and e[3] != 9])
|
308 |
+
new_dscore.extend(score)
|
309 |
|
310 |
+
new_escore = TMIDIX.delta_score_to_abs_score(new_dscore)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
311 |
|
312 |
+
#===============================================================================
|
|
|
|
|
|
|
|
|
313 |
|
314 |
print('Done!')
|
315 |
print('=' * 70)
|
316 |
|
317 |
+
#===============================================================================
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
318 |
|
319 |
print('Rendering results...')
|
320 |
|
321 |
print('=' * 70)
|
322 |
+
print('Sample MIDI events:', new_escore[:3])
|
323 |
print('=' * 70)
|
324 |
|
325 |
+
output_score, patches, overflow_patches = TMIDIX.patch_enhanced_score_notes(new_escore)
|
326 |
|
327 |
fn1 = "MIDI-Remixer-Composition"
|
328 |
|
|
|
349 |
|
350 |
#========================================================
|
351 |
|
|
|
352 |
output_midi = str(new_fn)
|
353 |
output_audio = (16000, audio)
|
354 |
|
|
|
360 |
|
361 |
print('Output MIDI file name:', output_midi)
|
362 |
print('=' * 70)
|
|
|
|
|
|
|
|
|
363 |
|
364 |
#========================================================
|
365 |
|
|
|
368 |
print('-' * 70)
|
369 |
print('Req execution time:', (reqtime.time() - start_time), 'sec')
|
370 |
|
371 |
+
return output_audio, output_plot, output_midi
|
372 |
|
373 |
#==================================================================================
|
374 |
|
|
|
407 |
chords_chunks_len = gr.Slider(6, 10, value=6, step=1, label="Number of loops chords to match")
|
408 |
loops_chords_set_len = gr.Slider(16, 24, value=16, step=1, label="Minimum number of unique chords in each loop")
|
409 |
|
410 |
+
mix_btn = gr.Button("Remix", variant="primary")
|
411 |
|
412 |
gr.Markdown("## Mixing results")
|
413 |
|
|
|
414 |
output_audio = gr.Audio(label="MIDI audio", format="wav", elem_id="midi_audio")
|
415 |
output_plot = gr.Plot(label="MIDI score plot")
|
416 |
output_midi = gr.File(label="MIDI file", file_types=[".mid"])
|
417 |
|
418 |
mix_btn.click(Remix_MIDI,
|
419 |
+
[input_midi,
|
420 |
max_num_loops,
|
421 |
comp_loops_mult,
|
422 |
chords_chunks_len,
|
423 |
loops_chords_set_len
|
424 |
],
|
425 |
+
[output_audio,
|
|
|
|
|
426 |
output_plot,
|
427 |
output_midi
|
428 |
]
|