Gap 7: master volume automation lane — render_engine automation.volume_db (dB interp -30..+3 sau fader truoc normalize), schema master.automation, UI AUTOM panel MasterStripConsole + realtime scheduling tren masterBus.output.gain (play/seek/stop), serialize/parse, test_65 (177 passed)
This commit is contained in:
@@ -63,6 +63,22 @@ def _find_default_sf2() -> str:
|
||||
return p
|
||||
return ""
|
||||
|
||||
def _apply_master_volume_automation(buf, sr, nodes):
|
||||
"""Gap 7: master volume automation lane (master.automation.volume_db).
|
||||
|
||||
nodes: [{time: giây, db}] — envelope tuyến tính dB, clamp -30..+3 dB như
|
||||
track automation (sub_tab_dsp). Áp TRÊN master_buffer (2, N) — trả copy."""
|
||||
nodes = [n for n in (nodes or []) if n.get("time") is not None and n.get("db") is not None]
|
||||
if not nodes:
|
||||
return buf
|
||||
nodes = sorted(nodes, key=lambda x: float(x["time"]))
|
||||
n_samples = buf.shape[1]
|
||||
times = np.array([float(n["time"]) for n in nodes])
|
||||
dbs = np.clip(np.array([float(n["db"]) for n in nodes]), -30.0, 3.0)
|
||||
sample_times = np.arange(n_samples) / sr
|
||||
interp = np.interp(sample_times, times, dbs, left=dbs[0], right=dbs[-1])
|
||||
return buf * (10.0 ** (interp / 20.0))
|
||||
|
||||
# ── Builtin custom FX (spec fx_chain_architecture §2 Step 2: Custom FX) ─────
|
||||
# Track FX chain slots: eq / eqpro / compressor / limiter / exciter / rebalance
|
||||
# (khớp tham số WebAudio track FX modules + EQ Pro bands) + legacy chorus/reverb
|
||||
@@ -907,6 +923,14 @@ class PythonRenderEngine:
|
||||
if vol_l:
|
||||
master_buffer *= 10 ** (vol_l / 20.0)
|
||||
|
||||
# Gap 7: master volume automation — envelope áp SAU fader, TRƯỚC
|
||||
# normalize (fader cuối; automation = lớp âm lượng trên fader).
|
||||
_auto = master.get("automation") or {}
|
||||
_auto_vol = _auto.get("volume_db") or []
|
||||
if _auto_vol:
|
||||
master_buffer = _apply_master_volume_automation(
|
||||
master_buffer, self.sample_rate, _auto_vol)
|
||||
|
||||
# Normalization to prevent clipping
|
||||
max_peak = np.max(np.abs(master_buffer))
|
||||
if max_peak > 1.0:
|
||||
|
||||
Reference in New Issue
Block a user