File size: 5,223 Bytes
b5a56ee d171350 fa8dc8b d171350 fa8dc8b d171350 b405196 d171350 fa8dc8b d171350 b5a56ee d171350 b5a56ee d171350 b5a56ee d171350 fa8dc8b d171350 b5a56ee d171350 fa8dc8b d171350 fa8dc8b d171350 fa8dc8b d171350 b5a56ee d171350 0a6e0ec fa8dc8b 0a6e0ec | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 | """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 = """
<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
# 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(
'<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; }",
)
|