File size: 8,360 Bytes
dee8df0
 
 
 
 
 
 
6b1f7f2
dee8df0
 
 
 
 
 
 
 
 
 
6b1f7f2
 
 
 
dee8df0
 
6b1f7f2
dee8df0
6b1f7f2
 
dee8df0
 
6b1f7f2
786959b
dee8df0
 
6b1f7f2
 
786959b
 
 
 
 
dee8df0
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
6b1f7f2
7b3fa89
 
dee8df0
6b1f7f2
dee8df0
786959b
 
 
 
 
 
614a4e6
 
dee8df0
7b3fa89
 
dee8df0
6b1f7f2
 
 
 
 
 
dee8df0
7b3fa89
6b1f7f2
085827b
6c2ab00
085827b
 
6b1f7f2
 
 
 
dee8df0
6b1f7f2
 
 
 
 
 
 
085827b
 
 
 
 
 
 
 
6b1f7f2
 
 
 
 
 
 
 
 
 
 
dee8df0
6b1f7f2
 
 
786959b
6b1f7f2
085827b
6b1f7f2
 
dee8df0
 
 
 
 
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
"""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("""<div id='hero'><h1>Hum <span style='color:#6474db'>♪</span></h1>
    <p>Напойте фразу в микрофон или загрузите короткую запись. Один запуск
    создаст все варианты: сэмплерные инструменты с исходным временем и три
    эксперимента YuE2. Первые результаты появятся до окончания YuE2.</p></div>""")
    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("""<div class='note'><b>Текущая цель:</b> один инструмент и
            приблизительно исходное время. Электрогитара и бас используют
            записанные сэмплы; регистр баса выбирается автоматически. Обработанные версии
            добавляют усиление и лёгкий эффект, но не новые ноты. Барабаны
            привязаны к долям SheetSage2. YuE2 может изменить
            длительность, добавить человеческие звуки или другие инструменты;
            отсутствие вокала не гарантируется. Это публичный Space: записи
            обрабатываются на сервере Hugging Face.</div>""")
        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)