ohfiftyb252 commited on
Commit
612ec05
·
verified ·
1 Parent(s): abd4fc8

Create ai_style_transfer.py

Browse files
Files changed (1) hide show
  1. ai_style_transfer.py +244 -0
ai_style_transfer.py ADDED
@@ -0,0 +1,244 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+ """
3
+ AI Style Transfer Module - Uses MusicGen/Riffusion to reimagine MIDI
4
+ """
5
+
6
+ import subprocess
7
+ from pathlib import Path
8
+ from typing import Optional
9
+ import tempfile
10
+
11
+ class AIStyleTransfer:
12
+ def __init__(self, provider="huggingface-api"):
13
+ """
14
+ provider options:
15
+ - "local" : Run MusicGen locally (GPU required)
16
+ - "huggingface-api" : Use HF Inference API (free tier available)
17
+ """
18
+ self.provider = provider
19
+
20
+ def extract_tempo(self, audio_path):
21
+ """Estimate tempo from audio using librosa"""
22
+ try:
23
+ import librosa
24
+ y, sr = librosa.load(str(audio_path), duration=10) # Load first 10s
25
+ tempo, _ = librosa.beat.beat_track(y=y, sr=sr)
26
+ return float(tempo)
27
+ except ImportError:
28
+ return 140.0 # Default trap BPM
29
+
30
+ def create_trap_prompt(self, instruments=None, mood="dark", intensity="aggressive"):
31
+ """Build optimized prompt for MusicGen/Riffusion"""
32
+ base_elements = [
33
+ f"{mood} trap beat",
34
+ "heavy 808 bass",
35
+ "fast hi-hat rolls",
36
+ f"{intensity} energy",
37
+ "140 bpm"
38
+ ]
39
+
40
+ if instruments:
41
+ # Add melodic elements based on original transcription
42
+ base_elements.append("melodic synth lead")
43
+
44
+ prompt = ", ".join(base_elements)
45
+ return prompt
46
+
47
+ def musicgen_local(self, audio_description: str, duration: int = 30):
48
+ """
49
+ Run MusicGen locally via transformers
50
+ Requires GPU with 16GB+ VRAM
51
+ """
52
+ try:
53
+ from transformers import AutoProcessor, AutoModelForTextToWaveform
54
+ import torch
55
+
56
+ processor = AutoProcessor.from_pretrained("facebook/musicgen-large")
57
+ model = AutoModelForTextToWaveform.from_pretrained(
58
+ "facebook/musicgen-large",
59
+ torch_dtype=torch.float16
60
+ ).to("cuda")
61
+
62
+ inputs = processor(
63
+ text=audio_description,
64
+ padding=True,
65
+ return_tensors="pt"
66
+ )
67
+
68
+ with torch.no_grad():
69
+ audio_values = model.generate(
70
+ **inputs.to("cuda"),
71
+ max_new_tokens=256,
72
+ guidance_scale=3,
73
+ do_sample=True,
74
+ temperature=1.0
75
+ )
76
+
77
+ # Convert tensor to WAV file
78
+ sampling_rate = model.config.sampling_rate
79
+ audio_array = audio_values[0, 0].cpu().numpy()
80
+
81
+ from scipy.io.wavfile import write
82
+ temp_wav = Path(tempfile.mktemp(suffix=".wav"))
83
+ write(temp_wav, sampling_rate, (audio_array * 32767).astype(np.int16))
84
+
85
+ return temp_wav
86
+
87
+ except Exception as e:
88
+ print(f"MusicGen local failed: {e}")
89
+ return None
90
+
91
+ def riffusion_hf_api(self, prompt: str, seed_image: str = None):
92
+ """
93
+ Use Riffusion via Hugging Face Inference API
94
+ No GPU needed, works on free tier
95
+ """
96
+ try:
97
+ from huggingface_hub import InferenceClient
98
+
99
+ client = InferenceClient(
100
+ token=os.environ.get("HF_TOKEN", ""),
101
+ model="riffusion/riffusion"
102
+ )
103
+
104
+ # Generate spectrogram-based audio
105
+ output = client.text_to_sound(
106
+ prompt=prompt,
107
+ duration=30 # seconds
108
+ )
109
+
110
+ # Save as WAV
111
+ temp_wav = Path(tempfile.mktemp(suffix=".wav"))
112
+ temp_wav.write_bytes(output)
113
+
114
+ return temp_wav
115
+
116
+ except Exception as e:
117
+ print(f"Riffusion failed: {e}")
118
+ return None
119
+
120
+ def musicgen_hf_api(self, prompt: str, duration: int = 30):
121
+ """
122
+ Use MusicGen via Hugging Face Inference API
123
+ Slower but no local GPU required
124
+ """
125
+ try:
126
+ from huggingface_hub import InferenceClient
127
+ import time
128
+
129
+ client = InferenceClient(token=os.environ.get("HF_TOKEN", ""))
130
+
131
+ # Start generation task
132
+ task = client.text_to_audio(
133
+ inputs=prompt,
134
+ parameters={
135
+ "model": "facebook/musicgen-large",
136
+ "duration": duration
137
+ }
138
+ )
139
+
140
+ # Poll for completion
141
+ max_retries = 60
142
+ for attempt in range(max_retries):
143
+ status = client.check_task_status(task.task_id)
144
+ if status["status"] == "completed":
145
+ return Path(status["output"]["audio_path"])
146
+ elif status["status"] == "failed":
147
+ print(f"Generation failed: {status}")
148
+ break
149
+ time.sleep(2)
150
+
151
+ return None
152
+
153
+ except Exception as e:
154
+ print(f"MusicGen API failed: {e}")
155
+ return None
156
+
157
+ def stem_separation(self, audio_path):
158
+ """
159
+ Separate vocals/instruments using Demucs
160
+ Useful for isolating melody before style transfer
161
+ """
162
+ try:
163
+ from demucs.apply import apply_model
164
+ from demucs.pretrained import get_model
165
+ import torchaudio
166
+
167
+ # Load pre-trained Demucs model
168
+ model = get_model("htdemucs")
169
+
170
+ # Load audio
171
+ wav, sr = torchaudio.load(str(audio_path))
172
+
173
+ # Apply separation
174
+ stems = apply_model(model, wav)
175
+
176
+ # Save separated tracks (vocals, drums, bass, other)
177
+ stem_names = model.stems
178
+ output_dir = Path(tempfile.mkdtemp())
179
+
180
+ for i, name in enumerate(stem_names):
181
+ stem_path = output_dir / f"{name}.wav"
182
+ torchaudio.save(str(stem_path), stems[:, :, i:i+1], sr)
183
+
184
+ return output_dir
185
+
186
+ except Exception as e:
187
+ print(f"Stem separation failed: {e}")
188
+ return None
189
+
190
+ def mix_trap_final(self, original_midi_path, ai_generated_wav, output_path):
191
+ """
192
+ Mix original MIDI with AI-generated Trap backing track
193
+ Creates final composite track
194
+ """
195
+ try:
196
+ from pydub import AudioSegment
197
+ import pretty_midi as pm
198
+
199
+ # Load AI-generated trap beat
200
+ trap_beat = AudioSegment.from_wav(str(ai_generated_wav))
201
+
202
+ # Render MIDI to audio (using FluidSynth or similar)
203
+ midi_audio = self.render_midi_to_audio(original_midi_path)
204
+
205
+ # Align and mix
206
+ mixed = trap_beat.overlay(midi_audio)
207
+
208
+ # Export final
209
+ mixed.export(str(output_path), format="mp3", bitrate="320k")
210
+
211
+ return output_path
212
+
213
+ except Exception as e:
214
+ print(f"Mixing failed: {e}")
215
+ return None
216
+
217
+ def render_midi_to_audio(self, midi_path, soundfont="/tmp/default.sf2"):
218
+ """Render MIDI file to audio using FluidSynth"""
219
+ try:
220
+ import fluidsynth
221
+ import io
222
+
223
+ fs = fluidsynth.Synth()
224
+ fs.start(driver="disk")
225
+
226
+ sfid = fs.sfload(soundfont)
227
+ fs.program_select(0, sfid, 0, 0)
228
+
229
+ midi_data = pm.PrettyMIDI(str(midi_path))
230
+ midi_data.fluidsynth(fs, sfid)
231
+
232
+ # Get rendered audio
233
+ audio = fs.get_samples()
234
+
235
+ # Save to file
236
+ from scipy.io.wavfile import write
237
+ temp_wav = Path(tempfile.mktemp(suffix=".wav"))
238
+ write(temp_wav, 48000, audio.T.astype('int16'))
239
+
240
+ return temp_wav
241
+
242
+ except Exception as e:
243
+ print(f"MIDI rendering failed: {e}")
244
+ return None