fix(playback): het retrigger 'play lai roi tat' khi stop - stop ngay clip source chua phat (playbackState=scheduled) truoc fade, source dang keu giu lai ramp 200ms; sync 5 ban JS + index.html ?v=202608181835

This commit is contained in:
2026-08-18 18:31:32 +07:00
parent eb5a1483ca
commit 4ddaf1f26a
3 changed files with 13 additions and 2 deletions
+8
View File
@@ -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 {
+4 -1
View File
@@ -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).
+1 -1
View File
@@ -50,7 +50,7 @@
<script src="/static/js/services/midiExtractor.js?v=202607281052"></script>
<script src="/static/js/services/promptTemplateManager.js?v=202607281039"></script>
<script src="/static/js/services/undoRedoEngine.js?v=202607290941"></script>
<script src="/static/js/app.precompiled.js?v=202608181827" defer></script>
<script src="/static/js/app.precompiled.js?v=202608181835" defer></script>
<link rel="stylesheet" href="/static/css/styles.css?v=202607271016">
<style>
:root {