import gradio as gr import os import base64 # CSS for custom styling and the visualizer container css = """ #visualizer-container { position: relative; width: 100%; height: 400px; background: #111; border-radius: 8px; overflow: hidden; box-shadow: 0 4px 6px rgba(0,0,0,0.3); } canvas { display: block; width: 100%; @media (max-width: 600px) { height: 300px; } } .piano-key { position: absolute; bottom: 0; background: linear-gradient(to bottom, #444, #222); border: 1px solid #000; border-top: none; border-radius: 0 0 4px 4px; z-index: 10; } .piano-key.black { background: linear-gradient(to bottom, #000, #333); height: 60% !important; z-index: 20; } .piano-key.active { background: #4caf50 !important; box-shadow: 0 0 10px #4caf50; } .controls { margin-top: 10px; display: flex; gap: 10px; align-items: center; justify-content: center; } """ # HTML Template containing the Logic html_template = """
00:00
Load a SoundFont (.sf2) for realistic instruments, otherwise uses synthesis.
""" # Define the Gradio Interface with gr.Blocks(title="MIDI Player & Visualizer") as demo: gr.Markdown("# 🎹 MIDI Player & Visualizer") gr.Markdown("Upload a MIDI file to play. Optionally upload a SoundFont (.sf2) for improved synthesis logic (simulated here).") with gr.Row(): with gr.Column(): midi_input = gr.File(label="Upload MIDI (.mid)", file_types=[".mid", ".midi"]) sf2_input = gr.File(label="Upload SoundFont (.sf2) [Optional]", file_types=[".sf2"]) with gr.Column(): # The HTML component renders our visualizer and controls gr.HTML(html_template) # def process_midi(file): if file is None: return None with open(file, "rb") as f: return base64.b64encode(f.read()).decode("utf-8") def process_sf2(file): if file is None: return None with open(file, "rb") as f: return base64.b64encode(f.read()).decode("utf-8") # We use hidden components to transfer data midi_b64 = gr.Textbox(visible=False) sf2_b64 = gr.Textbox(visible=False) # Logic flow: # Upload -> Process Function -> Hidden Textbox -> JS Change Event midi_input.upload(process_midi, midi_input, midi_b64) sf2_input.upload(process_sf2, sf2_input, sf2_b64) # JS to handle the base64 data from the hidden textboxes # We append this script to the main HTML to listen to Gradio events js_handler = """ """ # Append the handler script demo.load(None, None, None, js=js_handler) if __name__ == "__main__": demo.launch(css=css)