FIX: 3 bugs - soundfont engine fallback, media explorer icons/drag, carla midi playback routing

- render_engine: soundfont track không có plugin_id giờ vẫn dùng instrument sf2 thay vì rơi về wave synth
- fontawesome: sửa đường dẫn webfonts (bỏ ../) hết 404 icon
- media explorer: drag MIDI library items vào timeline tạo được midi item (sinh 6 MIDI loop mẫu + resolve drop file)
- app.jsx: 3 path gate window.SonicSF cho phép route playback qua SonicCarlaMidi
This commit is contained in:
2026-08-10 20:08:48 +07:00
parent 61cb4b846f
commit e89a594b7c
11 changed files with 21 additions and 12 deletions
+11 -4
View File
@@ -21306,13 +21306,13 @@ const App = () => {
// MIDI items playback
const midiItems = track.midiItems || [];
if ((track.type === 'MIDI' || midiItems.length > 0) && window.SonicSF) {
if ((track.type === 'MIDI' || midiItems.length > 0) && (window.SonicSF || (window.SonicCarlaMidi && window.SonicCarlaMidi.shouldRoutePlayback(track.synth_engine)))) {
// Preview cache: capture the soundfont (pre track-FX) for fast offline export
ensureMidiCapture(track, activeTrackNodesRef.current[track.id]);
if (window.SonicCarlaMidi && window.SonicCarlaMidi.shouldRoutePlayback(track.synth_engine)) ensureCarlaForPlayback(track.synth_engine);
var trkCh = assignTrackMidiChannel(track, allPlayTracks);
// Ensure instrument is loaded in FluidSynth
if (track.synth_engine && track.synth_engine.type === 'soundfont' && track.synth_engine.soundfont_id) {
if (window.SonicSF && track.synth_engine && track.synth_engine.type === 'soundfont' && track.synth_engine.soundfont_id) {
window.SonicSF.selectInstrument(trkCh, track.synth_engine.soundfont_bank || 0, track.synth_engine.soundfont_program || 0, track.synth_engine.soundfont_id);
}
const bpmVal = parseInt(bpm) || 120;
@@ -21464,7 +21464,7 @@ const App = () => {
// 2. Play MIDI items in subTrack
const subMidiItems = subTrack.midiItems || [];
if (window.SonicSF && subMidiItems.length > 0) {
if (subMidiItems.length > 0 && (window.SonicSF || (window.SonicCarlaMidi && window.SonicCarlaMidi.shouldRoutePlayback(subTrack.synth_engine)))) {
subMidiItems.forEach(item => {
const notes = item.notes || [];
notes.forEach(note => {
@@ -21592,7 +21592,7 @@ const App = () => {
// MIDI items playback
const midiItems = track.midiItems || [];
if ((track.type === 'MIDI' || midiItems.length > 0) && window.SonicSF) {
if ((track.type === 'MIDI' || midiItems.length > 0) && (window.SonicSF || (window.SonicCarlaMidi && window.SonicCarlaMidi.shouldRoutePlayback(track.synth_engine)))) {
var lcCh = assignTrackMidiChannel(track, tracks);
const bpmVal = parseInt(bpm) || 120;
const secondsPerBeat = 60.0 / bpmVal;
@@ -23905,6 +23905,13 @@ const App = () => {
const blob = await resp.blob();
return new File([blob], mef.name || mef.path.split(/[\\/]/).pop(), { type: blob.type || 'application/octet-stream' });
}
// Media Library samples: only metadata (name/kind) real bytes served
// from /static/midi (generated demo loops, see app/static/midi).
if (mef.kind === 'midi' && mef.name) {
const resp = await fetch(`${API_BASE_URL}/static/midi/${encodeURIComponent(mef.name)}`);
const blob = await resp.blob();
return new File([blob], mef.name, { type: 'audio/midi' });
}
} catch (e) {
showToast('Không thể nạp file từ Media Explorer: ' + e.message, 'error');
}