FIX: VU meter giữ animation đúng trường độ âm khi ARM + giữ phím MIDI keyboard (heldMidiNotesRef, không decay khi note còn giữ)

This commit is contained in:
2026-08-08 13:12:49 +00:00
parent b490aa9951
commit 3618e3c591
4 changed files with 71 additions and 16 deletions
+39 -6
View File
@@ -14500,6 +14500,11 @@ const App = () => {
if (window.triggerMidiVuActivity) {
window.triggerMidiVuActivity(as.trackId, scaledVel);
}
// Giữ VU theo trường độ: tăng counter note đang giữ
// (tick giữ peak cho tới khi note-off)
try {
heldMidiNotesRef.current[as.trackId] = (heldMidiNotesRef.current[as.trackId] || 0) + 1;
} catch (err) { }
window.SonicSF.playNote(pitch, scaledVel, 60000, undefined, asProg, null, asCh, asSe);
});
}
@@ -14512,6 +14517,10 @@ const App = () => {
if (window.triggerMidiVuActivity) {
window.triggerMidiVuActivity(at.id, scaledVel);
}
// Giữ VU theo trường độ: tăng counter note đang giữ
try {
heldMidiNotesRef.current[at.id] = (heldMidiNotesRef.current[at.id] || 0) + 1;
} catch (err) { }
window.SonicSF.playNote(pitch, scaledVel, 60000, undefined, atProg, atDest, atCh, atSe);
});
}
@@ -14535,6 +14544,16 @@ const App = () => {
if (!st.synth_engine && st.midiChannel === undefined) return;
var stCh = assignTrackMidiChannel(st, stopTracks);
window.SonicSF.stopNote(stCh, pitch);
// Giảm counter note đang giữ — hết note → VU được phép decay/tắt
// (tick sẽ thấy counter = 0 và không còn giữ peak nữa)
try {
if (heldMidiNotesRef.current[st.id] !== undefined) {
heldMidiNotesRef.current[st.id] = Math.max(0, heldMidiNotesRef.current[st.id] - 1);
if (heldMidiNotesRef.current[st.id] === 0) {
delete heldMidiNotesRef.current[st.id];
}
}
} catch (err) { }
});
}
}
@@ -15494,6 +15513,11 @@ const App = () => {
}, [isPlaying]);
const midiVuActivityRef = useRef({});
// Đếm số note MIDI đang GIỮ per-track (ARM + MIDI keyboard live input).
// VU tick dùng ref này: còn note giữ → giữ peak (không decay) → VU animate
// ĐÚNG trường độ âm thanh (user bug: nhấn phím giữ âm còn kêu nhưng VU tắt
// sau ~0.5s vì decay 0.75/frame). Hết note (note-off) → mới decay/tắt.
const heldMidiNotesRef = useRef({});
const triggerMidiVuActivity = (trackId, velocity) => {
if (!trackId) return;
const velFactor = typeof velocity === 'number' ? (velocity > 1 ? velocity / 127 : velocity) : 0.8;
@@ -20595,6 +20619,9 @@ const App = () => {
// âm cũ — user 06:45: tắt âm MAIN items khi vào SECTION-TAB → VU main
// items phải tắt theo, không "diễn" tiếp).
try { midiVuActivityRef.current = {}; } catch (e) { }
// Clear luôn counter note đang giữ — nếu không, sau stop (âm đã dừng)
// tick vẫn thấy heldCnt > 0 → giữ peak → VU dính mãi (user bug 08:08).
try { heldMidiNotesRef.current = {}; } catch (e) { }
stopMidiCapture();
if (window.SonicSF) {
try { window.SonicSF.stopAll(); } catch (e) { console.warn('[Stop] stopAll error:', e); }
@@ -25856,12 +25883,18 @@ STRICT CONSTRAINTS:
// velocity thấp (âm SF nhỏ < 0.03) → VU không nhảy (user bug 07:10).
let midiPeak = isAudible ? (midiVuActivityRef.current[vuKey] || 0) : 0;
if (midiPeak > 0) {
// Decay 0.75 (~0.5s) — cân bằng: note đơn/velocity thấp hiển thị rõ
// NHƯNG tắt nhanh sau hết note (decay 0.85 ~1s quá lâu — user:
// "vẫn diễn animation" sau khi âm hết — bug 07:15).
midiVuActivityRef.current[vuKey] = midiPeak * 0.75;
if (midiVuActivityRef.current[vuKey] < 0.01) {
midiVuActivityRef.current[vuKey] = 0;
// ARM + MIDI keyboard: còn note đang GIỮ → giữ nguyên peak, KHÔNG
// decay → VU animate đúng trường độ âm thanh (user bug 08:08: âm còn
// kêu nhưng VU tắt sau ~0.5s vì decay 0.75/frame). Hết note → decay
// 0.75 (~0.5s) tắt nhanh như trước.
const heldCnt = heldMidiNotesRef.current[vuKey] || 0;
if (heldCnt > 0) {
// Giữ nguyên peak trong khi âm đang kêu (không decay)
} else {
midiVuActivityRef.current[vuKey] = midiPeak * 0.75;
if (midiVuActivityRef.current[vuKey] < 0.01) {
midiVuActivityRef.current[vuKey] = 0;
}
}
}
// ⚠️ KHÔNG gộp sfAudioPeak vào audioPeak: SF là 1 output CHUNG cho mọi
File diff suppressed because one or more lines are too long