feat(piano-roll): vào tab lúc main play -> chỉ play MIDI notes track đang edit, các track khác mute

useEffect [activeTab] mới: activeTab là PIANO_ROLL và main/section đang play ->
stopAllPlayback + restart play CHỈ track piano roll tại vị trí tương ứng trong
item (mainPos - item.startTime). mainResumeRef giữ để quay lại main/section
resume đúng vị trí (nhánh resume cũ không đổi).
This commit is contained in:
2026-08-16 17:47:31 +07:00
parent e541d16132
commit cca58c4893
2 changed files with 37 additions and 9 deletions
+27 -4
View File
@@ -16943,6 +16943,29 @@ const App = () => {
console.log('[SectionTab] play CHỈ section items tại local', _pt.toFixed(2), '(secStart', _secStart.toFixed(2) + ')');
} catch (e) { console.warn('[SectionTab] restart error:', e); }
}
// Vào PIANO ROLL lúc MAIN/SECTION đang play → CHỈ play MIDI notes CỦA
// TRACK đang edit, TẮT âm MỌI track khác (user: vào piano roll phải play
// only midi notes đang active). Dừng main → play lại CHỈ track piano roll
// tại vị trí TƯƠNG ỨNG trong item (mainPos − item.startTime). Rời tab →
// nhánh resume (dưới) về main/section đúng vị trí (mainResumeRef vẫn giữ).
const _prTabNew = activeTab && activeTab.startsWith('midi_') ? subTabsRef.current.find(s => s.id === activeTab && s.type === 'PIANO_ROLL') : null;
if (_prTabNew && !_prTabNew.isPlaying && isPlaying) {
try {
const _ctx = getAudioContext();
const _mainPos = startOffsetTimeRef.current + (_ctx.currentTime - startAudioTimeRef.current);
const _itemInfo = getPianoRollItemInfo(_prTabNew);
const _prPos = _itemInfo ? Math.max(0, _mainPos - (_itemInfo.startTime || 0)) : (_prTabNew.currentTime || 0);
stopAllPlayback();
startOffsetTimeRef.current = _prPos;
startAudioTimeRef.current = _ctx.currentTime;
startBufferOffsetRef.current = _prPos * (_prTabNew.speed || 1.0);
schedulePianoRollMidi(_prTabNew, _prPos);
startSubTabPlayback(_prTabNew, _prPos);
setSubTabs(prev => prev.map(s => s.id === _prTabNew.id ? { ...s, isPlaying: true, currentTime: _prPos } : s));
animationFrameIdRef.current = requestAnimationFrame(updatePlayhead);
console.log('[PianoRollTab] play CHỈ track', _prTabNew.trackId, 'tại local', _prPos.toFixed(2), '(mainPos', _mainPos.toFixed(2), 'itemStart', _itemInfo ? _itemInfo.startTime.toFixed(2) : '?', ')');
} catch (e) { console.warn('[PianoRollTab] restart error:', e); }
}
const prevSub = subTabsRef.current.find(s => s.id === prevTab);
if (prevSub && prevSub.isPlaying) {
// Chuyển sang SUB-TAB KHÁC (piano roll khác/audio tab) → STOP âm tab
@@ -18950,10 +18973,10 @@ const App = () => {
const midiItem = (track.midiItems || []).find(m => m.id === midiItemId);
if (!midiItem) return;
// Clean stop playback ONLY khi KHÔNG đang play main — nếu main đang play,
// mở PIANO ROLL tab KHÔNG được dừng âm (user: dblclick mở tab lúc main
// play → âm main phải tiếp tục). Nhánh play sub-tab tự stopAllPlayback
// trước khi play nên không xung đột route.
// Main đang play → CHỈ lưu điểm resume; useEffect [activeTab] tự
// stopAllPlayback + play CHỈ track piano roll khi vào tab (user: piano roll
// play only midi notes đang active — mọi track khác mute). mainResumeRef
// giữ để quay lại MAIN/SECTION resume đúng vị trí.
if (isPlaying) {
// Lưu điểm resume: nếu user bấm Space trong piano roll (play piano roll
// → stopAllPlayback dừng main) → khi quay lại MAIN/SECTION resume main