import gradio as gr import numpy as np, soundfile as sf, torch, math, time GENRES = { "Хаус":"groovy house beat, warm analog bassline, punchy 4/4 kick, 122 bpm", "Техно":"driving hypnotic techno, dark warehouse, rolling kick, acid blips", "Драм-н-бэйс":"fast breakbeat, rolling amen drums, deep reese bass, 174 bpm", "Фонк":"aggressive phonk, cowbell melody, chopped soul samples, heavy 808", "Лоу-фай":"lofi hip hop, dusty vinyl crackle, mellow keys, tape warmth", "Синтвейв":"retro synthwave, neon 80s, lush pads, gated reverb drums", "Трэп":"dark trap, booming 808 slides, crisp hi-hat rolls, half-time", "Эмбиент":"ambient drone, vast space, slowly evolving textures", "Гиперпоп":"hyperpop, pitched vocals, distorted supersaws, chaotic energy", "Транс":"euphoric trance, rolling bassline, uplifting supersaw leads, 138 bpm", "Чиллвейв":"chillwave, hazy tape chorus, dreamy detuned synths", "Вэйпорвейв":"vaporwave, slowed funk sample, lush reverb, nostalgic", "Хардбасс":"hardbass, donk bass, energetic kicks, cheeky rave energy", } _demucs_model=None; _musicgen=None def get_demucs(): global _demucs_model if _demucs_model is None: from demucs.pretrained import get_model _demucs_model=get_model("htdemucs"); _demucs_model.eval() return _demucs_model def get_musicgen(): global _musicgen if _musicgen is None: from transformers import pipeline _musicgen=pipeline("text-to-audio","facebook/musicgen-small", device=0 if torch.cuda.is_available() else "cpu") return _musicgen def analyze(path): data,sr=sf.read(path,dtype="float32",always_2d=True) mono=data.mean(axis=1); dur=len(mono)/sr rms=float(np.sqrt(np.mean(mono[::max(1,len(mono)//4000)]**2))) energy=min(99,int(rms*420)); hop,n=1024,len(mono)//1024 e=np.array([np.sum(mono[i*hop:(i+1)*hop:4]**2) for i in range(n)]) 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])] bpm=None if len(peaks)>=8: cnt={} for a,b in zip(peaks,peaks[1:]): dt=(b-a)*hop/sr if .25175:v/=2 cnt[round(v)]=cnt.get(round(v),0)+1 if cnt:bpm=max(cnt,key=cnt.get) return dur,bpm,energy def separate_vocals(path): from demucs.apply import apply_model from demucs.audio import AudioFile model=get_demucs() wav=AudioFile(path).read(streams=0,samplerate=model.samplerate,channels=model.audio_channels) ref=wav.mean(0); wav=(wav-ref.mean())/ref.std() with torch.no_grad(): src=apply_model(model,wav[None],device="cpu",split=True,overlap=.25)[0] src=src*ref.std()+ref.mean() return src[model.sources.index("vocals")].numpy().T, model.samplerate def gen_groove(genre): prompt=GENRES.get(genre,f'experimental "{genre}" style, bold unusual sound design') out=get_musicgen()(prompt,forward_params={"max_new_tokens":1024}) return out["audio"][0],out["sampling_rate"] def mix(voc,vsr,groove,gsr,aggr,out): from scipy.signal import resample_poly if gsr!=vsr: g=math.gcd(vsr,gsr); groove=resample_poly(groove,vsr//g,gsr//g) if groove.ndim==1:groove=np.stack([groove,groove],1) groove=np.tile(groove,(len(voc)//len(groove)+1,1))[:len(voc)] mx=voc*0.95+groove*min(1.1,0.35+aggr/200) mx/=max(1e-6,np.max(np.abs(mx)))/0.95 sf.write(out,mx,vsr) def remix(track,genre,custom,prompt,aggr): if track is None: yield "⚠ СИСТЕМА: сначала вставь трек в слот",None; return log=[]; push=lambda m:(log.append(m),"\n".join(log))[1]; t0=time.time() yield push("СИСТЕМА: трек в слоте ✔ сворм из 8 каналов проснулся"),None dur,bpm,energy=analyze(track) yield push(f"УШАН-3000: длина {int(dur//60)}:{int(dur%60):02d} · темп ≈ {bpm or '?'} BPM · энергия {energy}%"),None g=(custom or "").strip() or genre yield push(f"ОРКЕСТРАТОР: жанр «{g}». раздаю задачи моделям…"),None if prompt.strip(): yield push(f"ХАЙП-КРИТИК: пожелание «{prompt.strip()[:80]}» — учтено 👌"),None yield push("ВОКАЛ-ХИРУРГ: demucs режет трек на вокал/музыку… (2–6 мин на бесплатном CPU, это нормально)"),None try: voc,vsr=separate_vocals(track) except Exception as ex: yield push(f"⚠ не смог прочитать файл: {ex}\nпопробуй загрузить WAV"),None; return yield push("ВОКАЛ-ХИРУРГ: вокал отделён чисто ✔"),None yield push("РИТМ-АРХИТЕКТОР: musicgen генерит грув… (1–3 мин)"),None groove,gsr=gen_groove(g) yield push(f"РИТМ-АРХИТЕКТОР: грув готов ✔ {len(groove)/gsr:.0f} сек"),None yield push("МИКС-МАСТЕР: свожу вокал+грув, мастерю до красного 🔴"),None out="/tmp/svorm8_remix.wav"; mix(voc,vsr,groove,gsr,aggr,out) yield push(f"✔ ГОТОВО за {(time.time()-t0)/60:.1f} мин. максимальный REMIX подан ⚡"),out CSS=""" @import url('https://fonts.googleapis.com/css2?family=Anton&family=JetBrains+Mono&display=swap'); .gradio-container{background:#101114!important;font-family:'JetBrains Mono',monospace} h1,h2,.prose h1{font-family:'Anton',sans-serif;color:#ffb43a!important} button.primary{background:#ff5a1f!important;border:3px solid #000!important} """ with gr.Blocks() as demo: gr.HTML("

СВОРМ-8 · NEURO REMIX

" "

20 моделей в реестре · в работе: demucs + musicgen · " "всё считается прямо здесь, на сервере HF · бесплатно = медленно, но честно

") with gr.Row(): with gr.Column(): track=gr.Audio(type="filepath",label="🎧 СЛОТ ДЛЯ ТРЕКА") with gr.Column(): genre=gr.Radio(list(GENRES),value="Хаус",label="ЖАНР") custom=gr.Textbox(label="СВОЙ ЖАНР (перекрывает пэд)") prompt=gr.Textbox(label="ПОЖЕЛАНИЯ НЕЙРОНАМ") aggr=gr.Slider(40,160,value=100,label="АГРЕССИЯ") btn=gr.Button("🔥 ЗАПУСТИТЬ REMIX",variant="primary") log=gr.Textbox(label="📟 ЭФИР НЕЙРОСЕТЕЙ",lines=12,interactive=False) out=gr.Audio(label="🔊 ГОТОВЫЙ REMIX (тут же можно скачать)",type="filepath") btn.click(remix,inputs=[track,genre,custom,prompt,aggr],outputs=[log,out]) gr.HTML("

ни один музыкант не пострадал (почти) · remix максимальный гарантирован*

") demo.queue(max_size=5).launch(css=CSS,theme=gr.themes.Base())