Curlyblaze commited on
Commit
34bb3fa
·
verified ·
1 Parent(s): 9eb6ad1

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +145 -92
app.py CHANGED
@@ -4,123 +4,176 @@ from audiocraft.data.audio import audio_write
4
  import torch
5
  import numpy as np
6
  import uuid
 
7
 
8
  # Load Model
9
  model = MusicGen.get_pretrained('facebook/musicgen-melody')
10
 
11
- # --- STYLE ENGINE (Upgraded for Bass House/Jayms Style) ---
12
- STYLE_MAP = {
13
- "Bass House (Jayms Style)": "Aggressive Bass House, metallic FM wobble bass, shuffling tech-house drums, growl fills, 126 BPM, heavy sidechain, high-energy club mix.",
14
- "Future House (Mainstage)": "Future House, bouncy metallic donk bass, bright lead synths, 4x4 shuffling beat, 126 BPM, Oliver Heldens style, clean production.",
15
- "Tech House (Deep)": "Minimal Tech House, rolling sub-bass, dry percussion, crisp hi-hats, 125 BPM, hypnotizing groove, dark atmosphere.",
16
- "Dubstep (Heavy)": "Heavy Dubstep drop, robotic growl bass, half-time riddim drums, sub-bass impact, 140 BPM, distorted textures.",
17
- "Hip Hop (90s Boom Bap)": "Golden era Hip Hop, dusty vinyl drums, jazz piano chop, upright bass, 90 BPM, swing groove, lo-fi.",
18
- "Trap (Dark)": "Hard dark trap, rapid hi-hat triplets, distorted 808 glides, ominous bell melody, 140 BPM, aggressive.",
19
- "RnB (Silk)": "Smooth contemporary RnB, velvet synth pads, deep sub-bass, snapped snare, 95 BPM, soulful atmosphere.",
20
- "Custom (Write Your Own)": ""
21
  }
22
 
23
- def generate_song(audio_input, style_choice, custom_text, total_duration, bpm, temp, cfg_scale, top_k, current_history):
24
- if audio_input is None:
25
- return None, current_history
26
-
27
- # 1. Prompt Engineering
28
- base_prompt = STYLE_MAP[style_choice] if style_choice != "Custom (Write Your Own)" else custom_text
29
- # We force "High Fidelity" and "Quantized" to ensure professional quality
30
- final_prompt = f"{base_prompt} strictly {bpm} BPM, professional mastering, high fidelity, quantized, clean mix."
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
31
 
32
- # 2. Audio Processing (Normalization)
33
  sr, data = audio_input
34
  audio_data = data.astype(np.float32)
35
- max_val = np.max(np.abs(audio_data))
36
- if max_val > 0:
37
- audio_data = audio_data / max_val
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
38
 
39
- # Convert to Mono for the model
40
- audio_tensor = torch.from_numpy(audio_data).t().unsqueeze(0)
41
- if audio_tensor.shape[1] > 1:
42
- audio_tensor = audio_tensor.mean(dim=1, keepdim=True)
43
-
44
- # 3. SETTINGS TUNING
45
- # For Bass House, we need high CFG (strictness) to get that specific sound
46
- model.set_generation_params(
47
- duration=min(total_duration, 30),
48
- temperature=temp,
49
- cfg_coef=cfg_scale,
50
- top_k=int(top_k)
51
- )
52
-
53
- # 4. GENERATION LOOP
54
- # Phase 1: The Foundation
55
- combined_wav = model.generate_with_chroma(
56
- descriptions=[final_prompt],
57
- melody_wavs=audio_tensor,
58
- melody_sample_rate=sr
59
- )
60
 
61
- # Phase 2: The Extension (Recursive Stitching)
62
- overlap = 5
63
- current_len = combined_wav.shape[-1] / model.sample_rate
64
-
65
- while current_len < total_duration:
66
- prompt_segment = combined_wav[..., -int(overlap * model.sample_rate):]
67
- remaining = total_duration - current_len
68
- chunk_len = min(30, remaining + overlap)
 
 
69
 
70
- # Ensure parameters stick during the loop
71
- model.set_generation_params(duration=chunk_len, temperature=temp, cfg_coef=cfg_scale, top_k=int(top_k))
 
 
 
 
 
 
 
 
 
 
 
 
 
