import os import gradio as gr import shutil from faster_whisper import WhisperModel import demucs.separate from matchering import process as match_process from mutagen.mp3 import MP3 from mutagen.id3 import ID3, TIT2, TPE1, TALB, APIC os.makedirs("uploads", exist_ok=True) os.makedirs("outputs", exist_ok=True) # 1. Stem Splitter Engine (Demucs CPU) def split_stems(audio_file): if audio_file is None: return [None]*4 demucs.separate.main(["-n", "htdemucs", "-o", "outputs/stems", audio_file]) track_name = os.path.splitext(os.path.basename(audio_file))[0] stem_dir = f"outputs/stems/htdemucs/{track_name}" stems = [] for stem in ["vocals.wav", "drums.wav", "bass.wav", "other.wav"]: path = os.path.join(stem_dir, stem) stems.append(path if os.path.exists(path) else None) return stems # 2. Synced Lyrics Engine (Whisper CPU) def generate_lrc(audio_file): if audio_file is None: return "Please upload an audio file." model = WhisperModel("tiny", device="cpu", compute_type="float32") segments, _ = model.transcribe(audio_file, beam_size=1) lrc_lines = [] for segment in segments: start_min = int(segment.start // 60) start_sec = segment.start % 60 time_str = f"[{start_min:02d}:{start_sec:05.2f}]" lrc_lines.append(f"{time_str} {segment.text.strip()}") return "\n".join(lrc_lines) # 3. Reference Mastering Engine (Matchering) def master_audio(target, reference): if not target or not reference: return None out_master = "outputs/mastered_track.wav" if os.path.exists(out_master): os.remove(out_master) match_process(target=target, reference=reference, results=[out_master]) return out_master # 4. Metadata Tagging Engine (Mutagen) def tag_audio(audio, title, artist, album, cover): if not audio: return None out_tagged = "outputs/tagged_track.mp3" shutil.copy(audio, out_tagged) audio_obj = MP3(out_tagged, ID3=ID3) try: audio_obj.add_tags() except Exception: pass audio_obj.tags.add(TIT2(encoding=3, text=title)) audio_obj.tags.add(TPE1(encoding=3, text=artist)) audio_obj.tags.add(TALB(encoding=3, text=album)) if cover: with open(cover, "rb") as f: art_data = f.read() audio_obj.tags.add(APIC(encoding=3, mime='image/jpeg', type=3, desc=u'Cover', data=art_data)) audio_obj.save() return out_tagged # UI Setup with gr.Blocks(theme=gr.themes.Soft()) as demo: gr.Markdown("# Free Cloud Audio AI Suite\nRun stem splitting, lyric syncing, mastering, and tagging 24/7 without billing limits.") with gr.Tab("Stem Splitter"): audio_input = gr.Audio(type="filepath", label="Upload Song") split_btn = gr.Button("Split Stems") vocals_out = gr.Audio(label="Vocals") drums_out = gr.Audio(label="Drums") bass_out = gr.Audio(label="Bass") other_out = gr.Audio(label="Instrumental/Other") split_btn.click(split_stems, inputs=audio_input, outputs=[vocals_out, drums_out, bass_out, other_out]) with gr.Tab("Synced Lyrics"): lyric_input = gr.Audio(type="filepath", label="Upload Vocal Track") lyric_btn = gr.Button("Generate Timed Lyrics") lrc_output = gr.Textbox(label="LRC File", show_copy_button=True) lyric_btn.click(generate_lrc, inputs=lyric_input, outputs=lrc_output) with gr.Tab("AI Mastering"): target_input = gr.Audio(type="filepath", label="Upload Your Mix (WAV)") ref_input = gr.Audio(type="filepath", label="Upload Reference Track (WAV)") master_btn = gr.Button("Apply Mastering") master_output = gr.Audio(label="Mastered Output") master_btn.click(master_audio, inputs=[target_input, ref_input], outputs=master_output) with gr.Tab("Metadata Tagging"): tag_audio_in = gr.Audio(type="filepath", label="Upload MP3") in_title = gr.Textbox(label="Song Title") in_artist = gr.Textbox(label="Artist Name") in_album = gr.Textbox(label="Album Name") in_cover = gr.Image(type="filepath", label="Cover Art (JPEG)") tag_btn = gr.Button("Tag Track") tag_output = gr.File(label="Ready for Distribution") tag_btn.click(tag_audio, inputs=[tag_audio_in, in_title, in_artist, in_album, in_cover], outputs=tag_output) demo.queue().launch()