fix(tcp): open VSTi GUI via bridge API on LAN browser; scale vol/pan ruler wheel by deltaY
This commit is contained in:
+39
-10
@@ -6482,10 +6482,21 @@ const loadVstToBridge = async (track) => {
|
||||
} catch (e) { console.warn('[Bridge] loadVstToBridge fail:', track.id, e); return false; }
|
||||
};
|
||||
const ensureAndOpenVstGui = async (trackId, instrumentId) => {
|
||||
if (!window.SonicMidiRouter || !window.SonicMidiRouter.isBridgeActive() || !window.NativeBridgeService) return;
|
||||
if (!instrumentId || (typeof instrumentId === 'string' && instrumentId.startsWith('sf_'))) return;
|
||||
if (!window.__bridgeLoadedChannels) window.__bridgeLoadedChannels = {};
|
||||
const bch = window.SonicMidiRouter.allocateChannel(trackId, false);
|
||||
const bch = (window.SonicMidiRouter && window.SonicMidiRouter.allocateChannel) ? window.SonicMidiRouter.allocateChannel(trackId, false) : 0;
|
||||
// LAN/standalone (browser không Tauri): NativeBridgeService chỉ log, không
|
||||
// invoke được open_vst_gui → nhờ engine đẩy LOAD+OPEN_GUI vào SHM qua route
|
||||
// /bridge/gui (E6). GUI hiện trên desktop máy chạy server.
|
||||
if (!window.SonicMidiRouter || !window.SonicMidiRouter.isBridgeActive() || !window.NativeBridgeService) {
|
||||
try {
|
||||
if (!window.SonicAPI || !window.SonicAPI.bridgeOpenGui) return;
|
||||
const r = await window.SonicAPI.bridgeOpenGui({ name: instrumentId, path: null, instrumentType: null, channel: bch });
|
||||
if (r && r.success) console.log('[Bridge] GUI open via API', instrumentId, 'ch', bch, r.path);
|
||||
else console.warn('[Bridge] GUI via API response:', r);
|
||||
} catch (e) { console.warn('[Bridge] GUI via API fail:', trackId, e); }
|
||||
return;
|
||||
}
|
||||
if (!window.__bridgeLoadedChannels[bch]) {
|
||||
const ok = await loadVstToBridge({ id: trackId, instrumentId });
|
||||
if (!ok) return;
|
||||
@@ -6505,6 +6516,20 @@ const openVstGuiRetry = async (instrumentId, bch, attempts) => {
|
||||
}
|
||||
return true;
|
||||
};
|
||||
// Wheel trên range input (Vol/Pan TCP): scale step theo deltaY — trackpad
|
||||
// smooth gửi deltaY nhỏ (~1-10px/sự kiện) nhưng rất nhiều sự kiện; wheel
|
||||
// notch gửi ~100-120px. Tích lũy theo key → trackpad lăn 100px = 1 nấc
|
||||
// (0.5dB vol / 5 pan), wheel notch giữ nguyên tốc độ cũ. deltaMode:
|
||||
// 0=px, 1=dòng (≈40px), 2=trang.
|
||||
const _wheelAcc = new Map();
|
||||
const wheelSteps = (key, deltaY, deltaMode, pxPerStep = 100) => {
|
||||
const norm = deltaMode === 1 ? deltaY * 40 : deltaMode === 2 ? deltaY * 100 : deltaY;
|
||||
// c dương = cuộn lên (deltaY<0) = tăng — đúng convention cũ (deltaY>0 → giảm)
|
||||
const c = (_wheelAcc.get(key) || 0) - norm;
|
||||
const steps = Math.trunc(c / pxPerStep);
|
||||
_wheelAcc.set(key, c - steps * pxPerStep);
|
||||
return steps;
|
||||
};
|
||||
// Module-level so both ProfileModal (open project) and App (auto-restore) can
|
||||
// warm the FluidSynth font cache for each track's instrument. This only loads
|
||||
// the soundfonts; the per-track channel re-selection happens at note time.
|
||||
@@ -30181,8 +30206,9 @@ STRICT CONSTRAINTS:
|
||||
onChange: e => updateTrackVolumeDb(track.id, parseFloat(e.target.value)),
|
||||
onWheel: e => {
|
||||
e.preventDefault();
|
||||
const step = e.deltaY > 0 ? -0.5 : 0.5;
|
||||
const nv = Math.max(-50, Math.min(7, (track.volumeDb ?? 0) + step));
|
||||
const steps = wheelSteps('vol:' + track.id, e.deltaY, e.deltaMode, 100);
|
||||
if (!steps) return;
|
||||
const nv = Math.max(-50, Math.min(7, (track.volumeDb ?? 0) + steps * 0.5));
|
||||
updateTrackVolumeDb(track.id, nv);
|
||||
},
|
||||
onDoubleClick: e => { e.stopPropagation(); updateTrackVolumeDb(track.id, 0); },
|
||||
@@ -30205,8 +30231,9 @@ STRICT CONSTRAINTS:
|
||||
onChange: e => updateTrackPan(track.id, parseInt(e.target.value)),
|
||||
onWheel: e => {
|
||||
e.preventDefault();
|
||||
const step = e.deltaY > 0 ? -5 : 5;
|
||||
const np = Math.max(-100, Math.min(100, (track.pan ?? 0) + step));
|
||||
const steps = wheelSteps('pan:' + track.id, e.deltaY, e.deltaMode, 100);
|
||||
if (!steps) return;
|
||||
const np = Math.max(-100, Math.min(100, (track.pan ?? 0) + steps * 5));
|
||||
updateTrackPan(track.id, np);
|
||||
},
|
||||
onDoubleClick: e => { e.stopPropagation(); updateTrackPan(track.id, 0); },
|
||||
@@ -30736,8 +30763,9 @@ STRICT CONSTRAINTS:
|
||||
onChange: e => updateTrackVolumeDb(vTrack.id, parseFloat(e.target.value)),
|
||||
onWheel: e => {
|
||||
e.preventDefault();
|
||||
const step = e.deltaY > 0 ? -0.5 : 0.5;
|
||||
const nv = Math.max(-50, Math.min(7, (vTrack.volumeDb ?? 0) + step));
|
||||
const steps = wheelSteps('vol:' + vTrack.id, e.deltaY, e.deltaMode, 100);
|
||||
if (!steps) return;
|
||||
const nv = Math.max(-50, Math.min(7, (vTrack.volumeDb ?? 0) + steps * 0.5));
|
||||
updateTrackVolumeDb(vTrack.id, nv);
|
||||
},
|
||||
onDoubleClick: e => { e.stopPropagation(); updateTrackVolumeDb(vTrack.id, 0); },
|
||||
@@ -30762,8 +30790,9 @@ STRICT CONSTRAINTS:
|
||||
onChange: e => updateTrackPan(vTrack.id, parseInt(e.target.value)),
|
||||
onWheel: e => {
|
||||
e.preventDefault();
|
||||
const step = e.deltaY > 0 ? -5 : 5;
|
||||
const np = Math.max(-100, Math.min(100, (vTrack.pan ?? 0) + step));
|
||||
const steps = wheelSteps('pan:' + vTrack.id, e.deltaY, e.deltaMode, 100);
|
||||
if (!steps) return;
|
||||
const np = Math.max(-100, Math.min(100, (vTrack.pan ?? 0) + steps * 5));
|
||||
updateTrackPan(vTrack.id, np);
|
||||
},
|
||||
onDoubleClick: e => { e.stopPropagation(); updateTrackPan(vTrack.id, 0); },
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -118,6 +118,8 @@ window.API_BASE_URL = (window.API_BASE_URL || window.location.origin).replace(/\
|
||||
bridgeStatus: () => apiRequest('/api/v1/plugins/bridge/status', { method: 'GET' }),
|
||||
bridgeLoad: (payload) => apiRequest('/api/v1/plugins/bridge/load', { method: 'POST', body: JSON.stringify(payload) }),
|
||||
bridgeLog: (lines = 100) => apiRequest(`/api/v1/plugins/bridge/log?lines=${lines}`, { method: 'GET' }),
|
||||
// E6: mở native GUI VSTi qua engine (browser LAN không Tauri) — GUI hiện trên máy chạy server
|
||||
bridgeOpenGui: (payload) => apiRequest('/api/v1/plugins/bridge/gui', { method: 'POST', body: JSON.stringify(payload) }),
|
||||
getAIPresets: () => apiRequest('/api/v1/ai/presets', { method: 'GET' }),
|
||||
saveAIPreset: (preset) => apiRequest('/api/v1/ai/presets', { method: 'POST', body: JSON.stringify(preset) }),
|
||||
deleteAIPreset: (presetId) => apiRequest(`/api/v1/ai/presets/${presetId}`, { method: 'DELETE' }),
|
||||
|
||||
Reference in New Issue
Block a user