72
 
 
 
 
 
 
 
 
 
73
  next_chunk = model.generate_continuation(
74
- prompt_segment,
75
- model.sample_rate,
76
- descriptions=[final_prompt]
 
77
  )
78
 
79
- combined_wav = torch.cat([combined_wav, next_chunk[..., int(overlap * model.sample_rate):]], dim=-1)
80
- current_len = combined_wav.shape[-1] / model.sample_rate
 
 
 
 
 
 
 
 
 
 
 
 
81
 
82
  # 5. EXPORT
83
  uid = str(uuid.uuid4())[:8]
84
- filename = f"track_{style_choice.split(' ')[0]}_{uid}"
85
- audio_write(filename, combined_wav[0].cpu(), model.sample_rate, strategy="loudness")
86
 
87
- path = f"{filename}.wav"
88
- return path, [path] + current_history
 
 
 
 
 
89
 
90
- # --- UI DESIGN ---
91
- with gr.Blocks(theme=gr.themes.Soft(primary_hue="cyan", secondary_hue="slate")) as demo:
92
- history_state = gr.State([])
93
-
94
- gr.Markdown("# 🎛️ Infinite Song Architect (Bass House Edition)")
95
- gr.Markdown("Upload a loop to generate a track in the style of Jayms, Oliver Heldens, or Tchami.")
96
-
97
  with gr.Row():
98
- with gr.Column(scale=2):
99
- audio_in = gr.Audio(label="🎧 Input Audio (Rough Idea / Melody)", type="numpy")
100
 
101
  with gr.Row():
102
- style_drop = gr.Dropdown(choices=list(STYLE_MAP.keys()), value="Bass House (Jayms Style)", label="🎵 Target Style")
103
- custom_text = gr.Textbox(label="✍️ Custom Prompt", placeholder="e.g. 'Aggressive wobble bass...'", visible=True)
104
 
105
- with gr.Accordion("🎚️ Mixing Console (Tweak the AI)", open=True):
106
- with gr.Row():
107
- bpm_slider = gr.Slider(120, 140, 126, step=1, label="BPM (126 is Standard)")
108
- len_slider = gr.Slider(15, 120, 30, step=15, label="Duration (Seconds)")
109
- with gr.Row():
110
- cfg_slider = gr.Slider(1.0, 15.0, 8.0, step=0.5, label="Style Strictness (Higher = More Metallic Bass)")
111
- temp_slider = gr.Slider(0.1, 1.5, 0.65, step=0.05, label="Groove/Swing (Lower = More Consistent)")
112
- top_k_slider = gr.Slider(10, 250, 250, step=10, label="Audio Stability")
113
-
114
- btn = gr.Button("🎹 Render Track", variant="primary", size="lg")
115
- out_audio = gr.Audio(label="💿 Final Master")
116
 
117
- with gr.Column(scale=1):
118
- history_list = gr.Files(label="📂 Session Library")
119
-
120
- btn.click(
121
- fn=generate_song,
122
- inputs=[audio_in, style_drop, custom_text, len_slider, bpm_slider, temp_slider, cfg_slider, top_k_slider, history_state],
123
- outputs=[out_audio, history_list]
124
- )
 
 
 
 
 
 
125
 
126
  demo.launch()
 
4
  import torch
5
  import numpy as np
6
  import uuid
7
+ import torchaudio
8
 
9
  # Load Model
10
  model = MusicGen.get_pretrained('facebook/musicgen-melody')
11
 
12
+ # --- STRUCTURE DEFINITIONS ---
13
+ # These act as "presets" for the song's roadmap
14
+ STRUCTURE_PRESETS = {
15
+ "Radio Hit (Intro-Verse-Chorus-Drop)": ["Intro", "Verse", "Build-Up", "Drop/Chorus", "Outro"],
16
+ "Club Extended (Intro-Build-Drop-Break-Drop)": ["Intro", "Build-Up", "Drop", "Breakdown", "Drop 2", "Outro"],
17
+ "Hip Hop Classic (Intro-Verse-Hook-Verse-Hook)": ["Intro", "Verse 1", "Hook", "Verse 2", "Hook", "Outro"],
18
+ "Custom (Single Prompt)": ["Full Track"]
 
 
 
19
  }
