| """midmid3: Guitar Hero Chart Generator Demo""" |
|
|
| import json |
| import os |
| from pathlib import Path |
|
|
| import gradio as gr |
|
|
| |
| 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), |
| "Hot Mess", |
| "Friday Pilots Club", |
| "", |
| "2022", |
| "rock", |
| viz_html, |
| str(zip_path), |
| ) |
|
|
|
|
| PLACEHOLDER_HTML = """ |
| <div style="font-family: system-ui, sans-serif; background: #111; border-radius: 12px; |
| padding: 60px 20px; text-align: center; color: #666; max-width: 900px; margin: 0 auto;"> |
| <div style="font-size: 48px; margin-bottom: 12px;">🎸</div> |
| <div style="font-size: 16px;">Upload a song and hit Generate to see your chart here</div> |
| </div> |
| """ |
|
|
|
|
| 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 |
|
|
|
|
| |
| if ON_ZEROGPU: |
| _generate_wrapper = spaces.GPU(duration=180)(_generate_wrapper) |
|
|
|
|
| |
| 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( |
| '<div style="display:flex; justify-content:center; gap:8px; padding:8px 0;">' |
| '<a href="https://github.com/markuryy/midmid"><img src="https://img.shields.io/badge/GitHub-midmid-181717?logo=github&logoColor=white" alt="GitHub"></a>' |
| '<a href="https://huggingface.co/markury/midmid3-19m-0326"><img src="https://img.shields.io/badge/%F0%9F%A4%97%20Model-midmid3--19m--0326-yellow" alt="Model"></a>' |
| '<a href="https://huggingface.co/spaces/markury/midmid3"><img src="https://img.shields.io/badge/%F0%9F%A4%97%20Demo-midmid3-blue" alt="Demo"></a>' |
| '</div>' |
| ) |
|
|
|
|
| if __name__ == "__main__": |
| demo.launch( |
| theme=gr.themes.Base(primary_hue="purple", neutral_hue="gray"), |
| css="#generate-btn { min-height: 48px; font-size: 16px; }", |
| ) |
|
|