NeonoV1 commited on
Commit
03005a1
·
verified ·
1 Parent(s): 723f3e0

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +121 -23
app.py CHANGED
@@ -1,30 +1,128 @@
1
- # svorm8_real_remix.py
2
- # pip install demucs transformers torch scipy pydub
3
- # + нужен ffmpeg в системе
4
 
5
- # ШАГ 1 — отделяем вокал (один раз, в терминале):
6
- # python -m demucs --two-stems=vocals "Painhatedyou - Дайте Дури.wav"
 
 
 
 
 
 
 
 
 
 
 
 
 
7
 
8
- # ШАГ 2 — генерим хаус-грув моделью MusicGen
9
- from transformers import pipeline
10
- import scipy.io.wavfile as wav
 
 
 
 
 
 
 
 
 
 
 
11
 
12
- gen = pipeline("text-to-audio", "facebook/musicgen-medium", device="cuda")
13
- # нет видеокарты? ставь device="cpu" — медленнее, но работает
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
14
 
15
- groove = gen(
16
- "groovy house beat, warm analog bassline, punchy 4/4 kick, 122 bpm",
17
- forward_params={"max_new_tokens": 1500},
18
- )
19
- wav.write("house_groove.wav", groove["sampling_rate"], groove["audio"][0])
 
 
 
 
 
20
 
21
- # ШАГ 3 — миксуем: вокал из оригинала + новый грув
22
- from pydub import AudioSegment
 
 
23
 
