asigalov61's picture
Update app.py
739896a verified
# =================================================================================================
# https://huggingface.co/spaces/asigalov61/MIDI-Chords-Mixer
# =================================================================================================
import time as reqtime
import datetime
from pytz import timezone
import copy
import gradio as gr
import random
from midi_to_colab_audio import midi_to_colab_audio
import TMIDIX
# =================================================================================================
def Mix_Chords(input_output_as_solo_piano,
input_remove_drums,
input_output_tempo,
input_transform,
input_transpose_to_C4,
input_transpose_value
):
print('=' * 70)
print('Req start time: {:%Y-%m-%d %H:%M:%S}'.format(datetime.datetime.now(PDT)))
start_time = reqtime.time()
print('=' * 70)
print('-' * 70)
print('Requested settings:')
print('-' * 70)
print('Output as Solo Piano:', input_output_as_solo_piano)
print('Remove drums:', input_remove_drums)
print('Output tempo:', input_output_tempo)
print('Transform:', input_transform)
print('Transpose to C4:', input_transpose_to_C4)
print('Transpose value:', input_transpose_value)
print('-' * 70)
print('Loading source and target MIDIs...')
#=============================================================================================================
sidx = random.randint(0, len(all_chords_chunks)-1)
src_score = all_chords_chunks[sidx]
sfn = src_score[0]
src_score_chords = src_score[1]
src_escore_notes = []
for s in src_score_chords:
chord_notes = [['note'] + list(c)[:2] + [(list(c)[2] // 16)+1] + list(c)[3:] + [list(c)[2]] for c in s]
for c in chord_notes[1:]:
c[1] = 0
src_escore_notes.extend(chord_notes)
src_escore_notes = TMIDIX.recalculate_score_timings(TMIDIX.delta_score_to_abs_score(src_escore_notes))
src_cscore = TMIDIX.chordify_score([1000, src_escore_notes])
src_counts = [chunks_lens[sidx]] + chords_drums_counts[sidx]
src_cidxs = all_chords_indexes[sidx]
src_avg_time = TMIDIX.escore_notes_averages(src_escore_notes)[0]
#=============================================================================================================
sidx = random.randint(0, len(all_chords_chunks)-1)
trg_score = all_chords_chunks[sidx]
tfn = trg_score[0]
trg_score_chords = trg_score[1]
trg_escore_notes = []
for s in trg_score_chords:
chord_notes = [['note'] + list(c)[:2] + [(list(c)[2] // 16)+1] + list(c)[3:] + [list(c)[2]] for c in s]
for c in chord_notes[1:]:
c[1] = 0
trg_escore_notes.extend(chord_notes)
trg_escore_notes = TMIDIX.recalculate_score_timings(TMIDIX.delta_score_to_abs_score(trg_escore_notes))
trg_cscore = TMIDIX.chordify_score([1000, trg_escore_notes])
trg_counts = [chunks_lens[sidx]] + chords_drums_counts[sidx]
trg_cidxs = all_chords_indexes[sidx]
trg_avg_time = TMIDIX.escore_notes_averages(trg_escore_notes)[0]
#=============================================================================================================
print('=' * 70)
print('Done loading source and target MIDIs...!')
print('=' * 70)
print('Mixing...')
max_chords_count = min(src_counts[1], trg_counts[1])
mixed_score = []
cidx = 0
for i, c in enumerate(src_cscore):
if i == src_cidxs[cidx]:
stime = c[0][1]
sdurs = [cc[2] for cc in c]
tchord = copy.deepcopy(trg_cscore[trg_cidxs[cidx]])
sdurs = sdurs + random.choices(sdurs, k=abs(len(tchord)-len(c)))
for j, n in enumerate(tchord):
n[1] = stime
n[2] = sdurs[j]
mixed_score.extend(tchord)
cidx += 1
if cidx == max_chords_count:
break
else:
mixed_score.extend(c)
print('=' * 70)
print('Done!')
print('=' * 70)
#===============================================================================
if input_output_as_solo_piano:
csong = TMIDIX.chordify_score([1000, mixed_score])
mixed_score = []
for c in csong:
pitches = []
for cc in c:
ccc = copy.deepcopy(cc)
if cc[3] != 9:
if cc[4] not in pitches:
ccc[3] = 0
ccc[6] = 0
mixed_score.append(ccc)
pitches.append(cc[4])
else:
mixed_score.append(ccc)
if input_remove_drums:
mixed_score = [e for e in mixed_score if e[3] != 9]
if input_output_tempo == 'Source MIDI':
time_k = src_avg_time / trg_avg_time
mixed_score = TMIDIX.adjust_escore_notes_timings(mixed_score, time_k)
elif input_output_tempo == 'Target MIDI':
time_k = trg_avg_time / src_avg_time
mixed_score = TMIDIX.adjust_escore_notes_timings(mixed_score, time_k)
if input_transform == 'Flip Mix':
mixed_score = TMIDIX.flip_enhanced_score_notes(mixed_score)
elif input_transform == 'Reverse Mix':
mixed_score = TMIDIX.reverse_enhanced_score_notes(mixed_score)
if input_transpose_value != 0:
mixed_score = TMIDIX.transpose_escore_notes(mixed_score, input_transpose_value)
if input_transpose_to_C4:
mixed_score = TMIDIX.transpose_escore_notes_to_pitch(mixed_score)
#===============================================================================
print('Rendering results...')
print('=' * 70)
print('Sample INTs', mixed_score[:5])
print('=' * 70)
fn1 = 'MIDI_Chords_Mixer_' + sfn + '_' + tfn
output_score, patches, overflow_patches = TMIDIX.patch_enhanced_score_notes(mixed_score)
detailed_stats = TMIDIX.Tegridy_ms_SONG_to_MIDI_Converter(output_score,
output_signature = 'MIDI Chords Mixer',
output_file_name = fn1,
track_name='Project Los Angeles',
list_of_MIDI_patches=patches,
timings_multiplier=16
)
new_fn = fn1+'.mid'
audio = midi_to_colab_audio(new_fn,
soundfont_path=soundfont,
sample_rate=16000,
volume_scale=10,
output_for_gradio=True
)
print('Done!')
print('=' * 70)
#========================================================
output_midi_title = str(fn1)
output_midi_summary = 'Source MIDI MD5: ' + sfn + '\n'
output_midi_summary += 'Target MIDI MD5: ' + tfn
output_midi = str(new_fn)
output_audio = (16000, audio)
for o in output_score:
o[1] *= 16
o[2] *= 16
output_plot = TMIDIX.plot_ms_SONG(output_score, plot_title=output_midi_title, return_plt=True)
print('Output MIDI file name:', output_midi)
print('Output MIDI title:', output_midi_title)
print('Output MIDI summary:', output_midi_summary)
print('=' * 70)
#========================================================
print('-' * 70)
print('Req end time: {:%Y-%m-%d %H:%M:%S}'.format(datetime.datetime.now(PDT)))
print('-' * 70)
print('Req execution time:', (reqtime.time() - start_time), 'sec')
return output_midi_title, output_midi_summary, output_midi, output_audio, output_plot
# =================================================================================================
if __name__ == "__main__":
#=====================================================================
PDT = timezone('US/Pacific')
print('=' * 70)
print('App start time: {:%Y-%m-%d %H:%M:%S}'.format(datetime.datetime.now(PDT)))
print('=' * 70)
#=====================================================================
soundfont = "SGM-v2.01-YamahaGrand-Guit-Bass-v2.7.sf2"
#=====================================================================
all_chords_chunks = TMIDIX.Tegridy_Any_Pickle_File_Reader('Los_Angeles_Chords_Songs_MIDI_Dataset_79898_128_256')
print('=' * 70)
print('Prepping loaded data...')
#=====================================================================
chunks_lens = [len(a[1]) for a in all_chords_chunks]
#=====================================================================
chords_drums_counts = []
for a in all_chords_chunks:
score = a[1]
ccount = 0
dcount = 0
for s in score:
if any(a[2] < 80 for a in s):
ccount += 1
if all(a[2] == 128 for a in s):
dcount += 1
chords_drums_counts.append([ccount, dcount])
#=====================================================================
all_chords_indexes = []
for a in all_chords_chunks:
score = a[1]
chords_indexes = []
for i, s in enumerate(score):
if any(a[2] < 80 for a in s):
chords_indexes.append(i)
all_chords_indexes.append(chords_indexes)
#=====================================================================
print('Done!')
print('=' * 70)
#=====================================================================
app = gr.Blocks()
with app:
gr.Markdown("<h1 style='text-align: center; margin-bottom: 1rem'>MIDI Chords Mixer</h1>")
gr.Markdown("<h1 style='text-align: center; margin-bottom: 1rem'>Mix chords from one MIDI to another MIDI</h1>")
gr.Markdown(
"![Visitors](https://api.visitorbadge.io/api/visitors?path=asigalov61.MIDI-Chords-Mixer&style=flat)\n\n"
"This is a demo for TMIDIX Python module from tegridy-tools and Los Angeles MIDI Dataset\n\n"
"Check out [tegridy-tools](https://github.com/asigalov61/tegridy-tools) on GitHub!\n\n"
"Check out [Los Angeles MIDI Dataset](https://github.com/asigalov61/Los-Angeles-MIDI-Dataset) on GitHub!\n\n"
)
gr.Markdown("## Select mixing options")
input_output_as_solo_piano = gr.Checkbox(label="Output as Solo Piano", value=False)
input_remove_drums = gr.Checkbox(label="Remove drums from output", value=False)
input_output_tempo = gr.Radio(["Source MIDI", "Target MIDI", "MIDI Mix"], value="MIDI Mix", label="Output tempo")
input_transform = gr.Radio(["As-is", "Flip Mix", "Reverse Mix"], value="As-is", label="Transform")
input_transpose_value = gr.Slider(-12, 12, value=0, step=1, label="Transpose value")
input_transpose_to_C4 = gr.Checkbox(label="Transpose to C4", value=False)
run_btn = gr.Button("Mix Chords", variant="primary")
gr.Markdown("## Mixing results")
output_midi_title = gr.Textbox(label="Output MIDI title")
output_midi_summary = gr.Textbox(label="Output MIDI summary")
output_audio = gr.Audio(label="Output MIDI audio", format="mp3", elem_id="midi_audio")
output_plot = gr.Plot(label="Output MIDI score plot")
output_midi = gr.File(label="Output MIDI file", file_types=[".mid"])
run_event = run_btn.click(Mix_Chords, [input_output_as_solo_piano,
input_remove_drums,
input_output_tempo,
input_transform,
input_transpose_to_C4,
input_transpose_value
],
[output_midi_title, output_midi_summary, output_midi, output_audio, output_plot])
app.queue().launch()