FIX: 11 bugs bảo mật/ổn định (static mount chặn dotfile, delete traversal, cleanup giữ clips serverFileId, upload whitelist, password strength, auth audio endpoints, pedalboard==0.9.19, vendor CDN local) + FEATURE: Carla bridge preview/export MIDI notes âm VSTi (POST /midi-render, /carla-play-notes, nút Preview VSTi/Export MIDI->Audio; pedalboard 0.9.19 raw MIDI bytes; SONICFORGE_STORAGE_DIR cô lập test storage)

This commit is contained in:
2026-08-10 18:46:54 +07:00
parent 67ad2b8e4b
commit 61cb4b846f
33 changed files with 1097 additions and 103 deletions
+6 -4
View File
@@ -226,8 +226,9 @@ class PythonRenderEngine:
total_needed = dur_samples
total_needed = max(total_needed, 1024)
silent = np.zeros((2, total_needed), dtype=np.float32)
board = Pedalboard([vst])
synth_buffer = board(silent, sample_rate=self.sample_rate, midi_messages=midi_messages)
# pedalboard >= 0.9: instrument KHÔNG vào Pedalboard container
synth_buffer = vst(midi_messages, sample_rate=self.sample_rate,
duration=total_needed / float(self.sample_rate), num_channels=2)
except Exception as e:
logger.warning(f"[RenderEngine] DecentSampler/Pianobook error: {e}")
synth_buffer = render_midi_events_to_audio(
@@ -266,8 +267,9 @@ class PythonRenderEngine:
total_needed = dur_samples
total_needed = max(total_needed, 1024)
silent = np.zeros((2, total_needed), dtype=np.float32)
board = Pedalboard([vst])
synth_buffer = board(silent, sample_rate=self.sample_rate, midi_messages=midi_messages)
# pedalboard >= 0.9: instrument KHÔNG vào Pedalboard container
synth_buffer = vst(midi_messages, sample_rate=self.sample_rate,
duration=total_needed / float(self.sample_rate), num_channels=2)
elif instrument_id and (instrument_id.startswith("sf_") or soundfont_id):
sf_path = _find_sf2_path(soundfont_id or instrument_id)
# 3-level fallback: selected SF → default SF → oscillator synth
+13 -12
View File
@@ -85,7 +85,7 @@ def ensure_pyfluidsynth():
if HAS_PEDALBOARD:
try:
from pedalboard import VST3Plugin, Pedalboard, Gain, MidiMessage
from pedalboard import VST3Plugin, Pedalboard, Gain
except Exception:
HAS_PEDALBOARD = False
@@ -383,22 +383,23 @@ class PluginManager:
if not HAS_PEDALBOARD:
return []
beat_duration_sec = 60.0 / max(30.0, bpm)
# pedalboard >= 0.9: MIDI messages là tuple (bytes, timestamp_seconds)
# (MidiMessage class đã bị bỏ). bytes là raw MIDI event:
# 0x9n note_on, 0x8n note_off, 0xB0 control_change, 0xC0 program_change
messages = []
if bank is not None:
messages.append(MidiMessage(control_change=0, value=bank, sample_offset=0))
messages.append((bytes([0xB0, 0, int(bank) & 0x7F]), 0.0))
if program is not None:
messages.append(MidiMessage(program_change=program, sample_offset=0))
messages.append((bytes([0xC0, int(program) & 0x7F]), 0.0))
for ev in midi_events:
note = ev.get("note", 60)
velocity = ev.get("velocity", 100)
start_beat = ev.get("start_beat", 0.0)
dur_beats = ev.get("duration_beats", 1.0)
note = int(ev.get("note", 60)) & 0x7F
velocity = max(0, min(127, int(ev.get("velocity", 100))))
start_beat = float(ev.get("start_beat", 0.0))
dur_beats = float(ev.get("duration_beats", 1.0))
start_sec = start_beat * beat_duration_sec
dur_sec = dur_beats * beat_duration_sec
sample_offset = int(start_sec * sr)
end_sample_offset = int((start_sec + dur_sec) * sr)
messages.append(MidiMessage(note_on=note, velocity=velocity, sample_offset=sample_offset))
messages.append(MidiMessage(note_off=note, velocity=0, sample_offset=end_sample_offset))
end_sec = (start_beat + dur_beats) * beat_duration_sec
messages.append((bytes([0x90, note, velocity]), start_sec))
messages.append((bytes([0x80, note, 0]), end_sec))
return messages
@staticmethod