“”” ai_music_studio_singlefile.py Single-file demo app (frontend + backend). Run this Python script and go to: http://127.0.0.1:8000 It implements: – Serves a single-page HTML UI (embedded below) – /api/generate -> starts a dummy generation job and returns job_id – /api/status/ -> returns {status, progress} – /api/result/ -> returns generated WAV when ready – /api/vocal-remove -> demo endpoint (returns same file as both vocal/instrumental) – /api/upload-voice -> demo (stores sample and returns a voice_id) How to run: 1) Install Python 3.10+ and pip 2) pip install flask numpy soundfile 3) python ai_music_studio_singlefile.py 4) Open http://127.0.0.1:8000 in your browser IMPORTANT: – This demo produces synthetic sine-wave audio as a placeholder. – To integrate real models (MusicGen/StableAudio), replace the function `do_real_generation(…)` with your PyTorch model inference code. That code will require GPU, PyTorch, audiocraft, etc. “”” import os import io import uuid import time import threading from typing import Dict from flask import Flask, request, send_file, jsonify, render_template_string, abort import numpy as np import soundfile as sf app = Flask(__name__) # allow file sending from same server (CORS not needed for local) # Simple in-memory jobs store for demo JOB_STORE: Dict[str, Dict] = {} OUTPUT_DIR = os.path.join(os.path.dirname(__file__), “outputs_singlefile”) os.makedirs(OUTPUT_DIR, exist_ok=True) # —————————– # HTML page embedded as string # —————————– INDEX_HTML = r””” AI Music Studio — Single-file Demo

AI Music Studio — Single-file Demo

Local demo: text → music (sine wave). Replace server code with MusicGen for real audio.
Credits: 5

Studio

Generation progress
Status: idle
Job:

Preview / Player

Library

Saved generations

Tools