20
 
21
+ # --- STYLE PROMPTS FOR SECTIONS ---
22
+ # How each section should sound based on the genre
23
+ SECTION_PROMPTS = {
24
+ "Bass House (Jayms Style)": {
25
+ "Intro": "Atmospheric intro, filtered bass, simple hi-hats, tension building.",
26
+ "Verse": "Minimal groove, shuffling hi-hats, deep sub-bass, metallic plucks, clean vocal chops.",
27
+ "Build-Up": "Rising snare roll, pitch riser, white noise sweep, accelerating energy, hype vocals.",
28
+ "Drop": "Explosive Bass House drop, metallic FM wobble bass, heavy kick, sidechain, festival energy.",
29
+ "Breakdown": "Atmospheric pads, filtered chords, no drums, emotional melody.",
30
+ "Outro": "Drum loop fading out, DJ friendly intro/outro, simple bass."
31
+ },
32
+ "Future House (Mainstage)": {
33
+ "Intro": "Bright piano chords, filtered kick, uplifting atmosphere.",
34
+ "Verse": "Plucky melody, snapping fingers, deep house bass, clean production.",
35
+ "Build-Up": "uplifting risers, snare build, hands in the air energy.",
36
+ "Drop": "Bouncy Future House drop, metallic donk bass, shuffling beat, catchy lead.",
37
+ "Outro": "Stripped back drums, fading melody."
38
+ },
39
+ "Dubstep (Heavy)": {
40
+ "Intro": "Dark cinematic drone, ominous atmosphere, slow percussion.",
41
+ "Build-Up": "Intense drum roll, siren rising, pre-drop vocal scream.",
42
+ "Drop": "Heavy dubstep drop, mechanical growl bass, half-time drums, sub-bass impact.",
43
+ "Breakdown": "Orchestral strings, emotional piano, dark ambience.",
44
+ "Outro": "Dark fading textures, slow drum hit."
45
+ }
46
+ }
47
+
48
+ def generate_structured_song(audio_input, genre_style, structure_preset, total_duration, bpm, temp, cfg_scale, top_k, history):
49
+ if audio_input is None: return None, history
50
 
51
+ # 1. SETUP AUDIO INPUT (The DNA)
52
  sr, data = audio_input
53
  audio_data = data.astype(np.float32)
54
+ if np.max(np.abs(audio_data)) > 0: audio_data /= np.max(np.abs(audio_data))
55
+
56
+ # Convert to Tensor
57
+ audio_tensor = torch.from_numpy(audio_data).t()
58
+ if audio_tensor.shape[0] > 1: audio_tensor = audio_tensor.mean(dim=0, keepdim=True)
59
+ else: audio_tensor = audio_tensor.unsqueeze(0)
60
+
61
+ if sr != 32000:
62
+ resampler = torchaudio.transforms.Resample(sr, 32000)
63
+ audio_tensor = resampler(audio_tensor)
64
+
65
+ # 2. DETERMINE SECTIONS
66
+ sections = STRUCTURE_PRESETS[structure_preset]
67
+ if structure_preset == "Custom (Single Prompt)":
68
+ # Fallback to simple generation
69
+ pass
70
+
71
+ # Calculate time per section
72
+ # e.g., 60s total / 4 sections = 15s per section
73
+ sec_duration = total_duration / len(sections)
74
+
75
+ full_song = audio_tensor # Start with the user's input as context (optional, or start fresh)
76
+ # Actually, let's treat the user input as the "Intro" DNA and generate from there.
77
+
78
+ current_context = audio_tensor.unsqueeze(0) # [1, 1, T]
79
 
80
+ print(f"Generating {len(sections)} sections...")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
81
 
82
+ generated_parts = []
83
+
84
+ # 3. GENERATION LOOP (The Architect)
85
+ for i, section_name in enumerate(sections):
86
+ # Get the specific prompt for this section (e.g., "Verse" description)
87
+ if genre_style in SECTION_PROMPTS and section_name in SECTION_PROMPTS[genre_style]:
88
+ specific_desc = SECTION_PROMPTS[genre_style][section_name]
89
+ else:
90
+ # Fallback if specific section text missing
91
+ specific_desc = f"{genre_style} style, {section_name} section, dynamic change."
92
 
