Spaces:
Running
Running
import os | |
import json | |
import shutil | |
import argparse | |
import warnings | |
import gradio as gr | |
from generate import generate_music, get_args | |
from utils import WEIGHTS_DIR, TEMP_DIR | |
def infer_by_template(dataset: str, v: str, a: str, add_chord: bool): | |
status = "Success" | |
audio = midi = pdf = xml = mxl = tunes = jpg = None | |
emotion = "Q1" | |
if v == "Low" and a == "High": | |
emotion = "Q2" | |
elif v == "Low" and a == "Low": | |
emotion = "Q3" | |
elif v == "High" and a == "Low": | |
emotion = "Q4" | |
try: | |
parser = argparse.ArgumentParser() | |
args = get_args(parser) | |
args.template = True | |
audio, midi, pdf, xml, mxl, tunes, jpg = generate_music( | |
args, | |
emo=emotion, | |
weights=f"{WEIGHTS_DIR}/{dataset.lower()}/weights.pth", | |
) | |
except Exception as e: | |
status = f"{e}" | |
return status, audio, midi, pdf, xml, mxl, tunes, jpg | |
def infer_by_features( | |
dataset: str, | |
pitch_std: str, | |
mode: str, | |
tempo: int, | |
octave: int, | |
rms: int, | |
add_chord: bool, | |
): | |
status = "Success" | |
audio = midi = pdf = xml = mxl = tunes = jpg = None | |
emotion = "Q1" | |
if mode == "Minor" and pitch_std == "High": | |
emotion = "Q2" | |
elif mode == "Minor" and pitch_std == "Low": | |
emotion = "Q3" | |
elif mode == "Major" and pitch_std == "Low": | |
emotion = "Q4" | |
try: | |
parser = argparse.ArgumentParser() | |
args = get_args(parser) | |
args.template = False | |
audio, midi, pdf, xml, mxl, tunes, jpg = generate_music( | |
args, | |
emo=emotion, | |
weights=f"{WEIGHTS_DIR}/{dataset.lower()}/weights.pth", | |
fix_tempo=tempo, | |
fix_pitch=octave, | |
fix_volume=rms, | |
) | |
except Exception as e: | |
status = f"{e}" | |
return status, audio, midi, pdf, xml, mxl, tunes, jpg | |
def feedback( | |
fixed_emo: str, | |
source_dir=f"./{TEMP_DIR}/output", | |
target_dir=f"./{TEMP_DIR}/feedback", | |
): | |
try: | |
if not fixed_emo: | |
raise ValueError("Please select feedback before submitting! ") | |
os.makedirs(target_dir, exist_ok=True) | |
for root, _, files in os.walk(source_dir): | |
for file in files: | |
if file.endswith(".mxl"): | |
prompt_emo = file.split("]")[0][1:] | |
if prompt_emo != fixed_emo: | |
file_path = os.path.join(root, file) | |
target_path = os.path.join( | |
target_dir, file.replace(".mxl", f"_{fixed_emo}.mxl") | |
) | |
shutil.copy(file_path, target_path) | |
return f"Copied {file_path} to {target_path}" | |
else: | |
return "Thanks for your feedback!" | |
return "No .mxl files found in the source directory." | |
except Exception as e: | |
return f"{e}" | |
def save_template(label: str, pitch_std: str, mode: str, tempo: int, octave: int, rms): | |
status = "Success" | |
template = None | |
try: | |
if ( | |
label | |
and pitch_std | |
and mode | |
and tempo != None | |
and octave != None | |
and rms != None | |
): | |
json_str = json.dumps( | |
{ | |
"label": label, | |
"pitch_std": pitch_std == "High", | |
"mode": mode == "Major", | |
"tempo": tempo, | |
"octave": octave, | |
"volume": rms, | |
} | |
) | |
with open( | |
f"./{TEMP_DIR}/feedback/templates.jsonl", | |
"a", | |
encoding="utf-8", | |
) as file: | |
file.write(json_str + "\n") | |
template = f"./{TEMP_DIR}/feedback/templates.jsonl" | |
else: | |
raise ValueError("Please check features") | |
except Exception as e: | |
status = f"{e}" | |
return status, template | |
if __name__ == "__main__": | |
warnings.filterwarnings("ignore") | |
with gr.Blocks() as demo: | |
gr.Markdown( | |
"## The current CPU-based version on HuggingFace has slow inference, you can access the GPU-based mirror on [ModelScope](https://www.modelscope.cn/studios/monetjoe/EMelodyGen)" | |
) | |
with gr.Row(): | |
with gr.Column(): | |
gr.Video( | |
"./demo.mp4", | |
label="Video demo", | |
show_download_button=False, | |
show_share_button=False, | |
) | |
dataset_option = gr.Dropdown( | |
["VGMIDI", "EMOPIA", "Rough4Q"], | |
label="Dataset", | |
value="Rough4Q", | |
) | |
with gr.Tab("By template"): | |
gr.Image( | |
"https://www.modelscope.cn/studio/monetjoe/EMelodyGen/resolve/master/src/4q.jpg", | |
show_label=False, | |
show_download_button=False, | |
show_fullscreen_button=False, | |
show_share_button=False, | |
) | |
valence_radio = gr.Radio( | |
["Low", "High"], | |
label="Valence (reflects negative-positive levels of emotion)", | |
value="High", | |
) | |
arousal_radio = gr.Radio( | |
["Low", "High"], | |
label="Arousal (reflects the calmness-intensity of the emotion)", | |
value="High", | |
) | |
chord_check = gr.Checkbox( | |
label="Generate chords (coming soon)", | |
value=False, | |
) | |
gen_btn_1 = gr.Button("Generate") | |
with gr.Tab("By feature control"): | |
std_option = gr.Radio( | |
["Low", "High"], label="Pitch SD", value="High" | |
) | |
mode_option = gr.Radio( | |
["Minor", "Major"], label="Mode", value="Major" | |
) | |
tempo_option = gr.Slider( | |
minimum=40, | |
maximum=228, | |
step=1, | |
value=120, | |
label="Tempo (BPM)", | |
) | |
octave_option = gr.Slider( | |
minimum=-24, | |
maximum=24, | |
step=12, | |
value=0, | |
label="Octave (Β±12)", | |
) | |
volume_option = gr.Slider( | |
minimum=-5, | |
maximum=10, | |
step=5, | |
value=0, | |
label="Volume (dB)", | |
) | |
chord_check_2 = gr.Checkbox( | |
label="Generate chords (coming soon)", | |
value=False, | |
) | |
gen_btn_2 = gr.Button("Generate") | |
template_radio = gr.Radio( | |
["Q1", "Q2", "Q3", "Q4"], | |
label="The emotion to which the current template belongs", | |
) | |
save_btn = gr.Button("Save template") | |
dld_template = gr.File(label="Download template") | |
with gr.Column(): | |
wav_audio = gr.Audio(label="Audio", type="filepath") | |
midi_file = gr.File(label="Download MIDI") | |
pdf_file = gr.File(label="Download PDF score") | |
xml_file = gr.File(label="Download MusicXML") | |
mxl_file = gr.File(label="Download MXL") | |
abc_textbox = gr.Textbox(label="ABC notation", show_copy_button=True) | |
staff_img = gr.Image(label="Staff", type="filepath") | |
with gr.Column(): | |
status_bar = gr.Textbox(label="Status", show_copy_button=True) | |
fdb_radio = gr.Radio( | |
["Q1", "Q2", "Q3", "Q4"], | |
label="Feedback: the emotion you believe the generated result should belong to", | |
) | |
fdb_btn = gr.Button("Submit") | |
gr.Markdown( | |
"""## Cite | |
```bibtex | |
@inproceedings{Zhou2025EMelodyGen, | |
title = {EMelodyGen: Emotion-Conditioned Melody Generation in ABC Notation with the Musical Feature Template}, | |
author = {Monan Zhou and Xiaobing Li and Feng Yu and Wei Li}, | |
month = {Mar}, | |
year = {2025}, | |
publisher = {GitHub}, | |
version = {0.1}, | |
url = {https://github.com/monetjoe/EMelodyGen} | |
} | |
```""" | |
) | |
# actions | |
gen_btn_1.click( | |
fn=infer_by_template, | |
inputs=[dataset_option, valence_radio, arousal_radio, chord_check], | |
outputs=[ | |
status_bar, | |
wav_audio, | |
midi_file, | |
pdf_file, | |
xml_file, | |
mxl_file, | |
abc_textbox, | |
staff_img, | |
], | |
) | |
gen_btn_2.click( | |
fn=infer_by_features, | |
inputs=[ | |
dataset_option, | |
std_option, | |
mode_option, | |
tempo_option, | |
octave_option, | |
volume_option, | |
chord_check, | |
], | |
outputs=[ | |
status_bar, | |
wav_audio, | |
midi_file, | |
pdf_file, | |
xml_file, | |
mxl_file, | |
abc_textbox, | |
staff_img, | |
], | |
) | |
save_btn.click( | |
fn=save_template, | |
inputs=[ | |
template_radio, | |
std_option, | |
mode_option, | |
tempo_option, | |
octave_option, | |
volume_option, | |
], | |
outputs=[status_bar, dld_template], | |
) | |
fdb_btn.click(fn=feedback, inputs=fdb_radio, outputs=status_bar) | |
demo.launch() | |