Demo single-file server. Replace server-side generation with MusicGen for full AI audio (server must have GPU).
“”” # —————————– # Utility: create a sine WAV (mono) into a file path # —————————– def synthesize_sine_wav(path: str, duration_seconds: int = 10, frequency: float = 440.0, sr: int = 32000): “””Create a mono WAV file with a sine wave. Uses soundfile (pysoundfile).””” t = np.linspace(0, duration_seconds, int(sr * duration_seconds), endpoint=False) audio = 0.3 * np.sin(2 * np.pi * frequency * t) sf.write(path, audio, sr, subtype=’PCM_16′) # —————————– # Dummy “model” generator (runs in worker thread) # —————————– def worker_generate(job_id: str, prompt: str, length_seconds: int = 30, genre: str = None, mood: str = None, voice_id: str = None): “”” Simulate generation progress and create a WAV file. Replace the contents of this function with real model inference for real audio. “”” JOB_STORE[job_id][“status”] = “running” # Simulate progressive updates for p in range(0, 90, 10): JOB_STORE[job_id][“progress”] = p time.sleep(0.45) # Create a filename fname = f”generation_{job_id}.wav” out_path = os.path.join(OUTPUT_DIR, fname) # Choose a pseudo-frequency influenced by prompt length so files sound slightly different freq = 220 + (len(prompt) % 200) synthesize_sine_wav(out_path, duration_seconds=length_seconds, frequency=freq, sr=32000) JOB_STORE[job_id][“progress”] = 100 JOB_STORE[job_id][“status”] = “complete” JOB_STORE[job_id][“output_path”] = out_path JOB_STORE[job_id][“finished_at”] = time.time() print(f”[worker] job {job_id} done -> {out_path}”) # —————————– # PLACEHOLDER for real generation (example instructions) # —————————– def do_real_generation_placeholder(job_id: str, prompt: str, length_seconds: int = 30, genre: str = None, mood: str = None, voice_id: str = None): “”” THIS FUNCTION IS A COMMENTED GUIDE for how to replace the dummy worker with real inference. DO NOT CALL THIS FUNCTION AS-IS from the demo; instead, copy/replace worker_generate with code like: from audiocraft.models import MusicGen import torch import soundfile as sf model = MusicGen.get_pretrained(‘facebook/musicgen-small’) model.to(‘cuda’) # requires GPU and proper PyTorch+CUDA install JOB_STORE[job_id][‘status’] = ‘running’ # If model provides callbacks for progress, update JOB_STORE periodically wav = model.generate([prompt], duration=length_seconds, progress=True) # pseudo-API out = os.path.join(OUTPUT_DIR, f’generation_{job_id}.wav’) sf.write(out, wav[0].cpu().numpy(), samplerate) # depends on model output type JOB_STORE[job_id][‘status’] = ‘complete’ JOB_STORE[job_id][‘output_path’] = out NOTE: Real integration depends on the model’s exact API/version. MusicGen/Audiocraft APIs change across releases. “”” raise NotImplementedError(“This is a placeholder. See the docstring for integration instructions.”) # —————————– # Flask routes # —————————– @app.route(“/”) def index(): return render_template_string(INDEX_HTML) @app.route(“/api/generate”, methods=[“POST”]) def api_generate(): prompt = request.form.get(“prompt”, “”) genre = request.form.get(“genre”) length = int(request.form.get(“length”, 30)) mood = request.form.get(“mood”) voice_id = request.form.get(“voice_id”) if not prompt: return jsonify({“error”: “prompt required”}), 400 job_id = uuid.uuid4().hex JOB_STORE[job_id] = {“status”: “queued”, “progress”: 0, “prompt”: prompt, “created_at”: time.time()} # Start worker thread (demo). In production use a queue (Redis + worker). t = threading.Thread(target=worker_generate, args=(job_id, prompt, length, genre, mood, voice_id), daemon=True) t.start() return jsonify({“job_id”: job_id}) @app.route(“/api/status/“, methods=[“GET”]) def api_status(job_id): job = JOB_STORE.get(job_id) if not job: return jsonify({“error”: “job not found”}), 404 return jsonify({“status”: job.get(“status”, “queued”), “progress”: int(job.get(“progress”, 0))}) @app.route(“/api/result/“, methods=[“GET”]) def api_result(job_id): job = JOB_STORE.get(job_id) if not job: return jsonify({“error”: “job not found”}), 404 if job.get(“status”) != “complete”: return jsonify({“error”: “not ready”}), 400 path = job.get(“output_path”) if not path or not os.path.exists(path): return jsonify({“error”: “output missing”}), 404 # send file return send_file(path, mimetype=”audio/wav”, as_attachment=True, download_name=os.path.basename(path)) @app.route(“/api/vocal-remove”, methods=[“POST”]) def api_vocal_remove(): “”” Demo vocal removal: store uploaded file and return URLs for ‘instrumental’ and ‘vocals’. Real implementation: run Demucs / Spleeter, store outputs in S3, return public/presigned URLs. “”” f = request.files.get(“file”) if not f: return jsonify({“error”: “file required”}), 400 # store upload uid = uuid.uuid4().hex upl_path = os.path.join(OUTPUT_DIR, f”uploaded_{uid}.wav”) f.save(upl_path) # For demo we return the same file as both outputs; frontend expects URLs. # We’ll serve via /api/raw/ fname = os.path.basename(upl_path) return jsonify({ “instrumental_url”: f”/api/raw/{fname}”, “vocals_url”: f”/api/raw/{fname}” }) @app.route(“/api/upload-voice”, methods=[“POST”]) def api_upload_voice(): f = request.files.get(“file”) if not f: return jsonify({“error”: “file required”}), 400 vid = uuid.uuid4().hex path = os.path.join(OUTPUT_DIR, f”voice_{vid}.wav”) f.save(path) return jsonify({“voice_id”: vid, “file”: f”/api/raw/{os.path.basename(path)}”}) @app.route(“/api/raw/“) def api_raw(filename): path = os.path.join(OUTPUT_DIR, filename) if not os.path.exists(path): return abort(404) # serve file return send_file(path, mimetype=”audio/wav”) # —————————– # Run server # —————————– if __name__ == “__main__”: import argparse parser = argparse.ArgumentParser(description=”Single-file AI Music Studio demo server”) parser.add_argument(“–host”, default=”127.0.0.1″, help=”Host to bind to”) parser.add_argument(“–port”, type=int, default=8000, help=”Port to bind to”) args = parser.parse_args() print(f”Starting server at http://{args.host}:{args.port} — outputs dir: {OUTPUT_DIR}”) app.run(host=args.host, port=args.port, debug=True)