V45.16: freeze playhead khi seek master FX active (het playhead chay truoc am ~128ms) v=202608311143
This commit is contained in:
+25
-3
@@ -309,6 +309,8 @@ let _dbgFirstAudiblePending = false;
|
||||
let _fxRtPlayheadSnapPending = false;
|
||||
let _fxRtFreezeTimer = null;
|
||||
let _fxRtFreezeTries = 0;
|
||||
let _fxRtSeekFreeze = false;
|
||||
let _fxRtSeekFreezeTimer = null;
|
||||
const _nativeTrackUrls = {};
|
||||
const _nativeTrackPending = {};
|
||||
// ── MIDI overlap cleanup + polyphony gain (spec midi_polyphony_loudness) ─
|
||||
@@ -21004,6 +21006,17 @@ const App = () => {
|
||||
if (fxRt && fxRt.active) {
|
||||
_fxRtPlayheadSnapPending = false;
|
||||
fxRtAnchorProcessed();
|
||||
// V45.16: seek/restart FX active — giữ playhead tại startOffset cho tới khi
|
||||
// worklet phát block đầu (fx_play_first). Trước đây playhead chạy theo
|
||||
// processedSamples trong lúc re-buffer FILL 24 (~128ms) → playhead trước
|
||||
// âm (Bug 1b). Fail-safe 1500ms: engine không phát (session fail) → thả.
|
||||
_fxRtSeekFreeze = true;
|
||||
if (_fxRtSeekFreezeTimer) { clearTimeout(_fxRtSeekFreezeTimer); }
|
||||
_fxRtSeekFreezeTimer = setTimeout(function () {
|
||||
_fxRtSeekFreeze = false;
|
||||
_fxRtSeekFreezeTimer = null;
|
||||
fxRtAnchorProcessed();
|
||||
}, 1500);
|
||||
return;
|
||||
}
|
||||
// V41: gate theo CHAIN (không chỉ active) — session FX warm (stop giữ warm,
|
||||
@@ -21034,6 +21047,13 @@ const App = () => {
|
||||
}, _estMs);
|
||||
};
|
||||
window.__fxRtSnapPlayhead = function () {
|
||||
// V45.16: hết seek-freeze — playhead bắt đầu từ startOffset tại mẫu nghe được.
|
||||
if (_fxRtSeekFreeze) {
|
||||
_fxRtSeekFreeze = false;
|
||||
if (_fxRtSeekFreezeTimer) { clearTimeout(_fxRtSeekFreezeTimer); _fxRtSeekFreezeTimer = null; }
|
||||
fxRtAnchorProcessed();
|
||||
return;
|
||||
}
|
||||
if (fxRt && fxRt.active && _fxRtPlayheadSnapPending) {
|
||||
_fxRtPlayheadSnapPending = false;
|
||||
startAudioTimeRef.current = getAudioContext().currentTime;
|
||||
@@ -24573,9 +24593,11 @@ const App = () => {
|
||||
const updatedTime = startOffsetTimeRef.current + elapsed;
|
||||
// G3: playhead display engine-derived khi FX active (wrap/loop trigger giu
|
||||
// wall-clock — transport truth).
|
||||
const _playheadSec = (fxRt && fxRt.active && typeof fxRt.processedSamples === 'number' && fxRt.processedAnchor != null)
|
||||
? Math.max(startOffsetTimeRef.current, startOffsetTimeRef.current + (fxRt.processedSamples - fxRt.processedAnchor - (fxRt.latencyTotal || 0)) / (context.sampleRate || 44100))
|
||||
: updatedTime;
|
||||
const _playheadSec = (_fxRtSeekFreeze && fxRt && fxRt.active)
|
||||
? startOffsetTimeRef.current
|
||||
: ((fxRt && fxRt.active && typeof fxRt.processedSamples === 'number' && fxRt.processedAnchor != null)
|
||||
? Math.max(startOffsetTimeRef.current, startOffsetTimeRef.current + (fxRt.processedSamples - fxRt.processedAnchor - (fxRt.latencyTotal || 0)) / (context.sampleRate || 44100))
|
||||
: updatedTime);
|
||||
|
||||
// Selection Loop - LOOP_MAKER.md + LOOP_EDITOR_2.md §4.2
|
||||
// If selection cleared by user, play linearly (don't loop)
|
||||
|
||||
Reference in New Issue
Block a user