FIX: Piano roll tab không xuất âm thanh qua mastering chain

This commit is contained in:
2026-08-05 12:10:50 +07:00
parent cfc114b9d7
commit 55d3464b1e
5 changed files with 64 additions and 13 deletions
+32 -4
View File
@@ -17734,16 +17734,22 @@ const App = () => {
// s rebuild loop + panic hy notes ch CÂM TOÀN CC exempt hoàn toàn
// (các fix setValueAtTime/NaN guard đã hết "state is bad" watchdog ch
// còn là lp cu cui cho main/audio-tab).
// PIANO_ROLL: watchdog CH rebuild khi output cha NaN (chain chết
// state-bad). KHÔNG rebuild khi im lng thưng (rests t nhiên gia các
// note false-positive = stopAllPlayback + reschedule = glitch).
const _anySubPlaying = subTabsRef.current.some(s => s.isPlaying);
const activeSub = subTabsRef.current.find(s => s.id === activeTabRef.current);
const isPianoRoll = activeSub && activeSub.type === 'PIANO_ROLL';
if (!isPianoRoll && (isPlaying || _anySubPlaying) && masterBus && masterBus.analyser && activeSourcesRef.current.length > 0) {
if ((isPlaying || _anySubPlaying) && masterBus && masterBus.analyser && (isPianoRoll || activeSourcesRef.current.length > 0)) {
try {
// "Đáng l đang có âm" quyết đnh watchdog có đưc rebuild không:
// - Main / sub-tab audio: source tht đang trong khong phát.
// - PIANO_ROLL: tab đang play (notes đã schedule) = đáng l có âm.
const ctxNow = getAudioContext().currentTime;
let anyPlaying = false;
if (_anySubPlaying) {
if (isPianoRoll) {
anyPlaying = _anySubPlaying;
} else if (_anySubPlaying) {
const _subs = subTabsRef.current || [];
for (let _si = 0; _si < _subs.length; _si++) {
const s = _subs[_si];
@@ -17760,7 +17766,18 @@ const App = () => {
masterBus.analyser.getByteTimeDomainData(d);
let pk = 0;
for (let i = 0; i < d.length; i++) { const v = Math.abs(d[i] - 128) / 128; if (v > pk) pk = v; }
if (pk < 0.001) {
// PIANO_ROLL: chain chết xut NaN getByteTimeDomainData đc NaN
// byte 0/128 pk CAO mù. Check float data (ch piano roll rests
// t nhiên thì KHÔNG rebuild).
let nanOut = false;
if (isPianoRoll) {
try {
const f = new Float32Array(128);
masterBus.analyser.getFloatTimeDomainData(f);
for (let i = 0; i < f.length; i++) { if (!isFinite(f[i])) { nanOut = true; break; } }
} catch (e) {}
}
if (pk < 0.001 || (isPianoRoll && nanOut)) {
masterSilenceFramesRef.current++;
const sinceRebuild = performance.now() - (lastMasterRebuildTimeRef.current || 0);
if (masterSilenceFramesRef.current > 45 && sinceRebuild > 3000) {
@@ -17772,7 +17789,18 @@ const App = () => {
stopAllPlayback();
Object.keys(activeTrackNodesRef.current).forEach(k => { const n = activeTrackNodesRef.current[k]; try { if (n && n.gainNode && n.gainNode.disconnect) n.gainNode.disconnect(); } catch (e) {} });
activeTrackNodesRef.current = {};
try { initMasterBus(getAudioContext()); } catch (e) { console.warn('[Recovery] initMasterBus error:', e); }
// Tháo chain cũ khi destination ri rebuild THT initMasterBus
// early-return khi masterBus còn tn ti recovery trưc đây là
// no-op chain "state is bad" b STUCK vĩnh vin.
try {
if (masterBus) {
try { if (masterBus.analyser) masterBus.analyser.disconnect(); } catch (e) {}
try { if (masterBus.output) masterBus.output.disconnect(); } catch (e) {}
try { if (masterBus.dryOutput) masterBus.dryOutput.disconnect(); } catch (e) {}
}
masterBus = null;
initMasterBus(getAudioContext());
} catch (e) { console.warn('[Recovery] initMasterBus error:', e); }
// Resume ĐÚNG chế đ play hin ti (main hoc sub-tab piano roll)
const curTab = activeTabRef.current;
const subSt = subTabsRef.current.find(s => s.id === curTab);