V45: D17 seamless loop wrap + D18 stop solo note-off (Qin) + D18b/c guard + engine VST load fixes
- D17: wrap_info/wrap-skip, fx wrap xfade, playhead-derived scheduling - D18: solo stop -> NOTE_OFF all sounding timeline pitches + CC123/CC120 - D18b: track audible gain guard, tracksRef fallback - D18c: timelinePitchesRef per-track Set, kill at applyAllTrackMuteSolo - bridge ring _MAX 16, index v=202608290928 - plugins.py/vst_engine.py/fx_realtime.py/JuceFxEngine.cpp: VSTi load + Qin fixes (uncommitted 12:18)
This commit is contained in:
@@ -23,10 +23,7 @@ import threading
|
||||
import time
|
||||
import uuid
|
||||
|
||||
import numpy as np
|
||||
|
||||
from app.config import settings
|
||||
from app.core.native_render import find_fx_bridge_exe, find_juce_fx_bridge_exe
|
||||
|
||||
FXRT_MAGIC = 0x46585254
|
||||
FXRT_BLOCK = 256
|
||||
@@ -91,6 +88,7 @@ class FxRealtimeSession:
|
||||
"""Một session realtime: SHM + subprocess fx_vst_bridge + I/O block."""
|
||||
|
||||
def __init__(self, fx_chain, sample_rate, block_size=FXRT_BLOCK):
|
||||
import numpy as np
|
||||
from multiprocessing import shared_memory
|
||||
self.fx_chain = fx_chain or []
|
||||
self.sample_rate = int(sample_rate)
|
||||
@@ -163,6 +161,7 @@ class FxRealtimeSession:
|
||||
return out
|
||||
|
||||
def _spawn(self):
|
||||
from app.core.native_render import find_fx_bridge_exe, find_juce_fx_bridge_exe
|
||||
juce_exe = os.getenv("SF_JUCE_FX_BRIDGE_PATH", "").strip()
|
||||
# G3: mặc định dùng JUCE bridge (latency graph thật + processed samples);
|
||||
# fallback bridge cũ khi không có exe JUCE (regression an toàn).
|
||||
@@ -265,6 +264,7 @@ class FxRealtimeSession:
|
||||
"""Gom FXRT_IN_SLOTS frame vào pending, đủ 4 → publish atomic vào ring
|
||||
(ghi data toàn bộ slot trước, sau đó in_write += n 1 lần). Ring đầy khi
|
||||
publish → drop batch cũ nhất (giữ latency thấp)."""
|
||||
import numpy as np
|
||||
arr = np.frombuffer(interleaved, dtype=np.float32)
|
||||
if arr.size != self.block_size * 2:
|
||||
return
|
||||
@@ -333,6 +333,7 @@ class FxRealtimeSession:
|
||||
self.stats['flush'] += 1
|
||||
|
||||
def read_output(self):
|
||||
import numpy as np
|
||||
"""Drain output ring → list bytes (mỗi block 2048 bytes interleaved)."""
|
||||
out = []
|
||||
with self._lock:
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
# SonicForge Studio VST / VSTi Engine Service
|
||||
from __future__ import annotations
|
||||
import os
|
||||
import json
|
||||
import re
|
||||
import time as _time
|
||||
import numpy as np
|
||||
import functools
|
||||
import threading
|
||||
from ctypes import c_char_p
|
||||
@@ -52,6 +52,7 @@ def render_soundfont_midi_to_audio(midi_events: list, sf_path: str, bank: int =
|
||||
Xử lí đúng note CHỒNG nhau + đuôi release (event-stream noteon/noteoff).
|
||||
Trả stereo float32 (2, N). Raise RuntimeError nếu pyfluidsynth thiếu / SF
|
||||
không load được."""
|
||||
import numpy as np
|
||||
import fluidsynth as _fs
|
||||
settings = _fs.new_fluid_settings()
|
||||
_fs.fluid_settings_setnum(settings, b'synth.sample-rate', float(sr))
|
||||
@@ -112,6 +113,7 @@ def render_soundfont_midi_to_audio(midi_events: list, sf_path: str, bank: int =
|
||||
|
||||
@_render_locked
|
||||
def render_midi_events_to_audio(midi_events: list, sr: int = 44100, bpm: float = 120.0, instrument: str = 'synth') -> np.ndarray:
|
||||
import numpy as np
|
||||
beat_duration_sec = 60.0 / max(30.0, bpm)
|
||||
max_duration_sec = 2.0
|
||||
for event in midi_events:
|
||||
|
||||
Reference in New Issue
Block a user