File size: 8,097 Bytes
10d9f73
 
 
545f8e1
5dc8e4b
943d8ef
545f8e1
 
10d9f73
545f8e1
 
10d9f73
545f8e1
87e4401
857db5b
545f8e1
87e4401
10d9f73
80cc045
 
 
 
 
87e4401
80cc045
87e4401
10d9f73
943d8ef
 
 
 
5dc8e4b
 
 
943d8ef
 
5dc8e4b
779076d
 
10d9f73
e05183d
857db5b
5dc8e4b
 
545f8e1
943d8ef
545f8e1
52fbb1b
545f8e1
10d9f73
5dc8e4b
10d9f73
5dc8e4b
 
 
943d8ef
5dc8e4b
10d9f73
943d8ef
5dc8e4b
 
 
 
943d8ef
5dc8e4b
 
 
 
545f8e1
10d9f73
943d8ef
5dc8e4b
943d8ef
 
545f8e1
 
 
 
52fbb1b
 
943d8ef
10d9f73
943d8ef
10d9f73
943d8ef
 
 
 
5dc8e4b
2c690c6
943d8ef
 
5dc8e4b
 
 
 
 
 
 
 
545f8e1
52fbb1b
80cc045
5dc8e4b
943d8ef
 
80cc045
545f8e1
5dc8e4b
80cc045
52fbb1b
 
5dc8e4b
c3aa73a
52fbb1b
5dc8e4b
2c690c6
5dc8e4b
52fbb1b
5dc8e4b
 
80cc045
5dc8e4b
80cc045
c3aa73a
10d9f73
 
80cc045
10d9f73
fdc5f70
80cc045
 
 
 
10d9f73
943d8ef
5dc8e4b
 
545f8e1
5dc8e4b
 
10d9f73
 
5dc8e4b
10d9f73
 
 
5dc8e4b
943d8ef
10d9f73
 
 
5dc8e4b
 
 
 
545f8e1
5dc8e4b
545f8e1
 
 
 
 
52fbb1b
80cc045
10d9f73
 
943d8ef
 
10d9f73
 
943d8ef
10d9f73
e05183d
 
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
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176

# ── 0. ZeroGPU decorator (must be first) ───────────────────────────
import spaces  # <-- leave this as the very first import

# ── 1. Standard libs ───────────────────────────────────────────────
import os, sys, gc, time, warnings, tempfile, subprocess, random
import numpy as np, psutil

# ── 2. Torch stack (torch 2.1.0 / torchaudio 2.1.0 from requirements) ─
import torch, torchaudio

# ── 3. Misc deps ──────────────────────────────────────────────────
import gradio as gr
from pydub import AudioSegment
from huggingface_hub import login
from torch.cuda.amp import autocast

# ── 4. Torch <2.3 shim (transformers 4.38 expects it) ─────────────
if not hasattr(torch, "get_default_device"):
    torch.get_default_device = lambda: torch.device(
        "cuda" if torch.cuda.is_available() else "cpu"
    )

warnings.filterwarnings("ignore")
os.environ["PYTORCH_CUDA_ALLOC_CONF"] = "max_split_size_mb:128"

# ── 5. Install audiocraft 1.3.0 (no deps) at runtime ──────────────
try:
    from audiocraft.models import MusicGen
except ModuleNotFoundError:
    print("πŸ”§ Installing audiocraft 1.3.0 (no-deps)…")
    subprocess.check_call(
        [sys.executable, "-m", "pip", "install", "audiocraft==1.3.0", "--no-deps", "-q"]
    )
    from audiocraft.models import MusicGen

# ── 6. Hugging Face authentication ────────────────────────────────
HF_TOKEN = os.getenv("HF_TOKEN")
if not HF_TOKEN:
    sys.exit("ERROR: Add HF_TOKEN as a secret in your Space settings.")
login(HF_TOKEN)

# ── 7. Load MusicGen model ────────────────────────────────────────
print("⏬  Loading facebook/musicgen-medium (first load β‰ˆ 6 GB)…")
musicgen = MusicGen.get_pretrained("facebook/musicgen-medium")
musicgen.to(torch.get_default_device())
musicgen.set_generation_params(duration=10, two_step_cfg=False)
SR = musicgen.sample_rate

# ── 8. Prompt builders (add more as needed) ───────────────────────
def _build(base,bpm,dr,syn,st,bass,gtr,def_bass,def_gtr,flow):
    step = f" with {st}" if st!="none" else flow.format(bpm=bpm)
    return (f"{base}"
            f"{def_bass if bass=='none' else ', '+bass}"
            f"{def_gtr if gtr=='none' else ', '+gtr+' guitar riffs'}"
            f"{'' if dr=='none' else ', '+dr+' drums'}"
            f"{'' if syn=='none' else ', '+syn+' accents'}"
            f"{step} at {bpm} BPM.")

def set_rhcp(bpm,dr,syn,st,bass,gtr):
    return _build("Instrumental funk rock",bpm,dr,syn,st,bass,gtr,
                  ", groovy basslines",", syncopated guitar riffs",
                  "{bpm} BPM funky flow" if bpm>120 else "groovy rhythmic flow")

