feat: VST FX rack per-track + masterbus render via native_bridge
This commit is contained in:
@@ -390,6 +390,39 @@ class PythonRenderEngine:
|
||||
except Exception as e:
|
||||
logger.warning("[RenderEngine] Fallback Reverb failed: %s", e)
|
||||
|
||||
# Track FX chain (VST3/builtin) — FX Rack per-track: render track
|
||||
# buffer qua native_bridge --render-fx. Ưu tiên fx_chain; fx_type
|
||||
# cũ (chorus/reverb scipy) giữ làm fallback khi không có fx_chain.
|
||||
track_fx_chain = track.get("vst_fx_chain") or []
|
||||
if track_fx_chain and not track.get("vst_fx_bypass"):
|
||||
if settings.RENDER_ENGINE == "bridge":
|
||||
try:
|
||||
from app.core.native_render import render_fx_chain
|
||||
tmp_in = os.path.join(
|
||||
settings.PROCESSED_DIR,
|
||||
f"trackfx_in_{os.getpid()}_{np.random.randint(100000)}.wav")
|
||||
tmp_out = tmp_in.replace("trackfx_in_", "trackfx_out_")
|
||||
try:
|
||||
sf.write(tmp_in, track_buffer.T, self.sample_rate, subtype="FLOAT")
|
||||
render_fx_chain(input_wav=tmp_in, fx_chain=track_fx_chain,
|
||||
sample_rate=self.sample_rate, out_path=tmp_out)
|
||||
data, _ = sf.read(tmp_out, dtype="float32", always_2d=True)
|
||||
if data.shape[1] >= 2:
|
||||
track_buffer = data.T[:2, :]
|
||||
else:
|
||||
track_buffer = np.repeat(data.T, 2, axis=0)
|
||||
finally:
|
||||
for f in (tmp_in, tmp_out):
|
||||
if os.path.exists(f):
|
||||
try:
|
||||
os.remove(f)
|
||||
except Exception:
|
||||
pass
|
||||
except Exception as e:
|
||||
logger.warning("[RenderEngine] Track FX chain skipped: %s", e)
|
||||
else:
|
||||
logger.warning("[RenderEngine] Track FX chain cần RENDER_ENGINE=bridge — bỏ qua")
|
||||
|
||||
# Process track volume
|
||||
gain_linear = 10 ** (vol_db / 20.0)
|
||||
processed_track = track_buffer * gain_linear
|
||||
@@ -427,6 +460,39 @@ class PythonRenderEngine:
|
||||
_cache={},
|
||||
)
|
||||
|
||||
# Masterbus FX chain (VST3 FX / builtin) — render qua native_bridge
|
||||
# --render-fx, rồi volume_db master; backward compatible (không có
|
||||
# master.fx_chain → giữ nguyên luồng cũ).
|
||||
master = main_session.get("master") or {}
|
||||
fx_chain = master.get("fx_chain") or []
|
||||
if fx_chain and not master.get("bypass"):
|
||||
if settings.RENDER_ENGINE == "bridge":
|
||||
try:
|
||||
from app.core.native_render import render_fx_chain
|
||||
tmp_in = os.path.join(settings.PROCESSED_DIR,
|
||||
f"master_in_{os.getpid()}_{np.random.randint(100000)}.wav")
|
||||
tmp_out = tmp_in.replace("master_in_", "master_out_")
|
||||
try:
|
||||
sf.write(tmp_in, master_buffer.T, self.sample_rate, subtype="FLOAT")
|
||||
render_fx_chain(input_wav=tmp_in, fx_chain=fx_chain,
|
||||
sample_rate=self.sample_rate, out_path=tmp_out)
|
||||
data, _ = sf.read(tmp_out, dtype="float32", always_2d=True)
|
||||
if data.shape[1] >= 2:
|
||||
master_buffer = data.T[:2, :]
|
||||
else:
|
||||
master_buffer = np.repeat(data.T, 2, axis=0)
|
||||
finally:
|
||||
for f in (tmp_in, tmp_out):
|
||||
if os.path.exists(f):
|
||||
try:
|
||||
os.remove(f)
|
||||
except Exception:
|
||||
pass
|
||||
except Exception as e:
|
||||
logger.warning("[RenderEngine] Masterbus FX skipped: %s", e)
|
||||
else:
|
||||
logger.warning("[RenderEngine] Masterbus FX cần RENDER_ENGINE=bridge — bỏ qua")
|
||||
|
||||
# Normalization to prevent clipping
|
||||
max_peak = np.max(np.abs(master_buffer))
|
||||
if max_peak > 1.0:
|
||||
|
||||
Reference in New Issue
Block a user