FEAT: cài đặt các thư viện để chuẩn bị build exe trên window
This commit is contained in:
+86
-6
@@ -14193,6 +14193,12 @@ const App = () => {
|
||||
const [selectedSoundFontId, setSelectedSoundFontId] = useState(null);
|
||||
const [sfPresets, setSfPresets] = useState(null); // presets from SoundFont
|
||||
const [instrumentDropdownTrackId, setInstrumentDropdownTrackId] = useState(null);
|
||||
// Plugin Manager — VST scan (spec desktop 2026-08-08)
|
||||
const [vstScanOpen, setVstScanOpen] = useState(false);
|
||||
const [vstScanPath, setVstScanPath] = useState('/opt/daw_engine/vst3');
|
||||
const [vstScanning, setVstScanning] = useState(false);
|
||||
const [vstPlugins, setVstPlugins] = useState([]);
|
||||
const [vstScanError, setVstScanError] = useState(null);
|
||||
const [instrumentDropdownBtnRect, setInstrumentDropdownBtnRect] = useState(null);
|
||||
const [instrumentSearchQuery, setInstrumentSearchQuery] = useState('');
|
||||
const [sfPresetSearchQuery, setSfPresetSearchQuery] = useState('');
|
||||
@@ -14249,8 +14255,9 @@ const App = () => {
|
||||
"Tinkle Bell","Agogo","Steel Drums","Woodblock","Taiko Drum","Melodic Tom","Synth Drum","Reverse Cymbal",
|
||||
"Guitar Fret Noise","Breath Noise","Seashore","Bird Tweet","Telephone Ring","Helicopter","Applause","Gunshot"
|
||||
];
|
||||
const setTrackInstrumentWithProgram = (trackId, instrumentId, programNumber, displayName, bankNumber) => {
|
||||
const setTrackInstrumentWithProgram = (trackId, instrumentId, programNumber, displayName, bankNumber, vstMeta) => {
|
||||
const isSfInstrument = instrumentId && typeof instrumentId === 'string' && instrumentId.startsWith('sf_');
|
||||
const isVstInstrument = instrumentId && typeof instrumentId === 'string' && (instrumentId.startsWith('vst3_') || instrumentId.startsWith('au_') || (vstMeta && vstMeta.format));
|
||||
const sfBank = bankNumber !== undefined ? bankNumber : (isSfInstrument ? 0 : undefined);
|
||||
const sfProg = programNumber !== undefined ? programNumber : undefined;
|
||||
var mt = activeTracksRef.current || tracks;
|
||||
@@ -14264,6 +14271,12 @@ const App = () => {
|
||||
const synthEngine = hasInstrument ? {
|
||||
type: instrType,
|
||||
plugin_id: instrumentId,
|
||||
// spec desktop 2026-08-08: synth_engine đầy đủ {type, plugin_id, plugin_name, format, plugin_path}
|
||||
...(isVstInstrument ? {
|
||||
plugin_name: (vstMeta && vstMeta.plugin_name) || (displayName || instrumentId).replace(/\s*\((VST3|AU|AudioUnit)\)\s*$/, ''),
|
||||
format: (vstMeta && vstMeta.format) || (instrumentId.startsWith('au_') ? 'AudioUnit' : 'VST3'),
|
||||
plugin_path: (vstMeta && vstMeta.plugin_path) || ''
|
||||
} : {}),
|
||||
soundfont_bank: sfBank !== undefined ? sfBank : 0,
|
||||
soundfont_program: sfProg !== undefined ? sfProg : 0,
|
||||
soundfont_id: isSfInstrument ? instrumentId.replace('sf_', '') : ''
|
||||
@@ -15114,7 +15127,7 @@ const App = () => {
|
||||
setAiPrompt(newText);
|
||||
};
|
||||
|
||||
const setTrackInstrumentWithUndo = (trackId, instrumentId, displayName, bankNumber, programNumber) => {
|
||||
const setTrackInstrumentWithUndo = (trackId, instrumentId, displayName, bankNumber, programNumber, vstMeta) => {
|
||||
const track = activeTracks.find(t => t.id === trackId);
|
||||
if (!track) return;
|
||||
const oldInstrumentId = track.instrumentId;
|
||||
@@ -15136,7 +15149,7 @@ const App = () => {
|
||||
}
|
||||
};
|
||||
if (window.UndoRedoEngine) window.UndoRedoEngine.execute(entry);
|
||||
setTrackInstrumentWithProgram(trackId, instrumentId, programNumber, displayName, bankNumber);
|
||||
setTrackInstrumentWithProgram(trackId, instrumentId, programNumber, displayName, bankNumber, vstMeta);
|
||||
};
|
||||
|
||||
const createSectionWithUndo = (trackId, section) => {
|
||||
@@ -29370,11 +29383,78 @@ STRICT CONSTRAINTS:
|
||||
filteredInstruments.vst.length > 0 && /*#__PURE__*/React.createElement("div", { className: "text-[10px] text-zinc-500 px-3 py-1 mt-1 uppercase font-bold" }, "VST Instruments"),
|
||||
filteredInstruments.vst.map((v, i) => /*#__PURE__*/React.createElement("button", {
|
||||
key: "vstd_" + i,
|
||||
onClick: () => { setInstrumentDropdownTrackId(null); setInstrumentDropdownBtnRect(null); setTrackInstrumentWithUndo(instrumentDropdownTrackId, v.id, v.name || v.id); },
|
||||
onClick: () => { setInstrumentDropdownTrackId(null); setInstrumentDropdownBtnRect(null); setTrackInstrumentWithUndo(instrumentDropdownTrackId, v.id, v.name || v.id, undefined, undefined, { plugin_name: v.name || v.id, format: v.type || 'VST3', plugin_path: v.path || '' }); },
|
||||
className: "w-full text-left px-3 py-1.5 text-xs bg-zinc-800 hover:bg-violet-800 text-zinc-200 flex items-center justify-between"
|
||||
}, /*#__PURE__*/React.createElement("span", { className: "truncate" }, v.name || v.id), /*#__PURE__*/React.createElement("span", { className: "text-[10px] text-cyan-400 shrink-0 ml-1" }, v.type || "VST"))),
|
||||
(!filteredInstruments.soundfonts.length && !filteredInstruments.vst.length) && /*#__PURE__*/React.createElement("p", { className: "text-xs text-zinc-500 py-4 text-center" }, "Kh\u00f4ng t\u00ecm th\u1ea5y nh\u1ea1c c\u1ee5 n\u00e0o")
|
||||
)));
|
||||
/*#__PURE__*/React.createElement("button", {
|
||||
onClick: () => { setInstrumentDropdownBtnRect(null); setVstScanOpen(true); },
|
||||
className: "w-full text-left px-3 py-1.5 text-xs bg-purple-900/40 hover:bg-purple-800/60 text-purple-300 border-t border-zinc-700"
|
||||
}, "\uD83D\uDD0C Quét VST Directory\u2026"),
|
||||
(!filteredInstruments.soundfonts.length && !filteredInstruments.vst.length) && /*#__PURE__*/React.createElement("p", { className: "text-xs text-zinc-500 py-4 text-center" }, "Kh\u00f4ng t\u00ecm th\u1EA5y nh\u1EA1c c\u1EE5 n\u00E0o")
|
||||
))),
|
||||
/* Plugin Manager Modal — scan VST3/AU (spec desktop 2026-08-08) */
|
||||
vstScanOpen && /*#__PURE__*/React.createElement("div", {
|
||||
className: "fixed inset-0 bg-black/80 backdrop-blur-sm z-[120] flex items-center justify-center p-4",
|
||||
onMouseDown: e => e.stopPropagation(),
|
||||
onClick: e => e.stopPropagation()
|
||||
}, /*#__PURE__*/React.createElement("div", { className: "w-full max-w-2xl bg-[#1e1e24] border border-zinc-700 rounded-2xl p-5 shadow-2xl space-y-4 text-zinc-200" },
|
||||
/*#__PURE__*/React.createElement("div", { className: "flex items-center justify-between border-b border-zinc-700 pb-3" },
|
||||
/*#__PURE__*/React.createElement("h2", { className: "text-sm font-bold text-purple-400 flex items-center gap-2" }, "\uD83D\uDD0C Plugin Manager (VST3 / AU)"),
|
||||
/*#__PURE__*/React.createElement("button", { onClick: () => setVstScanOpen(false), className: "text-zinc-400 hover:text-white text-lg" }, "\u2715")
|
||||
),
|
||||
/*#__PURE__*/React.createElement("div", { className: "space-y-2 max-h-[50vh] overflow-y-auto" },
|
||||
vstPlugins.length === 0 && !vstScanning && /*#__PURE__*/React.createElement("p", { className: "text-xs text-zinc-500 text-center py-6" }, "Ch\u01B0a qu\u00E9t — nh\u1EADp \u0111\u01B0\u1EDDng d\u1EABn th\u01B0 m\u1EE5c ch\u1EE9a plugin (m\u1EB7c \u0111\u1ECBnh /opt/daw_engine/vst3) r\u1ED3i b\u1EA5m Scan."),
|
||||
vstPlugins.map((plg) => /*#__PURE__*/React.createElement("div", {
|
||||
key: plg.id,
|
||||
onClick: () => {
|
||||
setTrackInstrumentWithUndo(instrumentDropdownTrackId, plg.id, plg.name + " (" + plg.format + ")", undefined, undefined, { plugin_name: plg.name, format: plg.format, plugin_path: plg.path });
|
||||
setVstScanOpen(false);
|
||||
setVstPlugins([]);
|
||||
},
|
||||
className: "bg-[#22222a] hover:bg-[#2c2c36] border border-zinc-700/60 p-3 rounded-xl flex items-center justify-between cursor-pointer transition-all"
|
||||
}, /*#__PURE__*/React.createElement("div", { className: "flex items-center gap-3" },
|
||||
/*#__PURE__*/React.createElement("div", { className: "w-8 h-8 rounded-lg bg-purple-950/80 border border-purple-800 flex items-center justify-center text-purple-400 text-xs" }, "\uD83C\uDFB5"),
|
||||
/*#__PURE__*/React.createElement("div", null,
|
||||
/*#__PURE__*/React.createElement("div", { className: "text-xs font-bold text-white" }, plg.name),
|
||||
/*#__PURE__*/React.createElement("div", { className: "text-[10px] text-zinc-400 font-mono" }, plg.path)
|
||||
)
|
||||
), /*#__PURE__*/React.createElement("span", { className: "text-[10px] font-mono font-bold bg-purple-950 text-purple-300 border border-purple-800 px-2 py-0.5 rounded-full" }, plg.format)))
|
||||
),
|
||||
/*#__PURE__*/React.createElement("div", { className: "pt-3 border-t border-zinc-700/80 space-y-1" },
|
||||
/*#__PURE__*/React.createElement("label", { className: "block text-[10px] font-bold text-zinc-400 uppercase" }, "ADD VST DIRECTORY"),
|
||||
/*#__PURE__*/React.createElement("div", { className: "flex gap-2" },
|
||||
/*#__PURE__*/React.createElement("input", {
|
||||
type: "text", value: vstScanPath,
|
||||
onChange: e => setVstScanPath(e.target.value),
|
||||
className: "flex-1 bg-[#141418] border border-zinc-700 rounded-lg px-3 py-1.5 text-xs text-zinc-200 font-mono outline-none focus:border-purple-500"
|
||||
}),
|
||||
/*#__PURE__*/React.createElement("button", {
|
||||
onClick: async () => {
|
||||
setVstScanning(true);
|
||||
setVstScanError(null);
|
||||
try {
|
||||
const resp = await fetch('/api/v1/desktop/plugins/scan', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ custom_directories: [vstScanPath], scan_formats: ['VST3', 'AU'], force_rescan: true })
|
||||
});
|
||||
const data = await resp.json();
|
||||
if (data.status === 'success') setVstPlugins(data.plugins || []);
|
||||
else setVstScanError(data.detail || 'Scan thất bại');
|
||||
} catch (err) {
|
||||
setVstScanError('Lỗi kết nối: ' + err.message);
|
||||
} finally {
|
||||
setVstScanning(false);
|
||||
}
|
||||
},
|
||||
disabled: vstScanning,
|
||||
className: "px-5 py-1.5 bg-purple-600 hover:bg-purple-500 disabled:bg-zinc-700 text-white rounded-lg text-xs font-bold transition-all flex items-center gap-2"
|
||||
}, vstScanning ? "Scanning..." : "Scan")
|
||||
),
|
||||
vstScanError && /*#__PURE__*/React.createElement("p", { className: "text-[10px] text-red-400" }, vstScanError),
|
||||
/*#__PURE__*/React.createElement("p", { className: "text-[10px] text-zinc-600" }, "Windows: C:\\Program Files\\Common Files\\VST3 \u00B7 macOS: /Library/Audio/Plug-Ins/Components \u00B7 Linux: /opt/daw_engine/vst3, ~/.vst3")
|
||||
)
|
||||
))
|
||||
};
|
||||
const root = ReactDOM.createRoot(document.getElementById('root'));
|
||||
root.render(/*#__PURE__*/React.createElement(App, null));
|
||||
|
||||
Reference in New Issue
Block a user