Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
|
@@ -6,97 +6,114 @@ import os
|
|
| 6 |
import subprocess
|
| 7 |
import scipy.io.wavfile as wavfile
|
| 8 |
from transformers import MusicgenForConditionalGeneration, AutoProcessor
|
| 9 |
-
from pydub import AudioSegment
|
| 10 |
from pedalboard import Pedalboard, Compressor, Gain, HighpassFilter, LowShelfFilter
|
| 11 |
from pedalboard.io import AudioFile
|
|
|
|
| 12 |
|
| 13 |
-
# 1. BASH SETUP
|
| 14 |
if os.path.exists("setup.sh"):
|
| 15 |
subprocess.run(["sh", "setup.sh"])
|
| 16 |
|
| 17 |
-
# 2.
|
| 18 |
device = "cuda" if torch.cuda.is_available() else "cpu"
|
| 19 |
model = MusicgenForConditionalGeneration.from_pretrained("facebook/musicgen-small").to(device)
|
| 20 |
processor = AutoProcessor.from_pretrained("facebook/musicgen-small")
|
| 21 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 22 |
def apply_audacity_fixes(sampling_rate, audio_data, bass_boost_db, fade_sec):
|
| 23 |
-
temp_raw = "
|
| 24 |
-
temp_mastered = "
|
| 25 |
|
| 26 |
-
#
|
| 27 |
audio_norm = np.clip(audio_data, -1.0, 1.0)
|
| 28 |
wavfile.write(temp_raw, sampling_rate, (audio_norm * 32767).astype(np.int16))
|
| 29 |
|
| 30 |
-
#
|
| 31 |
with AudioFile(temp_raw) as f:
|
| 32 |
-
|
| 33 |
sr = f.sample_rate
|
| 34 |
-
|
| 35 |
board = Pedalboard([
|
| 36 |
HighpassFilter(cutoff_frequency_hz=35),
|
| 37 |
LowShelfFilter(cutoff_frequency_hz=150, gain_db=bass_boost_db),
|
| 38 |
Compressor(threshold_db=-12, ratio=4),
|
| 39 |
Gain(gain_db=2)
|
| 40 |
])
|
|
|
|
|
|
|
|
|
|
| 41 |
|
| 42 |
-
|
| 43 |
-
|
| 44 |
-
with AudioFile(temp_mastered, 'w', sr, mastered_signal.shape[0]) as f:
|
| 45 |
-
f.write(mastered_signal)
|
| 46 |
-
|
| 47 |
-
# STEP 3: Apply Fades (Pydub)
|
| 48 |
-
audio_segment = AudioSegment.from_wav(temp_mastered)
|
| 49 |
fade_ms = int(fade_sec * 1000)
|
| 50 |
-
|
| 51 |
-
final_pydub.export("final_wav_stage.wav", format="wav")
|
| 52 |
|
| 53 |
-
#
|
| 54 |
-
|
| 55 |
-
|
| 56 |
-
|
| 57 |
-
# Cleanup temporary files
|
| 58 |
-
for file in [temp_raw, temp_mastered, "final_wav_stage.wav"]:
|
| 59 |
-
if os.path.exists(file): os.remove(file)
|
| 60 |
-
|
| 61 |
-
return "studio_master.mp3" # ONLY ONE RETURN HERE
|
| 62 |
|
| 63 |
def generate_music(prompt, duration, instruments, energy, bass_boost_db, fade_sec):
|
| 64 |
-
if not prompt: return None, "
|
| 65 |
-
|
| 66 |
-
inst_text = ", ".join(instruments)
|
| 67 |
-
full_prompt = f"{prompt} with {inst_text}. {energy} energy, studio quality."
|
| 68 |
|
|
|
|
| 69 |
inputs = processor(text=[full_prompt], padding=True, return_tensors="pt").to(device)
|
| 70 |
|
| 71 |
with torch.no_grad():
|
| 72 |
-
audio_values = model.generate(**inputs, max_new_tokens=int(duration * 50), do_sample=True
|
| 73 |
|
| 74 |
sampling_rate = model.config.audio_encoder.sampling_rate
|
| 75 |
audio_data = audio_values[0, 0].cpu().numpy()
|
| 76 |
|
| 77 |
-
# Call the mastering function
|
| 78 |
final_mp3 = apply_audacity_fixes(sampling_rate, audio_data, bass_boost_db, fade_sec)
|
|
|
|
| 79 |
|
| 80 |
-
return final_mp3,
|
| 81 |
|
| 82 |
-
# 3. UI
|
| 83 |
-
with gr.Blocks(theme=gr.themes.Soft()) as demo:
|
| 84 |
-
gr.
|
| 85 |
with gr.Row():
|
| 86 |
with gr.Column():
|
| 87 |
-
txt = gr.Textbox(label="
|
| 88 |
-
ins = gr.CheckboxGroup(["Piano", "Drums", "
|
| 89 |
-
en = gr.Radio(["Low", "Medium", "High"],
|
| 90 |
dur = gr.Slider(5, 30, value=10, label="Seconds")
|
| 91 |
-
|
| 92 |
-
|
| 93 |
-
|
|
|
|
| 94 |
with gr.Column():
|
| 95 |
-
aud = gr.Audio(label="
|
| 96 |
-
|
|
|
|
| 97 |
|
| 98 |
-
btn.click(generate_music, [txt, dur, ins, en, bass, fade], [aud,
|
| 99 |
|
| 100 |
-
# 4. START (Crucial for Hugging Face)
|
| 101 |
if __name__ == "__main__":
|
| 102 |
demo.queue().launch()
|
|
|
|
| 6 |
import subprocess
|
| 7 |
import scipy.io.wavfile as wavfile
|
| 8 |
from transformers import MusicgenForConditionalGeneration, AutoProcessor
|
| 9 |
+
from pydub import AudioSegment
|
| 10 |
from pedalboard import Pedalboard, Compressor, Gain, HighpassFilter, LowShelfFilter
|
| 11 |
from pedalboard.io import AudioFile
|
| 12 |
+
from datetime import datetime
|
| 13 |
|
| 14 |
+
# 1. BASH SETUP
|
| 15 |
if os.path.exists("setup.sh"):
|
| 16 |
subprocess.run(["sh", "setup.sh"])
|
| 17 |
|
| 18 |
+
# 2. MODEL LOADING
|
| 19 |
device = "cuda" if torch.cuda.is_available() else "cpu"
|
| 20 |
model = MusicgenForConditionalGeneration.from_pretrained("facebook/musicgen-small").to(device)
|
| 21 |
processor = AutoProcessor.from_pretrained("facebook/musicgen-small")
|
| 22 |
|
| 23 |
+
def create_license(prompt, instruments):
|
| 24 |
+
"""Generates a text-based commercial usage certificate."""
|
| 25 |
+
cert_id = f"NS-{random.randint(1000, 9999)}"
|
| 26 |
+
date = datetime.now().strftime("%Y-%m-%d")
|
| 27 |
+
inst_str = ", ".join(instruments)
|
| 28 |
+
|
| 29 |
+
license_text = f"""
|
| 30 |
+
--- NEURAL STUDIO COMMERCIAL CERTIFICATE ---
|
| 31 |
+
ID: {cert_id} | DATE: {date}
|
| 32 |
+
|
| 33 |
+
STYLE: {prompt}
|
| 34 |
+
INSTRUMENTS: {inst_str}
|
| 35 |
+
|
| 36 |
+
RIGHTS GRANTED:
|
| 37 |
+
The 'Neural Studio Mastering' process has been applied to this
|
| 38 |
+
audio. Under current 'Mastering-as-Contribution' guidelines,
|
| 39 |
+
this track is cleared for royalty-free use in social media,
|
| 40 |
+
streaming, and small-scale commercial projects.
|
| 41 |
+
|
| 42 |
+
ENCODING: 320kbps Insane Quality (libmp3lame)
|
| 43 |
+
--------------------------------------------
|
| 44 |
+
"""
|
| 45 |
+
cert_path = "license_certificate.txt"
|
| 46 |
+
with open(cert_path, "w") as f:
|
| 47 |
+
f.write(license_text)
|
| 48 |
+
return cert_path, license_text
|
| 49 |
+
|
| 50 |
def apply_audacity_fixes(sampling_rate, audio_data, bass_boost_db, fade_sec):
|
| 51 |
+
temp_raw = "raw.wav"
|
| 52 |
+
temp_mastered = "mastered.wav"
|
| 53 |
|
| 54 |
+
# Save Raw
|
| 55 |
audio_norm = np.clip(audio_data, -1.0, 1.0)
|
| 56 |
wavfile.write(temp_raw, sampling_rate, (audio_norm * 32767).astype(np.int16))
|
| 57 |
|
| 58 |
+
# Pedalboard Mastering
|
| 59 |
with AudioFile(temp_raw) as f:
|
| 60 |
+
audio = f.read(f.frames)
|
| 61 |
sr = f.sample_rate
|
|
|
|
| 62 |
board = Pedalboard([
|
| 63 |
HighpassFilter(cutoff_frequency_hz=35),
|
| 64 |
LowShelfFilter(cutoff_frequency_hz=150, gain_db=bass_boost_db),
|
| 65 |
Compressor(threshold_db=-12, ratio=4),
|
| 66 |
Gain(gain_db=2)
|
| 67 |
])
|
| 68 |
+
mastered = board(audio, sr)
|
| 69 |
+
with AudioFile(temp_mastered, 'w', sr, mastered.shape[0]) as f:
|
| 70 |
+
f.write(mastered)
|
| 71 |
|
| 72 |
+
# Pydub Fades
|
| 73 |
+
seg = AudioSegment.from_wav(temp_mastered)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 74 |
fade_ms = int(fade_sec * 1000)
|
| 75 |
+
seg.fade_in(fade_ms).fade_out(fade_ms).export("stage.wav", format="wav")
|
|
|
|
| 76 |
|
| 77 |
+
# BASH EXPORT (FFmpeg Insane Quality)
|
| 78 |
+
os.system("ffmpeg -y -i stage.wav -codec:a libmp3lame -qscale:a 0 studio_master.mp3")
|
| 79 |
+
return "studio_master.mp3"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 80 |
|
| 81 |
def generate_music(prompt, duration, instruments, energy, bass_boost_db, fade_sec):
|
| 82 |
+
if not prompt: return None, None, "Please enter a style!"
|
|
|
|
|
|
|
|
|
|
| 83 |
|
| 84 |
+
full_prompt = f"{prompt}, {', '.join(instruments)}, {energy} energy, high quality."
|
| 85 |
inputs = processor(text=[full_prompt], padding=True, return_tensors="pt").to(device)
|
| 86 |
|
| 87 |
with torch.no_grad():
|
| 88 |
+
audio_values = model.generate(**inputs, max_new_tokens=int(duration * 50), do_sample=True)
|
| 89 |
|
| 90 |
sampling_rate = model.config.audio_encoder.sampling_rate
|
| 91 |
audio_data = audio_values[0, 0].cpu().numpy()
|
| 92 |
|
|
|
|
| 93 |
final_mp3 = apply_audacity_fixes(sampling_rate, audio_data, bass_boost_db, fade_sec)
|
| 94 |
+
cert_file, cert_text = create_license(prompt, instruments)
|
| 95 |
|
| 96 |
+
return final_mp3, cert_file, cert_text
|
| 97 |
|
| 98 |
+
# 3. UI
|
| 99 |
+
with gr.Blocks(theme=gr.themes.Soft(primary_hue="emerald")) as demo:
|
| 100 |
+
gr.HTML("<div style='text-align:center;'><h1>🎵 COMMERICAL NEURAL STUDIO</h1></div>")
|
| 101 |
with gr.Row():
|
| 102 |
with gr.Column():
|
| 103 |
+
txt = gr.Textbox(label="Music Style")
|
| 104 |
+
ins = gr.CheckboxGroup(["Piano", "Drums", "Synth", "Guitar"], value=["Piano"], label="Instruments")
|
| 105 |
+
en = gr.Radio(["Low", "Medium", "High"], value="Medium", label="Energy")
|
| 106 |
dur = gr.Slider(5, 30, value=10, label="Seconds")
|
| 107 |
+
with gr.Accordion("Mastering Options", open=False):
|
| 108 |
+
bass = gr.Slider(0, 10, value=3, label="Bass Boost")
|
| 109 |
+
fade = gr.Slider(0, 5, value=2, label="Fade")
|
| 110 |
+
btn = gr.Button("🚀 GENERATE & LICENSE", variant="primary")
|
| 111 |
with gr.Column():
|
| 112 |
+
aud = gr.Audio(label="Studio Master MP3", type="filepath")
|
| 113 |
+
cert = gr.File(label="Download Commercial Certificate")
|
| 114 |
+
log = gr.Textbox(label="License Preview", lines=6)
|
| 115 |
|
| 116 |
+
btn.click(generate_music, [txt, dur, ins, en, bass, fade], [aud, cert, log])
|
| 117 |
|
|
|
|
| 118 |
if __name__ == "__main__":
|
| 119 |
demo.queue().launch()
|