-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmain.py
More file actions
87 lines (72 loc) · 2.69 KB
/
Copy pathmain.py
File metadata and controls
87 lines (72 loc) · 2.69 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
from fastapi import FastAPI
from pydantic import BaseModel
import tempfile
import requests
import librosa
import numpy as np
import pyloudnorm as pyln
app = FastAPI()
class AnalyzeRequest(BaseModel):
audio_url: str
session_id: str | None = None
@app.get("/")
def root():
return {"status": "WubLabz Audio Engine Online"}
@app.post("/analyze-audio")
def analyze_audio(req: AnalyzeRequest):
if req.audio_url.startswith("file://"):
file_path = req.audio_url.replace("file://", "")
y, sr = librosa.load(file_path, sr=None, mono=False)
else:
r = requests.get(req.audio_url, timeout=30)
r.raise_for_status()
with tempfile.NamedTemporaryFile(suffix=".audio") as f:
f.write(r.content)
f.flush()
y, sr = librosa.load(f.name, sr=None, mono=False)
channels = 1 if y.ndim == 1 else y.shape[0]
mono = y if y.ndim == 1 else np.mean(y, axis=0)
duration = librosa.get_duration(y=mono, sr=sr)
tempo, _ = librosa.beat.beat_track(y=mono, sr=sr)
meter = pyln.Meter(sr)
lufs = meter.integrated_loudness(mono.astype(float))
rms = librosa.feature.rms(y=mono)[0]
dynamic_range = float(np.percentile(rms, 95) - np.percentile(rms, 10))
stereo_width = 0.0
if channels == 2:
left, right = y[0], y[1]
corr = np.corrcoef(left, right)[0, 1]
stereo_width = float(1 - abs(corr))
energy_score = min(100, max(0, int(np.mean(rms) * 1000)))
dynamics_score = min(100, max(0, int(dynamic_range * 1000)))
mix_quality_score = 80
commercial_potential_score = int((energy_score + mix_quality_score) / 2)
wub_score = int(
(
energy_score
+ dynamics_score
+ mix_quality_score
+ commercial_potential_score
)
/ 4
)
return {
"duration_seconds": round(float(duration), 2),
"sample_rate": int(sr),
"channel_count": int(channels),
"bpm": round(float(tempo), 2),
"musical_key": "Unknown",
"integrated_loudness_lufs": round(float(lufs), 2),
"dynamic_range": round(float(dynamic_range), 4),
"stereo_width": round(float(stereo_width), 2),
"wub_score": wub_score,
"mix_quality_score": mix_quality_score,
"energy_score": energy_score,
"dynamics_score": dynamics_score,
"commercial_potential_score": commercial_potential_score,
"mix_observations_text": "Initial spectral scan complete.",
"frequency_balance_text": "Frequency balance analysis available in MVP mode.",
"producer_recommendations_text": (
"Tighten low-end, check vocal presence, and compare against a reference mix."
),
}