File size: 3,096 Bytes
99b10ee
18f8e1a
 
747b748
18f8e1a
 
e078bb0
 
18f8e1a
99b10ee
e078bb0
 
18f8e1a
 
e078bb0
18f8e1a
d9b6fe5
 
99b10ee
18f8e1a
 
 
 
d9b6fe5
99b10ee
 
18f8e1a
 
 
 
 
 
 
 
 
99b10ee
 
 
747b748
18f8e1a
99b10ee
 
18f8e1a
99b10ee
747b748
18f8e1a
747b748
99b10ee
 
 
18f8e1a
 
99b10ee
 
747b748
 
99b10ee
 
 
18f8e1a
 
99b10ee
 
18f8e1a
747b748
18f8e1a
99b10ee
 
18f8e1a
e078bb0
18f8e1a
 
 
01a36b4
712505a
99b10ee
 
 
 
712505a
e078bb0
18f8e1a
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
import gradio as gr
from pitchflower_app.ui import theme, CSS, header, build_editor
from pitchflower_app.callbacks import analyze, slider_changed, apply_drawing, regenerate

with gr.Blocks(theme=theme(), css=CSS) as demo:
    header()

    with gr.Row():
        inp = gr.Audio(sources=["upload","microphone"], type="filepath", label="Input Audio")
        out = gr.Audio(label="Output (Regenerated)")

    with gr.Row():
        with gr.Column(elem_id="controls", scale=1, min_width=330):
            semitones = gr.Slider(-12.0, 12.0, value=0.0, step=0.1, label="Semitone shift (±12 st)")

            with gr.Accordion("Advanced", open=False):
                steps = gr.Slider(1, 30, value=5, step=1, label="Flow steps")
                w_scale = gr.Slider(0.1, 6.0, value=3.0, step=0.1, label="F0 guidance strength")

        with gr.Column(scale=3):
            editor = build_editor()
            with gr.Row(elem_id="canvas-toolbar"):
                clear_btn = gr.Button("Clear Drawing", variant="secondary")
                use_btn = gr.Button("Record Drawing", variant="secondary")

    # Hidden states
    bg_state = gr.State(None)
    drawn_logf0_state = gr.State(None)
    times_state = gr.State(None)
    gt_f0_state = gr.State(None)
    y_minmax_state = gr.State(None)
    target_logf0_state = gr.State(None)
    status = gr.Markdown("", elem_classes=["toast"])

    # Wire
    inp.change(
        analyze,
        inputs=[inp],
        outputs=[editor, bg_state, times_state, gt_f0_state, y_minmax_state, target_logf0_state, drawn_logf0_state, status],
        show_progress=True, queue=True,
    )

    # Slider reacts; include smoothing here so preview respects it
    semitones.release(
        slider_changed,
        inputs=[times_state, gt_f0_state, y_minmax_state, semitones, drawn_logf0_state, target_logf0_state,],
        outputs=[editor, bg_state, target_logf0_state],
        queue=False,
    )

    # Toolbar buttons
    clear_btn.click(lambda bg: {"background": bg, "layers": [], "composite": None}, inputs=[bg_state], outputs=[editor], queue=False)
    use_btn.click(
        apply_drawing,
        inputs=[editor, bg_state, times_state, gt_f0_state, y_minmax_state, semitones],
        outputs=[editor, bg_state, status, target_logf0_state, drawn_logf0_state],
        queue=False,
    )

    with gr.Row(elem_id="sticky-cta"):
        regen_btn = gr.Button("Regenerate", variant="primary")
    regen_btn.click(
        regenerate,
        inputs=[inp, target_logf0_state, times_state, gt_f0_state, steps, w_scale, y_minmax_state],
        outputs=[out, editor, bg_state, status],
        show_progress=True, queue=True,
    )

    # warmup
    def _warmup():
        from pitchflower_app.models import load_models
        try: load_models()
        except Exception as e: print("Warmup failed:", e)
    demo.load(_warmup, None, None, show_progress=False)

try:
    demo.queue(max_size=8, default_concurrency_limit=1)
except TypeError:
    demo.queue(max_size=8)

if __name__ == "__main__":
    demo.launch(favicon_path="assets/favicon.png" if False else None)