93
+ final_prompt = f"{specific_desc} strictly {bpm} BPM, high fidelity."
94
+ print(f"Rendering {section_name}: {final_prompt}")
95
+
96
+ # Set params for this chunk
97
+ # Note: We generate a bit more than needed to allow for crossfading overlap
98
+ model.set_generation_params(
99
+ duration=sec_duration + 2, # +2s for overlap/continuity
100
+ temperature=temp,
101
+ cfg_coef=cfg_scale,
102
+ top_k=int(top_k)
103
+ )
104
+
105
+ # Generate Continuation from previous part
106
+ # We use the LAST 10 seconds of the previous audio as the "seed" for the new part
107
+ # to ensure flow, but we change the text prompt to change the energy.
108
 
109
+ # Grab last 10s of context
110
+ context_len = current_context.shape[-1]
111
+ trim_len = int(10 * 32000)
112
+ if context_len > trim_len:
113
+ input_seed = current_context[..., -trim_len:]
114
+ else:
115
+ input_seed = current_context
116
+
117
  next_chunk = model.generate_continuation(
118
+ prompt=input_seed,
119
+ prompt_sample_rate=32000,
120
+ descriptions=[final_prompt],
121
+ progress=True
122
  )
123
 
124
+ # Add to list
125
+ # Remove the input_seed part from the output to avoid duplication?
126
+ # generate_continuation returns the FULL audio (seed + new).
127
+ # We only want the NEW part.
128
+ new_audio = next_chunk[..., input_seed.shape[-1]:]
129
+
130
+ generated_parts.append(new_audio)
131
+
132
+ # Update context for next loop
133
+ current_context = next_chunk
134
+
135
+ # 4. STITCHING
136
+ # Concatenate all parts
137
+ final_mix = torch.cat(generated_parts, dim=-1)
138
 
139
  # 5. EXPORT
140
  uid = str(uuid.uuid4())[:8]
141
+ filename = f"structured_song_{uid}"
142
+ audio_write(filename, final_mix[0].cpu(), model.sample_rate, strategy="loudness")
143
 
144
+ return f"{filename}.wav", [f"{filename}.wav"] + history
145
+
146
+ # --- UI ---
147
+ with gr.Blocks(theme=gr.themes.Soft(primary_hue="purple", secondary_hue="zinc")) as demo:
148
+ history = gr.State([])
149
+ gr.Markdown("# 🏗️ Infinite Song Architect: Structure Mode")
150
+ gr.Markdown("Define a Verse-Chorus structure, and the AI will build each section dynamically.")
151
 
 
 
 
 
 
 
 
152
  with gr.Row():
153
+ with gr.Column():
154
+ audio_in = gr.Audio(label="🎧 Input DNA (Chords/Bass)", type="numpy")
155
 
156
  with gr.Row():
157
+ genre_drop = gr.Dropdown(list(SECTION_PROMPTS.keys()), value="Bass House (Jayms Style)", label="Sound Palette")
158
+ struct_drop = gr.Dropdown(list(STRUCTURE_PRESETS.keys()), value="Radio Hit (Intro-Verse-Chorus-Drop)", label="Song Structure")
159
 
160
+ with gr.Row():
161
+ bpm_slider = gr.Slider(60, 180, 126, label="BPM")
162
+ len_slider = gr.Slider(30, 120, 60, step=10, label="Total Length")
 
 
 
 
 
 
 
 
163
 
164
+ with gr.Accordion("Fine Tune", open=False):
165
+ cfg_slider = gr.Slider(1, 15, 8, label="Strictness")
166
+ temp_slider = gr.Slider(0.1, 1.5, 0.6, label="Creativity")
167
+ top_k_slider = gr.Slider(10, 250, 50, label="Stability")
168
+
169
+ btn = gr.Button("🏗️ BUILD FULL SONG", variant="primary")
170
+ out_audio = gr.Audio(label="Full Track Output")
171
+
172
+ with gr.Column():
173
+ history_list = gr.Files(label="History")
174
+
175
+ btn.click(generate_structured_song,
176
+ [audio_in, genre_drop, struct_drop, len_slider, bpm_slider, temp_slider, cfg_slider, top_k_slider, history],
177
+ [out_audio, history_list])
178
 
179
  demo.launch()