FEAT: thêm nút bypass cho track strip để bypass không qua mastering panel

This commit is contained in:
2026-08-03 15:47:10 +07:00
parent 6f55d36085
commit a9da813cb1
28 changed files with 2076 additions and 233 deletions
+59 -39
View File
@@ -2,7 +2,7 @@
import os
import numpy as np
import functools
from ctypes import c_int, c_char_p, c_void_p
from ctypes import c_char_p
def midi_note_to_freq(note_number: int) -> float:
return 440.0 * (2.0 ** ((note_number - 69) / 12.0))
@@ -110,7 +110,12 @@ def get_plugin_manager(vst_dir="/opt/daw_engine/vst3", sf_dir="/opt/daw_engine/s
return _PLUGIN_MANAGER_INSTANCE
def load_soundfont_cached(path: str):
"""Return a cached FluidSynth instance for path, incrementing refcount."""
"""Return a cached low-level FluidSynth instance for path, incrementing refcount.
Uses the CFFI binding API (new_fluid_synth / fluid_synth_sfload) — the same
API render_engine relies on. The high-level `FluidSynth()`/`Synth()` classes
do not exist in this binding, so they are never used here.
"""
global _FLUID_CACHE
if not HAS_PYFLUIDSYNTH:
return None
@@ -119,10 +124,15 @@ def load_soundfont_cached(path: str):
_FLUID_CACHE[path] = (fl, ref + 1)
return fl
try:
import fluidsynth
fl = fluidsynth.FluidSynth(sample_rate=44100, gain=0.5)
font_id = fl.sfload(path)
fl.program_select(0, font_id, 0, 0)
import fluidsynth as _fs
_settings = _fs.new_fluid_settings()
_fs.fluid_settings_setnum(_settings, b'synth.sample-rate', 44100.0)
fl = _fs.new_fluid_synth(_settings)
font_id = _fs.fluid_synth_sfload(fl, path.encode("utf-8"), 1)
if font_id < 0:
_fs.delete_fluid_synth(fl)
return None
_fs.fluid_synth_program_select(fl, 0, font_id, 0, 0)
_FLUID_CACHE[path] = (fl, 1)
return fl
except Exception:
@@ -136,7 +146,8 @@ def release_soundfont(path: str):
fl, ref = _FLUID_CACHE[path]
if ref <= 1:
try:
fl.delete()
import fluidsynth as _fs
_fs.delete_fluid_synth(fl)
except Exception:
pass
del _FLUID_CACHE[path]
@@ -245,38 +256,47 @@ class PluginManager:
if base == sf_id or base == sf_id.replace("sf_", ""):
path = os.path.join(d, f)
try:
import fluidsynth
fl = fluidsynth.Synth()
fid = fl.sfload(path)
if fid < 0:
fl.delete()
continue
presets = []
_fl = fluidsynth._fl
_fl.fluid_synth_get_sfont_by_id.restype = c_void_p
_fl.fluid_preset_get_name.restype = c_char_p
_fl.fluid_sfont_get_preset.restype = c_void_p
sfont_ptr = _fl.fluid_synth_get_sfont_by_id(c_void_p(fl.synth), c_int(fid))
if sfont_ptr:
for bank in range(0, 2):
for prog_num in range(0, 128):
try:
preset = fluidsynth.fluid_sfont_get_preset(sfont_ptr, c_int(bank), c_int(prog_num))
except Exception:
break
if preset:
name_ptr = fluidsynth.fluid_preset_get_name(preset)
if name_ptr:
name_val = c_char_p(name_ptr).value
if name_val:
presets.append({
"bank": bank,
"program": prog_num,
"name": name_val.decode("utf-8", errors="replace")
})
fl.delete()
_SF_INSTRUMENTS_CACHE[sf_id] = presets[:256]
return presets[:256]
import fluidsynth as _fs
# Low-level CFFI API (same as render_engine); never use
# the high-level Synth() class that this binding lacks.
_settings = _fs.new_fluid_settings()
_synth = _fs.new_fluid_synth(_settings)
try:
fid = _fs.fluid_synth_sfload(_synth, path.encode("utf-8"), 1)
if fid < 0:
continue
sfont = _fs.fluid_synth_get_sfont_by_id(_synth, fid)
presets = []
if sfont:
for bank in range(0, 2):
for prog_num in range(0, 128):
try:
preset = _fs.fluid_sfont_get_preset(sfont, bank, prog_num)
except Exception:
break
if preset:
try:
name_ptr = _fs.fluid_preset_get_name(preset)
if name_ptr:
if hasattr(_fs, "ffi"):
raw = _fs.ffi.string(name_ptr)
else:
raw = c_char_p(name_ptr).value
if raw:
presets.append({
"bank": bank,
"program": prog_num,
"name": raw.decode("utf-8", errors="replace")
})
except Exception:
continue
_SF_INSTRUMENTS_CACHE[sf_id] = presets[:256]
return presets[:256]
finally:
try:
_fs.delete_fluid_synth(_synth)
except Exception:
pass
except Exception:
import traceback; traceback.print_exc()
_SF_INSTRUMENTS_CACHE[sf_id] = []