File size: 8,333 Bytes
fdc5f70
545f8e1
52fbb1b
 
 
 
545f8e1
 
52fbb1b
 
545f8e1
52fbb1b
 
545f8e1
 
52fbb1b
545f8e1
 
52fbb1b
545f8e1
87e4401
2c690c6
857db5b
545f8e1
87e4401
52fbb1b
80cc045
 
 
 
 
87e4401
80cc045
87e4401
52fbb1b
779076d
 
52fbb1b
e05183d
857db5b
52fbb1b
545f8e1
52fbb1b
545f8e1
52fbb1b
545f8e1
52fbb1b
 
545f8e1
52fbb1b
 
 
 
 
 
80cc045
 
 
 
 
545f8e1
 
 
 
52fbb1b
545f8e1
52fbb1b
545f8e1
 
 
 
 
 
52fbb1b
 
 
545f8e1
80cc045
52fbb1b
 
80cc045
 
 
f950faf
2c690c6
545f8e1
80cc045
52fbb1b
 
 
 
 
 
 
80cc045
545f8e1
80cc045
52fbb1b
80cc045
 
545f8e1
52fbb1b
545f8e1
 
80cc045
545f8e1
80cc045
 
52fbb1b
 
c3aa73a
52fbb1b
80cc045
2c690c6
545f8e1
52fbb1b
545f8e1
 
c3aa73a
545f8e1
 
80cc045
 
 
c3aa73a
52fbb1b
 
80cc045
52fbb1b
 
fdc5f70
80cc045
 
 
 
52fbb1b
545f8e1
80cc045
 
545f8e1
52fbb1b
80cc045
545f8e1
80cc045
545f8e1
 
80cc045
545f8e1
52fbb1b
545f8e1
52fbb1b
545f8e1
 
 
52fbb1b
545f8e1
 
 
 
 
 
 
 
 
 
52fbb1b
80cc045
52fbb1b
 
80cc045
 
52fbb1b
 
 
545f8e1
52fbb1b
 
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
177
178
179
180
#!/usr/bin/env python3
"""
GhostAI Music Generator – ZeroGPU Edition
β€’ Streams facebook/musicgen-medium from the Hub using your HF_TOKEN
β€’ Runs on a transient GPU provided by the ZeroGPU scheduler
β€’ Keeps your genre prompt builders, EQ / fade FX, neon Gradio UI
"""

# ── ZeroGPU decorator must be imported *before* torch/CUDA ──────────
import spaces                                  # πŸ‘ˆ FIRST import

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

# ── Torch (CPU wheels; ZeroGPU moves tensors to the temp GPU) ───────
import torch, torchaudio

# ── Other deps ──────────────────────────────────────────────────────
import gradio as gr
from pydub import AudioSegment
from audiocraft.models import MusicGen
from huggingface_hub import login
from torch.cuda.amp import autocast

# ── Torch <2.3 shim (transformers 4.35 calls get_default_device) ───
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"

# ────────────────────────── HF 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)

print("πŸ”„  Loading facebook/musicgen-medium (first build β‰ˆ 6 GB)…")
musicgen = MusicGen.get_pretrained("facebook/musicgen-medium")
musicgen.to(torch.get_default_device())            # move entire model
musicgen.set_generation_params(duration=10, two_step_cfg=False)
SR = musicgen.sample_rate

# ────────────────────────── Prompt helpers ─────────────────────────
def _p(base,bpm,dr,syn,st,bass,gtr,db,dg,flow):
    step = f" with {st}" if st!="none" else flow.format(bpm=bpm)
    return (f"{base}"
            f"{', '+bass if bass!='none' else db}"
            f"{', '+gtr+' guitar riffs' if gtr!='none' else dg}"
            f"{', '+dr+' drums' if dr!='none' else ''}"
            f"{', '+syn+' accents' if syn!='none' else ''}"
            f"{step} at {bpm} BPM.")

def set_red_hot_chili_peppers_prompt(bpm,dr,syn,st,bass,gtr):
    return _p("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_grunge_prompt(bpm,dr,syn,st,bass,gtr):
    return _p("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 your other genre prompt functions here exactly as before …

# ────────────────────────── Audio FX helpers ───────────────────────
def apply_eq(s):   return s.low_pass_filter(8000).high_pass_filter(80)
def apply_fade(s): return s.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 mem alloc {a:.2f} GB  reserved {r:.2f} GB")
    print(f"CPU mem {psutil.virtual_memory().percent}% used")

# ──────────────────────── Core generator API ───────────────────────
@spaces.GPU                     # 🟒 ZeroGPU will allocate a GPU per call
def generate_music(prompt,cfg,k,p,temp,
                   total_len,chunk_len,xfade,
                   bpm,dr,syn,step,bass,gtr):

    if not prompt.strip():
        return None, "⚠️ Prompt is empty."

    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_len = chunk_len + overlap
    pieces     = []

    torch.manual_seed(42); np.random.seed(42)
    t0 = time.time()

    for i in range(n_chunks):
        log(f"before chunk {i+1}")
        musicgen.set_generation_params(
            duration=render_len, 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)
            seg = AudioSegment.from_wav(tmp.name)
        os.unlink(tmp.name)
        pieces.append(seg)

        torch.cuda.empty_cache(); gc.collect()
        log(f"after chunk {i+1}")

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

    out_path = "output_cleaned.mp3"
    track.export(out_path, format="mp3", bitrate="128k",
                 tags={"title":"GhostAI Track","artist":"GhostAI"})
    log("final"); print(f"⏱  {time.time()-t0:.1f}s total")
    return out_path, "βœ… Done!"

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

# ────────────────────────── Gradio UI ──────────────────────────────
css = "body{background:#0A0A0A;color:#E0E0E0;font-family:'Orbitron',sans-serif}"

with gr.Blocks(css=css) as demo:
    gr.HTML("<h1 style='text-align:center'>πŸ‘» GhostAI Music Generator</h1>")
    prompt = gr.Textbox(lines=4, label="Instrumental Prompt")
    with gr.Row():
        gr.Button("RHCP 🌢️").click(set_red_hot_chili_peppers_prompt,
            inputs=[gr.State(120),"none","none","none","none","none"],
            outputs=prompt)
        gr.Button("Nirvana 🎸").click(set_nirvana_grunge_prompt,
            inputs=[gr.State(120),"none","none","none","none","none"],
            outputs=prompt)
        # πŸ“Œ add remaining genre buttons here …

    cfg   = gr.Slider(1,10,3,label="CFG Scale")
    top_k = gr.Slider(10,500,250,step=10,label="Top-K")
    top_p = gr.Slider(0,1,0.9,step=0.05,label="Top-P")
    temp  = gr.Slider(0.1,2,1,step=0.1,label="Temperature")
    length= gr.Radio([30,60,90,120], value=30, label="Length (s)")
    chunk = gr.Slider(5,15,10,step=1,label="Chunk (s)")
    xfade = gr.Slider(100,2000,1000,step=100,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","Drum")
    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_out = gr.Audio(type="filepath")
    status    = gr.Textbox(interactive=False)

    gen.click(generate_music,
              inputs=[prompt,cfg,top_k,top_p,temp,length,chunk,xfade,
                      bpm,drum,synth,steps,bass,gtr],
              outputs=[audio_out,status])
    clr.click(clear_inputs,None,
              [prompt,cfg,top_k,top_p,temp,length,chunk,xfade,
               bpm,drum,synth,steps,bass,gtr])

demo.launch(share=False)