D3+D4: export stage PCM16/24 + TPDF dither + noise shaping, resample 44.1/48/96k, normalize -1dBTP/-14LUFS, mono side/mid check; Export modal mastering options + /plugins/render options (test 9 case, 23 passed)
This commit is contained in:
+29
-1
@@ -607,6 +607,15 @@ async def download_soundfont_asset(sf_id: str):
|
||||
class RenderRequest(BaseModel):
|
||||
project_json: dict
|
||||
output_filename: Optional[str] = "render_output.wav"
|
||||
# D3 export options: bit-depth 16|24|32 (32 = float), SR 44100|48000|96000,
|
||||
# dither TPDF+noise shaping (PCM only), normalize target -1dBTP|-14LUFS,
|
||||
# mono-compat check (side/mid ratio).
|
||||
bit_depth: Optional[int] = 32
|
||||
sample_rate: Optional[int] = 0
|
||||
dither: Optional[bool] = False
|
||||
normalize: Optional[bool] = False
|
||||
normalize_target: Optional[str] = "-1dbtp"
|
||||
mono_check: Optional[bool] = False
|
||||
|
||||
|
||||
class FxGuiRequest(BaseModel):
|
||||
@@ -1180,7 +1189,14 @@ def render_project(
|
||||
safe_name += ".wav"
|
||||
output_path = os.path.join(settings.PROCESSED_DIR, safe_name)
|
||||
try:
|
||||
result_path = engine.render_project(req.project_json, output_path)
|
||||
result_path = engine.render_project(
|
||||
req.project_json, output_path,
|
||||
bit_depth=req.bit_depth or 32,
|
||||
out_sample_rate=req.sample_rate or 0,
|
||||
dither=bool(req.dither),
|
||||
normalize=bool(req.normalize),
|
||||
normalize_target=req.normalize_target or "-1dbtp",
|
||||
)
|
||||
# EBU R128 loudness + true peak (D1) — trả kèm response để mastering
|
||||
# panel hiển thị LUFS/dBTP ngay sau export mà không cần đọc lại file.
|
||||
data, _sr = sf.read(result_path, dtype="float32", always_2d=True)
|
||||
@@ -1194,6 +1210,18 @@ def render_project(
|
||||
_tp = loudness.true_peak_db(audio, _sr)
|
||||
resp["lufs"] = round(_lufs, 2) if np.isfinite(_lufs) else None
|
||||
resp["true_peak_db"] = round(_tp, 2) if np.isfinite(_tp) else None
|
||||
# D3: mono-compat — side/mid RMS ratio, cảnh báo khi sum mono mất nhiều.
|
||||
if req.mono_check and data.shape[1] >= 2:
|
||||
_ratio = loudness.mono_side_ratio(data.T)
|
||||
resp["mono_side_ratio"] = round(_ratio, 3)
|
||||
if _ratio > 0.85:
|
||||
resp["mono_warning"] = ("Side/Mid %.2f — mono sum mất gần hết "
|
||||
"âm thanh, kiểm tra phase!" % _ratio)
|
||||
elif _ratio > 0.5:
|
||||
resp["mono_warning"] = ("Side/Mid %.2f — âm thanh phát mono "
|
||||
"yếu rõ, kiểm tra phase" % _ratio)
|
||||
else:
|
||||
resp["mono_warning"] = None
|
||||
return resp
|
||||
except Exception as e:
|
||||
raise HTTPException(status_code=500, detail=f"Render failed: {str(e)}")
|
||||
|
||||
Reference in New Issue
Block a user