fix(playback): het note chong am echo o bass - KHONG huy note-off cu cung pitch (Bug 2 huy mui lam note cu khong bao gio tat); giu neu note-off cu bam truoc note-on moi, doi ve ngay truoc note-on neu overlap; sync 6 ban JS + index.html ?v=202608181900
This commit is contained in:
+22
-9
@@ -118,25 +118,38 @@ const ensureSonicInstrument = (ctx) => {
|
||||
// câm. Map pending theo key channel:pitch — schedule NOTE_OFF mới cùng key →
|
||||
// hủy NOTE_OFF cũ (retrigger đúng, note mới ngân đủ duration).
|
||||
const pendingNoteOffMap = {};
|
||||
const scheduleNoteOff = (key, fn, delayMs) => {
|
||||
// V18: note-off cũ cùng key KHÔNG bị hủy mù — hủy mù làm note cùng pitch lặp
|
||||
// (bass: root note chạy liên tục) không bao giờ nhận note-off -> kêu dài chồng
|
||||
// âm echo, không decay. So sánh thời điểm: note-off cũ bắn TRƯỚC note-on mới →
|
||||
// giữ nguyên (decay đúng hạn). Note-off cũ bắn SAU note-on mới (overlap — Bug 2
|
||||
// cũ) → dời về NGAY TRƯỚC note-on mới: note cũ decay sạch, note mới ngân đủ.
|
||||
const scheduleNoteOff = (key, fn, noteOnDelayMs, durMs) => {
|
||||
const offDelay = noteOnDelayMs + (durMs || 1000) + 30;
|
||||
const prev = pendingNoteOffMap[key];
|
||||
if (prev) { try { clearTimeout(prev); } catch (e) {} }
|
||||
if (prev && prev.offDelay > noteOnDelayMs) {
|
||||
try { clearTimeout(prev.timer); } catch (e) {}
|
||||
const t = setTimeout(function () {
|
||||
if (pendingNoteOffMap[key] && pendingNoteOffMap[key].timer === t) delete pendingNoteOffMap[key];
|
||||
prev.fn();
|
||||
}, Math.max(0, noteOnDelayMs - 5));
|
||||
}
|
||||
const timer = setTimeout(function () {
|
||||
if (pendingNoteOffMap[key] === timer) delete pendingNoteOffMap[key];
|
||||
if (pendingNoteOffMap[key] && pendingNoteOffMap[key].timer === timer) delete pendingNoteOffMap[key];
|
||||
fn();
|
||||
}, delayMs);
|
||||
pendingNoteOffMap[key] = timer;
|
||||
}, offDelay);
|
||||
pendingNoteOffMap[key] = { timer: timer, fn: fn, offDelay: offDelay };
|
||||
return timer;
|
||||
};
|
||||
const clearAllPendingNoteOffs = () => {
|
||||
Object.keys(pendingNoteOffMap).forEach(function (k) {
|
||||
try { clearTimeout(pendingNoteOffMap[k]); } catch (e) {}
|
||||
const entry = pendingNoteOffMap[k];
|
||||
if (entry) { try { clearTimeout(entry.timer); } catch (e) {} }
|
||||
delete pendingNoteOffMap[k];
|
||||
});
|
||||
};
|
||||
const fireCarlaNote = (ch, pitch, vel, delay, durMs) => {
|
||||
setTimeout(function () { window.SonicCarlaMidi.noteOn(ch, pitch, vel); }, delay);
|
||||
scheduleNoteOff('C:' + ch + ':' + pitch, function () { window.SonicCarlaMidi.noteOff(ch, pitch); }, delay + durMs + 30);
|
||||
scheduleNoteOff('C:' + ch + ':' + pitch, function () { window.SonicCarlaMidi.noteOff(ch, pitch); }, delay, durMs);
|
||||
};
|
||||
// ⚠️ FIX (Bug 2): Carla mở ASYNC lúc play (ensureCarlaForPlayback) — nốt gửi
|
||||
// trước khi OSC engine bind cổng bị mất → item câm dù keybed kêu. Nốt khi
|
||||
@@ -22681,7 +22694,7 @@ const App = () => {
|
||||
if (epoch !== bridgeNoteEpochRef.current) return;
|
||||
if (!guardPlay()) return;
|
||||
try { window.SonicMidiRouter.pushEvent({ cmd: 'NOTE_OFF', channel: trkId, pitch: pitch || 60, velocity: 0, percussion: isPerc }); } catch (e) {}
|
||||
}, delayMs + (durMs || 1000) + 30);
|
||||
}, delayMs, durMs || 1000);
|
||||
return;
|
||||
}
|
||||
// Native VSTi (standalone browser, bridge inactive) → midi-render thay vì
|
||||
@@ -23215,7 +23228,7 @@ const App = () => {
|
||||
const carlaCh = (synthEngine && synthEngine.midi_channel !== undefined) ? synthEngine.midi_channel : mainCh;
|
||||
const carlaPitch = note.pitch || 60;
|
||||
setTimeout(function () { window.SonicCarlaMidi.noteOn(carlaCh, carlaPitch, carlaVel); }, carlaDelay);
|
||||
scheduleNoteOff('C:' + carlaCh + ':' + carlaPitch, function () { window.SonicCarlaMidi.noteOff(carlaCh, carlaPitch); }, carlaDelay + durMs + 30);
|
||||
scheduleNoteOff('C:' + carlaCh + ':' + carlaPitch, function () { window.SonicCarlaMidi.noteOff(carlaCh, carlaPitch); }, carlaDelay, durMs);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user