def set_nirvana(bpm,dr,syn,st,bass,gtr):
    return _build("Instrumental grunge",bpm,dr,syn,st,bass,gtr,
                  ", melodic basslines",", raw distorted guitar riffs",
                  "{bpm} BPM grungy pulse" if bpm>120 else "grungy rhythmic pulse")

# (βž• Add remaining genre prompt functions here the same way.)

# ── 9. Audio post-FX helpers ──────────────────────────────────────
def apply_eq(seg):   return seg.low_pass_filter(8000).high_pass_filter(80)
def apply_fade(seg): return seg.fade_in(1000).fade_out(1000)

def log(stage=""):
    if stage: print(f"── {stage} ──")
    if torch.cuda.is_available():
        a = torch.cuda.memory_allocated()/1024**3
        r = torch.cuda.memory_reserved()/1024**3
        print(f"GPU alloc {a:.2f} GB  reserved {r:.2f} GB")
    print(f"CPU {psutil.virtual_memory().percent}%")

# ── 10. Core generator (ZeroGPU wrapper) ──────────────────────────
@spaces.GPU
def generate(prompt,cfg,k,p,temp,
             total_len,chunk_len,xfade,
             bpm,dr,syn,step,bass,gtr):

    if not prompt.strip():
        return None, "⚠️ Empty prompt."

    total_len  = int(total_len)
    chunk_len  = max(5, min(int(chunk_len), 15))
    n_chunks   = max(1, total_len // chunk_len)
    chunk_len  = total_len / n_chunks
    overlap    = min(1.0, xfade / 1000.0)
    render     = chunk_len + overlap
    segments   = []

    torch.manual_seed(42); np.random.seed(42)

    for i in range(n_chunks):
        log(f"chunk {i+1}")
        musicgen.set_generation_params(duration=render,use_sampling=True,
                                       top_k=k,top_p=p,temperature=temp,cfg_coef=cfg)
        with torch.no_grad(), autocast():
            audio = musicgen.generate([prompt], progress=False)[0]

        audio = audio.cpu().float()
        if audio.dim()==1 or audio.shape[0]==1:
            audio = audio.repeat(2,1)

        with tempfile.NamedTemporaryFile(suffix=".wav", delete=False) as tmp:
            torchaudio.save(tmp.name, audio, SR)
            segments.append(AudioSegment.from_wav(tmp.name))
        os.unlink(tmp.name)
        torch.cuda.empty_cache(); gc.collect()

    track = segments[0]
    for seg in segments[1:]:
        track = track.append(seg, crossfade=xfade)
    track = track[: total_len*1000]
    track = apply_fade(apply_eq(track).normalize(headroom=-9.0))

    out_f = "output_cleaned.mp3"
    track.export(out_f, format="mp3", bitrate="128k",
                 tags={"title":"GhostAI Track","artist":"GhostAI"})
    return out_f, "βœ… Done!"

def clear_inputs():
    return ("",3.0,250,0.9,1.0,30,10,1000,
            120,"none","none","none","none","none")

# ── 11. Gradio UI ─────────────────────────────────────────────────
with gr.Blocks(css="body{background:#0A0A0A;color:#E0E0E0;font-family:'Orbitron',sans-serif}") as demo:
    gr.Markdown("<h1 style='text-align:center'>πŸ‘» GhostAI MusicGen</h1>")
    prompt = gr.Textbox(lines=4, label="Instrumental Prompt")

    with gr.Row():
        gr.Button("RHCP 🌢️").click(set_rhcp,
                                    inputs=[gr.State(120),"none","none","none","none","none"],
                                    outputs=prompt)
        gr.Button("Nirvana 🎸").click(set_nirvana,
                                      inputs=[gr.State(120),"none","none","none","none","none"],
                                      outputs=prompt)
        # βž• add more genre buttons …

    cfg   = gr.Slider(1,10,3,label="CFG")
    k     = gr.Slider(10,500,250,step=10,label="Top-K")
    p     = gr.Slider(0,1,0.9,step=0.05,label="Top-P")
    temp  = gr.Slider(0.1,2,1,label="Temp")
    length= gr.Radio([30,60,90,120],value=30,label="Length (s)")
    chunk = gr.Slider(5,15,10,label="Chunk (s)")
    xfade = gr.Slider(100,2000,1000,label="Cross-fade (ms)")

    bpm   = gr.Slider(60,180,120,label="BPM")
    drum  = gr.Dropdown(["none","standard rock","funk groove","techno kick","jazz swing"],"none","Drums")
    synth = gr.Dropdown(["none","analog synth","digital pad","arpeggiated synth"],"none","Synth")
    steps = gr.Dropdown(["none","syncopated steps","steady steps","complex steps"],"none","Steps")
    bass  = gr.Dropdown(["none","slap bass","deep bass","melodic bass"],"none","Bass")
    gtr   = gr.Dropdown(["none","distorted","clean","jangle"],"none","Guitar")

    gen = gr.Button("Generate πŸš€")
    clr = gr.Button("Clear 🧹")
    audio = gr.Audio(type="filepath")
    status= gr.Textbox(interactive=False)

    gen.click(generate,
              [prompt,cfg,k,p,temp,length,chunk,xfade,bpm,drum,synth,steps,bass,gtr],
              [audio,status])
    clr.click(clear_inputs, None,
              [prompt,cfg,k,p,temp,length,chunk,xfade,bpm,drum,synth,steps,bass,gtr])

demo.launch(share=False)