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()