"""midmid3: Guitar Hero Chart Generator Demo""" import json import os from pathlib import Path import gradio as gr # ZeroGPU: import spaces if available (no-op locally) try: import spaces ON_ZEROGPU = True except ImportError: ON_ZEROGPU = False from pipeline import generate_chart from visualizer import build_visualizer_html EXAMPLES_DIR = Path(__file__).parent / "examples" def _load_example(): """Load pre-computed demo - no GPU needed.""" chart_path = EXAMPLES_DIR / "hot_mess.json" zip_path = EXAMPLES_DIR / "Hot Mess - Friday Pilots Club.zip" audio_path = EXAMPLES_DIR / "hot_mess_input.ogg" with open(chart_path) as f: chart_json = json.load(f) viz_html = build_visualizer_html(chart_json) return ( str(audio_path), # audio_input "Hot Mess", # title "Friday Pilots Club", # artist "", # album "2022", # year "rock", # genre viz_html, # viz_output str(zip_path), # zip_output ) PLACEHOLDER_HTML = """
🎸
Upload a song and hit Generate to see your chart here
""" def _generate_wrapper(audio_path, title, artist, album, year, genre, progress=gr.Progress()): """Gradio-facing wrapper with validation and progress.""" if not audio_path: raise gr.Error("Please upload an audio file.") if not title or not title.strip(): raise gr.Error("Song title is required.") if not artist or not artist.strip(): raise gr.Error("Artist name is required.") zip_path, chart_json = generate_chart( audio_path=audio_path, title=title.strip(), artist=artist.strip(), album=album.strip() if album else "", year=year.strip() if year else "", genre=genre.strip() if genre else "rock", progress_cb=progress, ) html = build_visualizer_html(chart_json) return html, zip_path # Apply ZeroGPU decorator if running on HF Spaces if ON_ZEROGPU: _generate_wrapper = spaces.GPU(duration=180)(_generate_wrapper) # --- UI --- with gr.Blocks( title="midmid3: Guitar Hero Chart Generator", ) as demo: gr.Markdown( "# midmid3: Guitar Hero Chart Generator\n" "Upload a song, get a playable chart with 4 difficulty levels. " "Preview it here, then download the mod folder ready for GHWT:DE." ) with gr.Row(): with gr.Column(scale=1, min_width=280): audio_input = gr.Audio( label="Upload audio", type="filepath", sources=["upload"], ) title_input = gr.Textbox(label="Song title *", placeholder="e.g. Through the Fire and Flames") artist_input = gr.Textbox(label="Artist *", placeholder="e.g. DragonForce") with gr.Row(): album_input = gr.Textbox(label="Album", placeholder="(optional)") year_input = gr.Textbox(label="Year", placeholder="2026") genre_input = gr.Textbox(label="Genre", placeholder="rock", value="rock") generate_btn = gr.Button("Generate Chart", variant="primary", elem_id="generate-btn") example_btn = gr.Button("Load Example", variant="secondary", size="sm") zip_output = gr.File(label="Download song package (.zip)") with gr.Column(scale=3): viz_output = gr.HTML(value=PLACEHOLDER_HTML, label="Chart Preview") generate_btn.click( fn=_generate_wrapper, inputs=[audio_input, title_input, artist_input, album_input, year_input, genre_input], outputs=[viz_output, zip_output], ) example_btn.click( fn=_load_example, inputs=[], outputs=[audio_input, title_input, artist_input, album_input, year_input, genre_input, viz_output, zip_output], ) gr.Markdown( "---\n" "*Powered by [midmid3](https://huggingface.co/markury/midmid3-19m-0326) — " "a 19M-parameter masked-prediction transformer by Markury.*" ) gr.HTML( '
' 'GitHub' 'Model' 'Demo' '
' ) if __name__ == "__main__": demo.launch( theme=gr.themes.Base(primary_hue="purple", neutral_hue="gray"), css="#generate-btn { min-height: 48px; font-size: 16px; }", )