24
- voc = AudioSegment.from_wav("separated/htdemucs/Painhatedyou - Дайте Дури/vocals.wav")
25
- beat = AudioSegment.from_wav("house_groove.wav") - 4 # грув чуть тише
26
- beat = beat * (len(voc) // len(beat) + 1) # зацикливаем на длину трека
 
 
 
 
 
 
27
 
28
- mix = voc.overlay(beat[:len(voc)])
29
- mix.export("Painhatedyou - Дайте Дури_REAL_REMIX.wav", format="wav")
30
- print(" настоящий REMIX готов")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ import numpy as np, soundfile as sf, torch, math, time
 
3
 
4
+ GENRES = {
5
+ "Хаус":"groovy house beat, warm analog bassline, punchy 4/4 kick, 122 bpm",
6
+ "Техно":"driving hypnotic techno, dark warehouse, rolling kick, acid blips",
7
+ "Драм-н-бэйс":"fast breakbeat, rolling amen drums, deep reese bass, 174 bpm",
8
+ "Фонк":"aggressive phonk, cowbell melody, chopped soul samples, heavy 808",
9
+ "Лоу-фай":"lofi hip hop, dusty vinyl crackle, mellow keys, tape warmth",
10
+ "Синтвейв":"retro synthwave, neon 80s, lush pads, gated reverb drums",
11
+ "Трэп":"dark trap, booming 808 slides, crisp hi-hat rolls, half-time",
12
+ "Эмбиент":"ambient drone, vast space, slowly evolving textures",
13
+ "Гиперпоп":"hyperpop, pitched vocals, distorted supersaws, chaotic energy",
14
+ "Транс":"euphoric trance, rolling bassline, uplifting supersaw leads, 138 bpm",
15
+ "Чиллвейв":"chillwave, hazy tape chorus, dreamy detuned synths",
16
+ "Вэйпорвейв":"vaporwave, slowed funk sample, lush reverb, nostalgic",
17
+ "Хардбасс":"hardbass, donk bass, energetic kicks, cheeky rave energy",
18
+ }
19
 
20
+ _demucs_model=None; _musicgen=None
21
+ def get_demucs():
22
+ global _demucs_model
23
+ if _demucs_model is None:
24
+ from demucs.pretrained import get_model
25
+ _demucs_model=get_model("htdemucs"); _demucs_model.eval()
26
+ return _demucs_model
27
+ def get_musicgen():
28
+ global _musicgen
29
+ if _musicgen is None:
30
+ from transformers import pipeline
31
+ _musicgen=pipeline("text-to-audio","facebook/musicgen-small",
32
+ device=0 if torch.cuda.is_available() else "cpu")
33
+ return _musicgen
34
 
35
+ def analyze(path):
36
+ data,sr=sf.read(path,dtype="float32",always_2d=True)
37
+ mono=data.mean(axis=1); dur=len(mono)/sr
38
+ rms=float(np.sqrt(np.mean(mono[::max(1,len(mono)//4000)]**2)))
39
+ energy=min(99,int(rms*420)); hop,n=1024,len(mono)//1024
40
+ e=np.array([np.sum(mono[i*hop:(i+1)*hop:4]**2) for i in range(n)])
41
+ peaks=[i for i in range(2,n-2) if e[i]>e[i-1] and e[i]>=e[i+1] and e[i]>1.3*np.mean(e[max(0,i-22):i+22])]
42
+ bpm=None
43
+ if len(peaks)>=8:
44
+ cnt={}
45
+ for a,b in zip(peaks,peaks[1:]):
46
+ dt=(b-a)*hop/sr
47
+ if .25<dt<2:
48
+ v=60/dt
49
+ while v<80:v*=2
50
+ while v>175:v/=2
51
+ cnt[round(v)]=cnt.get(round(v),0)+1
52
+ if cnt:bpm=max(cnt,key=cnt.get)
53
+ return dur,bpm,energy
54
 
55
+ def separate_vocals(path):
56
+ from demucs.apply import apply_model
57
+ from demucs.audio import AudioFile
58
+ model=get_demucs()
59
+ wav=AudioFile(path).read(streams=0,samplerate=model.samplerate,channels=model.audio_channels)
60
+ ref=wav.mean(0); wav=(wav-ref.mean())/ref.std()
61
+ with torch.no_grad():
62
+ src=apply_model(model,wav[None],device="cpu",split=True,overlap=.25)[0]
63
+ src=src*ref.std()+ref.mean()
64
+ return src[model.sources.index("vocals")].numpy().T, model.samplerate
65
 
66
+ def gen_groove(genre):
67
+ prompt=GENRES.get(genre,f'experimental "{genre}" style, bold unusual sound design')
68
+ out=get_musicgen()(prompt,forward_params={"max_new_tokens":1024})
69
+ return out["audio"][0],out["sampling_rate"]
70
 
71
+ def mix(voc,vsr,groove,gsr,aggr,out):
72
+ from scipy.signal import resample_poly
73
+ if gsr!=vsr:
74
+ g=math.gcd(vsr,gsr); groove=resample_poly(groove,vsr//g,gsr//g)
75
+ if groove.ndim==1:groove=np.stack([groove,groove],1)
76
+ groove=np.tile(groove,(len(voc)//len(groove)+1,1))[:len(voc)]
77
+ mx=voc*0.95+groove*min(1.1,0.35+aggr/200)
78
+ mx/=max(1e-6,np.max(np.abs(mx)))/0.95
79
+ sf.write(out,mx,vsr)
80
 
81
+ def remix(track,genre,custom,prompt,aggr):
82
+ if track is None:
83
+ yield " СИСТЕМА: сначала вставь трек в слот",None; return
84
+ log=[]; push=lambda m:(log.append(m),"\n".join(log))[1]; t0=time.time()
85
+ yield push("СИСТЕМА: трек в слоте ✔ сворм из 8 каналов проснулся"),None
86
+ dur,bpm,energy=analyze(track)
87
+ yield push(f"УШАН-3000: длина {int(dur//60)}:{int(dur%60):02d} · темп ≈ {bpm or '?'} BPM · энергия {energy}%"),None
88
+ g=(custom or "").strip() or genre
89
+ yield push(f"ОРКЕСТРАТОР: жанр «{g}». раздаю задачи моделям…"),None
90
+ if prompt.strip(): yield push(f"ХАЙП-КРИТИК: пожелание «{prompt.strip()[:80]}» — учтено 👌"),None
91
+ yield push("ВОКАЛ-ХИРУРГ: demucs режет трек на вокал/музыку… (2–6 мин на бесплатном CPU, это нормально)"),None
92
+ try: voc,vsr=separate_vocals(track)
93
+ except Exception as ex:
94
+ yield push(f"⚠ не смог прочитать файл: {ex}\nпопробуй загрузить WAV"),None; return
95
+ yield push("ВОКАЛ-ХИРУРГ: вокал отделён чисто ✔"),None
96
+ yield push("РИТМ-АРХИТЕКТОР: musicgen генерит грув… (1–3 мин)"),None
97
+ groove,gsr=gen_groove(g)
98
+ yield push(f"РИТМ-АРХИТЕКТОР: грув готов ✔ {len(groove)/gsr:.0f} сек"),None
99
+ yield push("МИКС-МАСТЕР: свожу вокал+грув, мастерю до красного 🔴"),None
100
+ out="/tmp/svorm8_remix.wav"; mix(voc,vsr,groove,gsr,aggr,out)
101
+ yield push(f"✔ ГОТОВО за {(time.time()-t0)/60:.1f} мин. максимальный REMIX подан ⚡"),out
102
+
103
+ CSS="""
104
+ @import url('https://fonts.googleapis.com/css2?family=Anton&family=JetBrains+Mono&display=swap');
105
+ .gradio-container{background:#101114!important;font-family:'JetBrains Mono',monospace}
106
+ h1,h2,.prose h1{font-family:'Anton',sans-serif;color:#ffb43a!important}
107
+ button.primary{background:#ff5a1f!important;border:3px solid #000!important}
108
+ """
109
+
110
+ with gr.Blocks(css=CSS,title="СВОРМ-8",theme=gr.themes.Base()) as demo:
111
+ gr.HTML("<h1 style='font-size:42px'>СВОРМ-8 · NEURO REMIX</h1>"
112
+ "<p style='color:#8a8f9c'>20 моделей в реестре · в работе: demucs + musicgen · "
113
+ "всё считается прямо здесь, на сервере HF · бесплатно = медленно, но честно</p>")
114
+ with gr.Row():
115
+ with gr.Column():
116
+ track=gr.Audio(type="filepath",label="🎧 СЛОТ ДЛЯ ТРЕКА")
117
+ with gr.Column():
118
+ genre=gr.Radio(list(GENRES),value="Хаус",label="ЖАНР")
119
+ custom=gr.Textbox(label="СВОЙ ЖАНР (перекрывает пэд)")
120
+ prompt=gr.Textbox(label="ПОЖЕЛАНИЯ НЕЙРОНАМ")
121
+ aggr=gr.Slider(40,160,value=100,label="АГРЕССИЯ")
122
+ btn=gr.Button("🔥 ЗАПУСТИТЬ REMIX",variant="primary")
123
+ log=gr.Textbox(label="📟 ЭФИР НЕЙРОСЕТЕЙ",lines=12,interactive=False)
124
+ out=gr.Audio(label="🔊 ГОТОВЫЙ REMIX (тут же можно скачать)",type="filepath")
125
+ btn.click(remix,inputs=[track,genre,custom,prompt,aggr],outputs=[log,out])
126
+ gr.HTML("<p style='color:#5b606b'>ни один музыкант не пострадал (почти) · remix максимальный гарантирован*</p>")
127
+
128
+ demo.queue(default_concurrency_limit=1).launch(show_api=False)