Sửa lỗi trực tiếp trên window
This commit is contained in:
+106
-5
@@ -205,6 +205,37 @@ const shouldRouteCarla = (se) => !!(window.SonicCarlaMidi && window.SonicCarlaMi
|
||||
// Mỗi key (thường = track.id) một Audio element — note mới stop note cũ;
|
||||
// token chống stale (response cũ không đè response mới).
|
||||
const _nativeSfPreviews = {};
|
||||
// WASM fallback: backend pyfluidsynth render HONG tren ban standalone
|
||||
// (thieu libfluidsynth DLL) -> /soundfont-render 501 -> apiRequest throw ->
|
||||
// native path cam lang. Fallback choi note TRUC TIEP qua SonicSF (Web Audio
|
||||
// + libfluidsynth WASM da bundle) - am ra _gainNode -> masterBus.input.
|
||||
// window.__nativeSfOk: undefined (chua biet) | true (native OK) | false (dung WASM).
|
||||
const _sfWasmFallbackNote = (track, pitch, velocity, durationMs, startTime, key, token) => {
|
||||
try {
|
||||
const eng = track && track.synth_engine;
|
||||
const sfId = (eng && eng.soundfont_id) || (track && track.instrumentId && String(track.instrumentId).startsWith('sf_') ? track.instrumentId : null);
|
||||
if (!sfId) return;
|
||||
const bank = (eng && eng.soundfont_bank) || 0;
|
||||
const program = (eng && eng.soundfont_program) || (track && track.instrumentProgram !== undefined ? track.instrumentProgram : 0);
|
||||
const k = key || (track ? track.id : 'global');
|
||||
if (_nativeSfPreviews[k] && token != null && _nativeSfPreviews[k].token !== token) return; // stale
|
||||
const S = window.SonicSF;
|
||||
if (!S) return;
|
||||
const ch = (track && track.midiChannel != null) ? track.midiChannel : 0;
|
||||
const durMs = Math.max(200, durationMs || 500);
|
||||
const ctx = getAudioContext();
|
||||
const delaySec = startTime ? Math.max(0, (startTime - ctx.currentTime)) : 0;
|
||||
_nativeSfPreviews[k] = { wasm: { ch: ch, pitch: pitch }, token: token };
|
||||
const fire = function () {
|
||||
Promise.resolve(S.selectInstrument(ch, bank, program, sfId)).then(function () {
|
||||
S.playNote(pitch, velocity != null ? velocity : 0.8, durMs, undefined, eng ? undefined : program, null, ch, eng || undefined);
|
||||
}).catch(function () {
|
||||
try { S.playNote(pitch, velocity != null ? velocity : 0.8, durMs, undefined, eng ? undefined : program, null, ch, eng || undefined); } catch (e2) {}
|
||||
});
|
||||
};
|
||||
if (delaySec > 0) { setTimeout(fire, delaySec * 1000); } else { fire(); }
|
||||
} catch (e) { console.warn('[NativeSF] wasm fallback note error:', e); }
|
||||
};
|
||||
const playNativeSfNote = (track, pitch, velocity, durationMs, startTime, key) => {
|
||||
try {
|
||||
const eng = track && track.synth_engine;
|
||||
@@ -215,6 +246,11 @@ const playNativeSfNote = (track, pitch, velocity, durationMs, startTime, key) =>
|
||||
const k = key || (track ? track.id : 'global');
|
||||
const prev = _nativeSfPreviews[k];
|
||||
const token = (prev ? prev.token : 0) + 1;
|
||||
// Native hong da biet (501) -> di thang WASM fallback, khong goi API.
|
||||
if (window.__nativeSfOk === false) {
|
||||
_sfWasmFallbackNote(track, pitch, velocity, durationMs, startTime, k, token);
|
||||
return;
|
||||
}
|
||||
const durationSec = Math.max(0.2, (durationMs || 500) / 1000);
|
||||
window.SonicAPI.soundfontRender({
|
||||
soundfont_id: sfId,
|
||||
@@ -223,8 +259,13 @@ const playNativeSfNote = (track, pitch, velocity, durationMs, startTime, key) =>
|
||||
bpm: 120,
|
||||
notes: [{ pitch: pitch, start_beat: 0, duration_beats: durationSec * 2, velocity: velocity != null ? velocity : 0.8 }],
|
||||
}).then(function (res) {
|
||||
if (!res || !res.success || !res.url) return;
|
||||
if (!res || !res.success || !res.url) {
|
||||
window.__nativeSfOk = false;
|
||||
_sfWasmFallbackNote(track, pitch, velocity, durationMs, startTime, k, token);
|
||||
return;
|
||||
}
|
||||
if (_nativeSfPreviews[k] && _nativeSfPreviews[k].token !== token) return; // stale
|
||||
window.__nativeSfOk = true;
|
||||
const audio = new Audio(API_BASE_URL + res.url);
|
||||
_nativeSfPreviews[k] = { audio: audio, token: token };
|
||||
const ctx = getAudioContext();
|
||||
@@ -235,7 +276,10 @@ const playNativeSfNote = (track, pitch, velocity, durationMs, startTime, key) =>
|
||||
audio._sfStopTimer && clearTimeout(audio._sfStopTimer);
|
||||
audio._sfStopTimer = setTimeout(function () { try { audio.pause(); } catch (e) {} }, durationSec * 1000 + 400);
|
||||
}, delay);
|
||||
}).catch(function () {});
|
||||
}).catch(function () {
|
||||
window.__nativeSfOk = false;
|
||||
_sfWasmFallbackNote(track, pitch, velocity, durationMs, startTime, k, token);
|
||||
});
|
||||
} catch (e) { console.warn('[NativeSF] playNativeSfNote error:', e); }
|
||||
};
|
||||
const stopNativeSfNote = (key) => {
|
||||
@@ -245,6 +289,7 @@ const stopNativeSfNote = (key) => {
|
||||
if (!prev) return;
|
||||
prev.token++;
|
||||
try { if (prev.audio) { prev.audio.pause(); prev.audio.currentTime = 0; } } catch (e) {}
|
||||
try { if (prev.wasm && window.SonicSF) window.SonicSF.stopNote(prev.wasm.ch, prev.wasm.pitch); } catch (e) {}
|
||||
} catch (e) {}
|
||||
};
|
||||
const stopAllNativeSfNotes = () => {
|
||||
@@ -263,6 +308,10 @@ const scheduleNativeSfItem = (track, item, offsetTime, context, destNode, bpm, o
|
||||
if (!sfId) return;
|
||||
const notes = (item && item.notes) || [];
|
||||
if (!notes.length) return;
|
||||
if (window.__nativeSfOk === false) {
|
||||
scheduleNativeSfItemWasm(track, item, offsetTime, context, destNode, bpm, opts);
|
||||
return;
|
||||
}
|
||||
const secPerBeat = 60.0 / (parseInt(bpm) || 120);
|
||||
const baseOffsetSec = (opts && opts.baseOffsetSec) || 0;
|
||||
const itemStartAbs = baseOffsetSec + (item.startTime || 0);
|
||||
@@ -278,7 +327,12 @@ const scheduleNativeSfItem = (track, item, offsetTime, context, destNode, bpm, o
|
||||
bpm: parseFloat(bpm) || 120,
|
||||
notes: notes.map(function (n) { return { pitch: n.pitch || 60, start_beat: n.start_beat || 0, duration_beats: n.duration_beats || 1, velocity: n.velocity != null ? n.velocity : 0.8 }; }),
|
||||
}).then(function (res) {
|
||||
if (!res || !res.success || !res.url) return;
|
||||
if (!res || !res.success || !res.url) {
|
||||
window.__nativeSfOk = false;
|
||||
scheduleNativeSfItemWasm(track, item, offsetTime, context, destNode, bpm, opts);
|
||||
return;
|
||||
}
|
||||
window.__nativeSfOk = true;
|
||||
fetch(API_BASE_URL + res.url).then(function (r) { return r.arrayBuffer(); }).then(function (buf) {
|
||||
context.decodeAudioData(buf, function (audioBuf) {
|
||||
try {
|
||||
@@ -299,11 +353,58 @@ const scheduleNativeSfItem = (track, item, offsetTime, context, destNode, bpm, o
|
||||
if (opts && opts.sources && opts.sources.push) opts.sources.push(src);
|
||||
} catch (e) { console.warn('[NativeSF] schedule decode error:', e); }
|
||||
}, function () {});
|
||||
}).catch(function () {});
|
||||
}).catch(function () {});
|
||||
}).catch(function () {
|
||||
window.__nativeSfOk = false;
|
||||
scheduleNativeSfItemWasm(track, item, offsetTime, context, destNode, bpm, opts);
|
||||
});
|
||||
}).catch(function () {
|
||||
window.__nativeSfOk = false;
|
||||
scheduleNativeSfItemWasm(track, item, offsetTime, context, destNode, bpm, opts);
|
||||
});
|
||||
} catch (e) { console.warn('[NativeSF] scheduleNativeSfItem error:', e); }
|
||||
};
|
||||
|
||||
// WASM fallback cho item (backend 501): schedule TUNG NOTE qua SonicSF
|
||||
// (Web Audio) dung vi tri thoi gian - thay vi render 1 file WAV ca item.
|
||||
const scheduleNativeSfItemWasm = (track, item, offsetTime, context, destNode, bpm, opts) => {
|
||||
try {
|
||||
const eng = track && track.synth_engine;
|
||||
const sfId = eng && eng.soundfont_id;
|
||||
if (!sfId) return;
|
||||
const notes = (item && item.notes) || [];
|
||||
if (!notes.length) return;
|
||||
const S = window.SonicSF;
|
||||
if (!S) return;
|
||||
const secPerBeat = 60.0 / (parseInt(bpm) || 120);
|
||||
const baseOffsetSec = (opts && opts.baseOffsetSec) || 0;
|
||||
const itemStartAbs = baseOffsetSec + (item.startTime || 0);
|
||||
const now = context.currentTime;
|
||||
const ch = (track && track.midiChannel != null) ? track.midiChannel : 0;
|
||||
const bank = (eng && eng.soundfont_bank) || 0;
|
||||
const program = (eng && eng.soundfont_program) || 0;
|
||||
const fire = function () {
|
||||
if (opts && typeof opts.isActive === 'function' && !opts.isActive()) return;
|
||||
notes.forEach(function (n) {
|
||||
try {
|
||||
const noteStartSec = itemStartAbs + (n.start_beat || 0) * secPerBeat;
|
||||
const noteDurSec = (n.duration_beats || 1) * secPerBeat;
|
||||
const clipStart = Math.max(offsetTime, noteStartSec);
|
||||
var durMs = (noteStartSec + noteDurSec - clipStart) * 1000;
|
||||
if (opts && opts.limitSec) {
|
||||
const limitMs = (opts.limitSec - clipStart) * 1000;
|
||||
if (limitMs <= 0) return;
|
||||
durMs = Math.min(durMs, limitMs);
|
||||
}
|
||||
if (durMs <= 0) return;
|
||||
const startWall = now + Math.max(0, noteStartSec - offsetTime);
|
||||
S.playNote(n.pitch || 60, n.velocity != null ? n.velocity : 0.8, durMs, startWall, undefined, destNode || null, ch, eng);
|
||||
} catch (e) {}
|
||||
});
|
||||
};
|
||||
Promise.resolve(S.selectInstrument(ch, bank, program, sfId)).then(fire).catch(fire);
|
||||
} catch (e) { console.warn('[NativeSF] scheduleNativeSfItemWasm error:', e); }
|
||||
};
|
||||
|
||||
// Handle ?sfs=<encoded> from double-clicking a .sfs file (opens domain -> loads project)
|
||||
(function handleSfsDeepLink() {
|
||||
try {
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -120,6 +120,12 @@ window.SonicCarlaMidi = window.SonicCarlaMidi || {
|
||||
stopBridge: function () {
|
||||
var self = this;
|
||||
try { self.allNotesOff(); } catch (e) {}
|
||||
// Reset trạng thái Carla bridge — nếu không, sau unload các cờ stale
|
||||
// (__carlaRunning=true) khiến ensureCarlaForPlayback early-return và
|
||||
// GUI Carla KHÔNG mở lại được khi reload.
|
||||
window.__carlaRunning = false;
|
||||
window.__carlaOpening = false;
|
||||
window.__carlaNoteQueue = [];
|
||||
if (window.SonicAPI && window.SonicAPI.stopCarla) {
|
||||
return window.SonicAPI.stopCarla().catch(function () {});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user