"""Hum research Space: record, choose a rendering path, hear the result.""" from __future__ import annotations import gradio as gr from logic import INSTRUMENTS from pipeline import generate_all SOLO_STYLE = ( "instrumental solo {instrument}, clear single melody, intimate dry recording, " "natural instrumental tone" ) ARRANGEMENT_STYLE = ( "instrumental chamber pop, {instrument} melody, acoustic bass, " "brushed drums, soft strings, warm intimate mood" ) DRUM_STYLE = ( "instrumental {instrument} lead melody, steady acoustic drum kit, " "kick and snare, closed hi-hat, dry studio recording" ) def suggest_prompts(instrument: str) -> tuple[str, str, str]: name = INSTRUMENTS[instrument][1] return tuple(template.format(instrument=name) for template in (SOLO_STYLE, DRUM_STYLE, ARRANGEMENT_STYLE)) def run(audio: str | None, instrument: str, solo_style: str, drum_style: str, arrangement_style: str, seed: int, include_yue: bool, save_recording: bool, progress: gr.Progress = gr.Progress(track_tqdm=False)): try: styles = {"yue_solo": solo_style, "yue_drums": drum_style, "yue_arrangement": arrangement_style} for result in generate_all(audio, instrument, styles, int(seed), include_yue, progress, save_recording=save_recording): yield result if result[-1]["complete"] and "recording_archive" in result[-1]["errors"]: gr.Warning("Запись не сохранилась в приватном архиве; см. детали запуска.") except Exception as error: raise gr.Error(str(error)) from error CSS = """ .gradio-container {max-width: 1000px !important; margin: auto !important;} #hero {padding: 20px 4px 10px 4px;} #hero h1 {font-size: clamp(2.5rem, 6vw, 4.5rem); letter-spacing: -.045em; margin: 0;} #hero p {font-size: 1.08rem; max-width: 720px; line-height: 1.55; color: #566179;} .note {border: 1px solid #d9e0ed; border-radius: 16px; padding: 14px 18px; background: linear-gradient(120deg,#f5f7ff,#f1fbfc); color: #3e4b64;} """ with gr.Blocks(title="Hum · напев в инструмент", css=CSS, theme=gr.themes.Soft()) as demo: gr.HTML("""

Hum ♪

Напойте фразу в микрофон или загрузите короткую запись. Один запуск создаст все варианты: сэмплерные инструменты с исходным временем и три эксперимента YuE2. Первые результаты появятся до окончания YuE2.

""") with gr.Row(): with gr.Column(scale=4): audio = gr.Audio(label="Ваш напев", sources=["microphone", "upload"], type="filepath", format=None) save_recording = gr.Checkbox( label="Сохранить исходную запись в приватный архив владельца Space", value=False) gr.Markdown("Если включить сохранение, исходный файл с микрофона или загрузки " "останется в приватном архиве Hugging Face после перезапуска Space. " "Без галочки исходник остаётся лишь во временном хранилище Space " "до очистки или перезапуска.") instrument = gr.Dropdown(list(INSTRUMENTS), value="Флейта", label="Инструмент") include_yue = gr.Checkbox(label="Запустить YuE2 · три генерации (включено по умолчанию)", value=True) with gr.Accordion("Настройки YuE2", open=False): defaults = suggest_prompts("Флейта") solo_style = gr.Textbox(label="Соло · style", lines=2, value=defaults[0]) drum_style = gr.Textbox(label="Мелодия + барабаны · style", lines=2, value=defaults[1]) arrangement_style = gr.Textbox(label="Композиция · style", lines=2, value=defaults[2]) seed = gr.Number(label="Seed", value=4096, precision=0) go = gr.Button("Создать все варианты", variant="primary", size="lg") gr.HTML("""
Текущая цель: один инструмент и приблизительно исходное время. Электрогитара и бас используют записанные сэмплы; регистр баса выбирается автоматически. Обработанные версии добавляют усиление и лёгкий эффект, но не новые ноты. Барабаны привязаны к долям SheetSage2. YuE2 может изменить длительность, добавить человеческие звуки или другие инструменты; отсутствие вокала не гарантируется. Это публичный Space: записи обрабатываются на сервере Hugging Face.
""") with gr.Column(scale=6): with gr.Row(): with gr.Column(): instrument_only = gr.Audio(label="Инструмент · исходный ритм", interactive=False) instrument_drums = gr.Audio(label="Инструмент + синтезаторные барабаны", interactive=False) contour = gr.Audio(label="Непрерывная высота · synth", interactive=False) guitar_clean = gr.Audio(label="Электрогитара · чистая", interactive=False) guitar_amp = gr.Audio(label="Электрогитара · усилитель и эффекты", interactive=False) bass_clean = gr.Audio(label="Бас · чистый", interactive=False) bass_amp = gr.Audio(label="Бас · тёплый усилитель", interactive=False) with gr.Column(): yue_solo = gr.Audio(label="YuE2 · соло", interactive=False) yue_drums = gr.Audio(label="YuE2 · мелодия + барабаны", interactive=False) yue_arrangement = gr.Audio(label="YuE2 · композиция", interactive=False) with gr.Row(): midi = gr.File(label="Мелодия · MIDI") drum_midi = gr.File(label="Барабаны · MIDI") beat_lab = gr.File(label="Доли · LAB") abc = gr.File(label="Мелодия для YuE2 · ABC") details = gr.JSON(label="Детали запуска") instrument.change(suggest_prompts, inputs=instrument, outputs=[solo_style, drum_style, arrangement_style]) go.click(run, inputs=[audio, instrument, solo_style, drum_style, arrangement_style, seed, include_yue, save_recording], outputs=[instrument_only, instrument_drums, contour, guitar_clean, guitar_amp, bass_clean, bass_amp, yue_solo, yue_drums, yue_arrangement, midi, drum_midi, beat_lab, abc, details], show_progress="full") if __name__ == "__main__": demo.queue(max_size=8, default_concurrency_limit=1) demo.launch(server_name="0.0.0.0", server_port=7860, show_error=True)