diff --git a/app/static/js/app.jsx b/app/static/js/app.jsx index 79fb854..6c055f2 100644 --- a/app/static/js/app.jsx +++ b/app/static/js/app.jsx @@ -23353,6 +23353,14 @@ const App = () => { activeSourcesRef.current = []; activeTrackNodesRef.current = {}; const fadedGains = []; + // V16: stop NGAY clip source CHƯA phát (playbackState='scheduled') — nếu + // chờ tới doHardStop (sau FADE_MS) chúng đã bắt đầu phát trong lúc fade → + // nghe như "play lại rồi tắt". Source đang kêu ('playing') giữ lại cho ramp. + try { + capturedSources.forEach(src => { + try { if (src.playbackState === 'scheduled') src.stop(); } catch (e) {} + }); + } catch (e) {} let bridgeGainNode = null; if (fade && ctx) { try { diff --git a/app/static/js/app.precompiled.js b/app/static/js/app.precompiled.js index 4470aee..6501343 100644 --- a/app/static/js/app.precompiled.js +++ b/app/static/js/app.precompiled.js @@ -1722,7 +1722,10 @@ bridgeNoteEpochRef.current++;try{clearAllPendingNoteOffs();}catch(e){}try{if(sub // xuống 0 trong FADE_MS rồi mới hard-stop — hết click, âm ngân mượt. // Loop restart/seek (fade=false) giữ stop tức thì như cũ (không fade). // Lưu ref trước khi clear để doHardStop trễ không đụng playback mới. -const ctx=getAudioContext();const stopEpoch=_nativePlayEpoch;const FADE_MS=200;const capturedSources=activeSourcesRef.current.slice();const capturedNodes=Object.values(activeTrackNodesRef.current);activeSourcesRef.current=[];activeTrackNodesRef.current={};const fadedGains=[];let bridgeGainNode=null;if(fade&&ctx){try{const now=ctx.currentTime;capturedNodes.forEach(n=>{if(n&&n.gainNode&&n.gainNode.gain){fadedGains.push({node:n.gainNode,prev:n.gainNode.gain.value});n.gainNode.gain.cancelScheduledValues(now);n.gainNode.gain.setValueAtTime(n.gainNode.gain.value,now);n.gainNode.gain.linearRampToValueAtTime(0.0001,now+FADE_MS/1000);}});if(window.BridgeAudioNode&&window.BridgeAudioNode.getOutputNode){const bg=window.BridgeAudioNode.getOutputNode();if(bg&&bg.gain){bridgeGainNode=bg;bg.gain.cancelScheduledValues(now);bg.gain.setValueAtTime(bg.gain.value,now);bg.gain.linearRampToValueAtTime(0.0001,now+FADE_MS/1000);}}}catch(e){console.warn('[Stop] fade setup error:',e);}}const doHardStop=()=>{try{const stale=_nativePlayEpoch!==stopEpoch;// play mới bắt đầu trong lúc fade +const ctx=getAudioContext();const stopEpoch=_nativePlayEpoch;const FADE_MS=200;const capturedSources=activeSourcesRef.current.slice();const capturedNodes=Object.values(activeTrackNodesRef.current);activeSourcesRef.current=[];activeTrackNodesRef.current={};const fadedGains=[];// V16: stop NGAY clip source CHƯA phát (playbackState='scheduled') — nếu +// chờ tới doHardStop (sau FADE_MS) chúng đã bắt đầu phát trong lúc fade → +// nghe như "play lại rồi tắt". Source đang kêu ('playing') giữ lại cho ramp. +try{capturedSources.forEach(src=>{try{if(src.playbackState==='scheduled')src.stop();}catch(e){}});}catch(e){}let bridgeGainNode=null;if(fade&&ctx){try{const now=ctx.currentTime;capturedNodes.forEach(n=>{if(n&&n.gainNode&&n.gainNode.gain){fadedGains.push({node:n.gainNode,prev:n.gainNode.gain.value});n.gainNode.gain.cancelScheduledValues(now);n.gainNode.gain.setValueAtTime(n.gainNode.gain.value,now);n.gainNode.gain.linearRampToValueAtTime(0.0001,now+FADE_MS/1000);}});if(window.BridgeAudioNode&&window.BridgeAudioNode.getOutputNode){const bg=window.BridgeAudioNode.getOutputNode();if(bg&&bg.gain){bridgeGainNode=bg;bg.gain.cancelScheduledValues(now);bg.gain.setValueAtTime(bg.gain.value,now);bg.gain.linearRampToValueAtTime(0.0001,now+FADE_MS/1000);}}}catch(e){console.warn('[Stop] fade setup error:',e);}}const doHardStop=()=>{try{const stale=_nativePlayEpoch!==stopEpoch;// play mới bắt đầu trong lúc fade capturedSources.forEach(src=>{try{src.stop();}catch(e){}});capturedNodes.forEach(n=>{if(n.fxStopFn){try{n.fxStopFn();}catch(e){}}});if(stale)return;// play mới đang chạy — không dừng bridge/SF của nó stopMidiCapture();stopAllNativeSfNotes();stopAllNativeVstNotes();// D2/D6: bridge active -> transport STOP (bridge flush toàn pitch, hết // âm ngân tức thì; A13 C++ flush note-off). diff --git a/app/templates/index.html b/app/templates/index.html index c1f7b09..3b7cef6 100644 --- a/app/templates/index.html +++ b/app/templates/index.html @@ -50,7 +50,7 @@ - +